@@ -30,7 +30,7 @@ impl TryFrom<&str> for ClauseType {
30
30
match value {
31
31
"select" => Ok ( Self :: Select ) ,
32
32
"where" => Ok ( Self :: Where ) ,
33
- "from" | "keyword_from" => Ok ( Self :: From ) ,
33
+ "from" => Ok ( Self :: From ) ,
34
34
"update" => Ok ( Self :: Update ) ,
35
35
"delete" => Ok ( Self :: Delete ) ,
36
36
_ => {
@@ -49,8 +49,52 @@ impl TryFrom<&str> for ClauseType {
49
49
50
50
impl TryFrom < String > for ClauseType {
51
51
type Error = String ;
52
- fn try_from ( value : String ) -> Result < ClauseType , Self :: Error > {
53
- ClauseType :: try_from ( value. as_str ( ) )
52
+ fn try_from ( value : String ) -> Result < Self , Self :: Error > {
53
+ Self :: try_from ( value. as_str ( ) )
54
+ }
55
+ }
56
+
57
+ /// We can map a few nodes, such as the "update" node, to actual SQL clauses.
58
+ /// That gives us a lot of insight for completions.
59
+ /// Other nodes, such as the "relation" node, gives us less but still
60
+ /// relevant information.
61
+ /// `WrappingNode` maps to such nodes.
62
+ ///
63
+ /// Note: This is not the direct parent of the `node_under_cursor`, but the closest
64
+ /// *relevant* parent.
65
+ #[ derive( Debug , PartialEq , Eq ) ]
66
+ pub enum WrappingNode {
67
+ Relation ,
68
+ BinaryExpression ,
69
+ Assignment ,
70
+ }
71
+
72
+ impl TryFrom < & str > for WrappingNode {
73
+ type Error = String ;
74
+
75
+ fn try_from ( value : & str ) -> Result < Self , Self :: Error > {
76
+ match value {
77
+ "relation" => Ok ( Self :: Relation ) ,
78
+ "assignment" => Ok ( Self :: Assignment ) ,
79
+ "binary_expression" => Ok ( Self :: BinaryExpression ) ,
80
+ _ => {
81
+ let message = format ! ( "Unimplemented Relation: {}" , value) ;
82
+
83
+ // Err on tests, so we notice that we're lacking an implementation immediately.
84
+ if cfg ! ( test) {
85
+ panic ! ( "{}" , message) ;
86
+ }
87
+
88
+ Err ( message)
89
+ }
90
+ }
91
+ }
92
+ }
93
+
94
+ impl TryFrom < String > for WrappingNode {
95
+ type Error = String ;
96
+ fn try_from ( value : String ) -> Result < Self , Self :: Error > {
97
+ Self :: try_from ( value. as_str ( ) )
54
98
}
55
99
}
56
100
@@ -64,6 +108,9 @@ pub(crate) struct CompletionContext<'a> {
64
108
65
109
pub schema_name : Option < String > ,
66
110
pub wrapping_clause_type : Option < ClauseType > ,
111
+
112
+ pub wrapping_node_kind : Option < WrappingNode > ,
113
+
67
114
pub is_invocation : bool ,
68
115
pub wrapping_statement_range : Option < tree_sitter:: Range > ,
69
116
@@ -80,6 +127,7 @@ impl<'a> CompletionContext<'a> {
80
127
node_under_cursor : None ,
81
128
schema_name : None ,
82
129
wrapping_clause_type : None ,
130
+ wrapping_node_kind : None ,
83
131
wrapping_statement_range : None ,
84
132
is_invocation : false ,
85
133
mentioned_relations : HashMap :: new ( ) ,
@@ -133,6 +181,15 @@ impl<'a> CompletionContext<'a> {
133
181
} )
134
182
}
135
183
184
+ pub fn get_node_under_cursor_content ( & self ) -> Option < String > {
185
+ self . node_under_cursor
186
+ . and_then ( |n| self . get_ts_node_content ( n) )
187
+ . and_then ( |txt| match txt {
188
+ NodeText :: Replaced => None ,
189
+ NodeText :: Original ( c) => Some ( c. to_string ( ) ) ,
190
+ } )
191
+ }
192
+
136
193
fn gather_tree_context ( & mut self ) {
137
194
let mut cursor = self . tree . root_node ( ) . walk ( ) ;
138
195
@@ -163,23 +220,26 @@ impl<'a> CompletionContext<'a> {
163
220
) {
164
221
let current_node = cursor. node ( ) ;
165
222
223
+ let parent_node_kind = parent_node. kind ( ) ;
224
+ let current_node_kind = current_node. kind ( ) ;
225
+
166
226
// prevent infinite recursion – this can happen if we only have a PROGRAM node
167
- if current_node . kind ( ) == parent_node . kind ( ) {
227
+ if current_node_kind == parent_node_kind {
168
228
self . node_under_cursor = Some ( current_node) ;
169
229
return ;
170
230
}
171
231
172
- match parent_node . kind ( ) {
232
+ match parent_node_kind {
173
233
"statement" | "subquery" => {
174
- self . wrapping_clause_type = current_node . kind ( ) . try_into ( ) . ok ( ) ;
234
+ self . wrapping_clause_type = current_node_kind . try_into ( ) . ok ( ) ;
175
235
self . wrapping_statement_range = Some ( parent_node. range ( ) ) ;
176
236
}
177
237
"invocation" => self . is_invocation = true ,
178
238
179
239
_ => { }
180
240
}
181
241
182
- match current_node . kind ( ) {
242
+ match current_node_kind {
183
243
"object_reference" => {
184
244
let content = self . get_ts_node_content ( current_node) ;
185
245
if let Some ( node_txt) = content {
@@ -195,13 +255,12 @@ impl<'a> CompletionContext<'a> {
195
255
}
196
256
}
197
257
198
- // in Treesitter, the Where clause is nested inside other clauses
199
- "where" => {
200
- self . wrapping_clause_type = "where" . try_into ( ) . ok ( ) ;
258
+ "where" | "update" | "select" | "delete" | "from" => {
259
+ self . wrapping_clause_type = current_node_kind. try_into ( ) . ok ( ) ;
201
260
}
202
261
203
- "keyword_from " => {
204
- self . wrapping_clause_type = "keyword_from" . try_into ( ) . ok ( ) ;
262
+ "relation" | "binary_expression" | "assignment " => {
263
+ self . wrapping_node_kind = current_node_kind . try_into ( ) . ok ( ) ;
205
264
}
206
265
207
266
_ => { }
@@ -406,10 +465,6 @@ mod tests {
406
465
ctx. get_ts_node_content( node) ,
407
466
Some ( NodeText :: Original ( "from" ) )
408
467
) ;
409
- assert_eq ! (
410
- ctx. wrapping_clause_type,
411
- Some ( crate :: context:: ClauseType :: From )
412
- ) ;
413
468
}
414
469
415
470
#[ test]
0 commit comments