on main help sign in
refactor: move ansi escape function to the `ansiext` package
commit63efed61ace3200b9439e4a5995c0f91fc50deec authorAndrey Nering <andreynering@users.noreply.github.com> dateWed 23 Jul 2025, 14:36 (1 year ago) parente7f29ad
2 files changed+27−19
internal/ansiext/ansi.go+24 internal/tui/components/chat/messages/renderer.go+3−19
internal/ansiext/ansi.gonew file+24
@@ -0,0 +1,24 @@
1+package ansiext
2+
3+import (
4+ "strings"
5+
6+ "github.com/charmbracelet/x/ansi"
7+)
8+
9+// Escape replaces control characters with their Unicode Control Picture
10+// representations to ensure they are displayed correctly in the UI.
11+func Escape(content string) string {
12+ var sb strings.Builder
13+ for _, r := range content {
14+ switch {
15+ case r >= 0 && r <= 0x1f: // Control characters 0x00-0x1F
16+ sb.WriteRune('\u2400' + r)
17+ case r == ansi.DEL:
18+ sb.WriteRune('\u2421')
19+ default:
20+ sb.WriteRune(r)
21+ }
22+ }
23+ return sb.String()
24+}
internal/tui/components/chat/messages/renderer.go+3−19
@@ -6,6 +6,7 @@ import (
66 "strings"
77 "time"
88
9+ "github.com/charmbracelet/crush/internal/ansiext"
910 "github.com/charmbracelet/crush/internal/fsext"
1011 "github.com/charmbracelet/crush/internal/llm/agent"
1112 "github.com/charmbracelet/crush/internal/llm/tools"
@@ -702,7 +703,7 @@ func renderPlainContent(v *toolCallCmp, content string) string {
702703 if i >= responseContextHeight {
703704 break
704705 }
705− ln = escapeContent(ln)
706+ ln = ansiext.Escape(ln)
706707 ln = " " + ln // left padding
707708 if len(ln) > width {
708709 ln = v.fit(ln, width)
@@ -740,7 +741,7 @@ func renderCodeContent(v *toolCallCmp, path, content string, offset int) string
740741
741742 lines := strings.Split(truncated, "\n")
742743 for i, ln := range lines {
743− lines[i] = escapeContent(ln)
744+ lines[i] = ansiext.Escape(ln)
744745 }
745746
746747 highlighted, _ := highlight.SyntaxHighlight(strings.Join(lines, "\n"), path, t.BgBase)
@@ -816,20 +817,3 @@ func prettifyToolName(name string) string {
816817 return name
817818 }
818819}
819−
820−// escapeContent replaces control characters with their Unicode Control Picture
821−// representations to ensure they are displayed correctly in the UI.
822−func escapeContent(content string) string {
823− var sb strings.Builder
824− for _, r := range content {
825− switch {
826− case r >= 0 && r <= 0x1f: // Control characters 0x00-0x1F
827− sb.WriteRune('\u2400' + r)
828− case r == ansi.DEL:
829− sb.WriteRune('\u2421')
830− default:
831− sb.WriteRune(r)
832− }
833− }
834− return sb.String()
835−}