Skip to content

Commit 9a28bee

Browse files
initial commit
1 parent aa5c8f9 commit 9a28bee

File tree

13 files changed

+486
-41
lines changed

13 files changed

+486
-41
lines changed

Cargo.lock

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ pg_schema_cache = { path = "./crates/pg_schema_cache", version = "0.0.
7575
pg_statement_splitter = { path = "./crates/pg_statement_splitter", version = "0.0.0" }
7676
pg_syntax = { path = "./crates/pg_syntax", version = "0.0.0" }
7777
pg_text_edit = { path = "./crates/pg_text_edit", version = "0.0.0" }
78+
pg_treesitter_queries = { path = "./crates/pg_treesitter_queries", version = "0.0.0" }
7879
pg_type_resolver = { path = "./crates/pg_type_resolver", version = "0.0.0" }
7980
pg_typecheck = { path = "./crates/pg_typecheck", version = "0.0.0" }
8081
pg_workspace = { path = "./crates/pg_workspace", version = "0.0.0" }

crates/pg_completions/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ text-size.workspace = true
1919
pg_schema_cache.workspace = true
2020
tree-sitter.workspace = true
2121
tree_sitter_sql.workspace = true
22+
pg_treesitter_queries.workspace = true
2223

2324
sqlx.workspace = true
2425

crates/pg_completions/src/complete.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ impl IntoIterator for CompletionResult {
3030
}
3131
}
3232

33-
pub fn complete(params: CompletionParams) -> CompletionResult {
34-
let ctx = CompletionContext::new(&params);
33+
pub async fn complete<'a>(params: CompletionParams<'a>) -> CompletionResult {
34+
let ctx = CompletionContext::new(&params).await;
3535

3636
let mut builder = CompletionBuilder::new();
3737

crates/pg_completions/src/context.rs

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
use std::ops::Range;
2+
13
use pg_schema_cache::SchemaCache;
4+
use pg_treesitter_queries::{queries, TreeSitterQueriesExecutor};
25

36
use crate::CompletionParams;
47

@@ -52,10 +55,13 @@ pub(crate) struct CompletionContext<'a> {
5255
pub schema_name: Option<String>,
5356
pub wrapping_clause_type: Option<ClauseType>,
5457
pub is_invocation: bool,
58+
pub wrapping_statement_range: Option<Range<usize>>,
59+
60+
pub ts_query_executor: Option<TreeSitterQueriesExecutor<'a>>,
5561
}
5662

