wrapStructured quebra um corpo já renderizado pelo glamour para exibição dentro do envelope de resposta. Diferente de wrapText (word-wrap de prosa, que colapsa a indentação via strings.Fields), ele PRESERVA a indentação inicial de cada linha — é o fix do bug em que YAML/JSON/código colados no chat "
(text string, limit int)
| 967 | // de colunas intacto). Só as que estouram passam por word-wrap, repetindo |
| 968 | // o indent da linha em cada continuação. |
| 969 | func wrapStructured(text string, limit int) []string { |
| 970 | if limit <= 0 { |
| 971 | return []string{text} |
| 972 | } |
| 973 | rawLines := strings.Split(text, "\n") |
| 974 | |
| 975 | type lineSeg struct { |
| 976 | indent int |
| 977 | payload string // códigos ANSI iniciais + conteúdo |
| 978 | blank bool |
| 979 | } |
| 980 | segs := make([]lineSeg, 0, len(rawLines)) |
| 981 | commonIndent := -1 |
| 982 | for _, ln := range rawLines { |
| 983 | ind, codes, body := splitLeadingIndent(ln) |
| 984 | blank := strings.TrimSpace(stripANSIForCard(ln)) == "" |
| 985 | segs = append(segs, lineSeg{indent: ind, payload: codes + body, blank: blank}) |
| 986 | if !blank && (commonIndent < 0 || ind < commonIndent) { |
| 987 | commonIndent = ind |
| 988 | } |
| 989 | } |
| 990 | if commonIndent < 0 { |
| 991 | commonIndent = 0 |
| 992 | } |
| 993 | |
| 994 | out := make([]string, 0, len(rawLines)) |
| 995 | for _, s := range segs { |
| 996 | if s.blank { |
| 997 | out = append(out, "") |
| 998 | continue |
| 999 | } |
| 1000 | rel := s.indent - commonIndent |
| 1001 | if rel < 0 { |
| 1002 | rel = 0 |
| 1003 | } |
| 1004 | pad := strings.Repeat(" ", rel) |
| 1005 | full := pad + s.payload |
| 1006 | if VisibleLen(full) <= limit { |
| 1007 | // Cabe: verbatim — preserva qualquer alinhamento interno. |
| 1008 | out = append(out, full) |
| 1009 | continue |
| 1010 | } |
| 1011 | // Estoura: word-wrap do conteúdo, repetindo o indent nas continuações. |
| 1012 | avail := limit - rel |
| 1013 | if avail < 1 { |
| 1014 | avail = 1 |
| 1015 | } |
| 1016 | for _, chunk := range wrapText(s.payload, avail) { |
| 1017 | out = append(out, pad+chunk) |
| 1018 | } |
| 1019 | } |
| 1020 | return out |
| 1021 | } |
| 1022 | |
| 1023 | // RenderThinking exibe o pensamento da IA |
| 1024 | func (r *UIRenderer) RenderThinking(thought string) { |