fix(editor): restore quoted table keyword completion

This commit is contained in:
ekesaiting 2026-08-01 02:19:10 +08:00 committed by GitHub
parent 61e149bb9f
commit 7cf5795666
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 44 additions and 5 deletions

View File

@ -1329,6 +1329,12 @@ async function newQuery() {
databaseType: effectiveDatabaseTypeForConnection(conn),
});
const tabId = queryStore.createTab(conn.id, target.database, undefined, "query", target.schema, initialSql, target.catalog);
if (initialSql) {
const prefilledTab = queryStore.tabs.find((t) => t.id === tabId);
if (prefilledTab) {
prefilledTab.editorSelection = { anchor: initialSql.length, head: initialSql.length };
}
}
try {
await connectionStore.ensureConnected(target.connectionId);
if (target.shouldRefreshDefaultDatabase) {

View File

@ -469,4 +469,20 @@ WHERE a.id = b.fk_kpi_set_score_id`,
expect(context.suggestTables).toBe(true);
expect(items.filter((item) => item.type === "table").map((item) => item.label)).toEqual(["orders"]);
});
it.each([
["PostgreSQL quoted table", 'SELECT * FROM "users" wh|', "postgres", "postgres"],
["PostgreSQL quoted schema.table", 'SELECT * FROM "public"."users" wh|', "postgres", "postgres"],
["PostgreSQL quoted keyword table", 'SELECT * FROM "from" wh|', "postgres", "postgres"],
["PostgreSQL quoted schema.keyword table", 'SELECT * FROM "public"."from" wh|', "postgres", "postgres"],
["MySQL backtick table", "SELECT * FROM `users` wh|", "mysql", "mysql"],
["MySQL backtick keyword table", "SELECT * FROM `join` wh|", "mysql", "mysql"],
["SQL Server bracket table", "SELECT * FROM [users] wh|", "sqlserver", "sqlserver"],
["SQL Server bracket keyword table", "SELECT * FROM [update] wh|", "sqlserver", "sqlserver"],
] as const)("offers WHERE keyword completion after a quoted prefilled table (%s)", (_label, markedSql, databaseType, dialect) => {
const { context, items } = semanticCompletion(markedSql, {}, { databaseType, dialect });
expect(context.suggestKeywords).toBe(true);
expect(items.filter((item) => item.type === "keyword").map((item) => item.label)).toEqual(expect.arrayContaining(["WHERE", "WHEN", "WITH"]));
});
});

View File

@ -600,13 +600,13 @@ function trailingIdentifier(tokens: readonly SqlSemanticToken[], cursor: number,
}
function previousWord(tokens: readonly SqlSemanticToken[], cursor: number): string {
const before = tokens.filter((item) => item.span.end <= cursor && item.kind === "word");
return before[before.length - 1]?.normalized ?? "";
const before = tokens.filter((item) => item.span.end <= cursor && item.kind !== "comment");
return nearestPreviousSyntaxWord(before);
}
function wordBeforePosition(tokens: readonly SqlSemanticToken[], position: number): string {
const before = tokens.filter((item) => item.span.end <= position && item.kind === "word");
return before[before.length - 1]?.normalized ?? "";
const before = tokens.filter((item) => item.span.end <= position && item.kind !== "comment");
return nearestPreviousSyntaxWord(before);
}
function wordBeforeTrailingIdentifier(tokens: readonly SqlSemanticToken[], cursor: number, trailing: TrailingIdentifier): string {
@ -622,7 +622,24 @@ function wordBeforeTrailingIdentifier(tokens: readonly SqlSemanticToken[], curso
identifiersToSkip -= 1;
index -= 1;
}
return before[index]?.kind === "word" ? before[index].normalized : "";
return nearestPreviousSyntaxWord(before.slice(0, index + 1));
}
/**
* Scans backward from the end of `before` for the nearest unquoted syntax word.
* A quoted identifier is a barrier: its object name must not participate in
* keyword comparisons even when it is named `from`, `join`, or `update`.
*/
function nearestPreviousSyntaxWord(tokens: readonly SqlSemanticToken[]): string {
for (let index = tokens.length - 1; index >= 0; index -= 1) {
const item = tokens[index];
if (!item) continue;
if (item.kind === "word") return item.normalized;
if (item.kind === "quoted_identifier") return "";
if (item.text === "." || item.kind === "comment") continue;
break;
}
return "";
}
function isTableListContinuation(tokens: readonly SqlSemanticToken[], position: number): boolean {