/ src / languages / csharp.rs
csharp.rs
  1  use crate::languages::LanguageSupport;
  2  use std::sync::OnceLock;
  3  use tracing::error;
  4  use tree_sitter::{Language, Query};
  5  
  6  pub struct CSharp;
  7  
  8  static REFERENCE_QUERY: OnceLock<Query> = OnceLock::new();
  9  static BINDING_QUERY: OnceLock<Query> = OnceLock::new();
 10  static IMPORT_QUERY: OnceLock<Query> = OnceLock::new();
 11  static COMPLETION_QUERY: OnceLock<Query> = OnceLock::new();
 12  static REASSIGNMENT_QUERY: OnceLock<Query> = OnceLock::new();
 13  static IDENTIFIER_QUERY: OnceLock<Query> = OnceLock::new();
 14  static EXPORT_QUERY: OnceLock<Query> = OnceLock::new();
 15  static ASSIGNMENT_QUERY: OnceLock<Query> = OnceLock::new();
 16  static DESTRUCTURE_QUERY: OnceLock<Query> = OnceLock::new();
 17  static SCOPE_QUERY: OnceLock<Query> = OnceLock::new();
 18  
 19  fn compile_query(grammar: &Language, source: &str, query_name: &str) -> Query {
 20      match Query::new(grammar, source) {
 21          Ok(query) => query,
 22          Err(e) => {
 23              error!(
 24                  language = "csharp",
 25                  query = query_name,
 26                  error = %e,
 27                  "Failed to compile query, failing fast"
 28              );
 29              panic!("Failed to compile query '{}': {}", query_name, e)
 30          }
 31      }
 32  }
 33  
 34  impl LanguageSupport for CSharp {
 35      fn id(&self) -> &'static str {
 36          "csharp"
 37      }
 38  
 39      fn extensions(&self) -> &'static [&'static str] {
 40          &["cs", "csx"]
 41      }
 42  
 43      fn language_ids(&self) -> &'static [&'static str] {
 44          &["csharp", "c#"]
 45      }
 46  
 47      fn grammar(&self) -> Language {
 48          tree_sitter_c_sharp::LANGUAGE.into()
 49      }
 50  
 51      fn reference_query(&self) -> &Query {
 52          REFERENCE_QUERY.get_or_init(|| {
 53              compile_query(
 54                  &self.grammar(),
 55                  include_str!("../../queries/csharp/references.scm"),
 56                  "references",
 57              )
 58          })
 59      }
 60  
 61      fn binding_query(&self) -> Option<&Query> {
 62          Some(BINDING_QUERY.get_or_init(|| {
 63              compile_query(
 64                  &self.grammar(),
 65                  include_str!("../../queries/csharp/bindings.scm"),
 66                  "bindings",
 67              )
 68          }))
 69      }
 70  
 71      fn import_query(&self) -> Option<&Query> {
 72          Some(IMPORT_QUERY.get_or_init(|| {
 73              compile_query(
 74                  &self.grammar(),
 75                  include_str!("../../queries/csharp/imports.scm"),
 76                  "imports",
 77              )
 78          }))
 79      }
 80  
 81      fn completion_query(&self) -> Option<&Query> {
 82          Some(COMPLETION_QUERY.get_or_init(|| {
 83              compile_query(
 84                  &self.grammar(),
 85                  include_str!("../../queries/csharp/completion.scm"),
 86                  "completion",
 87              )
 88          }))
 89      }
 90  
 91      fn reassignment_query(&self) -> Option<&Query> {
 92          Some(REASSIGNMENT_QUERY.get_or_init(|| {
 93              compile_query(
 94                  &self.grammar(),
 95                  include_str!("../../queries/csharp/reassignments.scm"),
 96                  "reassignments",
 97              )
 98          }))
 99      }
