From 43864aa567dbc76c48ce2c5f963b68b6fd2186b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ng=C3=B4=20Qu=E1=BB=91c=20=C4=90=E1=BA=A1t?= Date: Fri, 12 Jun 2026 10:26:10 +0700 Subject: [PATCH] fix(editor): detect SQL clause from text before the token being typed --- TablePro/Core/Autocomplete/SQLContextAnalyzer.swift | 11 +++++++++-- .../Core/Autocomplete/SQLContextAnalyzerTests.swift | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/TablePro/Core/Autocomplete/SQLContextAnalyzer.swift b/TablePro/Core/Autocomplete/SQLContextAnalyzer.swift index 4efe9887f..b6734dee5 100644 --- a/TablePro/Core/Autocomplete/SQLContextAnalyzer.swift +++ b/TablePro/Core/Autocomplete/SQLContextAnalyzer.swift @@ -337,13 +337,20 @@ final class SQLContextAnalyzer { // Check if immediately after comma let isAfterComma = checkIfAfterComma(textBeforeCursor) + // Clause detection runs on the text BEFORE the token being typed: the + // prefix is what completion filters on, so it cannot also count as a + // committed clause keyword ("SELECT|" must still suggest the SELECT + // keyword, not switch to select-list completions). + let nsBeforeCursor = textBeforeCursor as NSString + let textBeforePrefix = nsBeforeCursor.substring(to: min(prefixStart, nsBeforeCursor.length)) + // For subquery context, extract text from the innermost subquery // so clause detection works on the subquery's SQL, not the outer query let clauseText: String if nestingLevel > 0 { - clauseText = extractInnermostSubqueryText(from: textBeforeCursor) + clauseText = extractInnermostSubqueryText(from: textBeforePrefix) } else { - clauseText = textBeforeCursor + clauseText = textBeforePrefix } // Determine clause type diff --git a/TableProTests/Core/Autocomplete/SQLContextAnalyzerTests.swift b/TableProTests/Core/Autocomplete/SQLContextAnalyzerTests.swift index 5cdf9b08c..ff739f4b1 100644 --- a/TableProTests/Core/Autocomplete/SQLContextAnalyzerTests.swift +++ b/TableProTests/Core/Autocomplete/SQLContextAnalyzerTests.swift @@ -766,7 +766,7 @@ struct SQLContextAnalyzerTests { @Test("Multiple block comments with code between") func testMultipleBlockComments() { - let context = analyzer.analyze(query: "/* c1 */ SELECT /* c2 */ * FROM ", cursorPosition: 31) + let context = analyzer.analyze(query: "/* c1 */ SELECT /* c2 */ * FROM ", cursorPosition: 32) #expect(context.isInsideComment == false) #expect(context.clauseType == .from) }