5763
impl<'a> CompletionContext<'a> {
58-
pub fn new(params: &'a CompletionParams) -> Self {
64+
pub async fn new(params: &'a CompletionParams<'a>) -> Self {
5965
let mut ctx = Self {
6066
tree: params.tree,
6167
text: &params.text,
@@ -65,14 +71,30 @@ impl<'a> CompletionContext<'a> {
6571
ts_node: None,
6672
schema_name: None,
6773
wrapping_clause_type: None,
74+
wrapping_statement_range: None,
6875
is_invocation: false,
76+
ts_query_executor: None,
6977
};
7078

7179
ctx.gather_tree_context();
80+
ctx.dispatch_ts_queries().await;
7281

7382
ctx
7483
}
7584

85+
async fn dispatch_ts_queries(&mut self) {
86+
let tree = match self.tree.as_ref() {
87+
None => return,
88+
Some(t) => t,
89+
};
90+
91+
let mut executor = TreeSitterQueriesExecutor::new(tree.root_node(), self.text);
92+
93+
executor.add_query_results::<queries::RelationMatch>().await;
94+
95+
self.ts_query_executor = Some(executor);
96+
}
97+
7698
pub fn get_ts_node_content(&self, ts_node: tree_sitter::Node<'a>) -> Option<&'a str> {
7799
let source = self.text;
78100
match ts_node.utf8_text(source.as_bytes()) {
@@ -100,36 +122,38 @@ impl<'a> CompletionContext<'a> {
100122
* We'll therefore adjust the cursor position such that it meets the last node of the AST.
101123
* `select * from use {}` becomes `select * from use{}`.
102124
*/
103-
let current_node_kind = cursor.node().kind();
125+
let current_node = cursor.node();
104126
while cursor.goto_first_child_for_byte(self.position).is_none() && self.position > 0 {
105127
self.position -= 1;
106128
}
107129

108-
self.gather_context_from_node(cursor, current_node_kind);
130+
self.gather_context_from_node(cursor, current_node);
109131
}
110132

111133
fn gather_context_from_node(
112134
&mut self,
113135
mut cursor: tree_sitter::TreeCursor<'a>,
114-
previous_node_kind: &str,
136+
previous_node: tree_sitter::Node<'a>,
115137
) {
116138
let current_node = cursor.node();
117-
let current_node_kind = current_node.kind();
118139

119140
// prevent infinite recursion – this can happen if we only have a PROGRAM node
120-
if current_node_kind == previous_node_kind {
141+
if current_node.kind() == previous_node.kind() {
121142
self.ts_node = Some(current_node);
122143
return;
123144
}
124145

125-
match previous_node_kind {
126-
"statement" => self.wrapping_clause_type = current_node_kind.try_into().ok(),
146+
match previous_node.kind() {
147+
"statement" => {
148+
self.wrapping_clause_type = current_node.kind().try_into().ok();
149+
self.wrapping_statement_range = Some(previous_node.byte_range());
150+
}
127151
"invocation" => self.is_invocation = true,
128152

129153
_ => {}
130154
}
131155

132-
match current_node_kind {
156+
match current_node.kind() {
133157
"object_reference" => {
134158
let txt = self.get_ts_node_content(current_node);
135159
if let Some(txt) = txt {
@@ -159,7 +183,7 @@ impl<'a> CompletionContext<'a> {
159183
}
160184

161185
cursor.goto_first_child_for_byte(self.position);
162-
self.gather_context_from_node(cursor, current_node_kind);
186+
self.gather_context_from_node(cursor, current_node);
163187
}
164188
}
165189

@@ -179,8 +203,8 @@ mod tests {
179203
parser.parse(input, None).expect("Unable to parse tree")
180204
}
181205

182-
#[test]
183-
fn identifies_clauses() {
206+
#[tokio::test]
207+
async fn identifies_clauses() {
184208
let test_cases = vec![
185209
(format!("Select {}* from users;", CURSOR_POS), "select"),
186210
(format!("Select * from u{};", CURSOR_POS), "from"),
@@ -220,14 +244,14 @@ mod tests {
220244
schema: &pg_schema_cache::SchemaCache::new(),
221245
};
222246

223-
let ctx = CompletionContext::new(&params);
247+
let ctx = CompletionContext::new(&params).await;
224248

225249
assert_eq!(ctx.wrapping_clause_type, expected_clause.try_into().ok());
226250
}
227251
}
228252

229-
#[test]
230-
fn identifies_schema() {
253+
#[tokio::test]
254+
async fn identifies_schema() {
231255
let test_cases = vec![
232256
(
233257
format!("Select * from private.u{}", CURSOR_POS),
@@ -252,14 +276,14 @@ mod tests {
252276
schema: &pg_schema_cache::SchemaCache::new(),
253277
};
254278

255-
let ctx = CompletionContext::new(&params);
279+
let ctx = CompletionContext::new(&params).await;
256280

257281
assert_eq!(ctx.schema_name, expected_schema.map(|f| f.to_string()));
258282
}
259283
}
260284

261-
#[test]
262-
fn identifies_invocation() {
285+
#[tokio::test]
286+
async fn identifies_invocation() {
263287
let test_cases = vec![
264288
(format!("Select * from u{}sers", CURSOR_POS), false),
265289
(format!("Select * from u{}sers()", CURSOR_POS), true),
@@ -286,14 +310,14 @@ mod tests {
286310
schema: &pg_schema_cache::SchemaCache::new(),
287311
};
288312

289-
let ctx = CompletionContext::new(&params);
313+
let ctx = CompletionContext::new(&params).await;
290314

291315
assert_eq!(ctx.is_invocation, is_invocation);
292316
}
293317
}
294318

295-
#[test]
296-
fn does_not_fail_on_leading_whitespace() {
319+
#[tokio::test]
320+
async fn does_not_fail_on_leading_whitespace() {
297321
let cases = vec![
298322
format!("{} select * from", CURSOR_POS),
299323
format!(" {} select * from", CURSOR_POS),
@@ -311,7 +335,7 @@ mod tests {
311335
schema: &pg_schema_cache::SchemaCache::new(),
312336
};
313337

314-
let ctx = CompletionContext::new(&params);
338+
let ctx = CompletionContext::new(&params).await;
315339

316340
let node = ctx.ts_node.map(|n| n.clone()).unwrap();
317341

@@ -324,8 +348,8 @@ mod tests {
324348
}
325349
}
326350

327-
#[test]
328-
fn does_not_fail_on_trailing_whitespace() {
351+
#[tokio::test]
352+
async fn does_not_fail_on_trailing_whitespace() {
329353
let query = format!("select * from {}", CURSOR_POS);
330354

331355
let (position, text) = get_text_and_position(query.as_str());
@@ -339,7 +363,7 @@ mod tests {
339363
schema: &pg_schema_cache::SchemaCache::new(),
340364
};
341365

342-
let ctx = CompletionContext::new(&params);
366+
let ctx = CompletionContext::new(&params).await;
343367

344368
let node = ctx.ts_node.map(|n| n.clone()).unwrap();
345369

@@ -350,8 +374,8 @@ mod tests {
350374
);
351375
}
352376

353-
#[test]
354-
fn does_not_fail_with_empty_statements() {
377+
#[tokio::test]
378+
async fn does_not_fail_with_empty_statements() {
355379
let query = format!("{}", CURSOR_POS);
356380

357381
let (position, text) = get_text_and_position(query.as_str());
@@ -365,16 +389,16 @@ mod tests {
365389
schema: &pg_schema_cache::SchemaCache::new(),
366390
};
367391

368-
let ctx = CompletionContext::new(&params);
392+
let ctx = CompletionContext::new(&params).await;
369393

370394
let node = ctx.ts_node.map(|n| n.clone()).unwrap();
371395

372396
assert_eq!(ctx.get_ts_node_content(node), Some(""));
373397
assert_eq!(ctx.wrapping_clause_type, None);
374398
}
375399

376-
#[test]
377-
fn does_not_fail_on_incomplete_keywords() {
400+
#[tokio::test]
401+
async fn does_not_fail_on_incomplete_keywords() {
378402
// Instead of autocompleting "FROM", we'll assume that the user
379403
// is selecting a certain column name, such as `frozen_account`.
380404
let query = format!("select * fro{}", CURSOR_POS);
@@ -390,7 +414,7 @@ mod tests {
390414
schema: &pg_schema_cache::SchemaCache::new(),
391415
};
392416

393-
let ctx = CompletionContext::new(&params);
417+
let ctx = CompletionContext::new(&params).await;
394418

395419
let node = ctx.ts_node.map(|n| n.clone()).unwrap();
396420

crates/pg_completions/src/providers/functions.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ mod tests {
4545

4646
let (tree, cache) = get_test_deps(setup, &query).await;
4747
let params = get_test_params(&tree, &cache, &query);
48-
let results = complete(params);
48+
let results = complete(params).await;
4949

5050
let CompletionItem { label, .. } = results
5151
.into_iter()
@@ -78,7 +78,7 @@ mod tests {
7878

7979
let (tree, cache) = get_test_deps(setup, &query).await;
8080
let params = get_test_params(&tree, &cache, &query);
81-
let results = complete(params);
81+
let results = complete(params).await;
8282

8383
let CompletionItem { label, kind, .. } = results
8484
.into_iter()
@@ -112,7 +112,7 @@ mod tests {
112112

113113
let (tree, cache) = get_test_deps(setup, &query).await;
114114
let params = get_test_params(&tree, &cache, &query);
115-
let results = complete(params);
115+
let results = complete(params).await;
116116

117117
let CompletionItem { label, kind, .. } = results
118118
.into_iter()
@@ -146,7 +146,7 @@ mod tests {
146146

147147
let (tree, cache) = get_test_deps(setup, &query).await;
148148
let params = get_test_params(&tree, &cache, &query);
149-
let results = complete(params);
149+
let results = complete(params).await;
150150

151151
let CompletionItem { label, kind, .. } = results
152152
.into_iter()

crates/pg_completions/src/providers/tables.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ mod tests {
4343

4444
let (tree, cache) = get_test_deps(setup, &query).await;
4545
let params = get_test_params(&tree, &cache, &query);
46-
let results = complete(params);
46+
let results = complete(params).await;
4747

4848
assert!(!results.items.is_empty());
4949

@@ -81,7 +81,7 @@ mod tests {
8181
for (query, expected_label) in test_cases {
8282
let (tree, cache) = get_test_deps(setup, &query).await;
8383
let params = get_test_params(&tree, &cache, &query);
84-
let results = complete(params);
84+
let results = complete(params).await;
8585

8686
assert!(!results.items.is_empty());
8787

@@ -126,7 +126,7 @@ mod tests {
126126
for (query, expected_label) in test_cases {
127127
let (tree, cache) = get_test_deps(setup, &query).await;
128128
let params = get_test_params(&tree, &cache, &query);
129-
let results = complete(params);
129+
let results = complete(params).await;
130130

131131
assert!(!results.items.is_empty());
132132

@@ -163,7 +163,7 @@ mod tests {
163163

164164
let (tree, cache) = get_test_deps(setup, &query).await;
165165
let params = get_test_params(&tree, &cache, &query);
166-
let results = complete(params);
166+
let results = complete(params).await;
167167

168168
let CompletionItem { label, kind, .. } = results
169169
.into_iter()

crates/pg_test_utils/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ version = "0.0.0"
1515
name = "tree_print"
1616
path = "src/bin/tree_print.rs"
1717

18+
[[bin]]
19+
name = "query_debug"
20+
path = "src/bin/tree_query_debug.rs"
21+
1822
[dependencies]
1923
anyhow = "1.0.81"
2024
clap = { version = "4.5.23", features = ["derive"] }

0 commit comments

Comments
 (0)