diff options
Diffstat (limited to 'cmd/krino/undo.go')
| -rw-r--r-- | cmd/krino/undo.go | 67 |
1 files changed, 32 insertions, 35 deletions
diff --git a/cmd/krino/undo.go b/cmd/krino/undo.go index 5a7db4b..85b74b5 100644 --- a/cmd/krino/undo.go +++ b/cmd/krino/undo.go @@ -26,9 +26,9 @@ func init() { commands["undo"] = cmdUndo } // the most recent one otherwise. Since the newest run in the log can never // itself be marked Undone - that would require a still-later run to have // reversed it - "the most recent run" and "the most recent run that has not -// been undone" are the same run in every case, including the one this -// task's own test exercises: undoing an undo run a second time with no RUN -// argument targets that very undo run, which PlanUndo then refuses by name. +// been undone" are the same run in every case, including the case tested +// below: undoing an undo run a second time with no RUN argument targets +// that very undo run, which PlanUndo then refuses by name. // // Undo builds a plan like any other, shown and approved the same way (spec // §10) - reviewUndoDir/-Files/-PerFile below are undo's own counterpart to @@ -74,10 +74,9 @@ func cmdUndo(g *globals, args []string, stdout, stderr io.Writer) int { } // Installed here, before any paging or review, not just around - // ApplyUndo: Ruling 5 (Task 7) is that SIGTERM landing between - // keystrokes or during the pager needs the terminal restored, and that - // window starts as soon as this command might show something on a - // terminal. + // ApplyUndo: SIGTERM landing between keystrokes or during the pager + // needs the terminal restored, and that window starts as soon as this + // command might show something on a terminal. ctx, cancel := context.WithCancel(context.Background()) defer cancel() stopSignals := installSignalHandler(cancel) @@ -101,9 +100,9 @@ func cmdUndo(g *globals, args []string, stdout, stderr io.Writer) int { return 0 } runID = runs[0].ID - // The most recent run is itself an undo: continue it, by planning the - // run it undid again - reversals it completed are not offered twice - // (review M10). Naming an undo run explicitly is still refused. + // The most recent run is itself an undo: continue it, by planning + // the run it undid again - reversals it completed are not offered + // twice. Naming an undo run explicitly is still refused. if runs[0].UndoOf != "" { runID = runs[0].UndoOf } @@ -128,9 +127,8 @@ func cmdUndo(g *globals, args []string, stdout, stderr io.Writer) int { return 1 } - // Fix round 2026-09-12 (widened per the coordinator's follow-up - // ruling): an undo moves files just as an apply does, so it needs - // cmdSort's same per-directory guard (spec §11: a second krino on the + // An undo moves files just as an apply does, so it needs cmdSort's + // same per-directory guard (spec §11: a second krino on the // same directory waits for the lock, or fails immediately with -y), // held across the SAME window cmdSort holds its own lock across - the // plan display and the review, not just the apply. Failing before the @@ -165,8 +163,8 @@ func cmdUndo(g *globals, args []string, stdout, stderr io.Writer) int { var buf bytes.Buffer printUndoPlan(&buf, up) text := colourRefused(buf.String(), p) - // Ruling 6 (Task 7), carried over: the plan goes through tui.Page for - // -n as much as for -y and the interactive path. + // The plan goes through tui.Page for -n as much as for -y and the + // interactive path. if err := show(g, stdout, text); err != nil { fmt.Fprintf(stderr, "krino: %v\n", err) return 1 @@ -204,9 +202,9 @@ func cmdUndo(g *globals, args []string, stdout, stderr io.Writer) int { toApply, notReviewed := finalizeUndoPlan(up, approved, action) - // Ruling 2 (Task 7), carried over: journal.Open creates the state - // directory and the log file as a side effect of merely being called, - // so the session opens it only now, when something will actually be + // journal.Open creates the state directory and the log file as a side + // effect of merely being called, so the session opens it only now, + // when something will actually be // applied - never for -n (returned above), and not merely because -y // or a review session ran, unlike cmdSort, which opens before it knows // whether anything is actionable (a difference forced by cmdSort not @@ -281,18 +279,17 @@ func releaseUndoLocks(locks []*lock.Lock) []error { // finalizeUndoPlan builds the *engine.UndoPlan ApplyUndo actually runs, // preserving up.Files' own order: every refused file rides along unchanged // (ApplyUndo declines these itself, silently, exactly as it already does -// when handed the unfiltered plan - spec §10's refusal is not this task's -// to make noisier); every actionable file approved marks true rides along +// when handed the unfiltered plan - spec §10's refusal is not made any +// noisier here); every actionable file approved marks true rides along // unchanged too. A file the user said no to, or left unmarked when [d] or -// [q] cut a per-file review short, is not dropped - fix round 2026-09-12, -// item 2 of Task 8's review: spec §9 says a declined file is logged even -// though nothing happens to it, the same as the forward path already does, -// so it is kept with Declined set, which tells ApplyUndo to log its steps -// as declined rather than reverse them. +// [q] cut a per-file review short, is not dropped: spec §9 says a +// declined file is logged even though nothing happens to it, the same as +// the forward path already does, so it is kept with Declined set, which +// tells ApplyUndo to log its steps as declined rather than reverse them. // // After [w] (action 'w'), a reversible file the review never reached is // left out of the plan entirely, as review's [w] leaves a forward file -// unlogged, and counted in notReviewed (review cli F2). +// unlogged, and counted in notReviewed. func finalizeUndoPlan(up *engine.UndoPlan, approved map[int]bool, action rune) (plan *engine.UndoPlan, notReviewed int) { out := &engine.UndoPlan{Run: up.Run, Cleanup: up.Cleanup} for i, f := range up.Files { @@ -374,15 +371,15 @@ func reviewUndoFiles(in io.Reader, out io.Writer, files []engine.UndoFile, p pal // its reason and reverses nothing of it regardless of anything chosen here // - but it still gets its own [i/N] line, so the numbering accounts for // every file in the plan, not just the reversible ones. It behaves as -// review.go's reviewPerFile does (review cli F2): a no is recorded as false, -// each choice is echoed in red, [w] ends with 'w' leaving unreached files -// out of approved, and [q] ends with 'q'. +// review.go's reviewPerFile does: a no is recorded as false, each choice is +// echoed in red, [w] ends with 'w' leaving unreached files out of +// approved, and [q] ends with 'q'. func reviewUndoPerFile(in io.Reader, out io.Writer, files []engine.UndoFile, p palette) (approved map[int]bool, end rune, err error) { approved = map[int]bool{} yesRest := false for i, f := range files { // Heading and steps wrap past the action column, so a long name or - // path cannot pass for a step line (plan 11 review L4). + // path cannot pass for a step line. width := widthPolicy(out) fmt.Fprintln(out) for _, l := range wrapped("", fmt.Sprintf("[%d/%d] %s/%s", i+1, len(files), display(f.Dir), display(f.File)), 7+undoStepWidth+2, width, plainText) { @@ -468,11 +465,11 @@ const undoStepWidth = len("undo-displace") // one (a sibling directory not yet empty for undo-mkdir - spec §10's one // case where a step's own failure does not refuse its whole file), the // directory removed for undo-mkdir (no destination to show), the file being -// trashed for undo-copy (fix wave item 3: its Dst is deliberately empty - -// trash.Put only chooses the entry name at execution time - so this is the -// one action with no path to point an arrow at; before this fix the cell -// rendered as a bare "undo-copy → ", the plan's one row that said -// nothing about what it would do to the user's file), or an arrow to where +// trashed for undo-copy (its Dst is deliberately empty - trash.Put only +// chooses the entry name at execution time - so this is the one action +// with no path to point an arrow at; rendering it as a bare "undo-copy +// → " would be the plan's one row that says nothing about what it would do +// to the user's file), or an arrow to where // the step puts the file back, ~-abbreviated - undo has no single root the // way a sort plan does (one run can span several directories), so there is // no root-relative form to render here the way actionCell has. |
