Fix info pane Esc close and preview background rendering

This commit is contained in:
vrubelroman 2026-04-24 11:05:31 +03:00
parent e0117650de
commit 5a27141298
2 changed files with 86 additions and 22 deletions

View file

@ -21,6 +21,7 @@ import (
) )
var sgrRegexp = regexp.MustCompile(`\x1b\[([0-9;:]*)m`) var sgrRegexp = regexp.MustCompile(`\x1b\[([0-9;:]*)m`)
var sgrNumberRegexp = regexp.MustCompile(`\d+`)
type PreviewKind string type PreviewKind string
@ -158,6 +159,10 @@ func highlightText(path string, source string, themeName string) string {
if style == nil { if style == nil {
return source return source
} }
style = styleWithoutBackground(style)
if style == nil {
return source
}
var output bytes.Buffer var output bytes.Buffer
if err := formatters.TTY16m.Format(&output, style, iterator); err != nil { if err := formatters.TTY16m.Format(&output, style, iterator); err != nil {
@ -166,6 +171,21 @@ func highlightText(path string, source string, themeName string) string {
return stripBackgroundSGR(output.String()) return stripBackgroundSGR(output.String())
} }
func styleWithoutBackground(base *chroma.Style) *chroma.Style {
if base == nil {
return nil
}
builder := base.Builder().Transform(func(entry chroma.StyleEntry) chroma.StyleEntry {
entry.Background = 0
return entry
})
stripped, err := builder.Build()
if err != nil {
return base
}
return stripped
}
func stripBackgroundSGR(text string) string { func stripBackgroundSGR(text string) string {
return sgrRegexp.ReplaceAllStringFunc(text, func(seq string) string { return sgrRegexp.ReplaceAllStringFunc(text, func(seq string) string {
matches := sgrRegexp.FindStringSubmatch(seq) matches := sgrRegexp.FindStringSubmatch(seq)
@ -185,41 +205,79 @@ func filterSGRParams(paramString string) string {
return "" return ""
} }
parts := strings.Split(paramString, ";") raw := sgrNumberRegexp.FindAllString(paramString, -1)
kept := make([]string, 0, len(parts)) if len(raw) == 0 {
return ""
for i := 0; i < len(parts); i++ { }
part := parts[i] codes := make([]int, 0, len(raw))
code, err := strconv.Atoi(part) for _, token := range raw {
value, err := strconv.Atoi(token)
if err != nil { if err != nil {
kept = append(kept, part) continue
}
codes = append(codes, value)
}
kept := make([]string, 0, len(codes))
for i := 0; i < len(codes); i++ {
code := codes[i]
if code == 0 {
// Do not hard-reset background to terminal default.
// Reset common text attributes + foreground only.
kept = append(kept, "39", "22", "23", "24", "59")
continue continue
} }
if code == 49 || (code >= 40 && code <= 47) || (code >= 100 && code <= 107) { if code == 49 || code == 7 || code == 27 || (code >= 40 && code <= 47) || (code >= 100 && code <= 107) {
continue continue
} }
if code == 48 { switch code {
// Skip explicit background color sequences: case 48:
// 48;5;n or 48;2;r;g;b // Background color payloads:
if i+1 < len(parts) { // 48;5;n or 48;2;r;g;b (also appears in ':' form; parsed as the same int stream).
mode, modeErr := strconv.Atoi(parts[i+1]) if i+1 < len(codes) {
if modeErr == nil { mode := codes[i+1]
switch mode { switch mode {
case 5: case 5:
i += 2 i += 2
continue case 2:
case 2: i += 4
i += 4 default:
continue i++
}
}
continue
case 38, 58:
// Preserve foreground (38) and underline color (58) payloads.
kept = append(kept, strconv.Itoa(code))
if i+1 < len(codes) {
mode := codes[i+1]
kept = append(kept, strconv.Itoa(mode))
switch mode {
case 5:
if i+2 < len(codes) {
kept = append(kept, strconv.Itoa(codes[i+2]))
} }
i += 2
case 2:
if i+4 < len(codes) {
kept = append(kept,
strconv.Itoa(codes[i+2]),
strconv.Itoa(codes[i+3]),
strconv.Itoa(codes[i+4]),
)
}
i += 4
default:
i++
} }
} }
continue continue
} }
kept = append(kept, part) kept = append(kept, strconv.Itoa(code))
} }
return strings.Join(kept, ";") return strings.Join(kept, ";")

View file

@ -424,6 +424,12 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.openHelpModal() m.openHelpModal()
return m, nil return m, nil
case key.Matches(msg, m.keys.Cancel): case key.Matches(msg, m.keys.Cancel):
if m.infoMode {
m.infoMode = false
m.selectMode = false
m.status = "Info pane closed"
return m, nil
}
if len(m.activePane().MarkedEntries()) > 0 { if len(m.activePane().MarkedEntries()) > 0 {
m.activePane().ClearMarks() m.activePane().ClearMarks()
m.status = "Selection cleared" m.status = "Selection cleared"