diff --git a/client/codemirror/fenced_code.ts b/client/codemirror/fenced_code.ts index 2a1e487b..56042c6f 100644 --- a/client/codemirror/fenced_code.ts +++ b/client/codemirror/fenced_code.ts @@ -69,8 +69,6 @@ export function fencedCodePlugin(client: Client) { }); const widget = new IFrameWidget( - from + lineStrings[0].length + 1, - to - lineStrings[lineStrings.length - 1].length - 1, client, lineStrings.slice(1, lineStrings.length - 1).join("\n"), codeWidgetCallback, diff --git a/client/codemirror/iframe_widget.ts b/client/codemirror/iframe_widget.ts index dc6cd468..904bd70c 100644 --- a/client/codemirror/iframe_widget.ts +++ b/client/codemirror/iframe_widget.ts @@ -10,8 +10,6 @@ export class IFrameWidget extends WidgetType { iframe?: HTMLIFrameElement; constructor( - readonly from: number, - readonly to: number, readonly client: Client, readonly bodyText: string, readonly codeWidgetCallback: CodeWidgetCallback, @@ -28,20 +26,21 @@ export class IFrameWidget extends WidgetType { } toDOM(): HTMLElement { - const from = this.from; const iframe = createWidgetSandboxIFrame( this.client, this.bodyText, this.codeWidgetCallback(this.bodyText, this.client.currentName()), (message) => { switch (message.type) { - case "blur": + case "blur": { + const pos = this.client.editorView.posAtDOM(iframe, 0); this.client.editorView.dispatch({ - selection: { anchor: from }, + selection: { anchor: pos }, }); this.client.focus(); break; + } case "reload": void this.codeWidgetCallback( this.bodyText, diff --git a/client/codemirror/lua_widget.ts b/client/codemirror/lua_widget.ts index 91aaf158..45482904 100644 --- a/client/codemirror/lua_widget.ts +++ b/client/codemirror/lua_widget.ts @@ -10,7 +10,7 @@ import { extendedMarkdownLanguage } from "../markdown_parser/parser.ts"; import { renderToText } from "@silverbulletmd/silverbullet/lib/tree"; import { attachWidgetEventHandlers, - moveCursorIntoText, + moveCursorToWidgetStart, } from "./widget_util.ts"; import { expandMarkdown } from "../markdown_renderer/inline.ts"; import { @@ -366,7 +366,11 @@ export class LuaWidget extends WidgetType { icon: '', listener: (e) => { e.stopPropagation(); - moveCursorIntoText(this.opts.client, this.opts.codeText!); + moveCursorToWidgetStart( + this.opts.client, + this.dom!, + this.opts.codeText, + ); }, }), ); diff --git a/client/codemirror/table.ts b/client/codemirror/table.ts index d04a1dfd..cd8eb526 100644 --- a/client/codemirror/table.ts +++ b/client/codemirror/table.ts @@ -25,7 +25,6 @@ class TableViewWidget extends WidgetType { tableBodyText: string; constructor( - readonly pos: number, readonly client: Client, readonly t: ParseTree, ) { @@ -46,9 +45,10 @@ class TableViewWidget extends WidgetType { // Pulling data-pos to put the cursor in the right place, falling back // to the start of the table. const dataAttributes = (e.target as any).dataset; + const fallbackPos = this.client.editorView.posAtDOM(dom, 0); this.client.editorView.dispatch({ selection: { - anchor: dataAttributes.pos ? +dataAttributes.pos : this.pos, + anchor: dataAttributes.pos ? +dataAttributes.pos : fallbackPos, }, }); }); @@ -138,7 +138,6 @@ export function tablePlugin(editor: Client) { widgets.push( Decoration.widget({ widget: new TableViewWidget( - from, editor, lezerToParseTree(text, node.node), ), diff --git a/client/codemirror/widget_util.ts b/client/codemirror/widget_util.ts index 847c0eeb..f3b9fbc8 100644 --- a/client/codemirror/widget_util.ts +++ b/client/codemirror/widget_util.ts @@ -2,18 +2,27 @@ import { parseToRef } from "@silverbulletmd/silverbullet/lib/ref"; import type { Client } from "../client.ts"; import type { EventPayLoad } from "./lua_widget.ts"; -export function moveCursorIntoText(client: Client, textToFind: string) { - const allText = client.editorView.state.sliceDoc(); - const pos = allText.indexOf(textToFind); - if (pos === -1) { - console.error("Could not find position of widget in text", textToFind); - return; +export function moveCursorToWidgetStart( + client: Client, + widgetDom: HTMLElement, + widgetText?: string, +) { + const view = client.editorView; + const pos = view.posAtDOM(widgetDom, 0); + + let anchor = pos; + if (widgetText) { + // The widget decoration may be placed at the end of the source range + // (node.to). Search near posAtDOM for the actual text to find its start. + const searchFrom = Math.max(0, pos - widgetText.length); + const region = view.state.sliceDoc(searchFrom, pos + widgetText.length); + const idx = region.lastIndexOf(widgetText); + if (idx !== -1) { + anchor = searchFrom + idx; + } } - client.editorView.dispatch({ - selection: { - anchor: pos, - }, - }); + + view.dispatch({ selection: { anchor } }); client.focus(); } @@ -28,7 +37,7 @@ export function attachWidgetEventHandlers( div.addEventListener("mousedown", (e) => { if (e.altKey && widgetText) { // Move cursor there - moveCursorIntoText(client, widgetText); + moveCursorToWidgetStart(client, div, widgetText); e.preventDefault(); } // CodeMirror overrides mousedown on parent elements to implement its own selection highlighting.