Skip to content

Commit 50455fa

Browse files
committed
Use useCallback to avoid running Monaco prop effects too much
1 parent 6feca9b commit 50455fa

File tree

1 file changed

+98
-78
lines changed

1 file changed

+98
-78
lines changed

ui/frontend/editor/MonacoEditorCore.tsx

Lines changed: 98 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -81,93 +81,113 @@ const MonacoEditorCore: React.FC<CommonEditorProps> = (props) => {
8181
editor.focus();
8282
}, []);
8383

84-
useEditorProp(editor, props.onEditCode, (_editor, model, onEditCode) => {
85-
model.onDidChangeContent(() => {
86-
onEditCode(model.getValue());
87-
});
88-
});
89-
90-
useEditorProp(editor, props.execute, (editor, _model, execute) => {
91-
editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter, () => {
92-
execute();
93-
});
94-
// Ace's Vim mode runs code with :w, so let's do the same
95-
editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {
96-
execute();
97-
});
98-
});
84+
useEditorProp(
85+
editor,
86+
props.onEditCode,
87+
useCallback((_editor, model, onEditCode) => {
88+
model.onDidChangeContent(() => {
89+
onEditCode(model.getValue());
90+
});
91+
}, []),
92+
);
9993

100-
useEditorProp(editor, props.code, (editor, model, code) => {
101-
// Short-circuit if nothing interesting to change.
102-
if (code === model.getValue()) {
103-
return;
104-
}
94+
useEditorProp(
95+
editor,
96+
props.execute,
97+
useCallback((editor, _model, execute) => {
98+
editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter, () => {
99+
execute();
100+
});
101+
// Ace's Vim mode runs code with :w, so let's do the same
102+
editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {
103+
execute();
104+
});
105+
}, []),
106+
);
105107

106-
editor.executeEdits('redux', [
107-
{
108-
text: code,
109-
range: model.getFullModelRange(),
110-
},
111-
]);
112-
});
108+
useEditorProp(
109+
editor,
110+
props.code,
111+
useCallback((editor, model, code) => {
112+
// Short-circuit if nothing interesting to change.
113+
if (code === model.getValue()) {
114+
return;
115+
}
116+
117+
editor.executeEdits('redux', [
118+
{
119+
text: code,
120+
range: model.getFullModelRange(),
121+
},
122+
]);
123+
}, []),
124+
);
113125

114-
useEditorProp(editor, theme, (editor, _model, theme) => {
115-
editor.updateOptions({ theme });
116-
});
126+
useEditorProp(
127+
editor,
128+
theme,
129+
useCallback((editor, _model, theme) => {
130+
editor.updateOptions({ theme });
131+
}, []),
132+
);
117133

118134
const autocompleteProps = useMemo(
119135
() => ({ autocompleteOnUse, crates: props.crates }),
120136
[autocompleteOnUse, props.crates],
121137
);
122138

123-
useEditorProp(editor, autocompleteProps, (_editor, _model, { autocompleteOnUse, crates }) => {
124-
completionProvider.current = monaco.languages.registerCompletionItemProvider('rust', {
125-
triggerCharacters: [' '],
126-
127-
provideCompletionItems(model, position, _context, _token) {
128-
const word = model.getWordUntilPosition(position);
129-
130-
function wordBefore(
131-
word: monaco.editor.IWordAtPosition,
132-
): monaco.editor.IWordAtPosition | null {
133-
const prevPos = { lineNumber: position.lineNumber, column: word.startColumn - 1 };
134-
return model.getWordAtPosition(prevPos);
135-
}
136-
137-
const preWord = wordBefore(word);
138-
const prePreWord = preWord && wordBefore(preWord);
139-
140-
const oldStyle = prePreWord?.word === 'extern' && preWord?.word === 'crate';
141-
const newStyle = autocompleteOnUse && preWord?.word === 'use';
142-
143-
const triggerPrefix = oldStyle || newStyle;
144-
145-
if (!triggerPrefix) {
146-
return { suggestions: [] };
147-
}
148-
149-
const range = {
150-
startLineNumber: position.lineNumber,
151-
endLineNumber: position.lineNumber,
152-
startColumn: word.startColumn,
153-
endColumn: word.endColumn,
154-
};
155-
156-
const suggestions = crates.map(({ name, version, id }) => ({
157-
kind: monaco.languages.CompletionItemKind.Module,
158-
label: `${name} (${version})`,
159-
insertText: `${id}; // ${version}`,
160-
range,
161-
}));
162-
163-
return { suggestions };
164-
},
165-
});
166-
167-
return () => {
168-
completionProvider.current?.dispose();
169-
};
170-
});
139+
useEditorProp(
140+
editor,
141+
autocompleteProps,
142+
useCallback((_editor, _model, { autocompleteOnUse, crates }) => {
143+
completionProvider.current = monaco.languages.registerCompletionItemProvider('rust', {
144+
triggerCharacters: [' '],
145+
146+
provideCompletionItems(model, position, _context, _token) {
147+
const word = model.getWordUntilPosition(position);
148+
149+
function wordBefore(
150+
word: monaco.editor.IWordAtPosition,
151+
): monaco.editor.IWordAtPosition | null {
152+
const prevPos = { lineNumber: position.lineNumber, column: word.startColumn - 1 };
153+
return model.getWordAtPosition(prevPos);
154+
}
155+
156+
const preWord = wordBefore(word);
157+
const prePreWord = preWord && wordBefore(preWord);
158+
159+
const oldStyle = prePreWord?.word === 'extern' && preWord?.word === 'crate';
160+
const newStyle = autocompleteOnUse && preWord?.word === 'use';
161+
162+
const triggerPrefix = oldStyle || newStyle;
163+
164+
if (!triggerPrefix) {
165+
return { suggestions: [] };
166+
}
167+
168+
const range = {
169+
startLineNumber: position.lineNumber,
170+
endLineNumber: position.lineNumber,
171+
startColumn: word.startColumn,
172+
endColumn: word.endColumn,
173+
};
174+
175+
const suggestions = crates.map(({ name, version, id }) => ({
176+
kind: monaco.languages.CompletionItemKind.Module,
177+
label: `${name} (${version})`,
178+
insertText: `${id}; // ${version}`,
179+
range,
180+
}));
181+
182+
return { suggestions };
183+
},
184+
});
185+
186+
return () => {
187+
completionProvider.current?.dispose();
188+
};
189+
}, []),
190+
);
171191

172192
return <div className={styles.monaco} ref={child} />;
173193
};

0 commit comments

Comments
 (0)