Skip to content

Commit ae15b56

Browse files
committed
fix(images): honor \> escapes inside angle-bracket image destinations
parseMarkdownDestination stopped at the first '>' even when escaped, while the scanner's findDestinationEnd already walks past '\\>' the way CommonMark requires. That made inputs like '<./foo\\>bar.png>' parse as './foo\\' and fail local-file resolution. Walk character by character in the angle-bracket branch, skip escape sequences, and stop only at the first unescaped '>' so the two halves of the parser agree.
1 parent 3a9eb0a commit ae15b56

2 files changed

Lines changed: 38 additions & 3 deletions

File tree

internal/cli/local_images.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -455,9 +455,20 @@ func parseMarkdownDestination(raw string) (string, bool) {
455455
}
456456

457457
if strings.HasPrefix(s, "<") {
458-
end := strings.Index(s, ">")
459-
if end > 1 {
460-
return unescapeMarkdownPunctuation(s[1:end]), true
458+
// Match the scanner's findDestinationEnd: walk past `\>` escapes
459+
// so inputs like `<./foo\>bar.png>` keep the full destination
460+
// instead of truncating at the first `>`.
461+
for i := 1; i < len(s); i++ {
462+
if s[i] == '\\' && i+1 < len(s) {
463+
i++
464+
continue
465+
}
466+
if s[i] == '>' {
467+
if i > 1 {
468+
return unescapeMarkdownPunctuation(s[1:i]), true
469+
}
470+
break
471+
}
461472
}
462473
}
463474

internal/cli/local_images_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,30 @@ func TestRewriteStandaloneLocalImagesSupportsAngleBracketDestinationWithTitle(t
331331
}
332332
}
333333

334+
func TestRewriteStandaloneLocalImagesHandlesEscapedGTInAngleBrackets(t *testing.T) {
335+
tmp := t.TempDir()
336+
doc := filepath.Join(tmp, "doc.md")
337+
img := filepath.Join(tmp, "foo>bar.png")
338+
if err := os.WriteFile(img, []byte("PNG"), 0o644); err != nil {
339+
t.Fatalf("WriteFile: %v", err)
340+
}
341+
342+
// CommonMark allows `\>` inside angle-bracket destinations.
343+
rewritten, placements, err := RewriteStandaloneLocalImages(`![Alt](<./foo\>bar.png>)`+"\n", doc)
344+
if err != nil {
345+
t.Fatalf("RewriteStandaloneLocalImages: %v", err)
346+
}
347+
if len(placements) != 1 {
348+
t.Fatalf("len(placements) = %d, want 1", len(placements))
349+
}
350+
if placements[0].Resolved != img {
351+
t.Fatalf("Resolved = %q, want %q", placements[0].Resolved, img)
352+
}
353+
if strings.Contains(rewritten, `foo\>bar.png`) {
354+
t.Fatalf("rewritten should have replaced image line, got %q", rewritten)
355+
}
356+
}
357+
334358
func TestFindStandaloneLocalImageLinesIgnoresEscapedImageMarker(t *testing.T) {
335359
input := `\![Demo](./example.png)` + "\n"
336360
rewritten, placements, err := FindStandaloneLocalImageLines(input)

0 commit comments

Comments
 (0)