feat(parse): add ImageRef type and OSC 9 marker parser

Introduces ImageRef struct and ParseImageOSC() to parse OSC 9 image
markers (\033]9;image:path=...;alt=...\007) emitted by filters. Supports
BEL and ESC-backslash terminators, tolerates markers embedded in larger
lines, and rejects malformed or path-less markers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Mortdecai
2026-04-07 19:57:17 -04:00
parent 083402a548
commit 00a6660db5
2 changed files with 157 additions and 0 deletions
+95
View File
@@ -0,0 +1,95 @@
package parse
import (
"testing"
)
func TestParseImageOSC_ValidFull(t *testing.T) {
line := []byte("\033]9;image:path=/tmp/aerc-xxx/img0.png;alt=product photo\007")
ref, ok := ParseImageOSC(line)
if !ok {
t.Fatal("expected successful parse")
}
if ref.Path != "/tmp/aerc-xxx/img0.png" {
t.Errorf("path = %q, want /tmp/aerc-xxx/img0.png", ref.Path)
}
if ref.Alt != "product photo" {
t.Errorf("alt = %q, want 'product photo'", ref.Alt)
}
}
func TestParseImageOSC_PathOnly(t *testing.T) {
line := []byte("\033]9;image:path=/tmp/img.jpg\007")
ref, ok := ParseImageOSC(line)
if !ok {
t.Fatal("expected successful parse")
}
if ref.Path != "/tmp/img.jpg" {
t.Errorf("path = %q, want /tmp/img.jpg", ref.Path)
}
if ref.Alt != "" {
t.Errorf("alt = %q, want empty", ref.Alt)
}
}
func TestParseImageOSC_EscBackslashTerminator(t *testing.T) {
line := []byte("\033]9;image:path=/tmp/img.png\033\\")
ref, ok := ParseImageOSC(line)
if !ok {
t.Fatal("expected successful parse with ESC\\ terminator")
}
if ref.Path != "/tmp/img.png" {
t.Errorf("path = %q", ref.Path)
}
}
func TestParseImageOSC_NoPath(t *testing.T) {
line := []byte("\033]9;image:alt=just alt text\007")
_, ok := ParseImageOSC(line)
if ok {
t.Error("expected failure when path is missing")
}
}
func TestParseImageOSC_NotOSC9(t *testing.T) {
line := []byte("Hello, this is plain text")
_, ok := ParseImageOSC(line)
if ok {
t.Error("expected failure on plain text")
}
}
func TestParseImageOSC_WrongOSCNumber(t *testing.T) {
line := []byte("\033]8;image:path=/tmp/img.png\007")
_, ok := ParseImageOSC(line)
if ok {
t.Error("expected failure on OSC 8 (not 9)")
}
}
func TestParseImageOSC_EmptyPath(t *testing.T) {
line := []byte("\033]9;image:path=\007")
_, ok := ParseImageOSC(line)
if ok {
t.Error("expected failure on empty path")
}
}
func TestParseImageOSC_MarkerEmbeddedInLine(t *testing.T) {
line := []byte("prefix text \033]9;image:path=/tmp/img.png\007 suffix")
ref, ok := ParseImageOSC(line)
if !ok {
t.Fatal("expected successful parse even with surrounding text")
}
if ref.Path != "/tmp/img.png" {
t.Errorf("path = %q", ref.Path)
}
}
func TestParseImageOSC_NoTerminator(t *testing.T) {
line := []byte("\033]9;image:path=/tmp/img.png")
_, ok := ParseImageOSC(line)
if ok {
t.Error("expected failure when no terminator present")
}
}