A local-first note taking app
0

Configure Feed

Select the types of activity you want to include in your feed.

Hide inline markers as soon as cursor leaves the span

Proximity reveal used a 2-char window, so after typing a closing marker
(e.g. the second *) the markers stayed visible until the cursor moved 3
characters past them. Set PROXIMITY_CHARS to 0 so markers reveal only
while the cursor is within/touching the span and hide the moment it moves
one character past the closing marker. Affects bold, italic, strikethrough,
inline code, and links.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

authored by

Ethan Graf
Claude Opus 4.8
and committed by
Tangled
(Jul 19, 2026, 5:59 PM +0300) bdd3e1e9 e45d0cbb

+37 -6
+16 -6
src/editors/automerge/livePreview/context.ts
··· 28 28 } from '@codemirror/view'; 29 29 import { syntaxTree } from '@codemirror/language'; 30 30 31 - /** How many characters away from an inline span still reveals its markers. */ 32 - export const PROXIMITY_CHARS = 2; 31 + /** 32 + * How far past a span's boundaries the cursor still reveals its markers. 33 + * 34 + * 0 means markers are shown only while the cursor is *within* the span 35 + * (boundaries inclusive), and hide as soon as it moves one character past the 36 + * closing marker. A wider window would keep e.g. `*abc*` markers visible for N 37 + * more characters after the closing `*` is typed, which reads as the markers 38 + * "sticking" after the text is already formatted. 39 + */ 40 + export const PROXIMITY_CHARS = 0; 33 41 34 42 export interface Range { 35 43 from: number; ··· 76 84 77 85 /** 78 86 * True iff the cursor is on the SAME LINE as the span [from, to] AND within 79 - * `slack` chars of its boundaries. Same-line gating stops proximity-reveal 80 - * from leaking onto neighbouring lines. Correct for bold/italic/strike/links, 81 - * which cannot cross newlines per the @lezer/markdown grammar. Inline code is 82 - * the exception (it may span newlines) — use `isCursorInRange` there. 87 + * `slack` chars of its boundaries (slack defaults to 0 → boundaries inclusive, 88 + * so the cursor must be within/touching the span). Same-line gating stops 89 + * proximity-reveal from leaking onto neighbouring lines. Correct for 90 + * bold/italic/strike/links, which cannot cross newlines per the 91 + * @lezer/markdown grammar. Inline code is the exception (it may span newlines) 92 + * — use `isCursorInRange` there. 83 93 */ 84 94 export function isCursorNearSameLine( 85 95 state: EditorState,
+21
src/editors/automerge/livePreview/livePreview.test.ts
··· 108 108 expect(withClass(list, 'cm-inline-formatting-hidden')).toHaveLength(0); 109 109 }); 110 110 111 + it('hides markers as soon as the cursor moves one char past the close', () => { 112 + // "*abc*def": Emphasis node is [0,5]; the closing "*" ends at offset 5. 113 + // At the boundary (just typed the closing marker) markers stay visible; 114 + // one character later they hide. 115 + const atClose = makeState('*abc*def', 5); // cursor right after closing "*" 116 + expect( 117 + withClass( 118 + decos(atClose, buildInlineFormatDecorations(atClose)), 119 + 'cm-inline-formatting-hidden', 120 + ), 121 + ).toHaveLength(0); 122 + 123 + const pastClose = makeState('*abc*def', 6); // one character past the "*" 124 + expect( 125 + withClass( 126 + decos(pastClose, buildInlineFormatDecorations(pastClose)), 127 + 'cm-inline-formatting-hidden', 128 + ).map((h) => h.text), 129 + ).toEqual(['*', '*']); 130 + }); 131 + 111 132 it('handles italic and strikethrough', () => { 112 133 const italic = makeState('hello world *it* end', 0); 113 134 expect(