Problem
When converting a Confluence page whose title contains an apostrophe (e.g. My team's page), images are downloaded to the local assets folder but the src attribute in the generated Markdown still points to the remote Confluence URL instead of the local file.
Root cause
In confluence.rs, download_images_and_rewrite_html uses two separate regexes:
IMG_RE — correctly uses alternation (?:"([^"]*)"|'([^']*)') to capture the src value without ambiguity.
REPLACE_RE — uses (["'])(.*?)(["']) with a lazy quantifier and a character class ["'] for both the opening and closing delimiter.
When the image URL contains an unencoded apostrophe (which happens whenever the Confluence page title has one, since Confluence embeds the raw title in attachment URLs), the lazy .*? stops at the first ' it finds inside the URL, mistaking it for the closing quote. Because quote_open (") ≠ quote_close ('), the guard condition fires and the replacement is skipped — even though the file was already downloaded successfully.
// URL produced by Confluence for a page titled "My team's page":
src="https://confluence.example.com/download/attachments/.../My%20team's%20page/image.jpg?api=v2"
// ^
// REPLACE_RE stops here, thinking ' is the closing quote
IMG_RE does not have this problem because its alternation branches use [^"]* / [^']* (negated character classes) which never match the wrong delimiter.
Suggested fix
Replace REPLACE_RE with the same alternation pattern used by IMG_RE:
// Before (buggy when URL contains an apostrophe):
static REPLACE_RE: Lazy<Regex> =
Lazy::new(|| Regex::new(r#"(?is)(<img\b[^>]*\bsrc=)(["'])(.*?)(["'])"#).unwrap());
// After:
static REPLACE_RE: Lazy<Regex> =
Lazy::new(|| Regex::new(r#"(?is)(<img\b[^>]*\bsrc=)(?:"([^"]*)"|'([^']*)')"#).unwrap());
The closure would then mirror the IMG_RE capture-group convention (group 2 = double-quoted src, group 3 = single-quoted src).
Steps to reproduce
- Create (or use) a Confluence page whose title contains an apostrophe.
- Add an image attachment to that page.
- Run
confluence2md against it.
- Observe that the image file is present in the
_assets/ folder, but the Markdown still references the remote URL.
Expected behaviour
The src in the generated Markdown points to the locally downloaded asset (e.g. My_team's_page_assets/image.jpg).
Actual behaviour
The src still points to the original remote Confluence URL.
Additional notes
- The
rewrite_image.html dump (via --dump-state-path) is identical to export.html, confirming the substitution never takes place.
- The downloaded file is present and valid in the assets folder, so the download step itself works correctly.
Problem
When converting a Confluence page whose title contains an apostrophe (e.g.
My team's page), images are downloaded to the local assets folder but thesrcattribute in the generated Markdown still points to the remote Confluence URL instead of the local file.Root cause
In
confluence.rs,download_images_and_rewrite_htmluses two separate regexes:IMG_RE— correctly uses alternation(?:"([^"]*)"|'([^']*)')to capture thesrcvalue without ambiguity.REPLACE_RE— uses(["'])(.*?)(["'])with a lazy quantifier and a character class["']for both the opening and closing delimiter.When the image URL contains an unencoded apostrophe (which happens whenever the Confluence page title has one, since Confluence embeds the raw title in attachment URLs), the lazy
.*?stops at the first'it finds inside the URL, mistaking it for the closing quote. Becausequote_open(") ≠quote_close('), the guard condition fires and the replacement is skipped — even though the file was already downloaded successfully.IMG_REdoes not have this problem because its alternation branches use[^"]*/[^']*(negated character classes) which never match the wrong delimiter.Suggested fix
Replace
REPLACE_REwith the same alternation pattern used byIMG_RE:The closure would then mirror the
IMG_REcapture-group convention (group 2 = double-quoted src, group 3 = single-quoted src).Steps to reproduce
confluence2mdagainst it._assets/folder, but the Markdown still references the remote URL.Expected behaviour
The
srcin the generated Markdown points to the locally downloaded asset (e.g.My_team's_page_assets/image.jpg).Actual behaviour
The
srcstill points to the original remote Confluence URL.Additional notes
rewrite_image.htmldump (via--dump-state-path) is identical toexport.html, confirming the substitution never takes place.