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 }