From a36773b1db89e5a59c59d07cde1def0d28345ed7 Mon Sep 17 00:00:00 2001 From: nxtcoder17 Date: Tue, 17 Feb 2026 20:57:42 +0530 Subject: [PATCH] fix: attempts to fix ANSI sequences leaking because of termenv's background color check --- cmd/run/main.go | 16 ++++++++++++++++ go.mod | 4 ++-- go.sum | 4 ---- pkg/runfile/resolver/task.go | 33 +++++++++++---------------------- 4 files changed, 29 insertions(+), 28 deletions(-) diff --git a/cmd/run/main.go b/cmd/run/main.go index cedbd1d..72ed7d0 100644 --- a/cmd/run/main.go +++ b/cmd/run/main.go @@ -12,7 +12,9 @@ import ( "syscall" "time" + "github.com/muesli/termenv" "github.com/nxtcoder17/fastlog" + term "golang.org/x/term" "github.com/nxtcoder17/go.errors" "github.com/nxtcoder17/runfile/pkg/runfile" "github.com/urfave/cli/v3" @@ -37,6 +39,20 @@ func main() { Version = fmt.Sprintf("nightly | %s", time.Now().Format(time.RFC3339)) } + // Detect terminal theme early, before any subprocesses run. + // This prevents ANSI response sequences from leaking onto stdin. + // Uses stderr for probing since stdout may be piped/redirected. + // When no TTY is available, RUNFILE_THEME stays unset and highlighting is skipped. + if os.Getenv("RUNFILE_THEME") == "" { + if term.IsTerminal(int(os.Stderr.Fd())) { + theme := "dark" + if !termenv.NewOutput(os.Stderr).HasDarkBackground() { + theme = "light" + } + os.Setenv("RUNFILE_THEME", theme) + } + } + cmd := cli.Command{ Name: "run", Version: Version, diff --git a/go.mod b/go.mod index 6d48c33..f6081da 100644 --- a/go.mod +++ b/go.mod @@ -7,12 +7,14 @@ toolchain go1.24.2 require ( github.com/alecthomas/chroma/v2 v2.15.0 github.com/charmbracelet/lipgloss v1.0.0 + github.com/creack/pty v1.1.24 github.com/joho/godotenv v1.5.1 github.com/muesli/termenv v0.15.2 github.com/nxtcoder17/fastlog v0.0.0-20251112144402-5324a708e570 github.com/nxtcoder17/fwatcher v1.2.2-0.20250804201159-543ad31be162 github.com/nxtcoder17/go.errors v0.0.0-20251116060059-d31bd582d4c8 github.com/urfave/cli/v3 v3.0.0-beta1 + golang.org/x/sync v0.19.0 golang.org/x/term v0.39.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -20,7 +22,6 @@ require ( require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/charmbracelet/x/ansi v0.4.2 // indirect - github.com/creack/pty v1.1.24 // indirect github.com/dlclark/regexp2 v1.11.4 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect @@ -33,7 +34,6 @@ require ( github.com/samber/lo v1.47.0 // indirect github.com/samber/slog-common v0.18.1 // indirect github.com/samber/slog-zerolog/v2 v2.7.3 // indirect - golang.org/x/sync v0.19.0 // indirect golang.org/x/sys v0.40.0 // indirect golang.org/x/text v0.16.0 // indirect ) diff --git a/go.sum b/go.sum index b1c48df..355961c 100644 --- a/go.sum +++ b/go.sum @@ -68,12 +68,8 @@ golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= diff --git a/pkg/runfile/resolver/task.go b/pkg/runfile/resolver/task.go index 3a54ce9..d11a25f 100644 --- a/pkg/runfile/resolver/task.go +++ b/pkg/runfile/resolver/task.go @@ -14,7 +14,6 @@ import ( "github.com/alecthomas/chroma/v2/quick" "github.com/charmbracelet/lipgloss" - "github.com/muesli/termenv" "github.com/nxtcoder17/fwatcher/pkg/watcher" "github.com/nxtcoder17/go.errors" "github.com/nxtcoder17/runfile/pkg/executor" @@ -272,21 +271,10 @@ func CreateCommand(ctx context.Context, args CmdArgs) *exec.Cmd { return c } -var ( - darkThemeOnce sync.Once - darkThemeResult bool -) - -func isDarkTheme() bool { - darkThemeOnce.Do(func() { - darkThemeResult = termenv.NewOutput(os.Stdout).HasDarkBackground() - }) - return darkThemeResult -} - func printCommand(w *writer.LogWriter, prefix, lang, cmd string) { borderColor := "#4388cc" - if !isDarkTheme() { + switch os.Getenv("RUNFILE_THEME") { + case "light": borderColor = "#3d5485" } @@ -312,19 +300,20 @@ func printCommand(w *writer.LogWriter, prefix, lang, cmd string) { } hlCode := new(bytes.Buffer) - // choose colorschemes from `https://swapoff.org/chroma/playground/` - colorscheme := "catppuccin-macchiato" - if !isDarkTheme() { - colorscheme = "xcode" + cmdStr := strings.TrimSpace(cmd) + + switch os.Getenv("RUNFILE_THEME") { + case "dark": + quick.Highlight(hlCode, cmdStr, lang, "terminal16m", "catppuccin-macchiato") + case "light": + quick.Highlight(hlCode, cmdStr, lang, "terminal16m", "xcode") + default: + hlCode.WriteString(cmdStr) } // INFO: 2 for spaces around prefix longestLen := longestLineLen(cmd) + len(prefix) + 2 - cmdStr := strings.TrimSpace(cmd) - - quick.Highlight(hlCode, cmdStr, lang, "terminal16m", colorscheme) - if width > 0 && longestLen >= width-2 { s = s.Width(width - 2) }