From 1745f965f5678ad4c953f4e5d1faf3126fe7d35d Mon Sep 17 00:00:00 2001 From: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Date: Fri, 20 Mar 2026 01:11:21 -0700 Subject: [PATCH 1/2] fix: respect TERM=dumb and NO_COLOR for ANSI escape codes PrettyPrintErrorMessage unconditionally emitted ANSI escape codes, which broke output in terminals that don't support them (TERM=dumb) and tools that pipe the output. Skip ANSI formatting when TERM is set to "dumb" or when NO_COLOR is set, following the NO_COLOR convention (https://no-color.org/). Fixes #105 --- nilaway.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/nilaway.go b/nilaway.go index 2c282fe5..ebc5006f 100644 --- a/nilaway.go +++ b/nilaway.go @@ -18,6 +18,7 @@ package nilaway import ( "fmt" + "os" "regexp" "go.uber.org/nilaway/accumulation" @@ -57,8 +58,14 @@ var codeReferencePattern = regexp.MustCompile("\\`(.*?)\\`") var pathPattern = regexp.MustCompile(`"(.*?)"`) var nilabilityPattern = regexp.MustCompile(`([\(|^\t](?i)(found\s|must\sbe\s)(nilable|nonnil)[\)]?)`) -// PrettyPrintErrorMessage is used in error reporting to post process and pretty print the output with colors +// PrettyPrintErrorMessage is used in error reporting to post process and pretty print the output with colors. +// It respects the TERM environment variable and NO_COLOR convention, skipping ANSI codes when +// TERM is set to "dumb" or NO_COLOR is set. func PrettyPrintErrorMessage(msg string) string { + if os.Getenv("TERM") == "dumb" || os.Getenv("NO_COLOR") != "" { + return "error: " + msg + } + // TODO: below string parsing should not be required after is implemented errorStr := fmt.Sprintf("\x1b[%dm%s\x1b[0m", 31, "error: ") // red codeStr := fmt.Sprintf("\u001B[%dm%s\u001B[0m", 95, "`${1}`") // magenta From 234b23525841c480fa5b047498fcaaaea3846e3b Mon Sep 17 00:00:00 2001 From: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Date: Thu, 14 May 2026 17:06:41 -0700 Subject: [PATCH 2/2] fix: respect TERM=dumb and NO_COLOR in PrettyPrint default Move the env check from PrettyPrintErrorMessage into the PrettyPrint flag default in config/config.go per @yuxincs review. The -pretty-print flag continues to override the default via the existing override path in run. Closes #105 --- config/config.go | 18 ++++++++++++++++-- nilaway.go | 7 ------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/config/config.go b/config/config.go index e78f6184..2a5a546d 100644 --- a/config/config.go +++ b/config/config.go @@ -19,6 +19,7 @@ import ( "flag" "go/ast" "go/types" + "os" "reflect" "strings" @@ -26,6 +27,19 @@ import ( "golang.org/x/tools/go/analysis" ) +// defaultPrettyPrint returns the default for the PrettyPrint config option. +// It respects the NO_COLOR and TERM=dumb conventions when no -pretty-print flag is provided. +// https://no-color.org/ and POSIX terminal-capability conventions. +func defaultPrettyPrint() bool { + if os.Getenv("NO_COLOR") != "" { + return false + } + if os.Getenv("TERM") == "dumb" { + return false + } + return true +} + // Config is the struct that stores the user-configurable options for NilAway. type Config struct { // PrettyPrint indicates whether the error messages should be pretty printed. @@ -148,7 +162,7 @@ func newFlagSet() flag.FlagSet { // We do not keep the returned pointer to the flags because we will not use them directly here. // Instead, we will use the flags through the analyzer's Flags field later. - _ = fs.Bool(PrettyPrintFlag, true, "Pretty print the error messages") + _ = fs.Bool(PrettyPrintFlag, defaultPrettyPrint(), "Pretty print the error messages") _ = fs.Bool(GroupErrorMessagesFlag, true, "Group similar error messages") _ = fs.String(IncludePkgsFlag, "", "Comma-separated list of packages to analyze") _ = fs.String(ExcludePkgsFlag, "", "Comma-separated list of packages to exclude from analysis") @@ -164,7 +178,7 @@ func newFlagSet() flag.FlagSet { func run(pass *analysis.Pass) (any, error) { // Set up default values for the config. conf := &Config{ - PrettyPrint: true, + PrettyPrint: defaultPrettyPrint(), GroupErrorMessages: true, // If the user does not provide an include list, we give an empty package prefix to catch // all packages. diff --git a/nilaway.go b/nilaway.go index ebc5006f..68fd5a36 100644 --- a/nilaway.go +++ b/nilaway.go @@ -18,7 +18,6 @@ package nilaway import ( "fmt" - "os" "regexp" "go.uber.org/nilaway/accumulation" @@ -59,13 +58,7 @@ var pathPattern = regexp.MustCompile(`"(.*?)"`) var nilabilityPattern = regexp.MustCompile(`([\(|^\t](?i)(found\s|must\sbe\s)(nilable|nonnil)[\)]?)`) // PrettyPrintErrorMessage is used in error reporting to post process and pretty print the output with colors. -// It respects the TERM environment variable and NO_COLOR convention, skipping ANSI codes when -// TERM is set to "dumb" or NO_COLOR is set. func PrettyPrintErrorMessage(msg string) string { - if os.Getenv("TERM") == "dumb" || os.Getenv("NO_COLOR") != "" { - return "error: " + msg - } - // TODO: below string parsing should not be required after is implemented errorStr := fmt.Sprintf("\x1b[%dm%s\x1b[0m", 31, "error: ") // red codeStr := fmt.Sprintf("\u001B[%dm%s\u001B[0m", 95, "`${1}`") // magenta