fix(editor): preserve snippet navigation after dismissing completion
This commit is contained in:
6 files changed
+468
-10
No files matched your search
@@ -136,6 +136,7 @@ import { EDITOR_FONT_FAMILY_CSS_VAR, EDITOR_FONT_SIZE_CSS_VAR, editorDiagnosticC
|
||||
import { createStatementGutterMarkerDom, shouldShowStatementGutter } from "@/lib/editor/codemirrorStatementGutter";
|
||||
import { createQueryEditorSqlShortcutDomHandler, isCharacterProducingShortcut } from "@/lib/editor/queryEditorSqlShortcut";
|
||||
import { createQueryEditorReplaceShortcutBindings, createQueryEditorReplaceShortcutHandler, createQueryEditorSearchKeymap } from "@/lib/editor/queryEditorSearchKeymap";
|
||||
import { createQueryEditorEscapeHandler } from "@/lib/editor/queryEditorEscape";
|
||||
import { buildQueryEditorLineNumbersExtension, createQueryEditorLineNumberAlignmentExtension } from "@/lib/editor/queryEditorLineNumbers";
|
||||
import { searchKeymapWithoutModD } from "@/lib/editor/codemirrorSearchKeymap";
|
||||
import { defaultKeymapForGlobalShortcuts } from "@/lib/editor/codemirrorDefaultKeymap";
|
||||
@@ -892,7 +893,12 @@ function editorIndentUnit(): string {
|
||||
}
|
||||
|
||||
function handleTab(view: EditorViewType): boolean {
|
||||
if (view.state.selection.ranges.some((range) => !range.empty)) return codeMirrorIndentMore?.(view) ?? false;
|
||||
if (isEditorComposing(view)) return false;
|
||||
if (view.state.selection.ranges.some((range) => !range.empty)) {
|
||||
// Snippet navigation selects the whole field, including after Shift+Tab.
|
||||
// Give that active session priority over ordinary selected-text indentation.
|
||||
return (codeMirrorNextSnippetField?.(view) ?? false) || (codeMirrorIndentMore?.(view) ?? false);
|
||||
}
|
||||
if (tabKeyAcceptsCompletion()) {
|
||||
return acceptCompletionOrNextSnippetField(view) || performNormalTab(view);
|
||||
}
|
||||
@@ -2393,9 +2399,8 @@ function selectAllSelectionOccurrencesFromContextMenu() {
|
||||
}
|
||||
|
||||
function acceptCompletionOrNextSnippetField(view: EditorViewType): boolean {
|
||||
// Any non-empty selection range means Tab is being used for block indent,
|
||||
// not word completion. A completion popup can still appear as a side effect
|
||||
// of the indent edit itself, so it must never hijack this or a following Tab.
|
||||
// A non-empty selection belongs to snippet navigation or block indentation,
|
||||
// not word completion. A popup opened by an indent edit must not hijack Tab.
|
||||
if (isEditorComposing(view)) return false;
|
||||
if (view.state.selection.ranges.every((range) => range.empty)) {
|
||||
const completionStatus = codeMirrorCompletionStatus?.(view.state) ?? null;
|
||||
@@ -6384,10 +6389,15 @@ onMounted(async () => {
|
||||
{ key: "Tab", run: handleTab },
|
||||
{
|
||||
key: "Escape",
|
||||
run: () => {
|
||||
clearBatchColumnSelectionSession();
|
||||
return searchPanelRef.value?.closeSearch() ?? false;
|
||||
},
|
||||
run: createQueryEditorEscapeHandler({
|
||||
clearBatchSelection: clearBatchColumnSelectionSession,
|
||||
cancelPendingAcceptance: () => {
|
||||
clearPendingCompletionEnter();
|
||||
clearPendingCompletionTab();
|
||||
},
|
||||
closeSearch: () => searchPanelRef.value?.closeSearch() ?? false,
|
||||
closeCompletion: (currentView) => codeMirrorCloseCompletion?.(currentView) ?? false,
|
||||
}),
|
||||
},
|
||||
]),
|
||||
),
|
||||
|
||||
Reference in new issue
Block a user