100  
101      fn identifier_query(&self) -> Option<&Query> {
102          Some(IDENTIFIER_QUERY.get_or_init(|| {
103              compile_query(
104                  &self.grammar(),
105                  include_str!("../../queries/csharp/identifiers.scm"),
106                  "identifiers",
107              )
108          }))
109      }
110  
111      fn export_query(&self) -> Option<&Query> {
112          Some(EXPORT_QUERY.get_or_init(|| {
113              compile_query(
114                  &self.grammar(),
115                  include_str!("../../queries/csharp/exports.scm"),
116                  "exports",
117              )
118          }))
119      }
120  
121      fn assignment_query(&self) -> Option<&Query> {
122          Some(ASSIGNMENT_QUERY.get_or_init(|| {
123              compile_query(
124                  &self.grammar(),
125                  include_str!("../../queries/csharp/assignments.scm"),
126                  "assignments",
127              )
128          }))
129      }
130  
131      fn destructure_query(&self) -> Option<&Query> {
132          Some(DESTRUCTURE_QUERY.get_or_init(|| {
133              compile_query(
134                  &self.grammar(),
135                  include_str!("../../queries/csharp/destructures.scm"),
136                  "destructures",
137              )
138          }))
139      }
140  
141      fn scope_query(&self) -> Option<&Query> {
142          Some(SCOPE_QUERY.get_or_init(|| {
143              compile_query(
144                  &self.grammar(),
145                  include_str!("../../queries/csharp/scopes.scm"),
146                  "scopes",
147              )
148          }))
149      }
150  
151      fn completion_trigger_characters(&self) -> &'static [&'static str] {
152          &["(\"", "('"]
153      }
154  
155      fn is_standard_env_object(&self, name: &str) -> bool {
156          name == "Environment"
157      }
158  
159      fn comment_node_kinds(&self) -> &'static [&'static str] {
160          &["comment"]
161      }
162  
163      fn is_scope_node(&self, node: tree_sitter::Node) -> bool {
164          matches!(
165              node.kind(),
166              "method_declaration"
167                  | "constructor_declaration"
168                  | "block"
169                  | "for_statement"
170                  | "foreach_statement"
171                  | "if_statement"
172                  | "while_statement"
173                  | "do_statement"
174                  | "switch_statement"
175                  | "try_statement"
176                  | "catch_clause"
177                  | "class_declaration"
178                  | "struct_declaration"
179                  | "interface_declaration"
180                  | "namespace_declaration"
181                  | "lambda_expression"
182                  | "local_function_statement"
183          )
184      }
185  }
186  
187  #[cfg(test)]
188  mod tests {
189      use super::*;
190  
191      fn get_csharp() -> CSharp {
192          CSharp
193      }
194  
195      #[test]
196      fn test_id() {
197          assert_eq!(get_csharp().id(), "csharp");
198      }
199  
200      #[test]
201      fn test_extensions() {
202          let exts = get_csharp().extensions();
203          assert!(exts.contains(&"cs"));
204          assert!(exts.contains(&"csx"));
205      }
206  
207      #[test]
208      fn test_language_ids() {
209          let ids = get_csharp().language_ids();
210          assert!(ids.contains(&"csharp"));
211      }
212  
213      #[test]
214      fn test_grammar_compiles() {
215          let csharp = get_csharp();
216          let _grammar = csharp.grammar();
217      }
218  
219      #[test]
220      fn test_reference_query_compiles() {
221          let csharp = get_csharp();
222          let _query = csharp.reference_query();
223      }
224  
225      #[test]
226      fn test_binding_query_compiles() {
227          let csharp = get_csharp();
228          assert!(csharp.binding_query().is_some());
229      }
230  
231      #[test]
232      fn test_import_query_compiles() {
233          let csharp = get_csharp();
234          assert!(csharp.import_query().is_some());
235      }
236  
237      #[test]
238      fn test_completion_query_compiles() {
239          let csharp = get_csharp();
240          assert!(csharp.completion_query().is_some());
241      }
242  
243      #[test]
244      fn test_reassignment_query_compiles() {
245          let csharp = get_csharp();
246          assert!(csharp.reassignment_query().is_some());
247      }
248  
249      #[test]
250      fn test_identifier_query_compiles() {
251          let csharp = get_csharp();
252          assert!(csharp.identifier_query().is_some());
253      }
254  
255      #[test]
256      fn test_export_query_compiles() {
257          let csharp = get_csharp();
258          assert!(csharp.export_query().is_some());
259      }
260  
261      #[test]
262      fn test_assignment_query_compiles() {
263          let csharp = get_csharp();
264          assert!(csharp.assignment_query().is_some());
265      }
266  
267      #[test]
268      fn test_scope_query_compiles() {
269          let csharp = get_csharp();
270          assert!(csharp.scope_query().is_some());
271      }
272  
273      #[test]
274      fn test_destructure_query_compiles() {
275          let csharp = get_csharp();
276          assert!(csharp.destructure_query().is_some());
277      }
278  }