Uh oh!
There was an error while loading. Please reload this page.
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 |
Uh oh!
There was an error while loading. Please reload this page.
…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.
waleedlatif1
commented
Jul 7, 2026
@cursor review |
waleedlatif1
commented
Jul 7, 2026
@greptile review |
Uh oh!
There was an error while loading. Please reload this page.
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').waleedlatif1
commented
Jul 7, 2026
@cursor review |
waleedlatif1
commented
Jul 7, 2026
@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.
Uh oh!
There was an error while loading. Please reload this page.
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