Fix client-driven directive updates

demo
Zef Hemel 2022-11-23 10:05:01 +01:00
parent 56e5466b19
commit 0ebbe2e7f3
1 changed files with 24 additions and 26 deletions

View File

@ -15,13 +15,13 @@ export async function updateDirectivesOnPageCommand() {
} }
// Collect all directives and their body replacements // Collect all directives and their body replacements
const replacements: { startInst: string; text?: string }[] = []; const replacements: { fullMatch: string; text?: string }[] = [];
await replaceAsync( await replaceAsync(
text, text,
directiveRegex, directiveRegex,
async (fullMatch, startInst, _type, _arg, _body, endInst, index) => { async (fullMatch, startInst, _type, _arg, _body, endInst, index) => {
const replacement: { startInst: string; text?: string } = { startInst }; const replacement: { fullMatch: string; text?: string } = { fullMatch };
// Pushing to the replacement array // Pushing to the replacement array
replacements.push(replacement); replacements.push(replacement);
const currentNode = nodeAtPos(tree, index + 1); const currentNode = nodeAtPos(tree, index + 1);
@ -44,34 +44,32 @@ export async function updateDirectivesOnPageCommand() {
} }
}, },
); );
let counter = 0;
// Iterate again and replace the bodies. Iterating again (not using previous positions) // Iterate again and replace the bodies. Iterating again (not using previous positions)
// because text may have changed in the mean time (directive processing may take some time) // because text may have changed in the mean time (directive processing may take some time)
// Hypothetically in the mean time directives in text may have been changed/swapped, in which // Hypothetically in the mean time directives in text may have been changed/swapped, in which
// case this will break. This would be a rare edge case, however. // case this will break. This would be a rare edge case, however.
await replaceAsync( for (const replacement of replacements) {
text, // Fetch the text every time, because dispatch() will have been made changes
directiveRegex, const text = await editor.getText();
async (fullMatch, startInst, _type, _arg, _body, endInst, index) => { // Determine the current position
const replacement = replacements[counter++]; const index = text.indexOf(replacement.fullMatch);
if (!replacement.text) {
return `${startInst}\n$**ERROR:** Internal error, no replacement found\n${endInst}`; // This may happen if the query itself, or the user is editing inside the directive block (WHY!?)
} if (index === -1) {
if (replacement.text === fullMatch) { console.warn(
// No change, no need to dispatch "Could not find directive in text, skipping",
return fullMatch; replacement.fullMatch,
} );
// Dispatch the change as a somewhat minimal diff in order not to interfere with current editing continue;
await editor.dispatch({ }
changes: { await editor.dispatch({
from: index, changes: {
to: index + fullMatch.length, from: index,
insert: replacement.text, to: index + replacement.fullMatch.length,
}, insert: replacement.text,
}); },
return replacement.text; });
}, }
);
} }
// Called from client, running on server // Called from client, running on server