diff --git a/apps/desktop/src/features/editor/extensions/livePreviewHelpers.ts b/apps/desktop/src/features/editor/extensions/livePreviewHelpers.ts index 0726a271..40ea5e29 100644 --- a/apps/desktop/src/features/editor/extensions/livePreviewHelpers.ts +++ b/apps/desktop/src/features/editor/extensions/livePreviewHelpers.ts @@ -9,6 +9,7 @@ import type { SyntaxNode } from "@lezer/common"; import { selectionTouchesLine, selectionTouchesRange, + selectionTouchesRangeBoundary, } from "./selectionActivity"; // --------------------------------------------------------------------------- @@ -127,8 +128,11 @@ export function hideInactiveChildMarks( state: EditorState, decos: DecoEntry[], hiddenDeco: Decoration, + includeEndBoundary = false, ) { - const tokenActive = selectionTouchesRange(state, activeFrom, activeTo); + const tokenActive = includeEndBoundary + ? selectionTouchesRangeBoundary(state, activeFrom, activeTo) + : selectionTouchesRange(state, activeFrom, activeTo); if (tokenActive) return; const cursor = parentNode.cursor(); diff --git a/apps/desktop/src/features/editor/extensions/livePreviewInline.test.ts b/apps/desktop/src/features/editor/extensions/livePreviewInline.test.ts index 421803c7..784bf19b 100644 --- a/apps/desktop/src/features/editor/extensions/livePreviewInline.test.ts +++ b/apps/desktop/src/features/editor/extensions/livePreviewInline.test.ts @@ -584,6 +584,31 @@ describe("createInlineLivePreviewPlugin", () => { parent.remove(); }); + it("reveals emphasis delimiters when the caret is at the closing boundary", () => { + const doc = "*Texto en cursiva para revisar contraste.*"; + const { plugin, parent, view } = createView( + doc, + EditorSelection.cursor(doc.length), + ); + + const decorations = collectDecorations(view, plugin); + + expect(hasHiddenRange(decorations, 0, 1, "cm-lp-hidden-inline")).toBe( + false, + ); + expect( + hasHiddenRange( + decorations, + doc.length - 1, + doc.length, + "cm-lp-hidden-inline", + ), + ).toBe(false); + + view.destroy(); + parent.remove(); + }); + it("reveals the full markdown link when the caret is inside the token", () => { const doc = "[text](url)"; const { plugin, parent, view } = createView( diff --git a/apps/desktop/src/features/editor/extensions/livePreviewInline.ts b/apps/desktop/src/features/editor/extensions/livePreviewInline.ts index 30bddf7a..2814810a 100644 --- a/apps/desktop/src/features/editor/extensions/livePreviewInline.ts +++ b/apps/desktop/src/features/editor/extensions/livePreviewInline.ts @@ -36,6 +36,7 @@ import { selectionHasMultilineRangeTouchingLine, selectionTouchesLine, selectionTouchesRange, + selectionTouchesRangeBoundary, } from "./selectionActivity"; import { parseMarkdownListItem } from "../markdownLists"; import { @@ -130,7 +131,7 @@ type RevealSensitiveRange = { key: string; from: number; to: number; - strategy: "line" | "range" | "multiline-line"; + strategy: "line" | "range" | "range-boundary" | "multiline-line"; }; class InlineBreakWidget extends WidgetType { @@ -550,6 +551,8 @@ function getRevealSensitiveSignature( const active = range.strategy === "line" ? selectionTouchesLine(state, range.from, range.to) + : range.strategy === "range-boundary" + ? selectionTouchesRangeBoundary(state, range.from, range.to) : range.strategy === "multiline-line" ? selectionHasMultilineRangeTouchingLine( state, @@ -596,7 +599,12 @@ function createInlineFormattingRule( ): NodeRule { return (node, context) => { if (node.name !== nodeName) return; - registerRevealSensitiveRange(context, "range", node.from, node.to); + registerRevealSensitiveRange( + context, + "range-boundary", + node.from, + node.to, + ); pushDeco(context, node.from, node.to, mark); hideInactiveChildMarks( node.node, @@ -606,6 +614,7 @@ function createInlineFormattingRule( context.state, context.decos, hideInlineMark, + true, ); }; } diff --git a/apps/desktop/src/features/editor/extensions/selectionActivity.ts b/apps/desktop/src/features/editor/extensions/selectionActivity.ts index 23ae1709..43ad8856 100644 --- a/apps/desktop/src/features/editor/extensions/selectionActivity.ts +++ b/apps/desktop/src/features/editor/extensions/selectionActivity.ts @@ -20,6 +20,26 @@ export function selectionTouchesRange( return false; } +export function selectionTouchesRangeBoundary( + state: EditorState, + from: number, + to: number, +): boolean { + for (const range of state.selection.ranges) { + if (range.empty) { + if (range.from >= from && range.from <= to) { + return true; + } + continue; + } + + if (range.to >= from && range.from <= to) { + return true; + } + } + return false; +} + export function selectionTouchesLine( state: EditorState, from: number,