Skip to content

Commit 525159f

Browse files
committed
Stabilize Monaco text harness sync
1 parent 1c45fa2 commit 525159f

1 file changed

Lines changed: 45 additions & 9 deletions

File tree

‎src/PrompterOne.Shared/wwwroot/editor/editor-monaco.js‎

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -541,15 +541,9 @@ function ensureHarness(options) {
541541
});
542542
return createHarnessState(state, options);
543543
},
544-
setText: (testId, text) => {
544+
setText: async (testId, text) => {
545545
const state = getRequiredHarnessState(testId);
546-
const model = state.editor.getModel();
547-
const nextText = text ?? emptyValue;
548-
if (model) {
549-
replaceModelTextPreservingViewport(state, nextText);
550-
}
551-
552-
return createHarnessState(state, options);
546+
return await applyTextForHarnessAsync(state, text ?? emptyValue, options);
553547
},
554548
tokenizeLine: (testId, lineNumber) => {
555549
const state = getRequiredHarnessState(testId);
@@ -743,7 +737,7 @@ function onEditorContentChanged(state) {
743737
renderSemanticSnapshot(state, state.editor.getValue());
744738
scheduleDecorations(state);
745739
if (!state.suppressTextNotification) {
746-
void state.dotNetRef.invokeMethodAsync(state.options.textChangedCallbackName, state.editor.getValue());
740+
void notifyTextChangedAsync(state);
747741
}
748742
}
749743

@@ -767,6 +761,16 @@ async function notifySelectionChangedAsync(state, dismissMenus) {
767761
}
768762
}
769763

764+
async function notifyTextChangedAsync(state) {
765+
if (state.suppressTextNotification) {
766+
return;
767+
}
768+
769+
await state.dotNetRef.invokeMethodAsync(
770+
state.options.textChangedCallbackName,
771+
state.editor.getValue());
772+
}
773+
770774
function waitForAnimationFrames(frameCount = 1) {
771775
return new Promise(resolve => {
772776
const pump = remaining => {
@@ -782,6 +786,24 @@ function waitForAnimationFrames(frameCount = 1) {
782786
});
783787
}
784788

789+
function textMatchesState(state, expectedText) {
790+
const currentText = state.editor.getValue();
791+
return currentText === expectedText && state.proxy.value === expectedText;
792+
}
793+
794+
async function waitForTextState(state, expectedText) {
795+
const attempts = 12;
796+
for (let attempt = 0; attempt < attempts; attempt++) {
797+
if (textMatchesState(state, expectedText)) {
798+
return createHarnessState(state, state.options);
799+
}
800+
801+
await waitForAnimationFrames(2);
802+
}
803+
804+
return createHarnessState(state, state.options);
805+
}
806+
785807
function selectionMatchesOffsets(state, start, end) {
786808
const selection = createSelectionState(state);
787809
const orderedStart = Math.min(start, end);
@@ -803,6 +825,20 @@ async function waitForSelectionState(state, start, end) {
803825
return createSelectionState(state);
804826
}
805827

828+
async function applyTextForHarnessAsync(state, nextText, options) {
829+
const model = state.editor.getModel();
830+
if (!model) {
831+
return createHarnessState(state, options);
832+
}
833+
834+
state.suppressTextNotification = true;
835+
replaceModelTextPreservingViewport(state, nextText);
836+
state.suppressTextNotification = false;
837+
838+
await notifyTextChangedAsync(state);
839+
return await waitForTextState(state, nextText);
840+
}
841+
806842
function notifyHistoryRequested(state, command) {
807843
void state.dotNetRef.invokeMethodAsync(state.options.historyRequestedCallbackName, command);
808844
}

0 commit comments

Comments
 (0)