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
+62
View File
@@ -0,0 +1,62 @@
package parse
import (
"bytes"
"strings"
)
// ImageRef represents an image referenced by a filter via OSC 9 marker.
type ImageRef struct {
Index int // Sequential position in the message
Path string // Absolute path to image file on disk
Alt string // Alt text fallback
}
var oscImagePrefix = []byte("\033]9;image:")
// ParseImageOSC parses an OSC 9 image marker from a byte slice.
// Format: \033]9;image:path=/tmp/foo.png;alt=text\007
// The marker may appear anywhere in the line.
// Returns the parsed reference and whether parsing succeeded.
func ParseImageOSC(line []byte) (*ImageRef, bool) {
start := bytes.Index(line, oscImagePrefix)
if start == -1 {
return nil, false
}
rest := line[start+len(oscImagePrefix):]
// Find string terminator: BEL (\007) or ST (ESC \)
end := -1
for i := 0; i < len(rest); i++ {
if rest[i] == '\007' {
end = i
break
}
if rest[i] == '\033' && i+1 < len(rest) && rest[i+1] == '\\' {
end = i
break
}
}
if end == -1 {
return nil, false
}
params := string(rest[:end])
ref := &ImageRef{}
for _, pair := range strings.Split(params, ";") {
k, v, ok := strings.Cut(pair, "=")
if !ok {
continue
}
switch k {
case "path":
ref.Path = v
case "alt":
ref.Alt = v
}
}
if ref.Path == "" {
return nil, false
}
return ref, true
}