@@ -63,6 +63,8 @@ pub static ALL_KEYWORDS: &[SqlKeyword] = &[
6363 SqlKeyword :: new ( "boolean" ) ,
6464 SqlKeyword :: new ( "brin" ) ,
6565 SqlKeyword :: new ( "btree" ) ,
66+ SqlKeyword :: new ( "buffer_usage_limit" ) ,
67+ SqlKeyword :: new ( "buffers" ) ,
6668 SqlKeyword :: new ( "by" ) ,
6769 SqlKeyword :: new ( "bytea" ) ,
6870 SqlKeyword :: new ( "cache" ) ,
@@ -77,7 +79,6 @@ pub static ALL_KEYWORDS: &[SqlKeyword] = &[
7779 SqlKeyword :: new ( "check" ) ,
7880 SqlKeyword :: new ( "collate" ) ,
7981 SqlKeyword :: new ( "column" ) ,
80- SqlKeyword :: new ( "columns" ) ,
8182 SqlKeyword :: new ( "comment" ) . starts_statement ( ) ,
8283 SqlKeyword :: new ( "commit" ) . starts_statement ( ) ,
8384 SqlKeyword :: new ( "committed" ) ,
@@ -89,6 +90,7 @@ pub static ALL_KEYWORDS: &[SqlKeyword] = &[
8990 SqlKeyword :: new ( "constraints" ) ,
9091 SqlKeyword :: new ( "copy" ) . starts_statement ( ) ,
9192 SqlKeyword :: new ( "cost" ) ,
93+ SqlKeyword :: new ( "costs" ) ,
9294 SqlKeyword :: new ( "create" ) . starts_statement ( ) ,
9395 SqlKeyword :: new ( "cross" ) ,
9496 SqlKeyword :: new ( "csv" ) ,
@@ -109,7 +111,6 @@ pub static ALL_KEYWORDS: &[SqlKeyword] = &[
109111 SqlKeyword :: new ( "delete" ) . starts_statement ( ) ,
110112 SqlKeyword :: new ( "delimiter" ) ,
111113 SqlKeyword :: new ( "desc" ) ,
112- SqlKeyword :: new ( "disable_page_skipping" ) ,
113114 SqlKeyword :: new ( "distinct" ) ,
114115 SqlKeyword :: new ( "do" ) . starts_statement ( ) ,
115116 SqlKeyword :: new ( "double" ) ,
@@ -149,6 +150,7 @@ pub static ALL_KEYWORDS: &[SqlKeyword] = &[
149150 SqlKeyword :: new ( "function" ) ,
150151 SqlKeyword :: new ( "functions" ) ,
151152 SqlKeyword :: new ( "generated" ) ,
153+ SqlKeyword :: new ( "generic_plan" ) ,
152154 SqlKeyword :: new ( "gin" ) ,
153155 SqlKeyword :: new ( "gist" ) ,
154156 SqlKeyword :: new ( "grant" ) . starts_statement ( ) ,
@@ -159,12 +161,12 @@ pub static ALL_KEYWORDS: &[SqlKeyword] = &[
159161 SqlKeyword :: new ( "having" ) ,
160162 SqlKeyword :: new ( "header" ) ,
161163 SqlKeyword :: new ( "if" ) ,
164+ SqlKeyword :: new ( "ignore" ) ,
162165 SqlKeyword :: new ( "immediate" ) ,
163166 SqlKeyword :: new ( "immutable" ) ,
164167 SqlKeyword :: new ( "in" ) . require_prefix ( ) ,
165168 SqlKeyword :: new ( "increment" ) ,
166169 SqlKeyword :: new ( "index" ) ,
167- SqlKeyword :: new ( "index_cleanup" ) ,
168170 SqlKeyword :: new ( "inet" ) ,
169171 SqlKeyword :: new ( "inherit" ) ,
170172 SqlKeyword :: new ( "initially" ) ,
@@ -194,14 +196,15 @@ pub static ALL_KEYWORDS: &[SqlKeyword] = &[
194196 SqlKeyword :: new ( "limit" ) ,
195197 SqlKeyword :: new ( "list" ) ,
196198 SqlKeyword :: new ( "local" ) ,
197- SqlKeyword :: new ( "location " ) ,
199+ SqlKeyword :: new ( "log_verbosity " ) ,
198200 SqlKeyword :: new ( "logged" ) ,
199201 SqlKeyword :: new ( "main" ) ,
200202 SqlKeyword :: new ( "maintain" ) ,
201203 SqlKeyword :: new ( "match" ) ,
202204 SqlKeyword :: new ( "matched" ) ,
203205 SqlKeyword :: new ( "materialized" ) ,
204206 SqlKeyword :: new ( "maxvalue" ) ,
207+ SqlKeyword :: new ( "memory" ) ,
205208 SqlKeyword :: new ( "merge" ) . starts_statement ( ) ,
206209 SqlKeyword :: new ( "minvalue" ) ,
207210 SqlKeyword :: new ( "money" ) ,
@@ -213,7 +216,6 @@ pub static ALL_KEYWORDS: &[SqlKeyword] = &[
213216 SqlKeyword :: new ( "none" ) ,
214217 SqlKeyword :: new ( "not" ) . require_prefix ( ) ,
215218 SqlKeyword :: new ( "nothing" ) ,
216- SqlKeyword :: new ( "nowait" ) ,
217219 SqlKeyword :: new ( "null" ) . require_prefix ( ) ,
218220 SqlKeyword :: new ( "nulls" ) ,
219221 SqlKeyword :: new ( "numeric" ) ,
@@ -224,6 +226,7 @@ pub static ALL_KEYWORDS: &[SqlKeyword] = &[
224226 SqlKeyword :: new ( "oids" ) ,
225227 SqlKeyword :: new ( "old" ) ,
226228 SqlKeyword :: new ( "on" ) ,
229+ SqlKeyword :: new ( "on_error" ) ,
227230 SqlKeyword :: new ( "only" ) . require_prefix ( ) ,
228231 SqlKeyword :: new ( "option" ) ,
229232 SqlKeyword :: new ( "or" ) . require_prefix ( ) ,
@@ -238,19 +241,16 @@ pub static ALL_KEYWORDS: &[SqlKeyword] = &[
238241 SqlKeyword :: new ( "owner" ) ,
239242 SqlKeyword :: new ( "parallel" ) ,
240243 SqlKeyword :: new ( "partition" ) ,
241- SqlKeyword :: new ( "partitioned" ) ,
242244 SqlKeyword :: new ( "password" ) ,
243245 SqlKeyword :: new ( "permissive" ) ,
244246 SqlKeyword :: new ( "plain" ) ,
245247 SqlKeyword :: new ( "policy" ) ,
246- SqlKeyword :: new ( "precedes" ) ,
247248 SqlKeyword :: new ( "preceding" ) ,
248249 SqlKeyword :: new ( "precision" ) ,
249250 SqlKeyword :: new ( "primary" ) ,
250251 SqlKeyword :: new ( "privileges" ) ,
251252 SqlKeyword :: new ( "procedure" ) ,
252253 SqlKeyword :: new ( "procedures" ) ,
253- SqlKeyword :: new ( "process_toast" ) ,
254254 SqlKeyword :: new ( "program" ) ,
255255 SqlKeyword :: new ( "public" ) ,
256256 SqlKeyword :: new ( "quote" ) ,
@@ -264,10 +264,10 @@ pub static ALL_KEYWORDS: &[SqlKeyword] = &[
264264 SqlKeyword :: new ( "regnamespace" ) ,
265265 SqlKeyword :: new ( "regproc" ) ,
266266 SqlKeyword :: new ( "regtype" ) ,
267+ SqlKeyword :: new ( "reject_limit" ) ,
267268 SqlKeyword :: new ( "rename" ) ,
268269 SqlKeyword :: new ( "repeatable" ) ,
269270 SqlKeyword :: new ( "replace" ) ,
270- SqlKeyword :: new ( "replication" ) ,
271271 SqlKeyword :: new ( "reset" ) . starts_statement ( ) ,
272272 SqlKeyword :: new ( "restart" ) ,
273273 SqlKeyword :: new ( "restrict" ) ,
@@ -277,7 +277,6 @@ pub static ALL_KEYWORDS: &[SqlKeyword] = &[
277277 SqlKeyword :: new ( "returning" ) ,
278278 SqlKeyword :: new ( "returns" ) ,
279279 SqlKeyword :: new ( "revoke" ) . starts_statement ( ) ,
280- SqlKeyword :: new ( "rewrite" ) ,
281280 SqlKeyword :: new ( "right" ) ,
282281 SqlKeyword :: new ( "role" ) ,
283282 SqlKeyword :: new ( "rollback" ) . starts_statement ( ) ,
@@ -296,7 +295,10 @@ pub static ALL_KEYWORDS: &[SqlKeyword] = &[
296295 SqlKeyword :: new ( "session_user" ) ,
297296 SqlKeyword :: new ( "set" ) . starts_statement ( ) ,
298297 SqlKeyword :: new ( "setof" ) ,
298+ SqlKeyword :: new ( "settings" ) ,
299+ SqlKeyword :: new ( "share" ) ,
299300 SqlKeyword :: new ( "show" ) . starts_statement ( ) ,
301+ SqlKeyword :: new ( "silent" ) ,
300302 SqlKeyword :: new ( "similar" ) . require_prefix ( ) ,
301303 SqlKeyword :: new ( "skip_locked" ) ,
302304 SqlKeyword :: new ( "smallint" ) ,
@@ -309,9 +311,12 @@ pub static ALL_KEYWORDS: &[SqlKeyword] = &[
309311 SqlKeyword :: new ( "statement" ) ,
310312 SqlKeyword :: new ( "statistics" ) ,
311313 SqlKeyword :: new ( "stdin" ) ,
314+ SqlKeyword :: new ( "stdout" ) ,
315+ SqlKeyword :: new ( "stop" ) ,
312316 SqlKeyword :: new ( "storage" ) ,
313317 SqlKeyword :: new ( "stored" ) ,
314318 SqlKeyword :: new ( "strict" ) ,
319+ SqlKeyword :: new ( "summary" ) ,
315320 SqlKeyword :: new ( "support" ) ,
316321 SqlKeyword :: new ( "system" ) ,
317322 SqlKeyword :: new ( "table" ) ,
@@ -325,6 +330,7 @@ pub static ALL_KEYWORDS: &[SqlKeyword] = &[
325330 SqlKeyword :: new ( "time" ) ,
326331 SqlKeyword :: new ( "timestamp" ) ,
327332 SqlKeyword :: new ( "timestamptz" ) ,
333+ SqlKeyword :: new ( "timing" ) ,
328334 SqlKeyword :: new ( "to" ) ,
329335 SqlKeyword :: new ( "transaction" ) ,
330336 SqlKeyword :: new ( "trigger" ) ,
@@ -353,13 +359,15 @@ pub static ALL_KEYWORDS: &[SqlKeyword] = &[
353359 SqlKeyword :: new ( "version" ) ,
354360 SqlKeyword :: new ( "view" ) ,
355361 SqlKeyword :: new ( "volatile" ) ,
362+ SqlKeyword :: new ( "wal" ) ,
356363 SqlKeyword :: new ( "when" ) ,
357364 SqlKeyword :: new ( "where" ) ,
358365 SqlKeyword :: new ( "window" ) ,
359366 SqlKeyword :: new ( "with" ) . starts_statement ( ) ,
360367 SqlKeyword :: new ( "without" ) ,
361368 SqlKeyword :: new ( "write" ) ,
362369 SqlKeyword :: new ( "xml" ) ,
370+ SqlKeyword :: new ( "yaml" ) ,
363371 SqlKeyword :: new ( "zone" ) ,
364372] ;
365373
@@ -409,17 +417,92 @@ pub fn complete_keywords<'a>(
409417
410418#[ cfg( test) ]
411419mod tests {
420+ use std:: collections:: HashSet ;
421+
412422 use pgls_test_utils:: QueryWithCursorPosition ;
423+ use regex:: Regex ;
413424 use sqlx:: PgPool ;
425+ use tree_sitter:: Language ;
414426
415427 use crate :: {
416428 CompletionItemKind ,
429+ providers:: keywords:: ALL_KEYWORDS ,
417430 test_helper:: {
418431 CompletionAssertion , TestCompletionsCase , TestCompletionsSuite ,
419432 assert_complete_results, assert_no_complete_results,
420433 } ,
421434 } ;
422435
436+ #[ test]
437+ fn has_all_keywords_from_treesitter_grammar ( ) {
438+ let expected_keywords = keywords_from_treesitter_grammar ( ) ;
439+ let actual_keywords = all_keywords_set ( ) ;
440+
441+ let mut missing_keywords = expected_keywords
442+ . difference ( & actual_keywords)
443+ . cloned ( )
444+ . collect :: < Vec < _ > > ( ) ;
445+ missing_keywords. sort_unstable ( ) ;
446+
447+ assert ! (
448+ missing_keywords. is_empty( ) ,
449+ "Found {} keyword(s) from tree-sitter grammar that are missing from ALL_KEYWORDS.\n \
450+ Add missing entries to ALL_KEYWORDS in crates/pgls_completions/src/providers/keywords.rs.\n \
451+ Missing keywords:\n {}",
452+ missing_keywords. len( ) ,
453+ missing_keywords. join( "\n " )
454+ ) ;
455+ }
456+
457+ #[ test]
458+ fn has_no_extra_keywords_outside_treesitter_grammar ( ) {
459+ let expected_keywords = keywords_from_treesitter_grammar ( ) ;
460+ let actual_keywords = all_keywords_set ( ) ;
461+
462+ let mut extra_keywords = actual_keywords
463+ . difference ( & expected_keywords)
464+ . cloned ( )
465+ . collect :: < Vec < _ > > ( ) ;
466+ extra_keywords. sort_unstable ( ) ;
467+
468+ assert ! (
469+ extra_keywords. is_empty( ) ,
470+ "Found {} keyword(s) in ALL_KEYWORDS that are not tree-sitter grammar keywords.\n \
471+ Remove these from ALL_KEYWORDS or add matching keyword_* symbols to grammar.js.\n \
472+ Extra keywords:\n {}",
473+ extra_keywords. len( ) ,
474+ extra_keywords. join( "\n " )
475+ ) ;
476+ }
477+
478+ fn all_keywords_set ( ) -> HashSet < String > {
479+ ALL_KEYWORDS
480+ . iter ( )
481+ . map ( |keyword| keyword. name . to_string ( ) )
482+ . collect :: < HashSet < _ > > ( )
483+ }
484+
485+ fn keywords_from_treesitter_grammar ( ) -> HashSet < String > {
486+ let language: Language = pgls_treesitter_grammar:: LANGUAGE . into ( ) ;
487+ // Tree-sitter generates auxiliary symbol names like `keyword_int_token2` for keyword
488+ // rules that use `choice(...)`. Strip the suffix to compare canonical keyword names.
489+ let generated_token_suffix =
490+ Regex :: new ( r"_token\d+$" ) . expect ( "valid regex for generated token suffix" ) ;
491+ let mut keywords = HashSet :: new ( ) ;
492+
493+ for id in 0 ..language. node_kind_count ( ) {
494+ let Some ( kind) = language. node_kind_for_id ( id as u16 ) else {
495+ continue ;
496+ } ;
497+ if let Some ( keyword) = kind. strip_prefix ( "keyword_" ) {
498+ let keyword = generated_token_suffix. replace ( keyword, "" ) . to_string ( ) ;
499+ keywords. insert ( keyword) ;
500+ }
501+ }
502+
503+ keywords
504+ }
505+
423506 #[ sqlx:: test]
424507 async fn completes_stmt_start_keywords ( pool : PgPool ) {
425508 let setup = r#"
0 commit comments