@@ -6,6 +6,7 @@ import (
9+ "github.com/charmbracelet/crush/internal/ansiext"
9 "github.com/charmbracelet/crush/internal/fsext"
10 "github.com/charmbracelet/crush/internal/fsext"
10 "github.com/charmbracelet/crush/internal/llm/agent"
11 "github.com/charmbracelet/crush/internal/llm/agent"
11 "github.com/charmbracelet/crush/internal/llm/tools"
12 "github.com/charmbracelet/crush/internal/llm/tools"
@@ -702,7 +703,7 @@ func renderPlainContent(v *toolCallCmp, content string) string {
702 if i >= responseContextHeight {
703 if i >= responseContextHeight {
705− ln = escapeContent(ln)
706+ ln = ansiext.Escape(ln)
706 ln = " " + ln // left padding
707 ln = " " + ln // left padding
707 if len(ln) > width {
708 if len(ln) > width {
708 ln = v.fit(ln, width)
709 ln = v.fit(ln, width)
@@ -740,7 +741,7 @@ func renderCodeContent(v *toolCallCmp, path, content string, offset int) string
741 lines := strings.Split(truncated, "\n")
742 lines := strings.Split(truncated, "\n")
742 for i, ln := range lines {
743 for i, ln := range lines {
743− lines[i] = escapeContent(ln)
744+ lines[i] = ansiext.Escape(ln)
746 highlighted, _ := highlight.SyntaxHighlight(strings.Join(lines, "\n"), path, t.BgBase)
747 highlighted, _ := highlight.SyntaxHighlight(strings.Join(lines, "\n"), path, t.BgBase)
@@ -816,20 +817,3 @@ func prettifyToolName(name string) string {
816 return name
817 return name
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 {
826− case r >= 0 && r <= 0x1f: // Control characters 0x00-0x1F
827− sb.WriteRune('\u2400' + r)
829− sb.WriteRune('\u2421')