feat(rich-markdown-editor): round-trip gate, VSCode/style paste, highlight, block reorder#5539
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Paste now turns VSCode copies with The read-only round-trip gate ( Tests cover block moves, highlight parse/serialize, paste paths, mark stacking idempotency, and the new gate cases. Reviewed by Cursor Bugbot for commit f2b07b1. Configure here. |
Greptile SummaryThis PR expands the rich markdown editor with safer round-tripping and new editing tools. The main changes are:
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (5): Last reviewed commit: "feat(rich-markdown-editor): keyboard blo..." | Re-trigger Greptile |
c8c4580 to
deff589
Compare
deff589 to
4241b65
Compare
|
@greptile review |
|
@cursor review |
4241b65 to
17530cd
Compare
|
@greptile review |
|
@cursor review |
17530cd to
eff75c3
Compare
|
@greptile review |
|
@cursor review |
…ies and orphan ref-defs Two silent-corruption cases the idempotency probe can't see: - The HTML-entity safe-list used a case-insensitive regex, so `&`/`<`/`>` were treated as the round-trippable canonical entities and let through as editable, but the serializer only round-trips the lowercase forms and mangles the uppercase ones. Make the safe-list case-sensitive. - An unused link/image reference definition (`[x]: url` with no `[x]` reference) is dropped entirely on serialize, a deletion the idempotency probe misses. Detect orphan definitions and open read-only; used definitions still inline losslessly and stay editable. The use check tolerates bracket-internal padding (`[ x ]`), and GFM footnote definitions (`[^id]: …`) are excluded since they round-trip verbatim.
…pt> from pasted HTML - Code copied from VSCode carries a `vscode-editor-data` payload with the source language, but its text/html is per-token colored spans that ProseMirror flattens into plain paragraphs. Read the payload and paste a real fenced code block with the mapped language. markdown/plaintext modes resolve to no language and fall through, so markdown copied from VSCode still parses as rich content rather than a fenced block. - Google Sheets and Word prepend a `<style>` block of CSS that PM's DOM parser walks into the document as literal text. Strip <style>/<script> in transformPastedHTML before parsing. - Add a `==…==` inline-mark hint (allowing a lone interior `=`) so a plain-text paste of `==highlight==` routes through the markdown parser and becomes a highlight mark.
Adds a highlight mark rendered as <mark> and serialized to/from ==text== (Pandoc/Obsidian syntax). A custom inline tokenizer parses ==text== (inner text parsed as inline markdown so nested marks like ==**bold**== survive; the body allows a lone `=` so ==a=b== round-trips). `==` cannot be encoded in the delimiter, so an appendTransaction guard strips the mark from any text that ends up containing `==` (e.g. a toolbar highlight over a==b), keeping the text and never emitting the corrupting ==a==b==. Comparison operators (x == y) stay literal. Wired with an input rule, paste rule, Mod-Shift-H, a bubble-menu button, and themed <mark> styling. Also locks in mark-stacking round-trips across contexts.
Mod-Shift-ArrowUp/ArrowDown swaps the current top-level block with its neighbour, carrying the caret at its original offset (newBefore + offset, no off-by-one), and no-ops at the document edges. Exposed as moveBlockUp/moveBlockDown commands (the keyboard shortcuts call them). Pure UI interaction, no schema change. Covered by tests (order, caret offset, edge no-op, list stays intact).
eff75c3 to
f2b07b1
Compare
|
@greptile review |
|
@cursor 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 f2b07b1. Configure here.
Summary
A correctness + capability pass on the rich-markdown (
.md) editor. Everything here is empirically verified in a real-browser ProseMirror harness and covered by CI tests.Correctness — read-only gate (
round-trip-safety.ts)Two silent-corruption cases the idempotency probe can't see:
&/</>) slipped past a case-insensitive safe-list but aren't round-tripped by the serializer → now case-sensitive, opens read-only.[x]: urlwith no[x]use) were dropped entirely on first edit → detected and opened read-only; used definitions still inline losslessly.Paste (
markdown-paste.ts)vscode-editor-datapayload and pastes a real fenced code block with the source language, instead of flattening the colored-span HTML into plain paragraphs.<style>/<script>strip —transformPastedHTMLremoves them so pasting from Google Sheets/Word doesn't leak raw CSS into the doc.Capabilities
==mark==— a<mark>mark serialized to/from==text==(custom marked tokenizer so nested marks like==**bold**==survive; comparison operatorsx == ystay literal). Input rule, paste rule,⌘⇧H, bubble-menu button, themed styling.⌘⇧↑/⌘⇧↓moves the current top-level block, carrying the caret.Validation
Deliberately not done
~x~—~x~and~~x~~both render<del>x</del>per the GFM spec (one-or-two tildes = strikethrough), so our single→double normalization is lossless, not a meaning change. Left as-is.+/grip drag-handle — the keyboard reorder above is the robust core; the hover UI needs a drag-handle dep + visual iteration, best done with live visual QA. Recommended as a focused follow-up.Testing
Real-browser harness (60+ cases) + committed Vitest in CI: round-trip idempotency, mark stacking, highlight parse/serialize/nesting/safety, block reorder, entity/ref-def gate. No regressions.