package parse import ( "bufio" "bytes" "fmt" "io" "git.sr.ht/~rjarry/aerc/lib/log" ) // ExtractImages scans a reader for OSC 9 image markers, replaces them with // null-byte-delimited placeholders (\x00IMG:N\x00), and returns the cleaned // reader plus a slice of ImageRef structs. // // Lines containing valid image markers are replaced entirely with the // placeholder. Lines with invalid markers (e.g. missing path) pass through // unchanged. func ExtractImages(r io.Reader) (io.Reader, []ImageRef) { var images []ImageRef buf := bytes.NewBuffer(nil) scanner := bufio.NewScanner(r) scanner.Buffer(nil, 1024*1024*1024) for scanner.Scan() { line := scanner.Bytes() if bytes.Contains(line, oscImagePrefix) { if ref, ok := ParseImageOSC(line); ok { ref.Index = len(images) images = append(images, *ref) fmt.Fprintf(buf, "\x00IMG:%d\x00\n", ref.Index) continue } } buf.Write(line) buf.WriteByte('\n') } if err := scanner.Err(); err != nil { log.Warnf("ExtractImages: scan error: %v", err) } return buf, images } // ReplacePlaceholders converts \x00IMG:N\x00 placeholders into human-readable // [image: alt] text suitable for display in a pager. func ReplacePlaceholders(data []byte, images []ImageRef) []byte { result := bytes.NewBuffer(nil) for _, line := range bytes.Split(data, []byte("\n")) { trimmed := bytes.TrimSpace(line) if len(trimmed) > 6 && trimmed[0] == 0 && bytes.HasPrefix(trimmed, []byte("\x00IMG:")) && trimmed[len(trimmed)-1] == 0 { // Extract index numStr := string(trimmed[5 : len(trimmed)-1]) idx := 0 for _, c := range numStr { if c >= '0' && c <= '9' { idx = idx*10 + int(c-'0') } } if idx < len(images) && images[idx].Alt != "" { fmt.Fprintf(result, "[image: %s]\n", images[idx].Alt) } else { result.WriteString("[image]\n") } } else { result.Write(line) result.WriteByte('\n') } } return result.Bytes() }