/ src / languages / elixir.rs
elixir.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 Elixir;
  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 = "elixir",
 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 Elixir {
 35      fn id(&self) -> &'static str {
 36          "elixir"
 37      }
 38  
 39      fn extensions(&self) -> &'static [&'static str] {
 40          &["ex", "exs"]
 41      }
 42  
 43      fn language_ids(&self) -> &'static [&'static str] {
 44          &["elixir"]
 45      }
 46  
 47      fn grammar(&self) -> Language {
 48          tree_sitter_elixir::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/elixir/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/elixir/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/elixir/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/elixir/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/elixir/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/elixir/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/elixir/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/elixir/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/elixir/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/elixir/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 == "System"
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              "do_block" | "anonymous_function" | "call" | "stab_clause"
167          )
168      }
169  }
170  
171  #[cfg(test)]
172  mod tests {
173      use super::*;
174  
175      fn get_elixir() -> Elixir {
176          Elixir
177      }
178  
179      #[test]
180      fn test_id() {
181          assert_eq!(get_elixir().id(), "elixir");
182      }
183  
184      #[test]
185      fn test_extensions() {
186          let exts = get_elixir().extensions();
187          assert!(exts.contains(&"ex"));
188          assert!(exts.contains(&"exs"));
189      }
190  
191      #[test]
192      fn test_language_ids() {
193          let ids = get_elixir().language_ids();
194          assert!(ids.contains(&"elixir"));
195      }
196  
197      #[test]
198      fn test_grammar_compiles() {
199          let elixir = get_elixir();
200          let _grammar = elixir.grammar();
201      }
202  
203      #[test]
204      fn test_reference_query_compiles() {
205          let elixir = get_elixir();
206          let _query = elixir.reference_query();
207      }
208  
209      #[test]
210      fn test_binding_query_compiles() {
211          let elixir = get_elixir();
212          assert!(elixir.binding_query().is_some());
213      }
214  
215      #[test]
216      fn test_import_query_compiles() {
217          let elixir = get_elixir();
218          assert!(elixir.import_query().is_some());
219      }
220  
221      #[test]
222      fn test_completion_query_compiles() {
223          let elixir = get_elixir();
224          assert!(elixir.completion_query().is_some());
225      }
226  
227      #[test]
228      fn test_reassignment_query_compiles() {
229          let elixir = get_elixir();
230          assert!(elixir.reassignment_query().is_some());
231      }
232  
233      #[test]
234      fn test_identifier_query_compiles() {
235          let elixir = get_elixir();
236          assert!(elixir.identifier_query().is_some());
237      }
238  
239      #[test]
240      fn test_export_query_compiles() {
241          let elixir = get_elixir();
242          assert!(elixir.export_query().is_some());
243      }
244  
245      #[test]
246      fn test_assignment_query_compiles() {
247          let elixir = get_elixir();
248          assert!(elixir.assignment_query().is_some());
249      }
250  
251      #[test]
252      fn test_scope_query_compiles() {
253          let elixir = get_elixir();
254          assert!(elixir.scope_query().is_some());
255      }
256  
257      #[test]
258      fn test_destructure_query_compiles() {
259          let elixir = get_elixir();
260          assert!(elixir.destructure_query().is_some());
261      }
262  }