@@ -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,45 @@ 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+ content = strings.ReplaceAll(content, "\r\n", "\n")
777+ lines := strings.Split(content, "\n")
778+ for i, line := range lines {
779+ lines[i] = escapeLine(t, line)
780+ }
781+
782+ content = strings.Join(lines, "\n")
783+ return content
784+}
785+
786+// escapeLine escapes ANSI escape sequences and control characters and styles
787+// them for display in the terminal.
788+func escapeLine(t *styles.Theme, text string) string {
789+ var (
790+ sb strings.Builder
791+ state byte
792+ seq string
793+ n int
794+ w int
795+ )
796+ var faint lipgloss.Style
797+ if t != nil {
798+ faint = t.S().Muted.Faint(true)
799+ }
800+ for len(text) > 0 {
801+ seq, w, n, state = ansi.DecodeSequence(text, state, nil)
802+ if w > 0 {
803+ sb.WriteString(seq)
804+ } else {
805+ quote := strconv.Quote(seq)
806+ quote = strings.TrimPrefix(quote, "\"")
807+ quote = strings.TrimSuffix(quote, "\"")
808+ sb.WriteString(faint.Render(quote))
809+ }
810+ text = text[n:]
811+ }
812+ return sb.String()
813+}