mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-21 04:55:32 +00:00
fix(editor): suppress completion after newline
This commit is contained in:
@@ -1778,7 +1778,7 @@ function runKeymapExtension(codeMirrorKeymap: (typeof import("@codemirror/view")
|
||||
codeMirrorKeymap.of([
|
||||
{
|
||||
key: "Enter",
|
||||
run: codeMirrorInsertNewlineKeepIndent ?? undefined,
|
||||
run: insertNewlineWithoutCompletion,
|
||||
},
|
||||
...binding(shortcuts.find, openSearch),
|
||||
...binding(shortcuts.replace, openReplace),
|
||||
@@ -1842,6 +1842,14 @@ function runKeymapExtension(codeMirrorKeymap: (typeof import("@codemirror/view")
|
||||
];
|
||||
}
|
||||
|
||||
function insertNewlineWithoutCompletion(view: EditorViewType): boolean {
|
||||
codeMirrorCloseCompletion?.(view);
|
||||
suppressNextSqlCompletionAutoStartUntil = Date.now() + 750;
|
||||
const handled = codeMirrorInsertNewlineKeepIndent?.(view) ?? false;
|
||||
if (!handled) suppressNextSqlCompletionAutoStartUntil = 0;
|
||||
return handled;
|
||||
}
|
||||
|
||||
function extendQueryEditorSelectionForView(currentView: EditorViewType): boolean {
|
||||
const databaseType = props.databaseType;
|
||||
const language = databaseType === "redis" || databaseType === "mongodb" || databaseType === "elasticsearch" || databaseType === "easysearch" || databaseType === "meilisearch" || databaseType === "victoriametrics" ? "text" : "sql";
|
||||
|
||||
@@ -46,29 +46,52 @@ interface MockView {
|
||||
|
||||
interface TabHarness {
|
||||
handleTab: (view: MockView) => boolean;
|
||||
insertNewlineWithoutCompletion: (view: MockView) => boolean;
|
||||
acceptCompletionOrNextSnippetField: (view: MockView) => boolean;
|
||||
clearPendingCompletionTab: () => void;
|
||||
consumeSqlCompletionAutoStartSuppression: () => boolean;
|
||||
}
|
||||
|
||||
function createHarness(options: { completionStatus: (state: MockState) => "active" | "pending" | null; acceptCompletion?: (view: MockView) => boolean; nextSnippetField?: (view: MockView) => boolean; indentMore?: (view: MockView) => boolean }): TabHarness {
|
||||
function createHarness(options: {
|
||||
completionStatus: (state: MockState) => "active" | "pending" | null;
|
||||
acceptCompletion?: (view: MockView) => boolean;
|
||||
closeCompletion?: (view: MockView) => boolean;
|
||||
insertNewlineKeepIndent?: (view: MockView) => boolean;
|
||||
nextSnippetField?: (view: MockView) => boolean;
|
||||
indentMore?: (view: MockView) => boolean;
|
||||
}): TabHarness {
|
||||
const source = [
|
||||
extractDeclaration(/const COMPLETION_REMOTE_LATENCY_BUDGET_MS = \d+;/, "remote completion latency budget"),
|
||||
extractDeclaration(/const COMPLETION_DEBOUNCE_DELAY_MS = \d+;/, "completion debounce delay"),
|
||||
extractDeclaration(/const COMPLETION_TAB_RETRY_DELAY_MS = \d+;/, "completion retry delay"),
|
||||
extractDeclaration(/const COMPLETION_TAB_MAX_WAIT_MS = [^;]+;/, "completion wait timeout"),
|
||||
"let pendingCompletionTabTimer: ReturnType<typeof setTimeout> | null = null;",
|
||||
"let suppressNextSqlCompletionAutoStartUntil = 0;",
|
||||
extractFunction("editorIndentUnit"),
|
||||
extractFunction("handleTab"),
|
||||
extractFunction("performNormalTab"),
|
||||
extractFunction("insertNewlineWithoutCompletion"),
|
||||
extractFunction("acceptCompletionOrNextSnippetField"),
|
||||
extractFunction("clearPendingCompletionTab"),
|
||||
extractFunction("waitForCompletionTab"),
|
||||
extractFunction("consumeSqlCompletionAutoStartSuppression"),
|
||||
].join("\n");
|
||||
const javascript = ts.transpileModule(source, {
|
||||
compilerOptions: { module: ts.ModuleKind.None, target: ts.ScriptTarget.ES2022 },
|
||||
}).outputText;
|
||||
const factory = new Function("codeMirrorCompletionStatus", "codeMirrorAcceptCompletion", "codeMirrorNextSnippetField", "codeMirrorIndentMore", "settingsStore", `${javascript}\nreturn { handleTab, acceptCompletionOrNextSnippetField, clearPendingCompletionTab };`);
|
||||
return factory(options.completionStatus, options.acceptCompletion ?? (() => false), options.nextSnippetField ?? (() => false), options.indentMore ?? (() => false), { editorSettings: { sqlFormatter: { useTabs: false, tabWidth: 2 } } }) as TabHarness;
|
||||
const factory = new Function(
|
||||
"codeMirrorCompletionStatus",
|
||||
"codeMirrorAcceptCompletion",
|
||||
"codeMirrorCloseCompletion",
|
||||
"codeMirrorInsertNewlineKeepIndent",
|
||||
"codeMirrorNextSnippetField",
|
||||
"codeMirrorIndentMore",
|
||||
"settingsStore",
|
||||
`${javascript}\nreturn { handleTab, insertNewlineWithoutCompletion, acceptCompletionOrNextSnippetField, clearPendingCompletionTab, consumeSqlCompletionAutoStartSuppression };`,
|
||||
);
|
||||
return factory(options.completionStatus, options.acceptCompletion ?? (() => false), options.closeCompletion ?? (() => false), options.insertNewlineKeepIndent ?? (() => false), options.nextSnippetField ?? (() => false), options.indentMore ?? (() => false), {
|
||||
editorSettings: { sqlFormatter: { useTabs: false, tabWidth: 2 } },
|
||||
}) as TabHarness;
|
||||
}
|
||||
|
||||
function createView(text = "SELECT", position = text.length): MockView {
|
||||
@@ -89,6 +112,26 @@ afterEach(() => {
|
||||
});
|
||||
|
||||
describe("QueryEditor completion Tab keymap", () => {
|
||||
it("closes completion and suppresses its restart for the Enter newline", () => {
|
||||
const closeCompletion = vi.fn(() => true);
|
||||
let harness: TabHarness;
|
||||
const insertNewlineKeepIndent = vi.fn(() => harness.consumeSqlCompletionAutoStartSuppression());
|
||||
harness = createHarness({ completionStatus: () => "active", closeCompletion, insertNewlineKeepIndent });
|
||||
const view = createView("SELECT * FROM demo WHERE id IN ()", 32);
|
||||
|
||||
expect(harness.insertNewlineWithoutCompletion(view)).toBe(true);
|
||||
expect(closeCompletion).toHaveBeenCalledWith(view);
|
||||
expect(insertNewlineKeepIndent).toHaveBeenCalledWith(view);
|
||||
expect(harness.consumeSqlCompletionAutoStartSuppression()).toBe(false);
|
||||
});
|
||||
|
||||
it("does not suppress later completion when Enter cannot insert a newline", () => {
|
||||
const harness = createHarness({ completionStatus: () => null, insertNewlineKeepIndent: () => false });
|
||||
|
||||
expect(harness.insertNewlineWithoutCompletion(createView())).toBe(false);
|
||||
expect(harness.consumeSqlCompletionAutoStartSuppression()).toBe(false);
|
||||
});
|
||||
|
||||
it("keeps CodeMirror prefix filtering enabled for SQL completion results", () => {
|
||||
const javascript = ts.transpileModule(extractFunction("buildCompletionResult"), {
|
||||
compilerOptions: { module: ts.ModuleKind.None, target: ts.ScriptTarget.ES2022 },
|
||||
|
||||
Reference in New Issue
Block a user