fix(rich-markdown-editor): strict, provenance-aware markdown paste#5463
Conversation
Pasting code-like text such as `5 * width * height` was italicized by StarterKit's lenient mark paste rules. Own emphasis with the strict CommonMark parser instead: - Disable StarterKit's mark paste rules (`enablePasteRules: false`); markdown paste is handled by MarkdownPaste (marked) and rich paste by real HTML tags. Input rules (typing) are unaffected. - Split the paste gate by provenance: structural markdown always parses (faithful GFM tables and escaping), while inline-only marks parse for a plain-text paste but defer to a rich HTML sibling so a copied table isn't flattened. Emphasis (`*_ ** __ ~~ ``) renders; `5 * width`, `*args`, and `snake_case` stay literal — matching Obsidian/Linear.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview
Tests cover the full gate matrix: inline marks render on plain paste, defer with HTML, code-like strings stay literal under strict flanking, and inline-code paste stays literal. Reviewed by Cursor Bugbot for commit aefb444. Configure here. |
Greptile SummaryThis PR replaces StarterKit's lenient mark paste rules with a provenance-aware two-tier markdown paste gate, fixing the bug where code-like expressions such as
Confidence Score: 5/5The change is safe to merge — it narrows a paste interception bug with a well-structured two-tier gate backed by a comprehensive test suite covering every branch of the new logic. The two-tier gate (structural vs. inline-only), the HTML-sibling deferral, and the inline-code guard all correctly handle the edge cases described. The marked strict-CommonMark parser preserves non-markdown text byte-for-byte, so the over-claiming in INLINE_MARK_HINTS is provably safe. Tests cover the full gate matrix including the new paths. No data-loss or auth risk is introduced. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Paste event] --> B{editor.isEditable?}
B -- No --> Z[return false\ndefault handler]
B -- Yes --> C{isActive codeBlock\nor inline code?}
C -- Yes --> Z
C -- No --> D{text/plain present?}
D -- No --> Z
D -- Yes --> E{STRUCTURAL_MARKDOWN_HINTS\nmatch?}
E -- Yes --> H[parseMarkdownToDoc\nmarked / strict CommonMark]
E -- No --> F{INLINE_MARK_HINTS\nmatch?}
F -- No --> Z
F -- Yes --> G{text/html sibling\npresent?}
G -- Yes --> Z2[return false\nDOM path handles HTML sibling]
G -- No --> H
H --> I{doc has content?}
I -- No --> Z
I -- Yes --> J[insertContent\nreturn true]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[Paste event] --> B{editor.isEditable?}
B -- No --> Z[return false\ndefault handler]
B -- Yes --> C{isActive codeBlock\nor inline code?}
C -- Yes --> Z
C -- No --> D{text/plain present?}
D -- No --> Z
D -- Yes --> E{STRUCTURAL_MARKDOWN_HINTS\nmatch?}
E -- Yes --> H[parseMarkdownToDoc\nmarked / strict CommonMark]
E -- No --> F{INLINE_MARK_HINTS\nmatch?}
F -- No --> Z
F -- Yes --> G{text/html sibling\npresent?}
G -- Yes --> Z2[return false\nDOM path handles HTML sibling]
G -- No --> H
H --> I{doc has content?}
I -- No --> Z
I -- Yes --> J[insertContent\nreturn true]
Reviews (3): Last reviewed commit: "fix(rich-markdown-editor): keep paste li..." | Re-trigger Greptile |
…reserved byte-for-byte The gate is intentionally lenient — a precise CommonMark-emphasis matcher would risk missing real emphasis. Over-claiming is safe because the strict parser (marked) preserves non-markdown exactly; assert the handler claims the paste and returns the input unchanged, not just that no mark is added.
|
@cursor review |
|
@greptile review |
The paste handler skipped a fenced code block but not the inline code mark. Now that inline marks
gate the parse, pasting `*italic*` inside inline code would render rich instead of staying literal —
extend the code-context guard to editor.isActive('code').
|
@cursor review |
|
@greptile review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit aefb444. Configure here.
Summary
Pasting code-like text such as
5 * width * heightwas being italicized ("width" became emphasis) by StarterKit's lenient mark paste rules. This makes markdown paste strict and correct — matching Obsidian/Linear.enablePasteRules: falseon both editor variants). Emphasis is owned byMarkdownPaste(strict CommonMark viamarked) on the plain-text path and by real HTML tags on the DOM path. Input rules (typing*x*→ italic) are unaffected — they're a separate mechanism.**bold**) always parses from the plain-text sibling — our parser is more faithful for GFM alignment/escaping. Inline-only marks (`*_ ~~ ``) parse for a plain-text-only paste, but defer to a rich HTML sibling (its presence signals a rich source that may carry structure the plain text can't — so a copied table isn't flattened).Behavior (verified)
*italic*,_italic_,**bold**,__bold__,~~strike~~,`code`, and all block constructs.5 * width * height,def foo(*args, **kwargs),snake_case,file_path_here, URLs with underscores.Type of Change
Testing
Committed unit tests cover the full gate matrix (constructs render, inline-only defers to HTML, code-like text isn't emphasized, structural parses with an HTML sibling, read-only/code-block/empty). Behavior additionally verified end-to-end in a real-browser paste harness (25 cases + typing/input-rule audit).
Checklist