on main help sign in
feat(bangmode): properly strip ansi in copy and context
175ce34Kieran Klukas
internal/message/content.go+2−1
@@ -14,6 +14,7 @@ import (
14 "charm.land/fantasy/providers/google"
14 "charm.land/fantasy/providers/google"
15 "charm.land/fantasy/providers/openai"
15 "charm.land/fantasy/providers/openai"
16 "github.com/charmbracelet/crush/internal/stringext"
16 "github.com/charmbracelet/crush/internal/stringext"
17+ "github.com/charmbracelet/x/ansi"
17)
18)
18
19
19type MessageRole string
20type MessageRole string
@@ -515,7 +516,7 @@ func (m *Message) ToAIMessage() []fantasy.Message {
515 text = PromptWithTextAttachments(text, textAttachments)
516 text = PromptWithTextAttachments(text, textAttachments)
516 // Include bang-mode shell commands as context for the agent.
517 // Include bang-mode shell commands as context for the agent.
517 for _, sc := range m.ShellCommands() {
518 for _, sc := range m.ShellCommands() {
518− shellText := fmt.Sprintf("$ %s\n%s\n(exit code %d)", sc.Command, sc.Output, sc.ExitCode)
519+ shellText := fmt.Sprintf("$ %s\n%s\n(exit code %d)", sc.Command, ansi.Strip(sc.Output), sc.ExitCode)
519 if text != "" {
520 if text != "" {
520 text += "\n\n" + shellText
521 text += "\n\n" + shellText
521 } else {
522 } else {
internal/ui/chat/shell.go+15−2
@@ -156,7 +156,7 @@ func (s *ShellItem) HandleMouseClick(btn ansi.MouseButton, x, y int) bool {
156func (s *ShellItem) HandleKeyEvent(key tea.KeyMsg) (bool, tea.Cmd) {
156func (s *ShellItem) HandleKeyEvent(key tea.KeyMsg) (bool, tea.Cmd) {
157 switch k := key.String(); k {
157 switch k := key.String(); k {
158 case "c", "y":
158 case "c", "y":
159− text := "$ " + s.command + "\n" + s.output
159+ text := "$ " + s.command + "\n" + ansi.Strip(s.output)
160 return true, common.CopyToClipboard(text, "Shell output copied to clipboard")
160 return true, common.CopyToClipboard(text, "Shell output copied to clipboard")
161 case "shift+left", "H":
161 case "shift+left", "H":
162 if s.xOffset > 0 {
162 if s.xOffset > 0 {
@@ -223,7 +223,20 @@ func (s *ShellItem) RawRender(width int) string {
223 // Remap raw ANSI 16-color codes onto legible Charmtone colors so
223 // Remap raw ANSI 16-color codes onto legible Charmtone colors so
224 // dark terminal defaults don't render illegibly on Crush's
224 // dark terminal defaults don't render illegibly on Crush's
225 // background.
225 // background.
226+ // Strip trailing whitespace and bare ANSI resets before remapping.
227+ // Programs like `task` emit "\x1b[0m\n" after their last line of
228+ // output; trimming only "\n" misses these because the reset bytes
229+ // sit between the content and the newline.
230+ raw := s.output
231+ for {
232+ trimmed := strings.TrimRight(raw, " \t\r\n")
233+ trimmed = strings.TrimSuffix(trimmed, "\x1b[0m")
234+ if trimmed == raw {
235+ break
236+ }
237+ raw = trimmed
238+ }
226− output := remapANSI16(strings.TrimRight(s.output, "\n"), s.sty.ANSI)
239+ output := remapANSI16(raw, s.sty.ANSI)
227 lines := strings.Split(output, "\n")
240 lines := strings.Split(output, "\n")
228
241
229 // While streaming, show the tail of the output so the most recent
242 // While streaming, show the tail of the output so the most recent