1//! The `language` crate provides a large chunk of Zed's language-related
2//! features (the other big contributors being project and lsp crates that revolve around LSP features).
3//! Namely, this crate:
4//! - Provides [`Language`], [`Grammar`] and [`LanguageRegistry`] types that
5//! use Tree-sitter to provide syntax highlighting to the editor; note though that `language` doesn't perform the highlighting by itself. It only maps ranges in a buffer to colors. Treesitter is also used for buffer outlines (lists of symbols in a buffer)
6//! - Exposes [`LanguageConfig`] that describes how constructs (like brackets or line comments) should be handled by the editor for a source file of a particular language.
7//!
8//! Notably we do *not* assign a single language to a single file; in real world a single file can consist of multiple programming languages - HTML is a good example of that - and `language` crate tends to reflect that status quo in it's API.
9mod buffer;
10mod diagnostic_set;
11mod highlight_map;
12mod language_registry;
13pub mod language_settings;
14mod outline;
15pub mod proto;
16mod syntax_map;
17
18#[cfg(test)]
19mod buffer_tests;
20pub mod markdown;
21
22use anyhow::{anyhow, Context, Result};
23use async_trait::async_trait;
24use collections::{HashMap, HashSet};
25use gpui::{AppContext, AsyncAppContext, Task};
26pub use highlight_map::HighlightMap;
27use lazy_static::lazy_static;
28use lsp::{CodeActionKind, LanguageServerBinary};
29use parking_lot::Mutex;
30use regex::Regex;
31use schemars::{
32 gen::SchemaGenerator,
33 schema::{InstanceType, Schema, SchemaObject},
34 JsonSchema,
35};
36use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
37use serde_json::Value;
38use std::{
39 any::Any,
40 cell::RefCell,
41 fmt::Debug,
42 hash::Hash,
43 mem,
44 ops::Range,
45 path::{Path, PathBuf},
46 str,
47 sync::{
48 atomic::{AtomicU64, AtomicUsize, Ordering::SeqCst},
49 Arc,
50 },
51};
52use syntax_map::SyntaxSnapshot;
53use theme::SyntaxTheme;
54use tree_sitter::{self, wasmtime, Query, WasmStore};
55use util::http::HttpClient;
56
57pub use buffer::Operation;
58pub use buffer::*;
59pub use diagnostic_set::DiagnosticEntry;
60pub use language_registry::{
61 LanguageQueries, LanguageRegistry, LanguageServerBinaryStatus, PendingLanguageServer,
62 QUERY_FILENAME_PREFIXES,
63};
64pub use lsp::LanguageServerId;
65pub use outline::{Outline, OutlineItem};
66pub use syntax_map::{OwnedSyntaxLayer, SyntaxLayer};
67pub use text::LineEnding;
68pub use tree_sitter::{Parser, Tree};
69
70/// Initializes the `language` crate.
71///
72/// This should be called before making use of items from the create.
73pub fn init(cx: &mut AppContext) {
74 language_settings::init(cx);
75}
76
77thread_local! {
78 static PARSER: RefCell<Parser> = {
79 let mut parser = Parser::new();
80 parser.set_wasm_store(WasmStore::new(WASM_ENGINE.clone()).unwrap()).unwrap();
81 RefCell::new(parser)
82 };
83}
84
85lazy_static! {
86 static ref NEXT_LANGUAGE_ID: AtomicUsize = Default::default();
87 static ref NEXT_GRAMMAR_ID: AtomicUsize = Default::default();
88 static ref WASM_ENGINE: wasmtime::Engine = wasmtime::Engine::default();
89
90 /// A shared grammar for plain text, exposed for reuse by downstream crates.
91 pub static ref PLAIN_TEXT: Arc<Language> = Arc::new(Language::new(
92 LanguageConfig {
93 name: "Plain Text".into(),
94 ..Default::default()
95 },
96 None,
97 ));
98}
99
100/// Types that represent a position in a buffer, and can be converted into
101/// an LSP position, to send to a language server.
102pub trait ToLspPosition {
103 /// Converts the value into an LSP position.
104 fn to_lsp_position(self) -> lsp::Position;
105}
106
107/// A name of a language server.
108#[derive(Clone, Debug, PartialEq, Eq, Hash)]
109pub struct LanguageServerName(pub Arc<str>);
110
111/// Represents a Language Server, with certain cached sync properties.
112/// Uses [`LspAdapter`] under the hood, but calls all 'static' methods
113/// once at startup, and caches the results.
114pub struct CachedLspAdapter {
115 pub name: LanguageServerName,
116 pub short_name: &'static str,
117 pub disk_based_diagnostic_sources: Vec<String>,
118 pub disk_based_diagnostics_progress_token: Option<String>,
119 pub language_ids: HashMap<String, String>,
120 pub adapter: Arc<dyn LspAdapter>,
121 pub reinstall_attempt_count: AtomicU64,
122}
123
124impl CachedLspAdapter {
125 pub async fn new(adapter: Arc<dyn LspAdapter>) -> Arc<Self> {
126 let name = adapter.name();
127 let short_name = adapter.short_name();
128 let disk_based_diagnostic_sources = adapter.disk_based_diagnostic_sources();
129 let disk_based_diagnostics_progress_token = adapter.disk_based_diagnostics_progress_token();
130 let language_ids = adapter.language_ids();
131
132 Arc::new(CachedLspAdapter {
133 name,
134 short_name,
135 disk_based_diagnostic_sources,
136 disk_based_diagnostics_progress_token,
137 language_ids,
138 adapter,
139 reinstall_attempt_count: AtomicU64::new(0),
140 })
141 }
142
143 pub async fn fetch_latest_server_version(
144 &self,
145 delegate: &dyn LspAdapterDelegate,
146 ) -> Result<Box<dyn 'static + Send + Any>> {
147 self.adapter.fetch_latest_server_version(delegate).await
148 }
149
150 pub fn will_fetch_server(
151 &self,
152 delegate: &Arc<dyn LspAdapterDelegate>,
153 cx: &mut AsyncAppContext,
154 ) -> Option<Task<Result<()>>> {
155 self.adapter.will_fetch_server(delegate, cx)
156 }
157
158 pub fn will_start_server(
159 &self,
160 delegate: &Arc<dyn LspAdapterDelegate>,
161 cx: &mut AsyncAppContext,
162 ) -> Option<Task<Result<()>>> {
163 self.adapter.will_start_server(delegate, cx)
164 }
165
166 pub async fn fetch_server_binary(
167 &self,
168 version: Box<dyn 'static + Send + Any>,
169 container_dir: PathBuf,
170 delegate: &dyn LspAdapterDelegate,
171 ) -> Result<LanguageServerBinary> {
172 self.adapter
173 .fetch_server_binary(version, container_dir, delegate)
174 .await
175 }
176
177 pub async fn cached_server_binary(
178 &self,
179 container_dir: PathBuf,
180 delegate: &dyn LspAdapterDelegate,
181 ) -> Option<LanguageServerBinary> {
182 self.adapter
183 .cached_server_binary(container_dir, delegate)
184 .await
185 }
186
187 pub fn can_be_reinstalled(&self) -> bool {
188 self.adapter.can_be_reinstalled()
189 }
190
191 pub async fn installation_test_binary(
192 &self,
193 container_dir: PathBuf,
194 ) -> Option<LanguageServerBinary> {
195 self.adapter.installation_test_binary(container_dir).await
196 }
197
198 pub fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
199 self.adapter.code_action_kinds()
200 }
201
202 pub fn workspace_configuration(&self, workspace_root: &Path, cx: &mut AppContext) -> Value {
203 self.adapter.workspace_configuration(workspace_root, cx)
204 }
205
206 pub fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
207 self.adapter.process_diagnostics(params)
208 }
209
210 pub async fn process_completion(&self, completion_item: &mut lsp::CompletionItem) {
211 self.adapter.process_completion(completion_item).await
212 }
213
214 pub async fn label_for_completion(
215 &self,
216 completion_item: &lsp::CompletionItem,
217 language: &Arc<Language>,
218 ) -> Option<CodeLabel> {
219 self.adapter
220 .label_for_completion(completion_item, language)
221 .await
222 }
223
224 pub async fn label_for_symbol(
225 &self,
226 name: &str,
227 kind: lsp::SymbolKind,
228 language: &Arc<Language>,
229 ) -> Option<CodeLabel> {
230 self.adapter.label_for_symbol(name, kind, language).await
231 }
232
233 pub fn prettier_plugins(&self) -> &[&'static str] {
234 self.adapter.prettier_plugins()
235 }
236}
237
238/// [`LspAdapterDelegate`] allows [`LspAdapter]` implementations to interface with the application
239// e.g. to display a notification or fetch data from the web.
240pub trait LspAdapterDelegate: Send + Sync {
241 fn show_notification(&self, message: &str, cx: &mut AppContext);
242 fn http_client(&self) -> Arc<dyn HttpClient>;
243}
244
245#[async_trait]
246pub trait LspAdapter: 'static + Send + Sync {
247 fn name(&self) -> LanguageServerName;
248
249 fn short_name(&self) -> &'static str;
250
251 async fn fetch_latest_server_version(
252 &self,
253 delegate: &dyn LspAdapterDelegate,
254 ) -> Result<Box<dyn 'static + Send + Any>>;
255
256 fn will_fetch_server(
257 &self,
258 _: &Arc<dyn LspAdapterDelegate>,
259 _: &mut AsyncAppContext,
260 ) -> Option<Task<Result<()>>> {
261 None
262 }
263
264 fn will_start_server(
265 &self,
266 _: &Arc<dyn LspAdapterDelegate>,
267 _: &mut AsyncAppContext,
268 ) -> Option<Task<Result<()>>> {
269 None
270 }
271
272 async fn fetch_server_binary(
273 &self,
274 version: Box<dyn 'static + Send + Any>,
275 container_dir: PathBuf,
276 delegate: &dyn LspAdapterDelegate,
277 ) -> Result<LanguageServerBinary>;
278
279 async fn cached_server_binary(
280 &self,
281 container_dir: PathBuf,
282 delegate: &dyn LspAdapterDelegate,
283 ) -> Option<LanguageServerBinary>;
284
285 /// Returns `true` if a language server can be reinstalled.
286 ///
287 /// If language server initialization fails, a reinstallation will be attempted unless the value returned from this method is `false`.
288 ///
289 /// Implementations that rely on software already installed on user's system
290 /// should have [`can_be_reinstalled`](Self::can_be_reinstalled) return `false`.
291 fn can_be_reinstalled(&self) -> bool {
292 true
293 }
294
295 async fn installation_test_binary(
296 &self,
297 container_dir: PathBuf,
298 ) -> Option<LanguageServerBinary>;
299
300 fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
301
302 /// A callback called for each [`lsp::CompletionItem`] obtained from LSP server.
303 /// Some LspAdapter implementations might want to modify the obtained item to
304 /// change how it's displayed.
305 async fn process_completion(&self, _: &mut lsp::CompletionItem) {}
306
307 async fn label_for_completion(
308 &self,
309 _: &lsp::CompletionItem,
310 _: &Arc<Language>,
311 ) -> Option<CodeLabel> {
312 None
313 }
314
315 async fn label_for_symbol(
316 &self,
317 _: &str,
318 _: lsp::SymbolKind,
319 _: &Arc<Language>,
320 ) -> Option<CodeLabel> {
321 None
322 }
323
324 /// Returns initialization options that are going to be sent to a LSP server as a part of [`lsp::InitializeParams`]
325 fn initialization_options(&self) -> Option<Value> {
326 None
327 }
328
329 fn workspace_configuration(&self, _workspace_root: &Path, _cx: &mut AppContext) -> Value {
330 serde_json::json!({})
331 }
332
333 /// Returns a list of code actions supported by a given LspAdapter
334 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
335 Some(vec![
336 CodeActionKind::EMPTY,
337 CodeActionKind::QUICKFIX,
338 CodeActionKind::REFACTOR,
339 CodeActionKind::REFACTOR_EXTRACT,
340 CodeActionKind::SOURCE,
341 ])
342 }
343
344 fn disk_based_diagnostic_sources(&self) -> Vec<String> {
345 Default::default()
346 }
347
348 fn disk_based_diagnostics_progress_token(&self) -> Option<String> {
349 None
350 }
351
352 fn language_ids(&self) -> HashMap<String, String> {
353 Default::default()
354 }
355
356 fn prettier_plugins(&self) -> &[&'static str] {
357 &[]
358 }
359}
360
361#[derive(Clone, Debug, PartialEq, Eq)]
362pub struct CodeLabel {
363 /// The text to display.
364 pub text: String,
365 /// Syntax highlighting runs.
366 pub runs: Vec<(Range<usize>, HighlightId)>,
367 /// The portion of the text that should be used in fuzzy filtering.
368 pub filter_range: Range<usize>,
369}
370
371#[derive(Clone, Deserialize, JsonSchema)]
372pub struct LanguageConfig {
373 /// Human-readable name of the language.
374 pub name: Arc<str>,
375 // The name of the grammar in a WASM bundle (experimental).
376 pub grammar: Option<Arc<str>>,
377 /// The criteria for matching this language to a given file.
378 #[serde(flatten)]
379 pub matcher: LanguageMatcher,
380 /// List of bracket types in a language.
381 #[serde(default)]
382 #[schemars(schema_with = "bracket_pair_config_json_schema")]
383 pub brackets: BracketPairConfig,
384 /// If set to true, auto indentation uses last non empty line to determine
385 /// the indentation level for a new line.
386 #[serde(default = "auto_indent_using_last_non_empty_line_default")]
387 pub auto_indent_using_last_non_empty_line: bool,
388 /// A regex that is used to determine whether the indentation level should be
389 /// increased in the following line.
390 #[serde(default, deserialize_with = "deserialize_regex")]
391 #[schemars(schema_with = "regex_json_schema")]
392 pub increase_indent_pattern: Option<Regex>,
393 /// A regex that is used to determine whether the indentation level should be
394 /// decreased in the following line.
395 #[serde(default, deserialize_with = "deserialize_regex")]
396 #[schemars(schema_with = "regex_json_schema")]
397 pub decrease_indent_pattern: Option<Regex>,
398 /// A list of characters that trigger the automatic insertion of a closing
399 /// bracket when they immediately precede the point where an opening
400 /// bracket is inserted.
401 #[serde(default)]
402 pub autoclose_before: String,
403 /// A placeholder used internally by Semantic Index.
404 #[serde(default)]
405 pub collapsed_placeholder: String,
406 /// A line comment string that is inserted in e.g. `toggle comments` action.
407 /// A language can have multiple flavours of line comments. All of the provided line comments are
408 /// used for comment continuations on the next line, but only the first one is used for Editor::ToggleComments.
409 #[serde(default)]
410 pub line_comments: Vec<Arc<str>>,
411 /// Starting and closing characters of a block comment.
412 #[serde(default)]
413 pub block_comment: Option<(Arc<str>, Arc<str>)>,
414 /// A list of language servers that are allowed to run on subranges of a given language.
415 #[serde(default)]
416 pub scope_opt_in_language_servers: Vec<String>,
417 #[serde(default)]
418 pub overrides: HashMap<String, LanguageConfigOverride>,
419 /// A list of characters that Zed should treat as word characters for the
420 /// purpose of features that operate on word boundaries, like 'move to next word end'
421 /// or a whole-word search in buffer search.
422 #[serde(default)]
423 pub word_characters: HashSet<char>,
424 /// The name of a Prettier parser that should be used for this language.
425 #[serde(default)]
426 pub prettier_parser_name: Option<String>,
427}
428
429#[derive(Clone, Debug, Serialize, Deserialize, Default, JsonSchema)]
430pub struct LanguageMatcher {
431 /// Given a list of `LanguageConfig`'s, the language of a file can be determined based on the path extension matching any of the `path_suffixes`.
432 #[serde(default)]
433 pub path_suffixes: Vec<String>,
434 /// A regex pattern that determines whether the language should be assigned to a file or not.
435 #[serde(
436 default,
437 serialize_with = "serialize_regex",
438 deserialize_with = "deserialize_regex"
439 )]
440 #[schemars(schema_with = "regex_json_schema")]
441 pub first_line_pattern: Option<Regex>,
442}
443
444/// Represents a language for the given range. Some languages (e.g. HTML)
445/// interleave several languages together, thus a single buffer might actually contain
446/// several nested scopes.
447#[derive(Clone, Debug)]
448pub struct LanguageScope {
449 language: Arc<Language>,
450 override_id: Option<u32>,
451}
452
453#[derive(Clone, Deserialize, Default, Debug, JsonSchema)]
454pub struct LanguageConfigOverride {
455 #[serde(default)]
456 pub line_comments: Override<Vec<Arc<str>>>,
457 #[serde(default)]
458 pub block_comment: Override<(Arc<str>, Arc<str>)>,
459 #[serde(skip_deserializing)]
460 #[schemars(skip)]
461 pub disabled_bracket_ixs: Vec<u16>,
462 #[serde(default)]
463 pub word_characters: Override<HashSet<char>>,
464 #[serde(default)]
465 pub opt_into_language_servers: Vec<String>,
466}
467
468#[derive(Clone, Deserialize, Debug, Serialize, JsonSchema)]
469#[serde(untagged)]
470pub enum Override<T> {
471 Remove { remove: bool },
472 Set(T),
473}
474
475impl<T> Default for Override<T> {
476 fn default() -> Self {
477 Override::Remove { remove: false }
478 }
479}
480
481impl<T> Override<T> {
482 fn as_option<'a>(this: Option<&'a Self>, original: Option<&'a T>) -> Option<&'a T> {
483 match this {
484 Some(Self::Set(value)) => Some(value),
485 Some(Self::Remove { remove: true }) => None,
486 Some(Self::Remove { remove: false }) | None => original,
487 }
488 }
489}
490
491impl Default for LanguageConfig {
492 fn default() -> Self {
493 Self {
494 name: "".into(),
495 grammar: None,
496 matcher: LanguageMatcher::default(),
497 brackets: Default::default(),
498 auto_indent_using_last_non_empty_line: auto_indent_using_last_non_empty_line_default(),
499 increase_indent_pattern: Default::default(),
500 decrease_indent_pattern: Default::default(),
501 autoclose_before: Default::default(),
502 line_comments: Default::default(),
503 block_comment: Default::default(),
504 scope_opt_in_language_servers: Default::default(),
505 overrides: Default::default(),
506 word_characters: Default::default(),
507 prettier_parser_name: None,
508 collapsed_placeholder: Default::default(),
509 }
510 }
511}
512
513fn auto_indent_using_last_non_empty_line_default() -> bool {
514 true
515}
516
517fn deserialize_regex<'de, D: Deserializer<'de>>(d: D) -> Result<Option<Regex>, D::Error> {
518 let source = Option::<String>::deserialize(d)?;
519 if let Some(source) = source {
520 Ok(Some(regex::Regex::new(&source).map_err(de::Error::custom)?))
521 } else {
522 Ok(None)
523 }
524}
525
526fn regex_json_schema(_: &mut SchemaGenerator) -> Schema {
527 Schema::Object(SchemaObject {
528 instance_type: Some(InstanceType::String.into()),
529 ..Default::default()
530 })
531}
532
533fn serialize_regex<S>(regex: &Option<Regex>, serializer: S) -> Result<S::Ok, S::Error>
534where
535 S: Serializer,
536{
537 match regex {
538 Some(regex) => serializer.serialize_str(regex.as_str()),
539 None => serializer.serialize_none(),
540 }
541}
542
543#[doc(hidden)]
544#[cfg(any(test, feature = "test-support"))]
545pub struct FakeLspAdapter {
546 pub name: &'static str,
547 pub initialization_options: Option<Value>,
548 pub capabilities: lsp::ServerCapabilities,
549 pub initializer: Option<Box<dyn 'static + Send + Sync + Fn(&mut lsp::FakeLanguageServer)>>,
550 pub disk_based_diagnostics_progress_token: Option<String>,
551 pub disk_based_diagnostics_sources: Vec<String>,
552 pub prettier_plugins: Vec<&'static str>,
553}
554
555/// Configuration of handling bracket pairs for a given language.
556///
557/// This struct includes settings for defining which pairs of characters are considered brackets and
558/// also specifies any language-specific scopes where these pairs should be ignored for bracket matching purposes.
559#[derive(Clone, Debug, Default, JsonSchema)]
560pub struct BracketPairConfig {
561 /// A list of character pairs that should be treated as brackets in the context of a given language.
562 pub pairs: Vec<BracketPair>,
563 /// A list of tree-sitter scopes for which a given bracket should not be active.
564 /// N-th entry in `[Self::disabled_scopes_by_bracket_ix]` contains a list of disabled scopes for an n-th entry in `[Self::pairs]`
565 #[schemars(skip)]
566 pub disabled_scopes_by_bracket_ix: Vec<Vec<String>>,
567}
568
569fn bracket_pair_config_json_schema(gen: &mut SchemaGenerator) -> Schema {
570 Option::<Vec<BracketPairContent>>::json_schema(gen)
571}
572
573#[derive(Deserialize, JsonSchema)]
574pub struct BracketPairContent {
575 #[serde(flatten)]
576 pub bracket_pair: BracketPair,
577 #[serde(default)]
578 pub not_in: Vec<String>,
579}
580
581impl<'de> Deserialize<'de> for BracketPairConfig {
582 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
583 where
584 D: Deserializer<'de>,
585 {
586 let result = Vec::<BracketPairContent>::deserialize(deserializer)?;
587 let mut brackets = Vec::with_capacity(result.len());
588 let mut disabled_scopes_by_bracket_ix = Vec::with_capacity(result.len());
589 for entry in result {
590 brackets.push(entry.bracket_pair);
591 disabled_scopes_by_bracket_ix.push(entry.not_in);
592 }
593
594 Ok(BracketPairConfig {
595 pairs: brackets,
596 disabled_scopes_by_bracket_ix,
597 })
598 }
599}
600
601/// Describes a single bracket pair and how an editor should react to e.g. inserting
602/// an opening bracket or to a newline character insertion in between `start` and `end` characters.
603#[derive(Clone, Debug, Default, Deserialize, PartialEq, JsonSchema)]
604pub struct BracketPair {
605 /// Starting substring for a bracket.
606 pub start: String,
607 /// Ending substring for a bracket.
608 pub end: String,
609 /// True if `end` should be automatically inserted right after `start` characters.
610 pub close: bool,
611 /// True if an extra newline should be inserted while the cursor is in the middle
612 /// of that bracket pair.
613 pub newline: bool,
614}
615
616#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
617pub(crate) struct LanguageId(usize);
618
619impl LanguageId {
620 pub(crate) fn new() -> Self {
621 Self(NEXT_LANGUAGE_ID.fetch_add(1, SeqCst))
622 }
623}
624
625pub struct Language {
626 pub(crate) id: LanguageId,
627 pub(crate) config: LanguageConfig,
628 pub(crate) grammar: Option<Arc<Grammar>>,
629 pub(crate) adapters: Vec<Arc<CachedLspAdapter>>,
630
631 #[cfg(any(test, feature = "test-support"))]
632 fake_adapter: Option<(
633 futures::channel::mpsc::UnboundedSender<lsp::FakeLanguageServer>,
634 Arc<FakeLspAdapter>,
635 )>,
636}
637
638#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
639pub struct GrammarId(pub usize);
640
641impl GrammarId {
642 pub(crate) fn new() -> Self {
643 Self(NEXT_GRAMMAR_ID.fetch_add(1, SeqCst))
644 }
645}
646
647pub struct Grammar {
648 id: GrammarId,
649 pub ts_language: tree_sitter::Language,
650 pub(crate) error_query: Query,
651 pub(crate) highlights_query: Option<Query>,
652 pub(crate) brackets_config: Option<BracketConfig>,
653 pub(crate) redactions_config: Option<RedactionConfig>,
654 pub(crate) indents_config: Option<IndentConfig>,
655 pub outline_config: Option<OutlineConfig>,
656 pub embedding_config: Option<EmbeddingConfig>,
657 pub(crate) injection_config: Option<InjectionConfig>,
658 pub(crate) override_config: Option<OverrideConfig>,
659 pub(crate) highlight_map: Mutex<HighlightMap>,
660}
661
662struct IndentConfig {
663 query: Query,
664 indent_capture_ix: u32,
665 start_capture_ix: Option<u32>,
666 end_capture_ix: Option<u32>,
667 outdent_capture_ix: Option<u32>,
668}
669
670pub struct OutlineConfig {
671 pub query: Query,
672 pub item_capture_ix: u32,
673 pub name_capture_ix: u32,
674 pub context_capture_ix: Option<u32>,
675 pub extra_context_capture_ix: Option<u32>,
676}
677
678#[derive(Debug)]
679pub struct EmbeddingConfig {
680 pub query: Query,
681 pub item_capture_ix: u32,
682 pub name_capture_ix: Option<u32>,
683 pub context_capture_ix: Option<u32>,
684 pub collapse_capture_ix: Option<u32>,
685 pub keep_capture_ix: Option<u32>,
686}
687
688struct InjectionConfig {
689 query: Query,
690 content_capture_ix: u32,
691 language_capture_ix: Option<u32>,
692 patterns: Vec<InjectionPatternConfig>,
693}
694
695struct RedactionConfig {
696 pub query: Query,
697 pub redaction_capture_ix: u32,
698}
699
700struct OverrideConfig {
701 query: Query,
702 values: HashMap<u32, (String, LanguageConfigOverride)>,
703}
704
705#[derive(Default, Clone)]
706struct InjectionPatternConfig {
707 language: Option<Box<str>>,
708 combined: bool,
709}
710
711struct BracketConfig {
712 query: Query,
713 open_capture_ix: u32,
714 close_capture_ix: u32,
715}
716
717impl Language {
718 pub fn new(config: LanguageConfig, ts_language: Option<tree_sitter::Language>) -> Self {
719 Self::new_with_id(
720 LanguageId(NEXT_LANGUAGE_ID.fetch_add(1, SeqCst)),
721 config,
722 ts_language,
723 )
724 }
725
726 fn new_with_id(
727 id: LanguageId,
728 config: LanguageConfig,
729 ts_language: Option<tree_sitter::Language>,
730 ) -> Self {
731 Self {
732 id,
733 config,
734 grammar: ts_language.map(|ts_language| {
735 Arc::new(Grammar {
736 id: GrammarId::new(),
737 highlights_query: None,
738 brackets_config: None,
739 outline_config: None,
740 embedding_config: None,
741 indents_config: None,
742 injection_config: None,
743 override_config: None,
744 redactions_config: None,
745 error_query: Query::new(&ts_language, "(ERROR) @error").unwrap(),
746 ts_language,
747 highlight_map: Default::default(),
748 })
749 }),
750 adapters: Vec::new(),
751
752 #[cfg(any(test, feature = "test-support"))]
753 fake_adapter: None,
754 }
755 }
756
757 pub fn lsp_adapters(&self) -> &[Arc<CachedLspAdapter>] {
758 &self.adapters
759 }
760
761 pub fn with_queries(mut self, queries: LanguageQueries) -> Result<Self> {
762 if let Some(query) = queries.highlights {
763 self = self
764 .with_highlights_query(query.as_ref())
765 .context("Error loading highlights query")?;
766 }
767 if let Some(query) = queries.brackets {
768 self = self
769 .with_brackets_query(query.as_ref())
770 .context("Error loading brackets query")?;
771 }
772 if let Some(query) = queries.indents {
773 self = self
774 .with_indents_query(query.as_ref())
775 .context("Error loading indents query")?;
776 }
777 if let Some(query) = queries.outline {
778 self = self
779 .with_outline_query(query.as_ref())
780 .context("Error loading outline query")?;
781 }
782 if let Some(query) = queries.embedding {
783 self = self
784 .with_embedding_query(query.as_ref())
785 .context("Error loading embedding query")?;
786 }
787 if let Some(query) = queries.injections {
788 self = self
789 .with_injection_query(query.as_ref())
790 .context("Error loading injection query")?;
791 }
792 if let Some(query) = queries.overrides {
793 self = self
794 .with_override_query(query.as_ref())
795 .context("Error loading override query")?;
796 }
797 if let Some(query) = queries.redactions {
798 self = self
799 .with_redaction_query(query.as_ref())
800 .context("Error loading redaction query")?;
801 }
802 Ok(self)
803 }
804
805 pub fn with_highlights_query(mut self, source: &str) -> Result<Self> {
806 let grammar = self.grammar_mut();
807 grammar.highlights_query = Some(Query::new(&grammar.ts_language, source)?);
808 Ok(self)
809 }
810
811 pub fn with_outline_query(mut self, source: &str) -> Result<Self> {
812 let grammar = self.grammar_mut();
813 let query = Query::new(&grammar.ts_language, source)?;
814 let mut item_capture_ix = None;
815 let mut name_capture_ix = None;
816 let mut context_capture_ix = None;
817 let mut extra_context_capture_ix = None;
818 get_capture_indices(
819 &query,
820 &mut [
821 ("item", &mut item_capture_ix),
822 ("name", &mut name_capture_ix),
823 ("context", &mut context_capture_ix),
824 ("context.extra", &mut extra_context_capture_ix),
825 ],
826 );
827 if let Some((item_capture_ix, name_capture_ix)) = item_capture_ix.zip(name_capture_ix) {
828 grammar.outline_config = Some(OutlineConfig {
829 query,
830 item_capture_ix,
831 name_capture_ix,
832 context_capture_ix,
833 extra_context_capture_ix,
834 });
835 }
836 Ok(self)
837 }
838
839 pub fn with_embedding_query(mut self, source: &str) -> Result<Self> {
840 let grammar = self.grammar_mut();
841 let query = Query::new(&grammar.ts_language, source)?;
842 let mut item_capture_ix = None;
843 let mut name_capture_ix = None;
844 let mut context_capture_ix = None;
845 let mut collapse_capture_ix = None;
846 let mut keep_capture_ix = None;
847 get_capture_indices(
848 &query,
849 &mut [
850 ("item", &mut item_capture_ix),
851 ("name", &mut name_capture_ix),
852 ("context", &mut context_capture_ix),
853 ("keep", &mut keep_capture_ix),
854 ("collapse", &mut collapse_capture_ix),
855 ],
856 );
857 if let Some(item_capture_ix) = item_capture_ix {
858 grammar.embedding_config = Some(EmbeddingConfig {
859 query,
860 item_capture_ix,
861 name_capture_ix,
862 context_capture_ix,
863 collapse_capture_ix,
864 keep_capture_ix,
865 });
866 }
867 Ok(self)
868 }
869
870 pub fn with_brackets_query(mut self, source: &str) -> Result<Self> {
871 let grammar = self.grammar_mut();
872 let query = Query::new(&grammar.ts_language, source)?;
873 let mut open_capture_ix = None;
874 let mut close_capture_ix = None;
875 get_capture_indices(
876 &query,
877 &mut [
878 ("open", &mut open_capture_ix),
879 ("close", &mut close_capture_ix),
880 ],
881 );
882 if let Some((open_capture_ix, close_capture_ix)) = open_capture_ix.zip(close_capture_ix) {
883 grammar.brackets_config = Some(BracketConfig {
884 query,
885 open_capture_ix,
886 close_capture_ix,
887 });
888 }
889 Ok(self)
890 }
891
892 pub fn with_indents_query(mut self, source: &str) -> Result<Self> {
893 let grammar = self.grammar_mut();
894 let query = Query::new(&grammar.ts_language, source)?;
895 let mut indent_capture_ix = None;
896 let mut start_capture_ix = None;
897 let mut end_capture_ix = None;
898 let mut outdent_capture_ix = None;
899 get_capture_indices(
900 &query,
901 &mut [
902 ("indent", &mut indent_capture_ix),
903 ("start", &mut start_capture_ix),
904 ("end", &mut end_capture_ix),
905 ("outdent", &mut outdent_capture_ix),
906 ],
907 );
908 if let Some(indent_capture_ix) = indent_capture_ix {
909 grammar.indents_config = Some(IndentConfig {
910 query,
911 indent_capture_ix,
912 start_capture_ix,
913 end_capture_ix,
914 outdent_capture_ix,
915 });
916 }
917 Ok(self)
918 }
919
920 pub fn with_injection_query(mut self, source: &str) -> Result<Self> {
921 let grammar = self.grammar_mut();
922 let query = Query::new(&grammar.ts_language, source)?;
923 let mut language_capture_ix = None;
924 let mut content_capture_ix = None;
925 get_capture_indices(
926 &query,
927 &mut [
928 ("language", &mut language_capture_ix),
929 ("content", &mut content_capture_ix),
930 ],
931 );
932 let patterns = (0..query.pattern_count())
933 .map(|ix| {
934 let mut config = InjectionPatternConfig::default();
935 for setting in query.property_settings(ix) {
936 match setting.key.as_ref() {
937 "language" => {
938 config.language = setting.value.clone();
939 }
940 "combined" => {
941 config.combined = true;
942 }
943 _ => {}
944 }
945 }
946 config
947 })
948 .collect();
949 if let Some(content_capture_ix) = content_capture_ix {
950 grammar.injection_config = Some(InjectionConfig {
951 query,
952 language_capture_ix,
953 content_capture_ix,
954 patterns,
955 });
956 }
957 Ok(self)
958 }
959
960 pub fn with_override_query(mut self, source: &str) -> anyhow::Result<Self> {
961 let query = Query::new(&self.grammar_mut().ts_language, source)?;
962
963 let mut override_configs_by_id = HashMap::default();
964 for (ix, name) in query.capture_names().iter().enumerate() {
965 if !name.starts_with('_') {
966 let value = self.config.overrides.remove(*name).unwrap_or_default();
967 for server_name in &value.opt_into_language_servers {
968 if !self
969 .config
970 .scope_opt_in_language_servers
971 .contains(server_name)
972 {
973 util::debug_panic!("Server {server_name:?} has been opted-in by scope {name:?} but has not been marked as an opt-in server");
974 }
975 }
976
977 override_configs_by_id.insert(ix as u32, (name.to_string(), value));
978 }
979 }
980
981 if !self.config.overrides.is_empty() {
982 let keys = self.config.overrides.keys().collect::<Vec<_>>();
983 Err(anyhow!(
984 "language {:?} has overrides in config not in query: {keys:?}",
985 self.config.name
986 ))?;
987 }
988
989 for disabled_scope_name in self
990 .config
991 .brackets
992 .disabled_scopes_by_bracket_ix
993 .iter()
994 .flatten()
995 {
996 if !override_configs_by_id
997 .values()
998 .any(|(scope_name, _)| scope_name == disabled_scope_name)
999 {
1000 Err(anyhow!(
1001 "language {:?} has overrides in config not in query: {disabled_scope_name:?}",
1002 self.config.name
1003 ))?;
1004 }
1005 }
1006
1007 for (name, override_config) in override_configs_by_id.values_mut() {
1008 override_config.disabled_bracket_ixs = self
1009 .config
1010 .brackets
1011 .disabled_scopes_by_bracket_ix
1012 .iter()
1013 .enumerate()
1014 .filter_map(|(ix, disabled_scope_names)| {
1015 if disabled_scope_names.contains(name) {
1016 Some(ix as u16)
1017 } else {
1018 None
1019 }
1020 })
1021 .collect();
1022 }
1023
1024 self.config.brackets.disabled_scopes_by_bracket_ix.clear();
1025 self.grammar_mut().override_config = Some(OverrideConfig {
1026 query,
1027 values: override_configs_by_id,
1028 });
1029 Ok(self)
1030 }
1031
1032 pub fn with_redaction_query(mut self, source: &str) -> anyhow::Result<Self> {
1033 let grammar = self.grammar_mut();
1034 let query = Query::new(&grammar.ts_language, source)?;
1035 let mut redaction_capture_ix = None;
1036 get_capture_indices(&query, &mut [("redact", &mut redaction_capture_ix)]);
1037
1038 if let Some(redaction_capture_ix) = redaction_capture_ix {
1039 grammar.redactions_config = Some(RedactionConfig {
1040 query,
1041 redaction_capture_ix,
1042 });
1043 }
1044
1045 Ok(self)
1046 }
1047
1048 fn grammar_mut(&mut self) -> &mut Grammar {
1049 Arc::get_mut(self.grammar.as_mut().unwrap()).unwrap()
1050 }
1051
1052 pub async fn with_lsp_adapters(mut self, lsp_adapters: Vec<Arc<dyn LspAdapter>>) -> Self {
1053 for adapter in lsp_adapters {
1054 self.adapters.push(CachedLspAdapter::new(adapter).await);
1055 }
1056 self
1057 }
1058
1059 #[cfg(any(test, feature = "test-support"))]
1060 pub async fn set_fake_lsp_adapter(
1061 &mut self,
1062 fake_lsp_adapter: Arc<FakeLspAdapter>,
1063 ) -> futures::channel::mpsc::UnboundedReceiver<lsp::FakeLanguageServer> {
1064 let (servers_tx, servers_rx) = futures::channel::mpsc::unbounded();
1065 self.fake_adapter = Some((servers_tx, fake_lsp_adapter.clone()));
1066 let adapter = CachedLspAdapter::new(Arc::new(fake_lsp_adapter)).await;
1067 self.adapters = vec![adapter];
1068 servers_rx
1069 }
1070
1071 pub fn name(&self) -> Arc<str> {
1072 self.config.name.clone()
1073 }
1074
1075 pub async fn disk_based_diagnostic_sources(&self) -> &[String] {
1076 match self.adapters.first().as_ref() {
1077 Some(adapter) => &adapter.disk_based_diagnostic_sources,
1078 None => &[],
1079 }
1080 }
1081
1082 pub async fn disk_based_diagnostics_progress_token(&self) -> Option<&str> {
1083 for adapter in &self.adapters {
1084 let token = adapter.disk_based_diagnostics_progress_token.as_deref();
1085 if token.is_some() {
1086 return token;
1087 }
1088 }
1089
1090 None
1091 }
1092
1093 pub async fn process_completion(self: &Arc<Self>, completion: &mut lsp::CompletionItem) {
1094 for adapter in &self.adapters {
1095 adapter.process_completion(completion).await;
1096 }
1097 }
1098
1099 pub async fn label_for_completion(
1100 self: &Arc<Self>,
1101 completion: &lsp::CompletionItem,
1102 ) -> Option<CodeLabel> {
1103 self.adapters
1104 .first()
1105 .as_ref()?
1106 .label_for_completion(completion, self)
1107 .await
1108 }
1109
1110 pub async fn label_for_symbol(
1111 self: &Arc<Self>,
1112 name: &str,
1113 kind: lsp::SymbolKind,
1114 ) -> Option<CodeLabel> {
1115 self.adapters
1116 .first()
1117 .as_ref()?
1118 .label_for_symbol(name, kind, self)
1119 .await
1120 }
1121
1122 pub fn highlight_text<'a>(
1123 self: &'a Arc<Self>,
1124 text: &'a Rope,
1125 range: Range<usize>,
1126 ) -> Vec<(Range<usize>, HighlightId)> {
1127 let mut result = Vec::new();
1128 if let Some(grammar) = &self.grammar {
1129 let tree = grammar.parse_text(text, None);
1130 let captures =
1131 SyntaxSnapshot::single_tree_captures(range.clone(), text, &tree, self, |grammar| {
1132 grammar.highlights_query.as_ref()
1133 });
1134 let highlight_maps = vec![grammar.highlight_map()];
1135 let mut offset = 0;
1136 for chunk in BufferChunks::new(text, range, Some((captures, highlight_maps)), vec![]) {
1137 let end_offset = offset + chunk.text.len();
1138 if let Some(highlight_id) = chunk.syntax_highlight_id {
1139 if !highlight_id.is_default() {
1140 result.push((offset..end_offset, highlight_id));
1141 }
1142 }
1143 offset = end_offset;
1144 }
1145 }
1146 result
1147 }
1148
1149 pub fn path_suffixes(&self) -> &[String] {
1150 &self.config.matcher.path_suffixes
1151 }
1152
1153 pub fn should_autoclose_before(&self, c: char) -> bool {
1154 c.is_whitespace() || self.config.autoclose_before.contains(c)
1155 }
1156
1157 pub fn set_theme(&self, theme: &SyntaxTheme) {
1158 if let Some(grammar) = self.grammar.as_ref() {
1159 if let Some(highlights_query) = &grammar.highlights_query {
1160 *grammar.highlight_map.lock() =
1161 HighlightMap::new(highlights_query.capture_names(), theme);
1162 }
1163 }
1164 }
1165
1166 pub fn grammar(&self) -> Option<&Arc<Grammar>> {
1167 self.grammar.as_ref()
1168 }
1169
1170 pub fn default_scope(self: &Arc<Self>) -> LanguageScope {
1171 LanguageScope {
1172 language: self.clone(),
1173 override_id: None,
1174 }
1175 }
1176
1177 pub fn prettier_parser_name(&self) -> Option<&str> {
1178 self.config.prettier_parser_name.as_deref()
1179 }
1180}
1181
1182impl LanguageScope {
1183 pub fn collapsed_placeholder(&self) -> &str {
1184 self.language.config.collapsed_placeholder.as_ref()
1185 }
1186
1187 /// Returns line prefix that is inserted in e.g. line continuations or
1188 /// in `toggle comments` action.
1189 pub fn line_comment_prefixes(&self) -> Option<&Vec<Arc<str>>> {
1190 Override::as_option(
1191 self.config_override().map(|o| &o.line_comments),
1192 Some(&self.language.config.line_comments),
1193 )
1194 }
1195
1196 pub fn block_comment_delimiters(&self) -> Option<(&Arc<str>, &Arc<str>)> {
1197 Override::as_option(
1198 self.config_override().map(|o| &o.block_comment),
1199 self.language.config.block_comment.as_ref(),
1200 )
1201 .map(|e| (&e.0, &e.1))
1202 }
1203
1204 /// Returns a list of language-specific word characters.
1205 ///
1206 /// By default, Zed treats alphanumeric characters (and '_') as word characters for
1207 /// the purpose of actions like 'move to next word end` or whole-word search.
1208 /// It additionally accounts for language's additional word characters.
1209 pub fn word_characters(&self) -> Option<&HashSet<char>> {
1210 Override::as_option(
1211 self.config_override().map(|o| &o.word_characters),
1212 Some(&self.language.config.word_characters),
1213 )
1214 }
1215
1216 /// Returns a list of bracket pairs for a given language with an additional
1217 /// piece of information about whether the particular bracket pair is currently active for a given language.
1218 pub fn brackets(&self) -> impl Iterator<Item = (&BracketPair, bool)> {
1219 let mut disabled_ids = self
1220 .config_override()
1221 .map_or(&[] as _, |o| o.disabled_bracket_ixs.as_slice());
1222 self.language
1223 .config
1224 .brackets
1225 .pairs
1226 .iter()
1227 .enumerate()
1228 .map(move |(ix, bracket)| {
1229 let mut is_enabled = true;
1230 if let Some(next_disabled_ix) = disabled_ids.first() {
1231 if ix == *next_disabled_ix as usize {
1232 disabled_ids = &disabled_ids[1..];
1233 is_enabled = false;
1234 }
1235 }
1236 (bracket, is_enabled)
1237 })
1238 }
1239
1240 pub fn should_autoclose_before(&self, c: char) -> bool {
1241 c.is_whitespace() || self.language.config.autoclose_before.contains(c)
1242 }
1243
1244 pub fn language_allowed(&self, name: &LanguageServerName) -> bool {
1245 let config = &self.language.config;
1246 let opt_in_servers = &config.scope_opt_in_language_servers;
1247 if opt_in_servers.iter().any(|o| *o == *name.0) {
1248 if let Some(over) = self.config_override() {
1249 over.opt_into_language_servers.iter().any(|o| *o == *name.0)
1250 } else {
1251 false
1252 }
1253 } else {
1254 true
1255 }
1256 }
1257
1258 fn config_override(&self) -> Option<&LanguageConfigOverride> {
1259 let id = self.override_id?;
1260 let grammar = self.language.grammar.as_ref()?;
1261 let override_config = grammar.override_config.as_ref()?;
1262 override_config.values.get(&id).map(|e| &e.1)
1263 }
1264}
1265
1266impl Hash for Language {
1267 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1268 self.id.hash(state)
1269 }
1270}
1271
1272impl PartialEq for Language {
1273 fn eq(&self, other: &Self) -> bool {
1274 self.id.eq(&other.id)
1275 }
1276}
1277
1278impl Eq for Language {}
1279
1280impl Debug for Language {
1281 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1282 f.debug_struct("Language")
1283 .field("name", &self.config.name)
1284 .finish()
1285 }
1286}
1287
1288impl Grammar {
1289 pub fn id(&self) -> GrammarId {
1290 self.id
1291 }
1292
1293 fn parse_text(&self, text: &Rope, old_tree: Option<Tree>) -> Tree {
1294 PARSER.with(|parser| {
1295 let mut parser = parser.borrow_mut();
1296 parser
1297 .set_language(&self.ts_language)
1298 .expect("incompatible grammar");
1299 let mut chunks = text.chunks_in_range(0..text.len());
1300 parser
1301 .parse_with(
1302 &mut move |offset, _| {
1303 chunks.seek(offset);
1304 chunks.next().unwrap_or("").as_bytes()
1305 },
1306 old_tree.as_ref(),
1307 )
1308 .unwrap()
1309 })
1310 }
1311
1312 pub fn highlight_map(&self) -> HighlightMap {
1313 self.highlight_map.lock().clone()
1314 }
1315
1316 pub fn highlight_id_for_name(&self, name: &str) -> Option<HighlightId> {
1317 let capture_id = self
1318 .highlights_query
1319 .as_ref()?
1320 .capture_index_for_name(name)?;
1321 Some(self.highlight_map.lock().get(capture_id))
1322 }
1323}
1324
1325impl CodeLabel {
1326 pub fn plain(text: String, filter_text: Option<&str>) -> Self {
1327 let mut result = Self {
1328 runs: Vec::new(),
1329 filter_range: 0..text.len(),
1330 text,
1331 };
1332 if let Some(filter_text) = filter_text {
1333 if let Some(ix) = result.text.find(filter_text) {
1334 result.filter_range = ix..ix + filter_text.len();
1335 }
1336 }
1337 result
1338 }
1339}
1340
1341impl Ord for LanguageMatcher {
1342 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1343 self.path_suffixes.cmp(&other.path_suffixes).then_with(|| {
1344 self.first_line_pattern
1345 .as_ref()
1346 .map(Regex::as_str)
1347 .cmp(&other.first_line_pattern.as_ref().map(Regex::as_str))
1348 })
1349 }
1350}
1351
1352impl PartialOrd for LanguageMatcher {
1353 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1354 Some(self.cmp(other))
1355 }
1356}
1357
1358impl Eq for LanguageMatcher {}
1359
1360impl PartialEq for LanguageMatcher {
1361 fn eq(&self, other: &Self) -> bool {
1362 self.path_suffixes == other.path_suffixes
1363 && self.first_line_pattern.as_ref().map(Regex::as_str)
1364 == other.first_line_pattern.as_ref().map(Regex::as_str)
1365 }
1366}
1367
1368#[cfg(any(test, feature = "test-support"))]
1369impl Default for FakeLspAdapter {
1370 fn default() -> Self {
1371 Self {
1372 name: "the-fake-language-server",
1373 capabilities: lsp::LanguageServer::full_capabilities(),
1374 initializer: None,
1375 disk_based_diagnostics_progress_token: None,
1376 initialization_options: None,
1377 disk_based_diagnostics_sources: Vec::new(),
1378 prettier_plugins: Vec::new(),
1379 }
1380 }
1381}
1382
1383#[cfg(any(test, feature = "test-support"))]
1384#[async_trait]
1385impl LspAdapter for Arc<FakeLspAdapter> {
1386 fn name(&self) -> LanguageServerName {
1387 LanguageServerName(self.name.into())
1388 }
1389
1390 fn short_name(&self) -> &'static str {
1391 "FakeLspAdapter"
1392 }
1393
1394 async fn fetch_latest_server_version(
1395 &self,
1396 _: &dyn LspAdapterDelegate,
1397 ) -> Result<Box<dyn 'static + Send + Any>> {
1398 unreachable!();
1399 }
1400
1401 async fn fetch_server_binary(
1402 &self,
1403 _: Box<dyn 'static + Send + Any>,
1404 _: PathBuf,
1405 _: &dyn LspAdapterDelegate,
1406 ) -> Result<LanguageServerBinary> {
1407 unreachable!();
1408 }
1409
1410 async fn cached_server_binary(
1411 &self,
1412 _: PathBuf,
1413 _: &dyn LspAdapterDelegate,
1414 ) -> Option<LanguageServerBinary> {
1415 unreachable!();
1416 }
1417
1418 async fn installation_test_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> {
1419 unreachable!();
1420 }
1421
1422 fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
1423
1424 fn disk_based_diagnostic_sources(&self) -> Vec<String> {
1425 self.disk_based_diagnostics_sources.clone()
1426 }
1427
1428 fn disk_based_diagnostics_progress_token(&self) -> Option<String> {
1429 self.disk_based_diagnostics_progress_token.clone()
1430 }
1431
1432 fn initialization_options(&self) -> Option<Value> {
1433 self.initialization_options.clone()
1434 }
1435
1436 fn prettier_plugins(&self) -> &[&'static str] {
1437 &self.prettier_plugins
1438 }
1439}
1440
1441fn get_capture_indices(query: &Query, captures: &mut [(&str, &mut Option<u32>)]) {
1442 for (ix, name) in query.capture_names().iter().enumerate() {
1443 for (capture_name, index) in captures.iter_mut() {
1444 if capture_name == name {
1445 **index = Some(ix as u32);
1446 break;
1447 }
1448 }
1449 }
1450}
1451
1452pub fn point_to_lsp(point: PointUtf16) -> lsp::Position {
1453 lsp::Position::new(point.row, point.column)
1454}
1455
1456pub fn point_from_lsp(point: lsp::Position) -> Unclipped<PointUtf16> {
1457 Unclipped(PointUtf16::new(point.line, point.character))
1458}
1459
1460pub fn range_to_lsp(range: Range<PointUtf16>) -> lsp::Range {
1461 lsp::Range {
1462 start: point_to_lsp(range.start),
1463 end: point_to_lsp(range.end),
1464 }
1465}
1466
1467pub fn range_from_lsp(range: lsp::Range) -> Range<Unclipped<PointUtf16>> {
1468 let mut start = point_from_lsp(range.start);
1469 let mut end = point_from_lsp(range.end);
1470 if start > end {
1471 mem::swap(&mut start, &mut end);
1472 }
1473 start..end
1474}
1475
1476#[cfg(test)]
1477mod tests {
1478 use super::*;
1479 use gpui::TestAppContext;
1480
1481 #[gpui::test(iterations = 10)]
1482 async fn test_first_line_pattern(cx: &mut TestAppContext) {
1483 let mut languages = LanguageRegistry::test();
1484
1485 languages.set_executor(cx.executor());
1486 let languages = Arc::new(languages);
1487 languages.register_test_language(LanguageConfig {
1488 name: "JavaScript".into(),
1489 matcher: LanguageMatcher {
1490 path_suffixes: vec!["js".into()],
1491 first_line_pattern: Some(Regex::new(r"\bnode\b").unwrap()),
1492 },
1493 ..Default::default()
1494 });
1495
1496 languages
1497 .language_for_file("the/script", None)
1498 .await
1499 .unwrap_err();
1500 languages
1501 .language_for_file("the/script", Some(&"nothing".into()))
1502 .await
1503 .unwrap_err();
1504 assert_eq!(
1505 languages
1506 .language_for_file("the/script", Some(&"#!/bin/env node".into()))
1507 .await
1508 .unwrap()
1509 .name()
1510 .as_ref(),
1511 "JavaScript"
1512 );
1513 }
1514
1515 #[gpui::test(iterations = 10)]
1516 async fn test_language_loading(cx: &mut TestAppContext) {
1517 let mut languages = LanguageRegistry::test();
1518 languages.set_executor(cx.executor());
1519 let languages = Arc::new(languages);
1520 languages.register_native_grammars([
1521 ("json", tree_sitter_json::language()),
1522 ("rust", tree_sitter_rust::language()),
1523 ]);
1524 languages.register_test_language(LanguageConfig {
1525 name: "JSON".into(),
1526 grammar: Some("json".into()),
1527 matcher: LanguageMatcher {
1528 path_suffixes: vec!["json".into()],
1529 ..Default::default()
1530 },
1531 ..Default::default()
1532 });
1533 languages.register_test_language(LanguageConfig {
1534 name: "Rust".into(),
1535 grammar: Some("rust".into()),
1536 matcher: LanguageMatcher {
1537 path_suffixes: vec!["rs".into()],
1538 ..Default::default()
1539 },
1540 ..Default::default()
1541 });
1542 assert_eq!(
1543 languages.language_names(),
1544 &[
1545 "JSON".to_string(),
1546 "Plain Text".to_string(),
1547 "Rust".to_string(),
1548 ]
1549 );
1550
1551 let rust1 = languages.language_for_name("Rust");
1552 let rust2 = languages.language_for_name("Rust");
1553
1554 // Ensure language is still listed even if it's being loaded.
1555 assert_eq!(
1556 languages.language_names(),
1557 &[
1558 "JSON".to_string(),
1559 "Plain Text".to_string(),
1560 "Rust".to_string(),
1561 ]
1562 );
1563
1564 let (rust1, rust2) = futures::join!(rust1, rust2);
1565 assert!(Arc::ptr_eq(&rust1.unwrap(), &rust2.unwrap()));
1566
1567 // Ensure language is still listed even after loading it.
1568 assert_eq!(
1569 languages.language_names(),
1570 &[
1571 "JSON".to_string(),
1572 "Plain Text".to_string(),
1573 "Rust".to_string(),
1574 ]
1575 );
1576
1577 // Loading an unknown language returns an error.
1578 assert!(languages.language_for_name("Unknown").await.is_err());
1579 }
1580}