in frontend/libs/code-editor/src/lib/hooks/useHandleDefaultFeatures.ts [12:380]
export function useHandleDefaultFeatures({
codeEditor,
codeEditorPlace,
makeCallback,
onEnter,
onTab,
onRightArrow,
onLeftArrow,
onTopArrow,
onBottomArrow,
onCtrlEnter,
onEscape,
onUndo,
onRedo,
}: Props & Partial<CodeEditorProps>) {
const [disposeFindAction, setDisposeFindAction] = useState<IDisposable>();
const [disposeHelpAction, setDisposeHelpAction] = useState<IDisposable>();
const [disposeEnterAction, setDisposeEnterAction] = useState<IDisposable>();
const [disposeTabAction, setDisposeTabAction] = useState<IDisposable>();
const [disposeRightArrowAction, setDisposeRightArrowAction] =
useState<IDisposable>();
const [disposeLeftArrowAction, setDisposeLeftArrowAction] =
useState<IDisposable>();
const [disposeTopArrowAction, setDisposeTopArrowAction] =
useState<IDisposable>();
const [disposeBottomArrowAction, setDisposeBottomArrowAction] =
useState<IDisposable>();
useEffect(() => {
// With addAction() we can dispose the action if needed unlike the addCommand()
// This needed when formula bar is expanded and enter key needs to play default role
// when formula bar is collapsed, we need to add the onEnter action back to save code
// *precondition* parameter is used to avoid the action when suggestion widget is open
if (!onEnter && disposeEnterAction) {
disposeEnterAction.dispose();
setDisposeEnterAction(undefined);
return;
}
if (onEnter && !disposeEnterAction && codeEditor) {
const disposeOnEnter = codeEditor.addAction({
id: 'onEnter',
label: 'onEnter',
keybindings: [KeyCode.Enter],
precondition: '!suggestWidgetVisible',
run: () => {
makeCallback('onEnter');
},
});
setDisposeEnterAction(disposeOnEnter);
return;
}
}, [codeEditor, disposeEnterAction, makeCallback, onEnter]);
useEffect(() => {
const needReplaceAction = codeEditorPlace === 'cellEditor';
if (!needReplaceAction || !codeEditor) return;
if (!onTab && disposeTabAction) {
disposeTabAction.dispose();
setDisposeTabAction(undefined);
return;
}
if (onTab && !disposeTabAction && codeEditor) {
const disposeOnTab = codeEditor.addAction({
id: 'onTab',
label: 'onTab',
keybindings: [KeyCode.Tab],
precondition: '!suggestWidgetVisible && !inlineSuggestionVisible',
run: () => {
makeCallback('onTab');
},
});
setDisposeTabAction(disposeOnTab);
return;
}
}, [codeEditor, codeEditorPlace, disposeTabAction, makeCallback, onTab]);
useEffect(() => {
const needReplaceAction = codeEditorPlace === 'cellEditor';
if (!needReplaceAction || !codeEditor) return;
if (!onRightArrow && disposeRightArrowAction) {
disposeRightArrowAction.dispose();
setDisposeRightArrowAction(undefined);
return;
}
if (onRightArrow && !disposeRightArrowAction && codeEditor) {
const disposeOnRightArrow = codeEditor.addAction({
id: 'onRightArrow',
label: 'onRightArrow',
keybindings: [KeyCode.RightArrow],
precondition: '!suggestWidgetVisible',
run: () => {
makeCallback('onRightArrow');
},
});
setDisposeRightArrowAction(disposeOnRightArrow);
return;
}
}, [
codeEditor,
codeEditorPlace,
disposeRightArrowAction,
makeCallback,
onRightArrow,
]);
useEffect(() => {
const needReplaceAction = codeEditorPlace === 'cellEditor';
if (!needReplaceAction || !codeEditor) return;
if (!onLeftArrow && disposeLeftArrowAction) {
disposeLeftArrowAction.dispose();
setDisposeLeftArrowAction(undefined);
return;
}
if (onLeftArrow && !disposeLeftArrowAction && codeEditor) {
const disposeOnLeftArrow = codeEditor.addAction({
id: 'onLeftArrow',
label: 'onLeftArrow',
keybindings: [KeyCode.LeftArrow],
precondition: '!suggestWidgetVisible',
run: () => {
makeCallback('onLeftArrow');
},
});
setDisposeLeftArrowAction(disposeOnLeftArrow);
return;
}
}, [
codeEditor,
codeEditorPlace,
disposeLeftArrowAction,
makeCallback,
onLeftArrow,
]);
useEffect(() => {
const needReplaceAction = codeEditorPlace === 'cellEditor';
if (!needReplaceAction || !codeEditor) return;
if (!onTopArrow && disposeTopArrowAction) {
disposeTopArrowAction.dispose();
setDisposeTopArrowAction(undefined);
return;
}
if (onTopArrow && !disposeTopArrowAction && codeEditor) {
const disposeOnTopArrow = codeEditor.addAction({
id: 'onTopArrow',
label: 'onTopArrow',
keybindings: [KeyCode.UpArrow],
precondition: '!suggestWidgetVisible',
run: () => {
makeCallback('onTopArrow');
},
});
setDisposeTopArrowAction(disposeOnTopArrow);
return;
}
}, [
codeEditor,
codeEditorPlace,
disposeTopArrowAction,
makeCallback,
onTopArrow,
]);
useEffect(() => {
const needReplaceAction = codeEditorPlace === 'cellEditor';
if (!needReplaceAction || !codeEditor) return;
if (!onBottomArrow && disposeBottomArrowAction) {
disposeBottomArrowAction.dispose();
setDisposeBottomArrowAction(undefined);
return;
}
if (onBottomArrow && !disposeBottomArrowAction && codeEditor) {
const disposeOnBottomArrow = codeEditor.addAction({
id: 'onBottomArrow',
label: 'onBottomArrow',
keybindings: [KeyCode.DownArrow],
precondition: '!suggestWidgetVisible',
run: () => {
makeCallback('onBottomArrow');
},
});
setDisposeBottomArrowAction(disposeOnBottomArrow);
return;
}
}, [
codeEditor,
codeEditorPlace,
disposeBottomArrowAction,
makeCallback,
onBottomArrow,
]);
// Replace ctrl+enter event for cell editor
useEffect(() => {
const needReplaceAction = codeEditorPlace === 'cellEditor';
if (!onCtrlEnter || !needReplaceAction || !codeEditor) return;
codeEditor.addAction({
id: 'replaceCtrlEnter',
label: 'replaceCtrlEnter',
keybindings: [KeyMod.CtrlCmd | KeyCode.Enter],
run: () => {
makeCallback('onCtrlEnter');
},
});
}, [codeEditor, codeEditorPlace, makeCallback, onCtrlEnter]);
// Change shift+enter to alt+enter shortcut for formula bar and cell editor
useEffect(() => {
const needReplaceAction =
codeEditorPlace === 'formulaBar' || codeEditorPlace === 'cellEditor';
if (!needReplaceAction || !codeEditor) return;
codeEditor.addAction({
id: 'disableDefaultNextLine',
label: 'disableDefaultNextLine',
keybindings: [KeyMod.Shift | KeyCode.Enter],
run: () => {},
});
codeEditor.addAction({
id: 'onNextLine',
label: 'onNextLine',
keybindings: [KeyMod.Alt | KeyCode.Enter],
run: () => {
const action = codeEditor.getAction('editor.action.insertLineAfter');
if (!action) return;
action.run();
},
});
}, [codeEditor, codeEditorPlace]);
// Disable ctrl+F shortcut for formula bar and cell editor
useEffect(() => {
const disableAction =
codeEditorPlace === 'formulaBar' || codeEditorPlace === 'cellEditor';
if (!disableAction && disposeFindAction) {
disposeFindAction.dispose();
setDisposeFindAction(undefined);
return;
}
if (disableAction && !disposeFindAction && codeEditor) {
const onFind = codeEditor.addAction({
id: 'onFind',
label: 'onFind',
keybindings: [KeyMod.CtrlCmd | KeyCode.KeyF, KeyCode.F3],
run: () => {},
});
setDisposeFindAction(onFind);
return;
}
}, [codeEditor, disposeFindAction, codeEditorPlace, onEnter]);
// Disable F1 shortcut for formula bar and cell editor
useEffect(() => {
const disableAction =
codeEditorPlace === 'formulaBar' || codeEditorPlace === 'cellEditor';
if (!disableAction && disposeHelpAction) {
disposeHelpAction.dispose();
setDisposeHelpAction(undefined);
return;
}
if (disableAction && !disposeHelpAction && codeEditor) {
const onHelp = codeEditor.addAction({
id: 'onHelp',
label: 'onHelp',
keybindings: [KeyCode.F1],
run: () => {},
});
setDisposeHelpAction(onHelp);
return;
}
}, [codeEditor, disposeHelpAction, codeEditorPlace, onEnter]);
// Add custom action for Escape key
useEffect(() => {
if (!codeEditor || !onEscape) return;
codeEditor.addAction({
id: 'onEsc',
label: 'onEsc',
keybindings: [KeyCode.Escape],
precondition:
'!suggestWidgetVisible && !parameterHintsVisible && !inlineSuggestionVisible',
run: () => {
makeCallback('onEscape');
},
});
}, [codeEditor, makeCallback, onEscape]);
// Add custom action for ctrl+Z shortcut
useEffect(() => {
if (!codeEditor || !onUndo) return;
codeEditor.addAction({
id: 'onUndo',
label: 'onUndo',
keybindings: [KeyMod.CtrlCmd | KeyCode.KeyZ],
run: () => {
makeCallback('onUndo');
},
});
}, [codeEditor, makeCallback, onUndo]);
// Add custom action for ctrl+Y and ctrl+shift+Z shortcut
useEffect(() => {
if (!codeEditor || !onRedo) return;
codeEditor.addAction({
id: 'onRedo',
label: 'onRedo',
keybindings: [
KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyZ,
KeyMod.CtrlCmd | KeyCode.KeyY,
],
run: () => {
makeCallback('onRedo');
},
});
}, [codeEditor, makeCallback, onRedo]);
}