fix(bonfire): strip control characters from error blocks, process views and tables

- bonfire.Sanitize (additive), moved from diary's console channel: tab
  kept, CR and LF to a space, every other control character dropped
- applied before styling to every error-block line (message,
  explanation, Try lines, -v chain), process-view item names and errors,
  the current item of spinner and progress, failure lines, and table
  headers and cells in both layouts
- diary's console handler calls bonfire.Sanitize; README and the
  writing-commands page say so (WR-05)
This commit is contained in:
Jakub Zych
2026-10-22 02:31:55 +02:00
parent 39677f1819
commit a9025c0d12
10 changed files with 181 additions and 51 deletions

View File

@@ -12,7 +12,6 @@ import (
"sync"
"sync/atomic"
"time"
"unicode"
"charm.land/lipgloss/v2"
"git.golem15.com/golem15/summercms/modules/bonfire"
@@ -141,12 +140,12 @@ func (h *consoleHandler) Handle(ctx context.Context, r slog.Record) error {
label, style := levelLabel(r.Level, p)
b.WriteString(style.Render(label))
b.WriteString(strings.Repeat(" ", max(0, 5-len(label))+1))
name := sanitize(component)
name := bonfire.Sanitize(component)
if name != "" {
b.WriteString(p.Header.Render(name))
}
b.WriteString(strings.Repeat(" ", max(0, componentWidth-len(name))+1))
b.WriteString(sanitize(r.Message))
b.WriteString(bonfire.Sanitize(r.Message))
for _, list := range [][]consoleAttr{h.attrs, recAttrs} {
for _, a := range list {
b.WriteByte(' ')
@@ -247,7 +246,7 @@ func appendAttr(out []consoleAttr, prefix string, a slog.Attr) []consoleAttr {
}
return out
}
return append(out, consoleAttr{key: sanitize(prefix + a.Key), value: formatValue(a.Value)})
return append(out, consoleAttr{key: bonfire.Sanitize(prefix + a.Key), value: formatValue(a.Value)})
}
func formatValue(v slog.Value) string {
@@ -266,35 +265,9 @@ func formatValue(v slog.Value) string {
default:
s = v.String()
}
s = sanitize(s)
s = bonfire.Sanitize(s)
if s == "" || strings.ContainsAny(s, " \t\"=") {
return strconv.Quote(s)
}
return s
}
// sanitize removes control characters other than tab; line breaks become
// spaces so a multi-line value stays on one line.
func sanitize(s string) string {
clean := true
for _, r := range s {
if r != '\t' && unicode.IsControl(r) {
clean = false
break
}
}
if clean {
return s
}
var b strings.Builder
for _, r := range s {
switch {
case r == '\n' || r == '\r':
b.WriteByte(' ')
case r != '\t' && unicode.IsControl(r):
default:
b.WriteRune(r)
}
}
return b.String()
}