Initial checklist
Problem
Doing "replaceAll' the cursor position is lost.
Solution
I'm now using the code below and it seems to be working well for me (so, my suggestion is add that -- or something close to it -- in the same context that replaceAll is added).
import { editorViewCtx, parserCtx } from "@milkdown/kit/core";
import { computeDocDiff } from "@milkdown/plugin-diff";
import type { EditorView } from "@milkdown/prose/view";
/**
* Applies a semantic patch to the current Milkdown document.
*
* Uses Milkdown's block-level LCS diff with per-block ChangeSet merging so
* edits are as small as possible (preserving cursor position when mapping allows).
*
* Returns true if a transaction was dispatched.
*/
export function patchMarkdown(
editor: { action: (action: (ctx: any) => unknown) => unknown },
newMarkdown: string,
): boolean {
return editor.action((ctx) => {
const view: EditorView = ctx.get(editorViewCtx);
const parser = ctx.get(parserCtx);
const oldDoc = view.state.doc;
const newDoc = parser(newMarkdown);
if (oldDoc.eq(newDoc)) {
return false;
}
const changes = computeDocDiff(oldDoc, newDoc);
if (changes.length === 0) {
return false;
}
let tr = view.state.tr;
for (let i = changes.length - 1; i >= 0; i--) {
const change = changes[i]!;
const newContent = newDoc.slice(change.fromB, change.toB);
tr = tr.replace(change.fromA, change.toA, newContent);
}
if (!tr.docChanged) {
return false;
}
tr.setSelection(view.state.selection.map(tr.doc, tr.mapping));
view.dispatch(tr);
return true;
}) as boolean;
}
Alternatives
I haven't found a good alternative to "migrate" to a new markdown structure without loosing the cursor (maybe I'm missing something?)
Initial checklist
Problem
Doing "replaceAll' the cursor position is lost.
Solution
I'm now using the code below and it seems to be working well for me (so, my suggestion is add that -- or something close to it -- in the same context that
replaceAllis added).Alternatives
I haven't found a good alternative to "migrate" to a new markdown structure without loosing the cursor (maybe I'm missing something?)