From d6b27ea202ff8888a05ca79609f863b33ee10a21 Mon Sep 17 00:00:00 2001 From: yummybomb <19238148+yummybomb@users.noreply.github.com> Date: Thu, 16 Jul 2026 17:14:53 +0000 Subject: [PATCH] Uppercase only the first rune of CLI error messages fang's default ErrorText transform title-cases the entire first word, which mangles errors that start with a path or identifier ("/tmp/out.gz already exists" rendered as "/Tmp/Out.gz already exists"). Replace the transform with one that uppercases only the first rune, preserving sentence casing for lowercase errors while leaving paths and flags untouched. --- cmd/root.go | 18 +++++++++++++++++- cmd/root_test.go | 15 +++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/cmd/root.go b/cmd/root.go index ac9f18bb..f75e636d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -9,6 +9,8 @@ import ( "runtime" "strings" "time" + "unicode" + "unicode/utf8" "github.com/charmbracelet/fang" "github.com/charmbracelet/lipgloss/v2" @@ -229,7 +231,12 @@ func Execute(m Metadata) { // remove margins so that it matches other pterm.error "style" // we should add them back later as it looks cleaner - errorTextStyle := styles.ErrorText.UnsetMargins() + // + // fang's default transform title-cases the first word, which + // mangles messages that start with a path or identifier + // ("/tmp/out.gz" becomes "/Tmp/Out.gz"); uppercase only the + // first rune instead. + errorTextStyle := styles.ErrorText.UnsetMargins().Transform(upperFirst) // Keep command errors on fang's error stream, normally stderr. This // gives curl-like commands a quiet stdout for response bodies and @@ -259,6 +266,15 @@ func Execute(m Metadata) { // isUsageError is a hack to detect usage errors. // See: https://github.com/spf13/cobra/pull/2266 // from github.com/charmbracelet/fang/help.go +// upperFirst uppercases the first rune of s, leaving the rest untouched. +func upperFirst(s string) string { + r, size := utf8.DecodeRuneInString(s) + if r == utf8.RuneError { + return s + } + return string(unicode.ToUpper(r)) + s[size:] +} + func isUsageError(err error) bool { s := err.Error() for _, prefix := range []string{ diff --git a/cmd/root_test.go b/cmd/root_test.go index 57cd1925..20ea8c08 100644 --- a/cmd/root_test.go +++ b/cmd/root_test.go @@ -94,3 +94,18 @@ func TestResolveProjectSelection(t *testing.T) { assert.Equal(t, "", resolveProjectSelection("")) }) } + +func TestUpperFirst(t *testing.T) { + tests := []struct { + in string + want string + }{ + {"unknown flag: --foo", "Unknown flag: --foo"}, + {"/tmp/out.jsonl.gz already exists", "/tmp/out.jsonl.gz already exists"}, + {"--start must be before --end", "--start must be before --end"}, + {"", ""}, + } + for _, test := range tests { + assert.Equal(t, test.want, upperFirst(test.in)) + } +}