fix(editor): show gutter run button for statements with leading whitespace (#2729)

Co-authored-by: zipg <4047349+zipg@users.noreply.github.com>
This commit is contained in:
zipg
2026-07-07 10:53:27 +08:00
committed by GitHub
co-authored by zipg
parent df1f53acb8
commit 6efe1797a3
2 changed files with 27 additions and 2 deletions
@@ -27,6 +27,25 @@ describe("executableStatementRangeCacheForDoc", () => {
expect(executableStatementRangeStartingAt(cache, secondStatementLine.from)?.sql).toBe("SELECT *\nFROM menus AS mn\nLIMIT 100");
});
it("resolves statements with leading whitespace for gutter run buttons", () => {
const doc = Text.of([" SELECT 1;", " SELECT 2;", "\t SELECT 3;", "", " "]);
const cache = executableStatementRangeCacheForDoc(null, doc, "mysql");
expect(executableStatementRangeStartingAt(cache, doc.line(1).from)?.sql).toBe("SELECT 1");
expect(executableStatementRangeStartingAt(cache, doc.line(2).from)?.sql).toBe("SELECT 2");
expect(executableStatementRangeStartingAt(cache, doc.line(3).from)?.sql).toBe("SELECT 3");
expect(executableStatementRangeStartingAt(cache, doc.line(4).from)).toBeNull();
expect(executableStatementRangeStartingAt(cache, doc.line(5).from)).toBeNull();
});
it("does not resolve gutter run buttons when non-whitespace precedes the statement on the same line", () => {
const doc = Text.of(["/* comment */ SELECT 1;"]);
const cache = executableStatementRangeCacheForDoc(null, doc, "mysql");
expect(executableStatementRangeStartingAt(cache, doc.line(1).from)).toBeNull();
expect(executableStatementRangeStartingAt(cache, doc.toString().indexOf("SELECT"))?.sql).toBe("SELECT 1");
});
it("resolves the current statement from a cursor inside a continuation line", () => {
const doc = Text.of(["SELECT *", "FROM apis AS ap", "LIMIT 100;", "", "SELECT *", "FROM menus AS mn", "LIMIT 100;"]);
const cache = executableStatementRangeCacheForDoc(null, doc, "mysql");
@@ -6,6 +6,7 @@ export interface ExecutableStatementRangeCache {
doc: Text;
databaseType?: DatabaseType;
byStart: Map<number, SqlTextRange>;
byExecutableLineStart: Map<number, SqlTextRange>;
ranges: SqlTextRange[];
}
@@ -15,15 +16,20 @@ export function executableStatementRangeCacheForDoc(cache: ExecutableStatementRa
if (cache?.doc === doc && cache.databaseType === databaseType) return cache;
const byStart = new Map<number, SqlTextRange>();
const byExecutableLineStart = new Map<number, SqlTextRange>();
const ranges = parse(doc.toString(), databaseType);
for (const range of ranges) {
byStart.set(range.from, range);
const line = doc.lineAt(range.from);
if (doc.sliceString(line.from, range.from).trim() === "") {
byExecutableLineStart.set(line.from, range);
}
}
return { doc, databaseType, byStart, ranges };
return { doc, databaseType, byStart, byExecutableLineStart, ranges };
}
export function executableStatementRangeStartingAt(cache: ExecutableStatementRangeCache, lineFrom: number): SqlTextRange | null {
return cache.byStart.get(lineFrom) ?? null;
return cache.byStart.get(lineFrom) ?? cache.byExecutableLineStart.get(lineFrom) ?? null;
}
export function executableStatementRangeAtCursor(cache: ExecutableStatementRangeCache, cursorPos: number): SqlTextRange | null {