From b3fc15d3ae9c0c200e5bde7303e5d3e8e6a55912 Mon Sep 17 00:00:00 2001 From: ruinivist Date: Sat, 21 Mar 2026 06:48:23 +0000 Subject: [PATCH] feat: NO_COLOR env to not use ansi colors in miro --- cmd/root_test.go | 5 ++- internal/output/output.go | 14 +++++--- internal/output/output_test.go | 58 ++++++++++++++++++++++++++++++++++ internal/output/termstyle.go | 2 +- 4 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 internal/output/output_test.go diff --git a/cmd/root_test.go b/cmd/root_test.go index a5c58cb..281569f 100644 --- a/cmd/root_test.go +++ b/cmd/root_test.go @@ -7,8 +7,6 @@ import ( "path/filepath" "strings" "testing" - - "miro/internal/output" ) func TestRunShowsHelpWhenNoArgs(t *testing.T) { @@ -551,6 +549,7 @@ func TestRunUnknownCommand(t *testing.T) { func captureOutput(t *testing.T, fn func()) (string, string) { t.Helper() + t.Setenv("NO_COLOR", "1") stdoutReader, stdoutWriter, err := os.Pipe() if err != nil { @@ -593,7 +592,7 @@ func captureOutput(t *testing.T, fn func()) (string, string) { } func prefixed(msg string) string { - return output.Format(msg) + return "miro › " + msg } func writeFile(t *testing.T, path, content string) { diff --git a/internal/output/output.go b/internal/output/output.go index 0b852e8..03b05db 100644 --- a/internal/output/output.go +++ b/internal/output/output.go @@ -21,9 +21,6 @@ var ( pass: 0x7bf1a8, fail: 0xff8fa3, } - - chevron = NewStyle().FG(palette.chevronTeal).Bold().Italic().Apply("›") - prefix = NewStyle().FG(palette.miroGreen).Bold().Italic().Apply("miro") + " " + chevron + " " ) func label(text string, color uint32) string { @@ -42,10 +39,19 @@ func LabelInfo(text string) string { return label(text, palette.info) } +func noColor() bool { + return os.Getenv("NO_COLOR") != "" +} + +func prefix() string { + chevron := NewStyle().FG(palette.chevronTeal).Bold().Italic().Apply("›") + return NewStyle().FG(palette.miroGreen).Bold().Italic().Apply("miro") + " " + chevron + " " +} + func Format(msg string) string { body := strings.TrimRight(msg, "\n") suffix := msg[len(body):] - return prefix + body + suffix + return prefix() + body + suffix } func Println(msg string) { diff --git a/internal/output/output_test.go b/internal/output/output_test.go new file mode 100644 index 0000000..dec5f31 --- /dev/null +++ b/internal/output/output_test.go @@ -0,0 +1,58 @@ +package output + +import ( + "os" + "strings" + "testing" +) + +func TestFormatIncludesANSIByDefault(t *testing.T) { + t.Setenv("NO_COLOR", "") + + got := Format("hello\n") + if !strings.Contains(got, "\x1b[") { + t.Fatalf("Format() = %q, want ANSI styling", got) + } + if !strings.Contains(got, "hello\n") { + t.Fatalf("Format() = %q, want message body", got) + } +} + +func TestFormatPlainWhenNoColorSet(t *testing.T) { + t.Setenv("NO_COLOR", "1") + + if got := Format("hello\n"); got != "miro › hello\n" { + t.Fatalf("Format() = %q, want %q", got, "miro › hello\n") + } +} + +func TestLabelsPlainWhenNoColorSet(t *testing.T) { + t.Setenv("NO_COLOR", "1") + + if got := LabelInfo("RUN"); got != "RUN" { + t.Fatalf("LabelInfo() = %q, want %q", got, "RUN") + } + if got := LabelPass("PASS"); got != "PASS" { + t.Fatalf("LabelPass() = %q, want %q", got, "PASS") + } + if got := LabelFail("FAIL"); got != "FAIL" { + t.Fatalf("LabelFail() = %q, want %q", got, "FAIL") + } +} + +func TestFormatReadsNoColorAtRuntime(t *testing.T) { + t.Setenv("NO_COLOR", "") + + styled := Format("hello\n") + if err := os.Setenv("NO_COLOR", "1"); err != nil { + t.Fatalf("Setenv() error = %v", err) + } + + plain := Format("hello\n") + if !strings.Contains(styled, "\x1b[") { + t.Fatalf("styled Format() = %q, want ANSI styling", styled) + } + if plain != "miro › hello\n" { + t.Fatalf("plain Format() = %q, want %q", plain, "miro › hello\n") + } +} diff --git a/internal/output/termstyle.go b/internal/output/termstyle.go index 4538fe2..5822780 100644 --- a/internal/output/termstyle.go +++ b/internal/output/termstyle.go @@ -40,7 +40,7 @@ func (s Style) BG(rgb uint32) Style { } func (s Style) Apply(text string) string { - if !s.bold && !s.italic && s.fg == nil && s.bg == nil { + if noColor() || (!s.bold && !s.italic && s.fg == nil && s.bg == nil) { return text }