Fix live preview empty list caret anchor#106
Conversation
spamsch
left a comment
There was a problem hiding this comment.
Independent confirmation: pulled the branch and ran the suite. 10/10 Playwright + 44/44 vitest in livePreviewInline.test.ts pass against PR #106.
Two notes after comparing approaches:
The decomposition is the right one. Keeping the hide and the caret anchor as separate decorations at separate positions reads more cleanly than collapsing the whole line as one Decoration.replace. It also leaves taskMarkerRule's existing hide intact, which keeps the responsibilities at "this rule hides this token" instead of having to remember that another rule already covered me.
The click-redirect is the part I missed in my own attempt. Without it, posAtCoords returning a position inside the collapsed prefix dropped the caret into hidden source and made it disappear on click — same artifact as before, different trigger. moveEmptyListPrefixClickToContentStart closes that gap, and the new clicking an active empty list prefix keeps the caret visible e2e case pins it.
One small style suggestion: addEmptyListCaretAnchor calls pushDeco with an inline Decoration.widget({ widget, side: -1 }) — building that wrapper once at module scope (the way emptyListCaretAnchorWidget already is) would avoid allocating a new spec object per anchor. Minor, take it or leave it.
LGTM. Glad to see this land.
|
Thank you for checking my work. I added a new commit with your suggestions. I’m really proud of this PR. Thank you for helping me chase it down. |
|
Small follow-up fix: I found one more path where the caret anchor could be missing. If an empty list item was initially inactive, its decorations were built without the caret anchor. Clicking into that line changed the selection, but the plugin did not always rebuild because the line was only registered as This commit registers empty list lines as normal line-selection-sensitive too, so entering/leaving an empty list item rebuilds the decorations and installs the caret anchor immediately. I also added an e2e case for clicking an initially inactive empty list item. Validation:
|
Summary
Fixes the live preview caret behavior for active empty list items.
The issue had two layers: collapsing only the marker left a real trailing source space that pushed the caret about one character past the rendered bullet, while collapsing the full prefix fixed the horizontal position but left
drawSelection()without real geometry for the cursor in empty items.This PR keeps the full source prefix collapsed and adds a zero-width caret anchor only for active empty list items, so CodeMirror has a natural-height geometry target without changing global cursor styling. It also normalizes clicks that land inside the collapsed list prefix so the caret moves to the visual content start instead of staying inside hidden source text.
Changes
Validation
npm test -- --run src/features/editor/extensions/livePreviewInline.test.tsnpm run test:e2eFixes #102.