From 343930fc558beeb9826d321fc70251d935a4b679 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 23 Feb 2026 12:42:40 +0000 Subject: [PATCH] Fix parseImageInput to handle shell-escaped \! in markdown image refs Some shells escape "!" to "\!" even in single-quoted strings, causing the markdown image reference parser to fail to recognize the ![alt](path) syntax. The entire escaped string was then treated as a file path, producing the error "image file not found: \![alt text](path)". Strip the leading backslash when the input starts with \![ before attempting to parse as a markdown image reference. https://claude.ai/code/session_01BqcPiZ39GE4j4ZhvHVFyZ8 --- cmd/build.go | 5 +++++ cmd/build_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/cmd/build.go b/cmd/build.go index 21a5715..06348fc 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -110,8 +110,13 @@ func Image(file, input, workdir string) error { // parseImageInput checks whether input is a markdown image reference // (![alt](path)) or a plain file path. It returns the image path and any // extracted alt text (empty when the input is a plain path). +// It also handles the common case where the shell escapes "!" to "\!". func parseImageInput(input string) (path, altText string) { trimmed := strings.TrimSpace(input) + // Some shells escape "!" to "\!", so strip the leading backslash. + if strings.HasPrefix(trimmed, `\![`) { + trimmed = trimmed[1:] + } if strings.HasPrefix(trimmed, "![") && strings.HasSuffix(trimmed, ")") { // Extract alt text between ![ and ] rest := trimmed[2:] diff --git a/cmd/build_test.go b/cmd/build_test.go index 87ce719..059a84a 100644 --- a/cmd/build_test.go +++ b/cmd/build_test.go @@ -304,6 +304,8 @@ func TestParseImageInput(t *testing.T) { {"![Screenshot of homepage](shot.png)", "shot.png", "Screenshot of homepage"}, {" ![padded](file.png) ", "file.png", "padded"}, {"not-markdown.png", "not-markdown.png", ""}, + {`\![escaped](file.png)`, "file.png", "escaped"}, + {`\![alt text](/path/to/img.png)`, "/path/to/img.png", "alt text"}, } for _, tt := range tests { path, alt := parseImageInput(tt.input) @@ -316,6 +318,36 @@ func TestParseImageInput(t *testing.T) { } } +func TestImageMarkdownRefEscapedBang(t *testing.T) { + dir := t.TempDir() + file := filepath.Join(dir, "demo.md") + + if err := Init(file, "Test", "dev"); err != nil { + t.Fatal(err) + } + + pngPath := filepath.Join(dir, "test.png") + if err := os.WriteFile(pngPath, minimalPNG, 0644); err != nil { + t.Fatal(err) + } + + input := `\![My screenshot](` + pngPath + ")" + + if err := Image(file, input, ""); err != nil { + t.Fatal(err) + } + + content, err := os.ReadFile(file) + if err != nil { + t.Fatal(err) + } + + s := string(content) + if !strings.Contains(s, "![My screenshot](") { + t.Errorf("expected alt text 'My screenshot' in image output, got: %s", s) + } +} + func TestImageMarkdownRefBadPath(t *testing.T) { dir := t.TempDir() file := filepath.Join(dir, "demo.md")