@@ -14,6 +14,12 @@ pub struct InstantiatedLanguage<'a> {
14
14
run_query : QueryFunction ,
15
15
}
16
16
17
+ #[ derive( Debug ) ]
18
+ pub enum InstantiationError {
19
+ NoMatchingField ( String ) ,
20
+ Query ( QueryError ) ,
21
+ Tags ( tree_sitter_tags:: Error ) ,
22
+ }
17
23
pub trait HasLanguageInformation {
18
24
/// The name of this language
19
25
fn language_name ( & self ) -> & ' static str ;
@@ -88,49 +94,59 @@ pub struct TreeSitter;
88
94
pub struct Tags ;
89
95
// TODO: hide in docs?
90
96
trait InstantiateHelper < Type > {
91
- fn instantiate ( & self , search : Box < str > ) -> QueryFunction ;
97
+ fn instantiate ( & self , search : Box < str > ) -> Result < QueryFunction , InstantiationError > ;
92
98
}
93
99
94
100
// TODO: hide in docs?
95
101
pub trait Assoc {
96
102
type Type ;
97
103
}
98
104
impl < T : IdentifierQuery > InstantiateHelper < Identifier > for T {
99
- fn instantiate ( & self , search : Box < str > ) -> QueryFunction {
100
- let query = Query :: new ( & self . language ( ) , & self . query_string ( ) . to_string ( ) ) . unwrap ( ) ;
101
- let method_field = query
102
- . capture_index_for_name ( & self . query_name ( ) . to_string ( ) )
103
- . unwrap ( ) ;
104
- Box :: new ( move |node, code| {
105
- let name = & * search;
106
- let mut query_cursor = tree_sitter:: QueryCursor :: new ( ) ;
107
- let matches = query_cursor. matches ( & query, node, code) ;
108
- let ranges = matches
109
- . filter ( move |m| {
110
- m. captures
111
- . iter ( )
112
- . any ( |c| c. index == method_field && c. node . utf8_text ( code) . unwrap ( ) == name)
113
- } )
114
- . map ( |m| m. captures [ 0 ] . node . range ( ) ) ;
115
-
116
- ranges. collect ( )
117
- } )
105
+ fn instantiate ( & self , search : Box < str > ) -> Result < QueryFunction , InstantiationError > {
106
+ Query :: new ( & self . language ( ) , & self . query_string ( ) . to_string ( ) )
107
+ . map_err ( InstantiationError :: Query )
108
+ . and_then ( |query : Query | {
109
+ query
110
+ . capture_index_for_name ( & self . query_name ( ) . to_string ( ) )
111
+ . ok_or_else ( || {
112
+ InstantiationError :: NoMatchingField ( self . query_name ( ) . to_string ( ) )
113
+ } )
114
+ . map ( |method_field| -> QueryFunction {
115
+ Box :: new ( move |node, code| {
116
+ let name = & * search;
117
+ let mut query_cursor = tree_sitter:: QueryCursor :: new ( ) ;
118
+ let matches = query_cursor. matches ( & query, node, code) ;
119
+ let ranges = matches
120
+ . filter ( move |m| {
121
+ m. captures . iter ( ) . any ( |c| {
122
+ c. index == method_field
123
+ && c. node . utf8_text ( code) . unwrap_or ( "" ) == name
124
+ } )
125
+ } )
126
+ . map ( |m| m. captures [ 0 ] . node . range ( ) ) ;
127
+
128
+ ranges. collect ( )
129
+ } )
130
+ } )
131
+ } )
118
132
}
119
133
}
120
134
impl < T : TreeSitterQuery > InstantiateHelper < TreeSitter > for T {
121
- fn instantiate ( & self , search : Box < str > ) -> QueryFunction {
122
- let query = Query :: new (
135
+ fn instantiate ( & self , search : Box < str > ) -> Result < QueryFunction , InstantiationError > {
136
+ Query :: new (
123
137
& self . language ( ) ,
124
138
& self . query_string_function ( search. as_ref ( ) ) ,
125
139
)
126
- . unwrap ( ) ;
127
- Box :: new ( move |node, code| {
128
- let mut query_cursor = tree_sitter:: QueryCursor :: new ( ) ;
129
- let matches = query_cursor. matches ( & query, node, code) ;
130
-
131
- let ranges = matches. map ( |m| m. captures [ 0 ] . node . range ( ) ) ;
132
- ranges. collect ( )
140
+ . map ( |query| -> QueryFunction {
141
+ Box :: new ( move |node, code| {
142
+ let mut query_cursor = tree_sitter:: QueryCursor :: new ( ) ;
143
+ let matches = query_cursor. matches ( & query, node, code) ;
144
+
145
+ let ranges = matches. map ( |m| m. captures [ 0 ] . node . range ( ) ) ;
146
+ ranges. collect ( )
147
+ } )
133
148
} )
149
+ . map_err ( InstantiationError :: Query )
134
150
}
135
151
}
136
152
struct TagsConfigurationThreadSafe ( TagsConfiguration ) ;
@@ -156,64 +172,75 @@ impl TagsConfigurationThreadSafe {
156
172
}
157
173
}
158
174
impl < T : TreeSitterTags > InstantiateHelper < Tags > for T {
159
- fn instantiate ( & self , search : Box < str > ) -> QueryFunction {
160
- let tag_config = TagsConfigurationThreadSafe (
161
- TagsConfiguration :: new ( self . language ( ) , & self . tag_query ( ) . to_string ( ) , "" ) . unwrap ( ) ,
162
- ) ;
163
- Box :: new ( move |node, code| {
164
- let mut tag_context = TagsContext :: new ( ) ;
165
- let name = & * search;
166
- // TODO: don't double parse
167
- let tags = tag_config
168
- . generate_tags ( & mut tag_context, code, None )
169
- . unwrap ( )
170
- . 0 ;
171
- let ranges = tags
172
- . filter_map ( Result :: ok)
173
- . filter ( |tag| {
174
- [ "method" , "function" ]
175
- . contains ( & tag_config. syntax_type_name ( tag. syntax_type_id ) )
176
- && str:: from_utf8 ( & code[ tag. name_range . clone ( ) ] ) . unwrap_or ( "" ) == name
175
+ fn instantiate ( & self , search : Box < str > ) -> Result < QueryFunction , InstantiationError > {
176
+ TagsConfiguration :: new ( self . language ( ) , & self . tag_query ( ) . to_string ( ) , "" )
177
+ . map_err ( InstantiationError :: Tags )
178
+ . map ( |tag_config| -> QueryFunction {
179
+ let tag_config = TagsConfigurationThreadSafe ( tag_config) ;
180
+ Box :: new ( move |node, code| {
181
+ let mut tag_context = TagsContext :: new ( ) ;
182
+ let name = & * search;
183
+ // TODO: don't double parse
184
+ tag_config
185
+ . generate_tags ( & mut tag_context, code, None )
186
+ . map ( |tags| {
187
+ let ranges = tags
188
+ . 0
189
+ . filter_map ( Result :: ok)
190
+ . filter ( |tag| {
191
+ [ "method" , "function" ]
192
+ . contains ( & tag_config. syntax_type_name ( tag. syntax_type_id ) )
193
+ && str:: from_utf8 ( & code[ tag. name_range . clone ( ) ] )
194
+ . unwrap_or ( "" )
195
+ == name
196
+ } )
197
+ . filter_map ( |tag| {
198
+ node. descendant_for_byte_range ( tag. range . start , tag. range . end )
199
+ . map ( |node| node. range ( ) )
200
+ } ) ;
201
+ ranges. collect ( )
202
+ } )
203
+ . unwrap_or_else ( |_| vec ! [ ] . into_boxed_slice ( ) )
177
204
} )
178
- . filter_map ( |tag| {
179
- node. descendant_for_byte_range ( tag. range . start , tag. range . end )
180
- . map ( |node| node. range ( ) )
181
- } ) ;
182
- ranges. collect ( )
183
- } )
205
+ } )
184
206
}
185
207
}
208
+
186
209
impl < T : Assoc + InstantiateHelper < T :: Type > + HasLanguageInformation > SupportedLanguage for T {
187
- fn instantiate ( & self , search : Box < str > ) -> QueryFunction {
210
+ fn instantiate ( & self , search : Box < str > ) -> Result < QueryFunction , InstantiationError > {
188
211
self . instantiate ( search)
189
212
}
190
213
}
214
+ // TODO: maybe make this fallable
191
215
type QueryFunction = Box < dyn for <' x , ' y > Fn ( Node < ' x > , & ' y [ u8 ] ) -> Box < [ Range ] > + Send + Sync > ;
192
216
193
217
pub trait SupportedLanguage : HasLanguageInformation {
194
- fn instantiate ( & self , search : Box < str > ) -> QueryFunction ;
195
- fn to_language < ' a > ( & self , search : & ' a str ) -> InstantiatedLanguage < ' a > {
196
- InstantiatedLanguage :: new (
197
- search ,
198
- self . language_info ( ) ,
199
- self . instantiate ( search. into ( ) ) ,
200
- )
218
+ fn instantiate ( & self , search : Box < str > ) -> Result < QueryFunction , InstantiationError > ;
219
+ fn to_language < ' a > (
220
+ & self ,
221
+ search : & ' a str ,
222
+ ) -> Result < InstantiatedLanguage < ' a > , InstantiationError > {
223
+ self . instantiate ( search. into ( ) )
224
+ . map ( |f| InstantiatedLanguage :: new ( search , self . language_info ( ) , f ) )
201
225
}
202
226
}
203
227
204
228
pub trait InstantiateMap < ' a > {
205
- fn instantiate_map ( self , name : & ' a str ) -> Result < Vec < InstantiatedLanguage < ' a > > , QueryError > ;
229
+ fn instantiate_map (
230
+ self ,
231
+ name : & ' a str ,
232
+ ) -> Result < Vec < InstantiatedLanguage < ' a > > , InstantiationError > ;
206
233
}
207
234
impl < ' a , T , U > InstantiateMap < ' a > for T
208
235
where
209
236
T : IntoIterator < Item = U > ,
210
237
U : Deref < Target = & ' a dyn SupportedLanguage > ,
211
238
{
212
- fn instantiate_map ( self , name : & ' a str ) -> Result < Vec < InstantiatedLanguage < ' a > > , QueryError > {
213
- Ok ( self
214
- . into_iter ( )
215
- . map ( |l| InstantiatedLanguage :: new ( name , l . language_info ( ) , l . instantiate ( name . into ( ) ) ) )
216
- . collect ( ) )
239
+ fn instantiate_map (
240
+ self ,
241
+ name : & ' a str ,
242
+ ) -> Result < Vec < InstantiatedLanguage < ' a > > , InstantiationError > {
243
+ self . into_iter ( ) . map ( |l| l . to_language ( name ) ) . collect ( )
217
244
}
218
245
}
219
246
impl < ' a > InstantiatedLanguage < ' a > {
0 commit comments