Disable automatic inline images in Herdr
- commit
- 6af4e0f2ece7193709355d730adcc84a5057de59
- author
- patriceckhart · · 2026-07-23 12:50 UTC
- parent
- c0a7154
- signature
- unsigned
- refs
- tag: v0.3.2
3 files · +16 -7
M README.md +3 -1
| @@ -703,11 +703,13 @@ When a tool returns an image (for example `read` on a PNG), zot renders it inlin | |||
| 703 | 703 | ||
| 704 | 704 | | Value | Effect | | |
| 705 | 705 | |---|---| | |
| 706 | - | | unset (default) | Auto-detect based on `TERM_PROGRAM`. | | |
| 706 | + | | unset (default) | Auto-detect based on `TERM_PROGRAM`; use the text placeholder inside VS Code and Herdr. | | |
| 707 | 707 | | `iterm`, `iterm2` | Force the iTerm2 OSC 1337 protocol. | | |
| 708 | 708 | | `kitty` | Force the Kitty graphics protocol. | | |
| 709 | 709 | | `off`, `none` | Always use the text placeholder. | | |
| 710 | 710 | ||
| 711 | + | Herdr's Kitty graphics support is currently experimental, so zot does not enable inline images there automatically. After enabling `experimental.kitty_graphics` in Herdr, set `ZOT_INLINE_IMAGES=kitty` to opt in. | |
| 712 | + | ||
| 711 | 713 | Frames containing images are full-repainted (no differential diff) to prevent stale image pixels from lingering through scroll. That costs one terminal flash per image-containing frame; set `ZOT_INLINE_IMAGES=off` if that bothers you. | |
| 712 | 714 | ||
| 713 | 715 | ## Tool rendering | |
| @@ -703,11 +703,13 @@ When a tool returns an image (for example `read` on a PNG), zot renders it inlin | |||||
| 703 | 703 | ||||
| 704 | | Value | Effect | | 704 | | Value | Effect | | ||
| 705 | |---|---| | 705 | |---|---| | ||
| 706 | - | | unset (default) | Auto-detect based on `TERM_PROGRAM`. | | 706 | + | | unset (default) | Auto-detect based on `TERM_PROGRAM`; use the text placeholder inside VS Code and Herdr. | |
| 707 | | `iterm`, `iterm2` | Force the iTerm2 OSC 1337 protocol. | | 707 | | `iterm`, `iterm2` | Force the iTerm2 OSC 1337 protocol. | | ||
| 708 | | `kitty` | Force the Kitty graphics protocol. | | 708 | | `kitty` | Force the Kitty graphics protocol. | | ||
| 709 | | `off`, `none` | Always use the text placeholder. | | 709 | | `off`, `none` | Always use the text placeholder. | | ||
| 710 | 710 | ||||
| 711 | + | Herdr's Kitty graphics support is currently experimental, so zot does not enable inline images there automatically. After enabling `experimental.kitty_graphics` in Herdr, set `ZOT_INLINE_IMAGES=kitty` to opt in. | |||
| 712 | + | ||||
| 711 | Frames containing images are full-repainted (no differential diff) to prevent stale image pixels from lingering through scroll. That costs one terminal flash per image-containing frame; set `ZOT_INLINE_IMAGES=off` if that bothers you. | 713 | Frames containing images are full-repainted (no differential diff) to prevent stale image pixels from lingering through scroll. That costs one terminal flash per image-containing frame; set `ZOT_INLINE_IMAGES=off` if that bothers you. | ||
| 712 | 714 | ||||
| 713 | ## Tool rendering | 715 | ## Tool rendering | ||
M packages/tui/image.go +5 -5
| @@ -55,11 +55,11 @@ func detectImageProtocolAuto() ImageProtocol { | |||
| 55 | 55 | term := os.Getenv("TERM") | |
| 56 | 56 | kittyWindow := os.Getenv("KITTY_WINDOW_ID") | |
| 57 | 57 | ||
| 58 | - | // VS Code's integrated terminal exposes several protocol-ish env | |
| 59 | - | // combinations depending on the underlying shell/pty, but its image | |
| 60 | - | // layer is inconsistent enough that auto-enable is more annoying than | |
| 61 | - | // useful. Users can still force a protocol via ZOT_INLINE_IMAGES. | |
| 62 | - | if strings.EqualFold(termProgram, "vscode") { | |
| 58 | + | // VS Code's integrated terminal and Herdr panes can inherit protocol | |
| 59 | + | // indicators from their host terminal without reliably rendering the | |
| 60 | + | // corresponding image escapes. Default to the text fallback in these | |
| 61 | + | // intermediaries. Users can still force a protocol via ZOT_INLINE_IMAGES. | |
| 62 | + | if strings.EqualFold(termProgram, "vscode") || os.Getenv("HERDR_ENV") != "" { | |
| 63 | 63 | return ImageProtocolNone | |
| 64 | 64 | } | |
| 65 | 65 | ||
| @@ -55,11 +55,11 @@ func detectImageProtocolAuto() ImageProtocol { | |||||
| 55 | term := os.Getenv("TERM") | 55 | term := os.Getenv("TERM") | ||
| 56 | kittyWindow := os.Getenv("KITTY_WINDOW_ID") | 56 | kittyWindow := os.Getenv("KITTY_WINDOW_ID") | ||
| 57 | 57 | ||||
| 58 | - | // VS Code's integrated terminal exposes several protocol-ish env | 58 | + | // VS Code's integrated terminal and Herdr panes can inherit protocol |
| 59 | - | // combinations depending on the underlying shell/pty, but its image | 59 | + | // indicators from their host terminal without reliably rendering the |
| 60 | - | // layer is inconsistent enough that auto-enable is more annoying than | 60 | + | // corresponding image escapes. Default to the text fallback in these |
| 61 | - | // useful. Users can still force a protocol via ZOT_INLINE_IMAGES. | 61 | + | // intermediaries. Users can still force a protocol via ZOT_INLINE_IMAGES. |
| 62 | - | if strings.EqualFold(termProgram, "vscode") { | 62 | + | if strings.EqualFold(termProgram, "vscode") || os.Getenv("HERDR_ENV") != "" { |
| 63 | return ImageProtocolNone | 63 | return ImageProtocolNone | ||
| 64 | } | 64 | } | ||
| 65 | 65 | ||||
M packages/tui/image_test.go +8 -1
| @@ -112,19 +112,26 @@ func TestRowsForInlineImageCellAspectOverride(t *testing.T) { | |||
| 112 | 112 | } | |
| 113 | 113 | } | |
| 114 | 114 | ||
| 115 | - | func TestDetectImageProtocolPlaceholderAndVSCode(t *testing.T) { | |
| 115 | + | func TestDetectImageProtocolPlaceholderAndIntermediaries(t *testing.T) { | |
| 116 | 116 | t.Setenv("ZOT_INLINE_IMAGES", "placeholder") | |
| 117 | 117 | if got := DetectImageProtocol(); got != ImageProtocolNone { | |
| 118 | 118 | t.Fatalf("placeholder protocol = %v, want none", got) | |
| 119 | 119 | } | |
| 120 | 120 | ||
| 121 | 121 | t.Setenv("ZOT_INLINE_IMAGES", "") | |
| 122 | + | t.Setenv("HERDR_ENV", "") | |
| 122 | 123 | t.Setenv("TERM_PROGRAM", "vscode") | |
| 123 | 124 | t.Setenv("KITTY_WINDOW_ID", "1") | |
| 124 | 125 | if got := DetectImageProtocol(); got != ImageProtocolNone { | |
| 125 | 126 | t.Fatalf("vscode auto protocol = %v, want none", got) | |
| 126 | 127 | } | |
| 127 | 128 | ||
| 129 | + | t.Setenv("TERM_PROGRAM", "ghostty") | |
| 130 | + | t.Setenv("HERDR_ENV", "1") | |
| 131 | + | if got := DetectImageProtocol(); got != ImageProtocolNone { | |
| 132 | + | t.Fatalf("Herdr auto protocol = %v, want none", got) | |
| 133 | + | } | |
| 134 | + | ||
| 128 | 135 | t.Setenv("ZOT_INLINE_IMAGES", "kitty") | |
| 129 | 136 | if got := DetectImageProtocol(); got != ImageProtocolKitty { | |
| 130 | 137 | t.Fatalf("forced kitty protocol = %v, want kitty", got) | |
| @@ -112,19 +112,26 @@ func TestRowsForInlineImageCellAspectOverride(t *testing.T) { | |||||
| 112 | } | 112 | } | ||
| 113 | } | 113 | } | ||
| 114 | 114 | ||||
| 115 | - | func TestDetectImageProtocolPlaceholderAndVSCode(t *testing.T) { | 115 | + | func TestDetectImageProtocolPlaceholderAndIntermediaries(t *testing.T) { |
| 116 | t.Setenv("ZOT_INLINE_IMAGES", "placeholder") | 116 | t.Setenv("ZOT_INLINE_IMAGES", "placeholder") | ||
| 117 | if got := DetectImageProtocol(); got != ImageProtocolNone { | 117 | if got := DetectImageProtocol(); got != ImageProtocolNone { | ||
| 118 | t.Fatalf("placeholder protocol = %v, want none", got) | 118 | t.Fatalf("placeholder protocol = %v, want none", got) | ||
| 119 | } | 119 | } | ||
| 120 | 120 | ||||
| 121 | t.Setenv("ZOT_INLINE_IMAGES", "") | 121 | t.Setenv("ZOT_INLINE_IMAGES", "") | ||
| 122 | + | t.Setenv("HERDR_ENV", "") | |||
| 122 | t.Setenv("TERM_PROGRAM", "vscode") | 123 | t.Setenv("TERM_PROGRAM", "vscode") | ||
| 123 | t.Setenv("KITTY_WINDOW_ID", "1") | 124 | t.Setenv("KITTY_WINDOW_ID", "1") | ||
| 124 | if got := DetectImageProtocol(); got != ImageProtocolNone { | 125 | if got := DetectImageProtocol(); got != ImageProtocolNone { | ||
| 125 | t.Fatalf("vscode auto protocol = %v, want none", got) | 126 | t.Fatalf("vscode auto protocol = %v, want none", got) | ||
| 126 | } | 127 | } | ||
| 127 | 128 | ||||
| 129 | + | t.Setenv("TERM_PROGRAM", "ghostty") | |||
| 130 | + | t.Setenv("HERDR_ENV", "1") | |||
| 131 | + | if got := DetectImageProtocol(); got != ImageProtocolNone { | |||
| 132 | + | t.Fatalf("Herdr auto protocol = %v, want none", got) | |||
| 133 | + | } | |||
| 134 | + | ||||
| 128 | t.Setenv("ZOT_INLINE_IMAGES", "kitty") | 135 | t.Setenv("ZOT_INLINE_IMAGES", "kitty") | ||
| 129 | if got := DetectImageProtocol(); got != ImageProtocolKitty { | 136 | if got := DetectImageProtocol(); got != ImageProtocolKitty { | ||
| 130 | t.Fatalf("forced kitty protocol = %v, want kitty", got) | 137 | t.Fatalf("forced kitty protocol = %v, want kitty", got) | ||