diff options
Diffstat (limited to 'cmd/krino/undo.go')
| -rw-r--r-- | cmd/krino/undo.go | 44 |
1 files changed, 22 insertions, 22 deletions
diff --git a/cmd/krino/undo.go b/cmd/krino/undo.go index c773f9a..cc65eea 100644 --- a/cmd/krino/undo.go +++ b/cmd/krino/undo.go @@ -61,6 +61,7 @@ func cmdUndo(g *globals, args []string, stdout, stderr io.Writer) int { printDiags(stderr, errs) return 2 } + p := palette{on: colourOn(g, stdout)} // Spec §8.4/§10: with neither -y nor -n, krino asks; a non-terminal // stdin would just hang, so it refuses instead - the same check @@ -140,10 +141,10 @@ func cmdUndo(g *globals, args []string, stdout, stderr io.Writer) int { }() } - fmt.Fprintf(stdout, "krino: undo %s\n", up.Run) + fmt.Fprintln(stdout, p.bold("krino: undo "+up.Run)) var buf bytes.Buffer printUndoPlan(&buf, up) - text := colourRefused(buf.String(), tui.Colour(stdout)) + 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. if err := tui.Page(stdout, text); err != nil { @@ -169,7 +170,7 @@ func cmdUndo(g *globals, args []string, stdout, stderr io.Writer) int { approved, action = approveAllUndo(up.Files), 'a' } else { var rerr error - approved, action, rerr = reviewUndoDir(stdout, up.Files) + approved, action, rerr = reviewUndoDir(stdout, up.Files, p) if rerr != nil { fmt.Fprintf(stderr, "krino: %v\n", rerr) return 1 @@ -214,7 +215,7 @@ func cmdUndo(g *globals, args []string, stdout, stderr io.Writer) int { fmt.Fprintf(stderr, "krino: %v\n", aerr) return 1 } - fmt.Fprintf(stdout, "%d applied · %d failed · %d declined\n", res.Applied, res.Failed, res.Declined) + fmt.Fprintln(stdout, outcome(p, res.Applied, res.Failed, res.Declined)) if ctx.Err() != nil { return 130 @@ -312,9 +313,10 @@ func finalizeUndoPlan(up *engine.UndoPlan, approved map[int]bool) *engine.UndoPl } // reviewUndoDir drives the interactive review over the real terminal, -// mirroring review.go's reviewDir for the forward path. -func reviewUndoDir(out io.Writer, files []engine.UndoFile) (map[int]bool, rune, error) { - return reviewUndoFiles(keyReader{stdin}, out, files) +// mirroring review.go's reviewDir for the forward path; p styles the +// prompts. +func reviewUndoDir(out io.Writer, files []engine.UndoFile, p palette) (map[int]bool, rune, error) { + return reviewUndoFiles(keyReader{stdin}, out, files, p) } // reviewUndoFiles is spec §10's approval flow for an undo plan: the @@ -331,8 +333,8 @@ func reviewUndoDir(out io.Writer, files []engine.UndoFile) (map[int]bool, rune, // name). action is always one of 'a', 'c', 's' or 'q', with the same [q] // folding rule reviewChains uses: a [c] session's own [q] becomes the same // top-level 'q', and approved is emptied to match. -func reviewUndoFiles(in io.Reader, out io.Writer, files []engine.UndoFile) (map[int]bool, rune, error) { - fmt.Fprint(out, "\n[a] apply all [c] choose per file [s] skip [q] quit\n") +func reviewUndoFiles(in io.Reader, out io.Writer, files []engine.UndoFile, p palette) (map[int]bool, rune, error) { + fmt.Fprint(out, "\n"+p.keys("[a] apply all [c] choose per file [s] skip [q] quit")+"\n") for { key, err := readKey(in) if err != nil { @@ -346,7 +348,7 @@ func reviewUndoFiles(in io.Reader, out io.Writer, files []engine.UndoFile) (map[ case 'q': return map[int]bool{}, 'q', nil case 'c': - approved, quit, err := reviewUndoPerFile(in, out, files) + approved, quit, err := reviewUndoPerFile(in, out, files, p) if err != nil { return nil, 0, err } @@ -365,7 +367,7 @@ func reviewUndoFiles(in io.Reader, out io.Writer, files []engine.UndoFile) (map[ // 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. -func reviewUndoPerFile(in io.Reader, out io.Writer, files []engine.UndoFile) (approved map[int]bool, quit bool, err error) { +func reviewUndoPerFile(in io.Reader, out io.Writer, files []engine.UndoFile, p palette) (approved map[int]bool, quit bool, err error) { approved = map[int]bool{} yesRest := false for i, f := range files { @@ -382,7 +384,7 @@ func reviewUndoPerFile(in io.Reader, out io.Writer, files []engine.UndoFile) (ap continue } - fmt.Fprint(out, " [y] yes [n] no [a] yes to this and all remaining [d] done, apply chosen so far [q] quit, apply nothing\n") + fmt.Fprint(out, " "+p.keys("[y] yes [n] no [a] yes to this and all remaining [d] done, apply chosen so far [q] quit, apply nothing")+"\n") for { key, kerr := readKey(in) if kerr != nil { @@ -520,16 +522,14 @@ func printUndoTable(w io.Writer, files []engine.UndoFile) { } } -// colourRefused highlights "refused:" in the terminal's own ANSI red (bold, -// slot 1 - never hex), the undo counterpart of sort.go's -// colourDeletePermanently: the one thing an undo plan singles out for -// attention is the file or step nothing will be reversed for. Same -// no-op-when-plain guarantee: with colour false this never touches the -// text, which is what keeps every escape byte out of a plan piped to a -// file or read by another tool. -func colourRefused(text string, colour bool) string { - if !colour { +// colourRefused styles every "refused:" in an undo plan bold red (spec +// §8.2): the one thing an undo plan singles out is the file or step nothing +// will be reversed for. With the plain palette the text is untouched, which +// keeps every escape byte out of a plan piped to a file or read by another +// tool. +func colourRefused(text string, p palette) string { + if !p.on { return text } - return strings.ReplaceAll(text, "refused:", "\x1b[1;31mrefused:\x1b[0m") + return strings.ReplaceAll(text, "refused:", p.alarm("refused:")) } |
