on main help sign in
fix(tui): escape ANSI escape sequences and control characters in tool

call content This would ensure that the content is displayed correctly in the terminal, without any unintended formatting or control characters or escape sequences. It will also style the escaped content for display in the terminal, making it more readable.

commit49059f8ddb8c9270484c082e1d5a20c50df1af39 authorAyman Bagabas <ayman.bagabas@gmail.com> dateMon 14 Jul 2025, 12:00 (1 year ago) parente8212e5
1 file changed+41
internal/tui/components/chat/messages/renderer.go+41
internal/tui/components/chat/messages/renderer.go+41
@@ -3,6 +3,7 @@ package messages
33import (
44 "encoding/json"
55 "fmt"
6+ "strconv"
67 "strings"
78 "time"
89
@@ -656,6 +657,7 @@ func joinHeaderBody(header, body string) string {
656657func renderPlainContent(v *toolCallCmp, content string) string {
657658 t := styles.CurrentTheme()
658659 content = strings.TrimSpace(content)
660+ content = escapeContent(t, content)
659661 lines := strings.Split(content, "\n")
660662
661663 width := v.textWidth() - 2 // -2 for left padding
@@ -694,6 +696,7 @@ func pad(v any, width int) string {
694696
695697func renderCodeContent(v *toolCallCmp, path, content string, offset int) string {
696698 t := styles.CurrentTheme()
699+ content = escapeContent(t, content)
697700 truncated := truncateHeight(content, responseContextHeight)
698701
699702 highlighted, _ := highlight.SyntaxHighlight(truncated, path, t.BgBase)
@@ -766,3 +769,41 @@ func prettifyToolName(name string) string {
766769 return name
767770 }
768771}
772+
773+// escapeContent escapes ANSI escape sequences and control characters in the
774+// content and styles it for display in the terminal.
775+func escapeContent(t *styles.Theme, content string) string {
776+ lines := strings.Split(content, "\n")
777+ for i, line := range lines {
778+ lines[i] = escapeLine(t, line)
779+ }
780+
781+ content = strings.Join(lines, "\n")
782+ return content
783+}
784+
785+// escapeLine escapes ANSI escape sequences and control characters and styles
786+// them for display in the terminal.
787+func escapeLine(t *styles.Theme, text string) string {
788+ var (
789+ sb strings.Builder
790+ state byte
791+ seq string
792+ n int
793+ w int
794+ )
795+ faint := ansi.NewStyle().Faint().ForegroundColor(t.FgMuted)
796+ for len(text) > 0 {
797+ seq, w, n, state = ansi.DecodeSequence(text, state, nil)
798+ if w > 0 {
799+ sb.WriteString(seq)
800+ } else {
801+ quote := strconv.Quote(seq)
802+ quote = strings.TrimPrefix(quote, "\"")
803+ quote = strings.TrimSuffix(quote, "\"")
804+ sb.WriteString(faint.Styled(quote))
805+ }
806+ text = text[n:]
807+ }
808+ return sb.String()
809+}