1use tree_sitter::Language;
5
6pub struct LanguageSpec {
8 pub extensions: &'static [&'static str],
9 pub symbol_query: &'static str,
10 pub import_query: &'static str,
11 pub call_query: &'static str,
12}
13
14const PYTHON: LanguageSpec = LanguageSpec {
17 extensions: &[".py", ".pyi"],
18 symbol_query: r#"
19 (function_definition name: (identifier) @name) @definition.function
20 (class_definition name: (identifier) @name) @definition.class
21 "#,
22 import_query: r#"
23 (import_statement) @import
24 (import_from_statement) @import
25 "#,
26 call_query: r#"
27 (call function: (identifier) @name) @call
28 (call function: (attribute attribute: (identifier) @name)) @call
29 "#,
30};
31
32const JAVASCRIPT: LanguageSpec = LanguageSpec {
33 extensions: &[".js", ".jsx", ".mjs", ".cjs"],
34 symbol_query: r#"
35 (function_declaration name: (identifier) @name) @definition.function
36 (class_declaration name: (identifier) @name) @definition.class
37 (method_definition name: (property_identifier) @name) @definition.method
38 (export_statement declaration: (function_declaration name: (identifier) @name)) @definition.function
39 (export_statement declaration: (class_declaration name: (identifier) @name)) @definition.class
40 (lexical_declaration (variable_declarator name: (identifier) @name value: (arrow_function))) @definition.function
41 "#,
42 import_query: r#"
43 (import_statement) @import
44 "#,
45 call_query: r#"
46 (call_expression function: (identifier) @name) @call
47 (call_expression function: (member_expression property: (property_identifier) @name)) @call
48 "#,
49};
50
51const TYPESCRIPT: LanguageSpec = LanguageSpec {
52 extensions: &[".ts", ".tsx"],
53 symbol_query: r#"
54 (function_declaration name: (identifier) @name) @definition.function
55 (class_declaration name: (type_identifier) @name) @definition.class
56 (method_definition name: (property_identifier) @name) @definition.method
57 (interface_declaration name: (type_identifier) @name) @definition.type
58 (type_alias_declaration name: (type_identifier) @name) @definition.type
59 (enum_declaration name: (identifier) @name) @definition.type
60 (lexical_declaration (variable_declarator name: (identifier) @name value: (arrow_function))) @definition.function
61 (export_statement declaration: (function_declaration name: (identifier) @name)) @definition.function
62 (export_statement declaration: (class_declaration name: (type_identifier) @name)) @definition.class
63 (export_statement declaration: (interface_declaration name: (type_identifier) @name)) @definition.type
64 (export_statement declaration: (type_alias_declaration name: (type_identifier) @name)) @definition.type
65 (export_statement declaration: (enum_declaration name: (identifier) @name)) @definition.type
66 (export_statement declaration: (lexical_declaration (variable_declarator name: (identifier) @name value: (arrow_function)))) @definition.function
67 "#,
68 import_query: r#"
69 (import_statement) @import
70 "#,
71 call_query: r#"
72 (call_expression function: (identifier) @name) @call
73 (call_expression function: (member_expression property: (property_identifier) @name)) @call
74 "#,
75};
76
77const GO: LanguageSpec = LanguageSpec {
78 extensions: &[".go"],
79 symbol_query: r#"
80 (function_declaration name: (identifier) @name) @definition.function
81 (method_declaration name: (field_identifier) @name) @definition.method
82 (type_declaration (type_spec name: (type_identifier) @name)) @definition.type
83 "#,
84 import_query: r#"
85 (import_declaration) @import
86 "#,
87 call_query: r#"
88 (call_expression function: (identifier) @name) @call
89 (call_expression function: (selector_expression field: (field_identifier) @name)) @call
90 "#,
91};
92
93const RUST: LanguageSpec = LanguageSpec {
94 extensions: &[".rs"],
95 symbol_query: r#"
96 (function_item name: (identifier) @name) @definition.function
97 (struct_item name: (type_identifier) @name) @definition.class
98 (enum_item name: (type_identifier) @name) @definition.type
99 (trait_item name: (type_identifier) @name) @definition.type
100 (impl_item type: (type_identifier) @name) @definition.class
101 (type_item name: (type_identifier) @name) @definition.type
102 "#,
103 import_query: r#"
104 (use_declaration) @import
105 "#,
106 call_query: r#"
107 (call_expression function: (identifier) @name) @call
108 (call_expression function: (scoped_identifier name: (identifier) @name)) @call
109 (call_expression function: (field_expression field: (field_identifier) @name)) @call
110 "#,
111};
112
113const JAVA: LanguageSpec = LanguageSpec {
114 extensions: &[".java"],
115 symbol_query: r#"
116 (method_declaration name: (identifier) @name) @definition.method
117 (class_declaration name: (identifier) @name) @definition.class
118 (interface_declaration name: (identifier) @name) @definition.type
119 (enum_declaration name: (identifier) @name) @definition.type
120 (constructor_declaration name: (identifier) @name) @definition.method
121 "#,
122 import_query: r#"
123 (import_declaration) @import
124 "#,
125 call_query: r#"
126 (method_invocation name: (identifier) @name) @call
127 "#,
128};
129
130const PHP: LanguageSpec = LanguageSpec {
131 extensions: &[".php"],
132 symbol_query: r#"
133 (function_definition name: (name) @name) @definition.function
134 (class_declaration name: (name) @name) @definition.class
135 (method_declaration name: (name) @name) @definition.method
136 (interface_declaration name: (name) @name) @definition.type
137 (trait_declaration name: (name) @name) @definition.type
138 "#,
139 import_query: r#"
140 (namespace_use_declaration) @import
141 "#,
142 call_query: r#"
143 (function_call_expression function: (name) @name) @call
144 (function_call_expression function: (qualified_name) @name) @call
145 (scoped_call_expression scope: [(name) (qualified_name)] name: (name) @name) @call
146 (member_call_expression name: (name) @name) @call
147 "#,
148};
149
150const DART: LanguageSpec = LanguageSpec {
151 extensions: &[".dart"],
152 symbol_query: r#"
153 (function_signature name: (identifier) @name) @definition.function
154 (class_definition name: (identifier) @name) @definition.class
155 (method_signature (function_signature (identifier) @name)) @definition.method
156 (enum_declaration name: (identifier) @name) @definition.type
157 "#,
158 import_query: r#"
159 (import_or_export) @import
160 "#,
161 call_query: "",
164};
165
166const CSHARP: LanguageSpec = LanguageSpec {
167 extensions: &[".cs"],
168 symbol_query: r#"
169 (method_declaration name: (identifier) @name) @definition.method
170 (class_declaration name: (identifier) @name) @definition.class
171 (interface_declaration name: (identifier) @name) @definition.type
172 (struct_declaration name: (identifier) @name) @definition.type
173 (enum_declaration name: (identifier) @name) @definition.type
174 (constructor_declaration name: (identifier) @name) @definition.method
175 "#,
176 import_query: r#"
177 (using_directive) @import
178 "#,
179 call_query: r#"
180 (invocation_expression function: (identifier) @name) @call
181 (invocation_expression function: (member_access_expression name: (identifier) @name)) @call
182 "#,
183};
184
185const C_LANG: LanguageSpec = LanguageSpec {
186 extensions: &[".c", ".h"],
187 symbol_query: r#"
188 (function_definition declarator: (function_declarator declarator: (identifier) @name)) @definition.function
189 (struct_specifier name: (type_identifier) @name) @definition.type
190 (enum_specifier name: (type_identifier) @name) @definition.type
191 (type_definition declarator: (type_identifier) @name) @definition.type
192 "#,
193 import_query: r#"
194 (preproc_include) @import
195 "#,
196 call_query: r#"
197 (call_expression function: (identifier) @name) @call
198 "#,
199};
200
201const CPP: LanguageSpec = LanguageSpec {
202 extensions: &[".cpp", ".cc", ".cxx", ".hpp", ".hxx", ".hh"],
203 symbol_query: r#"
204 (function_definition declarator: (function_declarator declarator: (identifier) @name)) @definition.function
205 (function_definition declarator: (function_declarator declarator: (qualified_identifier name: (identifier) @name))) @definition.function
206 (class_specifier name: (type_identifier) @name) @definition.class
207 (struct_specifier name: (type_identifier) @name) @definition.type
208 "#,
209 import_query: r#"
210 (preproc_include) @import
211 "#,
212 call_query: r#"
213 (call_expression function: (identifier) @name) @call
214 (call_expression function: (field_expression field: (field_identifier) @name)) @call
215 "#,
216};
217
218const ELIXIR: LanguageSpec = LanguageSpec {
219 extensions: &[".ex", ".exs"],
220 symbol_query: r#"
221 (call target: (identifier) @_keyword (#any-of? @_keyword "def" "defp" "defmacro") (arguments (identifier) @name)) @definition.function
222 (call target: (identifier) @_keyword (#any-of? @_keyword "defmodule") (arguments (alias) @name)) @definition.class
223 "#,
224 import_query: r#"
225 (call target: (identifier) @_keyword (#any-of? @_keyword "import" "alias" "use" "require")) @import
226 "#,
227 call_query: r#"
228 (call target: (identifier) @name) @call
229 (call target: (dot right: (identifier) @name)) @call
230 "#,
231};
232
233const RUBY: LanguageSpec = LanguageSpec {
234 extensions: &[".rb", ".rake", ".gemspec"],
235 symbol_query: r#"
236 (method name: (identifier) @name) @definition.function
237 (singleton_method name: (identifier) @name) @definition.function
238 (class name: (constant) @name) @definition.class
239 (module name: (constant) @name) @definition.class
240 "#,
241 import_query: r#"
242 (call method: (identifier) @_m (#any-of? @_m "require" "require_relative" "load" "include" "extend" "prepend")) @import
243 "#,
244 call_query: r#"
245 (call method: (identifier) @name) @call
246 "#,
247};
248
249const KOTLIN: LanguageSpec = LanguageSpec {
250 extensions: &[".kt", ".kts"],
251 symbol_query: r#"
252 (function_declaration name: (identifier) @name) @definition.function
253 (class_declaration name: (identifier) @name) @definition.class
254 (object_declaration name: (identifier) @name) @definition.class
255 "#,
256 import_query: r#"
257 (import) @import
258 "#,
259 call_query: r#"
260 (call_expression (identifier) @name) @call
261 (call_expression (navigation_expression (identifier) (identifier) @name)) @call
262 "#,
263};
264
265const MARKDOWN: LanguageSpec = LanguageSpec {
266 extensions: &[".md", ".markdown"],
267 symbol_query: r#"
268 (atx_heading heading_content: (_) @name) @definition.section
269 (setext_heading heading_content: (_) @name) @definition.section
270 "#,
271 import_query: "",
272 call_query: "",
273};
274
275const YAML: LanguageSpec = LanguageSpec {
276 extensions: &[".yaml", ".yml"],
277 symbol_query: r#"
278 (block_mapping_pair key: (_) @name) @definition.property
279 "#,
280 import_query: "",
281 call_query: "",
282};
283
284const JSON_LANG: LanguageSpec = LanguageSpec {
285 extensions: &[".json", ".jsonc"],
286 symbol_query: r#"
287 (pair key: (string (string_content) @name)) @definition.property
288 "#,
289 import_query: "",
290 call_query: "",
291};
292
293const SWIFT: LanguageSpec = LanguageSpec {
294 extensions: &[".swift"],
295 symbol_query: r#"
296 (function_declaration name: (simple_identifier) @name) @definition.function
297 (class_declaration name: (type_identifier) @name) @definition.class
298 (protocol_declaration name: (type_identifier) @name) @definition.type
299 (struct_declaration name: (type_identifier) @name) @definition.type
300 (enum_declaration name: (type_identifier) @name) @definition.type
301 "#,
302 import_query: r#"
303 (import_declaration) @import
304 "#,
305 call_query: r#"
306 (call_expression (simple_identifier) @name) @call
307 (call_expression (navigation_expression suffix: (navigation_suffix suffix: (simple_identifier) @name))) @call
308 "#,
309};
310
311const SPECS: &[(&str, &LanguageSpec)] = &[
315 ("python", &PYTHON),
316 ("javascript", &JAVASCRIPT),
317 ("typescript", &TYPESCRIPT),
318 ("go", &GO),
319 ("rust", &RUST),
320 ("java", &JAVA),
321 ("php", &PHP),
322 ("dart", &DART),
323 ("csharp", &CSHARP),
324 ("c", &C_LANG),
325 ("cpp", &CPP),
326 ("elixir", &ELIXIR),
327 ("ruby", &RUBY),
328 ("kotlin", &KOTLIN),
329 ("swift", &SWIFT),
330 ("markdown", &MARKDOWN),
331 ("yaml", &YAML),
332 ("json", &JSON_LANG),
333];
334
335pub fn detect_language(file_path: &str) -> Option<&'static str> {
337 let path = std::path::Path::new(file_path);
338 let ext = path
339 .extension()
340 .map(|e| format!(".{}", e.to_string_lossy().to_lowercase()))?;
341
342 for (name, spec) in SPECS {
343 if spec.extensions.contains(&ext.as_str()) {
344 return Some(name);
345 }
346 }
347 None
348}
349
350pub fn get_spec(lang: &str) -> Option<&'static LanguageSpec> {
352 SPECS
353 .iter()
354 .find(|(name, _)| *name == lang)
355 .map(|(_, s)| *s)
356}
357
358pub fn get_ts_language(lang: &str) -> Option<Language> {
360 let lang_fn = match lang {
361 "python" => tree_sitter_python::LANGUAGE,
362 "javascript" => tree_sitter_javascript::LANGUAGE,
363 "typescript" => tree_sitter_typescript::LANGUAGE_TYPESCRIPT,
364 "go" => tree_sitter_go::LANGUAGE,
365 "rust" => tree_sitter_rust::LANGUAGE,
366 "java" => tree_sitter_java::LANGUAGE,
367 "c" => tree_sitter_c::LANGUAGE,
368 "cpp" => tree_sitter_cpp::LANGUAGE,
369 "csharp" => tree_sitter_c_sharp::LANGUAGE,
370 "ruby" => tree_sitter_ruby::LANGUAGE,
371 "php" => tree_sitter_php::LANGUAGE_PHP,
372 "swift" => tree_sitter_swift::LANGUAGE,
373 "kotlin" => tree_sitter_kotlin_ng::LANGUAGE,
374 "dart" => tree_sitter_dart::LANGUAGE,
375 "elixir" => tree_sitter_elixir::LANGUAGE,
376 "json" => tree_sitter_json::LANGUAGE,
377 "yaml" => tree_sitter_yaml::LANGUAGE,
378 "markdown" => tree_sitter_md::LANGUAGE,
379 _ => return None,
380 };
381 Some(lang_fn.into())
382}