fix(editor): suppress completion after punctuation

This commit is contained in:
t8y2 2026-05-15 14:56:26 +08:00
parent b06ab4f27f
commit 1563173173
3 changed files with 34 additions and 3 deletions

View File

@ -6,7 +6,11 @@ import { resolveExecutableSql } from "@/lib/sqlExecutionTarget";
import { formatSqlText, type SqlFormatDialect } from "@/lib/sqlFormatter";
import { useConnectionStore } from "@/stores/connectionStore";
import { useSettingsStore } from "@/stores/settingsStore";
import { buildSqlCompletionItemsFromContext, getSqlCompletionContext } from "@/lib/sqlCompletion";
import {
buildSqlCompletionItemsFromContext,
getSqlCompletionContext,
shouldAutoOpenSqlCompletion,
} from "@/lib/sqlCompletion";
import { extractIdentifierAt, isSqlKeyword, matchTable } from "@/lib/sqlNavigation";
import { loadEditorTheme, editorFontTheme } from "@/lib/editorThemes";
import type { SqlCompletionColumn } from "@/lib/sqlCompletion";
@ -122,11 +126,17 @@ async function formatCurrentSql() {
}
}
async function provideSqlCompletions(currentState: import("@codemirror/state").EditorState, position: number) {
async function provideSqlCompletions(
currentState: import("@codemirror/state").EditorState,
position: number,
explicit: boolean,
) {
if (!props.connectionId || !props.database) return null;
try {
const fullDoc = currentState.doc.toString();
if (!explicit && !shouldAutoOpenSqlCompletion(fullDoc, position)) return null;
const completionContext = getSqlCompletionContext(fullDoc, position);
const shouldLoadTables = completionContext.suggestTables || !!completionContext.qualifier;
let tables = shouldLoadTables
@ -338,7 +348,9 @@ onMounted(async () => {
sql({ dialect }),
autocompletion({
activateOnTyping: true,
override: [async (context: CompletionContext) => provideSqlCompletions(context.state, context.pos)],
override: [
async (context: CompletionContext) => provideSqlCompletions(context.state, context.pos, context.explicit),
],
}),
codeMirrorTheme.of(theme),
closeBrackets(),

View File

@ -333,6 +333,12 @@ export function buildSqlCompletionItemsFromContext(
return dedupeAndSort(items);
}
export function shouldAutoOpenSqlCompletion(sql: string, cursor: number): boolean {
const previousChar = sql[cursor - 1];
if (!previousChar) return false;
return /[\w$.]/.test(previousChar);
}
/**
* Find the start position of the SQL statement containing the cursor.
* Respects semicolons and string literals.

View File

@ -2,6 +2,7 @@ import { strict as assert } from "node:assert";
import test from "node:test";
import {
buildSqlCompletionItems,
shouldAutoOpenSqlCompletion,
type SqlCompletionColumn,
type SqlCompletionTable,
} from "../src/lib/sqlCompletion.ts";
@ -159,6 +160,18 @@ test("suggests SQL Server data types in CREATE TABLE column definitions", () =>
assert.ok(items.some((item) => item.type === "keyword" && item.label === "NVARCHAR"));
});
test("does not auto-open completion after structural punctuation", () => {
for (const sql of ["select count(*)", "select * from users;", "select * from users,"]) {
assert.equal(shouldAutoOpenSqlCompletion(sql, sql.length), false, sql);
}
});
test("auto-opens completion after word characters and explicit dot qualifiers", () => {
for (const sql of ["sel", "select * from us", "select u."]) {
assert.equal(shouldAutoOpenSqlCompletion(sql, sql.length), true, sql);
}
});
test("limits table suggestions for large schemas after filtering by prefix", () => {
const largeTables: SqlCompletionTable[] = Array.from({ length: 500 }, (_, index) => ({
name: `erp_invoice_${String(index).padStart(4, "0")}`,