Documentation
¶
Overview ¶
Package mutate is the single ULID-keyed mutation engine shared by the CLI and (later) the TUI, implementing the write contract from SPEC §6.1–6.3. Every write to tasks.txt goes through Apply: acquire the lock, re-read the file from disk, run the caller's mutation against the fresh Doc while recording before-images, append the undo transaction, then atomically write. Nothing else writes tasks.txt, so a concurrent `nt add` can never be clobbered by a stale in-memory snapshot.
Index ¶
- func Complete(d *task.Doc, rec *Recorder, t *task.Task, today string)
- func Today() string
- type DoctorReport
- type Engine
- func (e *Engine) Apply(op string, fn func(d *task.Doc, rec *Recorder) error) error
- func (e *Engine) Archive() (int, error)
- func (e *Engine) Doctor(apply bool) (DoctorReport, error)
- func (e *Engine) Read() (*task.Doc, error)
- func (e *Engine) RenameNote(src *note.Note, all []*note.Note, dest string) (newRel string, updated int, err error)
- func (e *Engine) Undo() (op string, did bool, err error)
- type Recorder
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Complete ¶
Complete marks a task done, spawning the next occurrence if it recurs (SPEC §9). Both the completion and the spawned task are recorded in the same undo transaction (rec captures the original's before-image and the spawn as an add), so a single `nt undo` reopens the original and removes the new one (SPEC §6.3). Must run inside an Engine.Apply closure.
Types ¶
type DoctorReport ¶
type DoctorReport struct {
DupIDsRemoved int // duplicate-ULID lines dropped
IDsAssigned int // task lines that lacked an id and got one
Actions []string // human-readable, one per fix
}
DoctorReport summarizes what Doctor found (and, unless dry-run, fixed).
func (DoctorReport) Issues ¶
func (r DoctorReport) Issues() int
Issues is the total number of problems found.
type Engine ¶
Engine owns the store and serializes all task-file writes.
func (*Engine) Apply ¶
Apply runs fn under the lock against a freshly-read Doc, journals the resulting transaction, and atomically writes the file. fn mutates the Doc and uses rec to record what it touched.
func (*Engine) Archive ¶
Archive moves completed tasks from tasks.txt to done.txt under the lock. It is an explicit housekeeping action and is intentionally not journaled — the cross-file move is the open question in SPEC §15, so `nt undo` does not revert it (the CLI says so). Returns the number of tasks moved.
func (*Engine) Doctor ¶
func (e *Engine) Doctor(apply bool) (DoctorReport, error)
Doctor reconciles tasks.txt after a git merge (or hand-editing): it drops duplicate-ULID lines that a `merge=union` merge can leave behind, and assigns ids to any task line missing one. Like Archive it runs under the lock and is intentionally NOT journaled — it's a repair, and git is the recovery path for a git-tracked store. With apply=false it reports without writing (dry-run).
Duplicate resolution keeps one line per id, preferring a completed line so a "done on one branch" state is never lost.
func (*Engine) Read ¶
Read returns the current parsed document (no lock; read-only callers such as list/search tolerate a consistent-at-read-time snapshot).
func (*Engine) RenameNote ¶
func (e *Engine) RenameNote(src *note.Note, all []*note.Note, dest string) (newRel string, updated int, err error)
RenameNote renames or moves a note file and rewrites every [[link]] to it across tasks.txt and notes/ (preserving each link's folder prefix, #fragment, and |alias). dest is a new name or a folder/path relative to notes/ (.md optional); a bare name keeps the note in its current folder. It refuses a destination whose basename collides with another note (which would make bare links ambiguous). A pure move (same basename) needs no link rewrite, since resolution is by path-suffix. Like Archive it is not a single undo transaction.
func (*Engine) Undo ¶
Undo reverts the most recent transaction. It pops the journal, applies each change's inverse (restoring before-images by ULID), writes the file, and appends a swapped transaction so a subsequent `nt undo` redoes the change (SPEC §6.3). The returned op label names what was undone; did is false when there is nothing to undo.
type Recorder ¶
type Recorder struct {
// contains filtered or unexported fields
}
Recorder accumulates the before/after images of touched tasks so a single undo transaction can reverse the whole mutation.