Skip to content

fix(core): fixed-width tabs with reliable caret coords - #123

Draft
jsimonrichard wants to merge 7 commits into
mainfrom
cursor/fixed-tab-widget-cursor-height-47f0
Draft

fix(core): fixed-width tabs with reliable caret coords#123
jsimonrichard wants to merge 7 commits into
mainfrom
cursor/fixed-tab-widget-cursor-height-47f0

Conversation

@jsimonrichard

@jsimonrichard jsimonrichard commented Apr 12, 2026

Copy link
Copy Markdown
Owner

Summary

Disappearing caret (mark + overflow: hidden)

A Decoration.mark around \t with a narrower inline-block and overflow: hidden still lays out the tab using native tab stops. The text node’s getClientRects() can end up outside the clipped box. EditorView.coordsAtPos then sees left === right, bails out, and drawSelection draws a zero-width caret — it looks like the cursor vanished.

Fix

Go back to Decoration.replace, but the widget DOM is a span that still contains a literal \t (like CodeMirror’s own TabWidget in highlightSpecialChars). That keeps moveVisually / default arrow keys working without a custom keymap.

  • Width: TAB_WIDTH_CH * defaultCharacterWidth / scaleX in pixels (recomputed on geometryChanged and via updateDOM).
  • Caret coords: implement WidgetType.coordsAt to return the left or right edge of the box (zero-width caret segment), so drawSelection never depends on clipped glyph rects.
  • Display: color: transparent, caret-color: currentColor, overflow: hidden, vertical-align / height as before.

Changeset

.changeset/fixed-tab-cursor-height.md@prosemark/core (patch).

Open in Web Open in Cursor 

@changeset-bot

changeset-bot Bot commented Apr 12, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 628ddef

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@prosemark/core Patch
vscode-prosemark Patch
@prosemark/latex Patch
@prosemark/render-html Patch
@prosemark/spellcheck-frontend Patch
vscode-prosemark-cspell-integration Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Apr 12, 2026

Copy link
Copy Markdown
@prosemark/core

npm i https://pkg.pr.new/jsimonrichard/ProseMark/@prosemark/core@123

@prosemark/latex

npm i https://pkg.pr.new/jsimonrichard/ProseMark/@prosemark/latex@123

@prosemark/paste-rich-text

npm i https://pkg.pr.new/jsimonrichard/ProseMark/@prosemark/paste-rich-text@123

@prosemark/render-html

npm i https://pkg.pr.new/jsimonrichard/ProseMark/@prosemark/render-html@123

@prosemark/spellcheck-frontend

npm i https://pkg.pr.new/jsimonrichard/ProseMark/@prosemark/spellcheck-frontend@123

@prosemark/vscode-extension-integrator

npm i https://pkg.pr.new/jsimonrichard/ProseMark/@prosemark/vscode-extension-integrator@123

commit: 81e090c

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Apr 12, 2026

Copy link
Copy Markdown

Deploying prosemark with  Cloudflare Pages  Cloudflare Pages

Latest commit: 628ddef
Status: ✅  Deploy successful!
Preview URL: https://62b788d3.prosemark.pages.dev
Branch Preview URL: https://cursor-fixed-tab-widget-curs.prosemark.pages.dev

View logs

@cursor cursor Bot changed the title fix(core): stable caret height after fixed-width tab widget fix(core): fixed-width tabs via marks (caret + motion) Apr 12, 2026
@cursor cursor Bot changed the title fix(core): fixed-width tabs via marks (caret + motion) fix(core): fixed-width tabs with reliable caret coords Apr 12, 2026
cursoragent and others added 6 commits April 12, 2026 01:32
Empty inline-block tabs used the baseline box model and stretched the
line, so coordsAtPos reported a taller rect when the cursor followed
a tab. Align like cm-widgetBuffer and set height to 1em.

Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com>
CodeMirror's visual char motion can skip the document index of a
replaced tab. Run a Prec.high keymap that steps across tab code units
in logical forward/backward order (matching default ArrowLeft/Right)
before the default keymap handles the key.

Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com>
Decoration.replace removes tabs from the text layout tree, so
moveVisually never steps through them. Use Decoration.mark with a
fixed-width transparent span so the \t remains in the line string,
arrow keys need no override, and soft-indent pixel width stays stable.

Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com>
Mark + overflow:hidden left the tab glyph's client rects outside the
box, so coordsAtPos got left==right and the overlay caret vanished.
Use replace widget with literal tab, fixed px width from char width,
and WidgetType.coordsAt on box edges; refresh on geometryChanged.

Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com>
coordsInWidget passes pos=0/1 for ends of replaced range; using the
document side argument picked the wrong edge and broke drawSelection.
Clamp tall rects like Placeholder.coordsAt.

Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com>
@cursor
cursor Bot force-pushed the cursor/fixed-tab-widget-cursor-height-47f0 branch from 42f5fc9 to f93b3a8 Compare April 12, 2026 01:34
Similar layout to debug-vsc-extn-in-web but without VS Code flows,
spellcheck, latex, or render-html. Includes drawSelection and tab
fixture buttons for reproducing caret/coords issues.

Co-authored-by: J. Simon Richard <jsimonrichard@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants