From b1a8f8ad7f8a49b89faeafb5a5f5d7b1620015a1 Mon Sep 17 00:00:00 2001 From: Gamosoft Date: Mon, 6 Jul 2026 09:55:05 +0200 Subject: [PATCH] fix for tasks --- backend/export.py | 35 ++++++++++++++++++++++++++++------- frontend/app.js | 9 +++++++++ frontend/index.html | 4 ++++ 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/backend/export.py b/backend/export.py index 6bd2a28..1d3b597 100644 --- a/backend/export.py +++ b/backend/export.py @@ -284,19 +284,26 @@ def convert_wikilinks_to_html(markdown_content: str) -> str: """ Convert wikilinks [[note]] or [[note|display text]] to HTML links. In standalone export mode, these are non-functional decorative links. + Wikilinks inside fenced or inline code are left literal, mirroring the + in-app preview pipeline. """ - # Pattern for wikilinks: [[target]] or [[target|display text]] - # But NOT image wikilinks (those start with !) wikilink_pattern = r'(?{display}' - - return re.sub(wikilink_pattern, replace_wikilink, markdown_content) + + code_blocks: list = [] + + def stash(match): + code_blocks.append(match.group(0)) + return f"\x00CODEBLOCK{len(code_blocks) - 1}\x00" + + protected = re.sub(r'```[\s\S]*?```', stash, markdown_content) + protected = re.sub(r'`[^`]+`', stash, protected) + converted = re.sub(wikilink_pattern, replace_wikilink, protected) + return re.sub(r'\x00CODEBLOCK(\d+)\x00', lambda m: code_blocks[int(m.group(1))], converted) def generate_export_html( @@ -600,6 +607,10 @@ def generate_export_html( .markdown-preview input[type="checkbox"] {{ margin-right: 0.5em; }} + .markdown-preview li:has(> input[type="checkbox"]) {{ + list-style: none; + margin-left: -1.25em; + }} /* Enhanced Shell/Bash Syntax Highlighting */ .markdown-preview pre code.language-shell .hljs-meta, @@ -839,6 +850,16 @@ def generate_export_html( }} processed = outLines.join('\\n') .replace(/\\x00CODEBLOCK(\\d+)\\x00/g, function(_, idx) {{ return codeBlocks[parseInt(idx)]; }}); + // Escape same-line block-starters after a task marker so they + // render as literal text. Matches Obsidian. Issue #247. + processed = processed.replace( + /^(\\s*[-*+]\\s+\\[[xX ]\\]\\s+)(\\d+)\\.(\\s)/gm, + '$1$2\\\\.$3' + ); + processed = processed.replace( + /^(\\s*[-*+]\\s+\\[[xX ]\\]\\s+)([#>*+\\-])(\\s)/gm, + '$1\\\\$2$3' + ); }} // Render markdown with XSS sanitization diff --git a/frontend/app.js b/frontend/app.js index 95c84b8..3658cec 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -5963,6 +5963,15 @@ function noteApp() { contentToRender = outLines.join('\n'); } + contentToRender = contentToRender.replace( + /^(\s*[-*+]\s+\[[xX ]\]\s+)(\d+)\.(\s)/gm, + '$1$2\\.$3' + ); + contentToRender = contentToRender.replace( + /^(\s*[-*+]\s+\[[xX ]\]\s+)([#>*+\-])(\s)/gm, + '$1\\$2$3' + ); + // Step 3: Restore code blocks contentToRender = contentToRender.replace(/\x00CODEBLOCK(\d+)\x00/g, (match, index) => { return codeBlocks[parseInt(index)]; diff --git a/frontend/index.html b/frontend/index.html index b98079e..971f2ab 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -577,6 +577,10 @@ .markdown-preview input[type="checkbox"] { margin-right: 0.5rem; } + .markdown-preview li:has(> input[type="checkbox"]) { + list-style: none; + margin-left: -1.25rem; + } /* Math/LaTeX styling */ .markdown-preview .MathJax {