feat(ext-panel): allow invisible selection marker via U+200B
ext_panel_dialog.Render sniffs the leading glyph of each panel line to decide which row is selected and apply the theme's selection band: today that's '> ' (U+25B8) or '* ' (U+25CF), both visible. Extensions that want the highlight without a visible glyph had no way to opt in - they had to ship the arrow. Adds U+200B (zero-width space) as a third recognised prefix. Extensions can now emit '\u200B' at the start of the selected row to get the blue selection band without any visible marker; the character renders as zero columns so other rows that omit it line up perfectly. The visible arrow markers keep working unchanged. Used by zot-workspaces to highlight the cursor row without inserting a triangle into the otherwise clean list.
- commit
- d46f1d58245096b11e540ecf2124c6b1ea4682d1
- author
- patriceckhart · · 2026-05-19 17:48 UTC
- parent
- e48f4dd
- signature
- unsigned
- refs
- tag: v0.1.86
1 file · +8 -1
M internal/agent/modes/ext_panel_dialog.go +8 -1
| @@ -63,7 +63,14 @@ func (d *extPanelDialog) Render(th tui.Theme, width int) []string { | |||
| 63 | 63 | for _, l := range d.lines { | |
| 64 | 64 | plain := stripANSIBytes(l) | |
| 65 | 65 | trimmed := strings.TrimLeft(plain, " ") | |
| 66 | - | selected := strings.HasPrefix(trimmed, "▸ ") || strings.HasPrefix(trimmed, "● ") | |
| 66 | + | // Selection markers, in order of precedence: | |
| 67 | + | // "▸ " / "● " visible glyph the user sees | |
| 68 | + | // "\u200b" invisible zero-width-space sentinel for | |
| 69 | + | // extensions that want the row highlight | |
| 70 | + | // without rendering an arrow | |
| 71 | + | selected := strings.HasPrefix(trimmed, "▸ ") || | |
| 72 | + | strings.HasPrefix(trimmed, "● ") || | |
| 73 | + | strings.HasPrefix(trimmed, "\u200b") | |
| 67 | 74 | out = append(out, styleExtPanelLine(th, l, plain, width, selected)) | |
| 68 | 75 | } | |
| 69 | 76 | if strings.TrimSpace(d.footer) != "" { | |
| @@ -63,7 +63,14 @@ func (d *extPanelDialog) Render(th tui.Theme, width int) []string { | |||||
| 63 | for _, l := range d.lines { | 63 | for _, l := range d.lines { | ||
| 64 | plain := stripANSIBytes(l) | 64 | plain := stripANSIBytes(l) | ||
| 65 | trimmed := strings.TrimLeft(plain, " ") | 65 | trimmed := strings.TrimLeft(plain, " ") | ||
| 66 | - | selected := strings.HasPrefix(trimmed, "▸ ") || strings.HasPrefix(trimmed, "● ") | 66 | + | // Selection markers, in order of precedence: |
| 67 | + | // "▸ " / "● " visible glyph the user sees | |||
| 68 | + | // "\u200b" invisible zero-width-space sentinel for | |||
| 69 | + | // extensions that want the row highlight | |||
| 70 | + | // without rendering an arrow | |||
| 71 | + | selected := strings.HasPrefix(trimmed, "▸ ") || | |||
| 72 | + | strings.HasPrefix(trimmed, "● ") || | |||
| 73 | + | strings.HasPrefix(trimmed, "\u200b") | |||
| 67 | out = append(out, styleExtPanelLine(th, l, plain, width, selected)) | 74 | out = append(out, styleExtPanelLine(th, l, plain, width, selected)) | ||
| 68 | } | 75 | } | ||
| 69 | if strings.TrimSpace(d.footer) != "" { | 76 | if strings.TrimSpace(d.footer) != "" { | ||