1mod buffer;
2mod diagnostic_set;
3mod highlight_map;
4mod outline;
5pub mod proto;
6mod syntax_map;
7
8#[cfg(test)]
9mod buffer_tests;
10
11use anyhow::{anyhow, Context, Result};
12use async_trait::async_trait;
13use client::http::HttpClient;
14use collections::HashMap;
15use futures::{
16 channel::oneshot,
17 future::{BoxFuture, Shared},
18 FutureExt, TryFutureExt as _,
19};
20use gpui::{executor::Background, MutableAppContext, Task};
21use highlight_map::HighlightMap;
22use lazy_static::lazy_static;
23use parking_lot::{Mutex, RwLock};
24use postage::watch;
25use regex::Regex;
26use serde::{de, Deserialize, Deserializer};
27use serde_json::Value;
28use std::{
29 any::Any,
30 borrow::Cow,
31 cell::RefCell,
32 fmt::Debug,
33 hash::Hash,
34 mem,
35 ops::Range,
36 path::{Path, PathBuf},
37 str,
38 sync::{
39 atomic::{AtomicUsize, Ordering::SeqCst},
40 Arc,
41 },
42};
43use syntax_map::SyntaxSnapshot;
44use theme::{SyntaxTheme, Theme};
45use tree_sitter::{self, Query};
46use unicase::UniCase;
47use util::{merge_json_value_into, post_inc, ResultExt, TryFutureExt as _, UnwrapFuture};
48
49#[cfg(any(test, feature = "test-support"))]
50use futures::channel::mpsc;
51
52pub use buffer::Operation;
53pub use buffer::*;
54pub use diagnostic_set::DiagnosticEntry;
55pub use outline::{Outline, OutlineItem};
56pub use tree_sitter::{Parser, Tree};
57
58thread_local! {
59 static PARSER: RefCell<Parser> = RefCell::new(Parser::new());
60}
61
62lazy_static! {
63 pub static ref NEXT_GRAMMAR_ID: AtomicUsize = Default::default();
64 pub static ref PLAIN_TEXT: Arc<Language> = Arc::new(Language::new(
65 LanguageConfig {
66 name: "Plain Text".into(),
67 ..Default::default()
68 },
69 None,
70 ));
71}
72
73pub trait ToLspPosition {
74 fn to_lsp_position(self) -> lsp::Position;
75}
76
77#[derive(Clone, Debug, PartialEq, Eq, Hash)]
78pub struct LanguageServerName(pub Arc<str>);
79
80#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
81pub enum ServerExecutionKind {
82 Launch,
83 Node,
84}
85
86/// Represents a Language Server, with certain cached sync properties.
87/// Uses [`LspAdapter`] under the hood, but calls all 'static' methods
88/// once at startup, and caches the results.
89pub struct CachedLspAdapter {
90 pub name: LanguageServerName,
91 pub server_args: Vec<String>,
92 pub initialization_options: Option<Value>,
93 pub disk_based_diagnostic_sources: Vec<String>,
94 pub disk_based_diagnostics_progress_token: Option<String>,
95 pub language_ids: HashMap<String, String>,
96 pub adapter: Arc<dyn LspAdapter>,
97}
98
99impl CachedLspAdapter {
100 pub async fn new(adapter: Arc<dyn LspAdapter>) -> Arc<Self> {
101 let name = adapter.name().await;
102 let server_args = adapter.server_args().await;
103 let initialization_options = adapter.initialization_options().await;
104 let disk_based_diagnostic_sources = adapter.disk_based_diagnostic_sources().await;
105 let disk_based_diagnostics_progress_token =
106 adapter.disk_based_diagnostics_progress_token().await;
107 let language_ids = adapter.language_ids().await;
108
109 Arc::new(CachedLspAdapter {
110 name,
111 server_args,
112 initialization_options,
113 disk_based_diagnostic_sources,
114 disk_based_diagnostics_progress_token,
115 language_ids,
116 adapter,
117 })
118 }
119
120 pub async fn fetch_latest_server_version(
121 &self,
122 http: Arc<dyn HttpClient>,
123 ) -> Result<Box<dyn 'static + Send + Any>> {
124 self.adapter.fetch_latest_server_version(http).await
125 }
126
127 pub async fn fetch_server_binary(
128 &self,
129 version: Box<dyn 'static + Send + Any>,
130 http: Arc<dyn HttpClient>,
131 container_dir: PathBuf,
132 ) -> Result<PathBuf> {
133 self.adapter
134 .fetch_server_binary(version, http, container_dir)
135 .await
136 }
137
138 pub async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<PathBuf> {
139 self.adapter.cached_server_binary(container_dir).await
140 }
141
142 pub fn workspace_configuration(
143 &self,
144 cx: &mut MutableAppContext,
145 ) -> Option<BoxFuture<'static, Value>> {
146 self.adapter.workspace_configuration(cx)
147 }
148
149 pub async fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
150 self.adapter.process_diagnostics(params).await
151 }
152
153 pub async fn process_completion(&self, completion_item: &mut lsp::CompletionItem) {
154 self.adapter.process_completion(completion_item).await
155 }
156
157 pub async fn label_for_completion(
158 &self,
159 completion_item: &lsp::CompletionItem,
160 language: &Arc<Language>,
161 ) -> Option<CodeLabel> {
162 self.adapter
163 .label_for_completion(completion_item, language)
164 .await
165 }
166
167 pub async fn label_for_symbol(
168 &self,
169 name: &str,
170 kind: lsp::SymbolKind,
171 language: &Arc<Language>,
172 ) -> Option<CodeLabel> {
173 self.adapter.label_for_symbol(name, kind, language).await
174 }
175}
176
177#[async_trait]
178pub trait LspAdapter: 'static + Send + Sync {
179 async fn name(&self) -> LanguageServerName;
180
181 async fn server_execution_kind(&self) -> ServerExecutionKind;
182
183 async fn fetch_latest_server_version(
184 &self,
185 http: Arc<dyn HttpClient>,
186 ) -> Result<Box<dyn 'static + Send + Any>>;
187
188 async fn fetch_server_binary(
189 &self,
190 version: Box<dyn 'static + Send + Any>,
191 http: Arc<dyn HttpClient>,
192 container_dir: PathBuf,
193 ) -> Result<PathBuf>;
194
195 async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<PathBuf>;
196
197 async fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
198
199 async fn process_completion(&self, _: &mut lsp::CompletionItem) {}
200
201 async fn label_for_completion(
202 &self,
203 _: &lsp::CompletionItem,
204 _: &Arc<Language>,
205 ) -> Option<CodeLabel> {
206 None
207 }
208
209 async fn label_for_symbol(
210 &self,
211 _: &str,
212 _: lsp::SymbolKind,
213 _: &Arc<Language>,
214 ) -> Option<CodeLabel> {
215 None
216 }
217
218 async fn server_args(&self) -> Vec<String> {
219 Vec::new()
220 }
221
222 async fn initialization_options(&self) -> Option<Value> {
223 None
224 }
225
226 fn workspace_configuration(
227 &self,
228 _: &mut MutableAppContext,
229 ) -> Option<BoxFuture<'static, Value>> {
230 None
231 }
232
233 async fn disk_based_diagnostic_sources(&self) -> Vec<String> {
234 Default::default()
235 }
236
237 async fn disk_based_diagnostics_progress_token(&self) -> Option<String> {
238 None
239 }
240
241 async fn language_ids(&self) -> HashMap<String, String> {
242 Default::default()
243 }
244}
245
246#[derive(Clone, Debug, PartialEq, Eq)]
247pub struct CodeLabel {
248 pub text: String,
249 pub runs: Vec<(Range<usize>, HighlightId)>,
250 pub filter_range: Range<usize>,
251}
252
253#[derive(Clone, Deserialize)]
254pub struct LanguageConfig {
255 pub name: Arc<str>,
256 pub path_suffixes: Vec<String>,
257 pub brackets: BracketPairConfig,
258 #[serde(default = "auto_indent_using_last_non_empty_line_default")]
259 pub auto_indent_using_last_non_empty_line: bool,
260 #[serde(default, deserialize_with = "deserialize_regex")]
261 pub increase_indent_pattern: Option<Regex>,
262 #[serde(default, deserialize_with = "deserialize_regex")]
263 pub decrease_indent_pattern: Option<Regex>,
264 #[serde(default)]
265 pub autoclose_before: String,
266 #[serde(default)]
267 pub line_comment: Option<Arc<str>>,
268 #[serde(default)]
269 pub block_comment: Option<(Arc<str>, Arc<str>)>,
270 #[serde(default)]
271 pub overrides: HashMap<String, LanguageConfigOverride>,
272}
273
274#[derive(Debug, Default)]
275pub struct LanguageQueries {
276 pub highlights: Option<Cow<'static, str>>,
277 pub brackets: Option<Cow<'static, str>>,
278 pub indents: Option<Cow<'static, str>>,
279 pub outline: Option<Cow<'static, str>>,
280 pub injections: Option<Cow<'static, str>>,
281 pub overrides: Option<Cow<'static, str>>,
282}
283
284#[derive(Clone, Debug)]
285pub struct LanguageScope {
286 language: Arc<Language>,
287 override_id: Option<u32>,
288}
289
290#[derive(Clone, Deserialize, Default, Debug)]
291pub struct LanguageConfigOverride {
292 #[serde(default)]
293 pub line_comment: Override<Arc<str>>,
294 #[serde(default)]
295 pub block_comment: Override<(Arc<str>, Arc<str>)>,
296 #[serde(skip_deserializing)]
297 pub disabled_bracket_ixs: Vec<u16>,
298}
299
300#[derive(Clone, Deserialize, Debug)]
301#[serde(untagged)]
302pub enum Override<T> {
303 Remove { remove: bool },
304 Set(T),
305}
306
307impl<T> Default for Override<T> {
308 fn default() -> Self {
309 Override::Remove { remove: false }
310 }
311}
312
313impl<T> Override<T> {
314 fn as_option<'a>(this: Option<&'a Self>, original: Option<&'a T>) -> Option<&'a T> {
315 match this {
316 Some(Self::Set(value)) => Some(value),
317 Some(Self::Remove { remove: true }) => None,
318 Some(Self::Remove { remove: false }) | None => original,
319 }
320 }
321}
322
323impl Default for LanguageConfig {
324 fn default() -> Self {
325 Self {
326 name: "".into(),
327 path_suffixes: Default::default(),
328 brackets: Default::default(),
329 auto_indent_using_last_non_empty_line: auto_indent_using_last_non_empty_line_default(),
330 increase_indent_pattern: Default::default(),
331 decrease_indent_pattern: Default::default(),
332 autoclose_before: Default::default(),
333 line_comment: Default::default(),
334 block_comment: Default::default(),
335 overrides: Default::default(),
336 }
337 }
338}
339
340fn auto_indent_using_last_non_empty_line_default() -> bool {
341 true
342}
343
344fn deserialize_regex<'de, D: Deserializer<'de>>(d: D) -> Result<Option<Regex>, D::Error> {
345 let source = Option::<String>::deserialize(d)?;
346 if let Some(source) = source {
347 Ok(Some(regex::Regex::new(&source).map_err(de::Error::custom)?))
348 } else {
349 Ok(None)
350 }
351}
352
353#[cfg(any(test, feature = "test-support"))]
354pub struct FakeLspAdapter {
355 pub name: &'static str,
356 pub capabilities: lsp::ServerCapabilities,
357 pub initializer: Option<Box<dyn 'static + Send + Sync + Fn(&mut lsp::FakeLanguageServer)>>,
358 pub disk_based_diagnostics_progress_token: Option<String>,
359 pub disk_based_diagnostics_sources: Vec<String>,
360}
361
362#[derive(Clone, Debug, Default)]
363pub struct BracketPairConfig {
364 pub pairs: Vec<BracketPair>,
365 pub disabled_scopes_by_bracket_ix: Vec<Vec<String>>,
366}
367
368impl<'de> Deserialize<'de> for BracketPairConfig {
369 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
370 where
371 D: Deserializer<'de>,
372 {
373 #[derive(Deserialize)]
374 pub struct Entry {
375 #[serde(flatten)]
376 pub bracket_pair: BracketPair,
377 #[serde(default)]
378 pub not_in: Vec<String>,
379 }
380
381 let result = Vec::<Entry>::deserialize(deserializer)?;
382 let mut brackets = Vec::with_capacity(result.len());
383 let mut disabled_scopes_by_bracket_ix = Vec::with_capacity(result.len());
384 for entry in result {
385 brackets.push(entry.bracket_pair);
386 disabled_scopes_by_bracket_ix.push(entry.not_in);
387 }
388
389 Ok(BracketPairConfig {
390 pairs: brackets,
391 disabled_scopes_by_bracket_ix,
392 })
393 }
394}
395
396#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
397pub struct BracketPair {
398 pub start: String,
399 pub end: String,
400 pub close: bool,
401 pub newline: bool,
402}
403
404pub struct Language {
405 pub(crate) config: LanguageConfig,
406 pub(crate) grammar: Option<Arc<Grammar>>,
407 pub(crate) adapter: Option<Arc<CachedLspAdapter>>,
408
409 #[cfg(any(test, feature = "test-support"))]
410 fake_adapter: Option<(
411 mpsc::UnboundedSender<lsp::FakeLanguageServer>,
412 Arc<FakeLspAdapter>,
413 )>,
414}
415
416pub struct Grammar {
417 id: usize,
418 pub(crate) ts_language: tree_sitter::Language,
419 pub(crate) error_query: Query,
420 pub(crate) highlights_query: Option<Query>,
421 pub(crate) brackets_config: Option<BracketConfig>,
422 pub(crate) indents_config: Option<IndentConfig>,
423 pub(crate) outline_config: Option<OutlineConfig>,
424 pub(crate) injection_config: Option<InjectionConfig>,
425 pub(crate) override_config: Option<OverrideConfig>,
426 pub(crate) highlight_map: Mutex<HighlightMap>,
427}
428
429struct IndentConfig {
430 query: Query,
431 indent_capture_ix: u32,
432 start_capture_ix: Option<u32>,
433 end_capture_ix: Option<u32>,
434 outdent_capture_ix: Option<u32>,
435}
436
437struct OutlineConfig {
438 query: Query,
439 item_capture_ix: u32,
440 name_capture_ix: u32,
441 context_capture_ix: Option<u32>,
442}
443
444struct InjectionConfig {
445 query: Query,
446 content_capture_ix: u32,
447 language_capture_ix: Option<u32>,
448 patterns: Vec<InjectionPatternConfig>,
449}
450
451struct OverrideConfig {
452 query: Query,
453 values: HashMap<u32, (String, LanguageConfigOverride)>,
454}
455
456#[derive(Default, Clone)]
457struct InjectionPatternConfig {
458 language: Option<Box<str>>,
459 combined: bool,
460}
461
462struct BracketConfig {
463 query: Query,
464 open_capture_ix: u32,
465 close_capture_ix: u32,
466}
467
468#[derive(Clone)]
469pub enum LanguageServerBinaryStatus {
470 CheckingForUpdate,
471 Downloading,
472 Downloaded,
473 Cached,
474 Failed { error: String },
475}
476
477type AvailableLanguageId = usize;
478
479#[derive(Clone)]
480struct AvailableLanguage {
481 id: AvailableLanguageId,
482 path: &'static str,
483 config: LanguageConfig,
484 grammar: tree_sitter::Language,
485 lsp_adapter: Option<Arc<dyn LspAdapter>>,
486 get_queries: fn(&str) -> LanguageQueries,
487}
488
489pub struct LanguageRegistry {
490 state: RwLock<LanguageRegistryState>,
491 language_server_download_dir: Option<Arc<Path>>,
492 lsp_binary_statuses_tx: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
493 lsp_binary_statuses_rx: async_broadcast::Receiver<(Arc<Language>, LanguageServerBinaryStatus)>,
494 login_shell_env_loaded: Shared<Task<()>>,
495 node_path: Shared<Task<Option<PathBuf>>>,
496 #[allow(clippy::type_complexity)]
497 lsp_binary_paths: Mutex<
498 HashMap<
499 LanguageServerName,
500 Shared<BoxFuture<'static, Result<PathBuf, Arc<anyhow::Error>>>>,
501 >,
502 >,
503 executor: Option<Arc<Background>>,
504}
505
506struct LanguageRegistryState {
507 languages: Vec<Arc<Language>>,
508 available_languages: Vec<AvailableLanguage>,
509 next_available_language_id: AvailableLanguageId,
510 loading_languages: HashMap<AvailableLanguageId, Vec<oneshot::Sender<Result<Arc<Language>>>>>,
511 subscription: (watch::Sender<()>, watch::Receiver<()>),
512 theme: Option<Arc<Theme>>,
513 version: usize,
514}
515
516impl LanguageRegistry {
517 pub fn new(login_shell_env_loaded: Task<()>, node_path: Task<Option<PathBuf>>) -> Self {
518 let (lsp_binary_statuses_tx, lsp_binary_statuses_rx) = async_broadcast::broadcast(16);
519 Self {
520 state: RwLock::new(LanguageRegistryState {
521 languages: vec![PLAIN_TEXT.clone()],
522 available_languages: Default::default(),
523 next_available_language_id: 0,
524 loading_languages: Default::default(),
525 subscription: watch::channel(),
526 theme: Default::default(),
527 version: 0,
528 }),
529 language_server_download_dir: None,
530 lsp_binary_statuses_tx,
531 lsp_binary_statuses_rx,
532 login_shell_env_loaded: login_shell_env_loaded.shared(),
533 node_path: node_path.shared(),
534 lsp_binary_paths: Default::default(),
535 executor: None,
536 }
537 }
538
539 #[cfg(any(test, feature = "test-support"))]
540 pub fn test() -> Self {
541 Self::new(Task::ready(()), Task::Ready(None))
542 }
543
544 pub fn set_executor(&mut self, executor: Arc<Background>) {
545 self.executor = Some(executor);
546 }
547
548 pub fn register(
549 &self,
550 path: &'static str,
551 config: LanguageConfig,
552 grammar: tree_sitter::Language,
553 lsp_adapter: Option<Arc<dyn LspAdapter>>,
554 get_queries: fn(&str) -> LanguageQueries,
555 ) {
556 let state = &mut *self.state.write();
557 state.available_languages.push(AvailableLanguage {
558 id: post_inc(&mut state.next_available_language_id),
559 path,
560 config,
561 grammar,
562 lsp_adapter,
563 get_queries,
564 });
565 }
566
567 pub fn language_names(&self) -> Vec<String> {
568 let state = self.state.read();
569 let mut result = state
570 .available_languages
571 .iter()
572 .map(|l| l.config.name.to_string())
573 .chain(state.languages.iter().map(|l| l.config.name.to_string()))
574 .collect::<Vec<_>>();
575 result.sort_unstable_by_key(|language_name| language_name.to_lowercase());
576 result
577 }
578
579 pub fn workspace_configuration(&self, cx: &mut MutableAppContext) -> Task<serde_json::Value> {
580 let lsp_adapters = {
581 let state = self.state.read();
582 state
583 .available_languages
584 .iter()
585 .filter_map(|l| l.lsp_adapter.clone())
586 .chain(
587 state
588 .languages
589 .iter()
590 .filter_map(|l| l.adapter.as_ref().map(|a| a.adapter.clone())),
591 )
592 .collect::<Vec<_>>()
593 };
594
595 let mut language_configs = Vec::new();
596 for adapter in &lsp_adapters {
597 if let Some(language_config) = adapter.workspace_configuration(cx) {
598 language_configs.push(language_config);
599 }
600 }
601
602 cx.background().spawn(async move {
603 let mut config = serde_json::json!({});
604 let language_configs = futures::future::join_all(language_configs).await;
605 for language_config in language_configs {
606 merge_json_value_into(language_config, &mut config);
607 }
608 config
609 })
610 }
611
612 pub fn add(&self, language: Arc<Language>) {
613 self.state.write().add(language);
614 }
615
616 pub fn subscribe(&self) -> watch::Receiver<()> {
617 self.state.read().subscription.1.clone()
618 }
619
620 pub fn version(&self) -> usize {
621 self.state.read().version
622 }
623
624 pub fn set_theme(&self, theme: Arc<Theme>) {
625 let mut state = self.state.write();
626 state.theme = Some(theme.clone());
627 for language in &state.languages {
628 language.set_theme(&theme.editor.syntax);
629 }
630 }
631
632 pub fn set_language_server_download_dir(&mut self, path: impl Into<Arc<Path>>) {
633 self.language_server_download_dir = Some(path.into());
634 }
635
636 pub fn language_for_name(
637 self: &Arc<Self>,
638 name: &str,
639 ) -> UnwrapFuture<oneshot::Receiver<Result<Arc<Language>>>> {
640 let name = UniCase::new(name);
641 self.get_or_load_language(|config| UniCase::new(config.name.as_ref()) == name)
642 }
643
644 pub fn language_for_name_or_extension(
645 self: &Arc<Self>,
646 string: &str,
647 ) -> UnwrapFuture<oneshot::Receiver<Result<Arc<Language>>>> {
648 let string = UniCase::new(string);
649 self.get_or_load_language(|config| {
650 UniCase::new(config.name.as_ref()) == string
651 || config
652 .path_suffixes
653 .iter()
654 .any(|suffix| UniCase::new(suffix) == string)
655 })
656 }
657
658 pub fn language_for_path(
659 self: &Arc<Self>,
660 path: impl AsRef<Path>,
661 ) -> UnwrapFuture<oneshot::Receiver<Result<Arc<Language>>>> {
662 let path = path.as_ref();
663 let filename = path.file_name().and_then(|name| name.to_str());
664 let extension = path.extension().and_then(|name| name.to_str());
665 let path_suffixes = [extension, filename];
666 self.get_or_load_language(|config| {
667 config
668 .path_suffixes
669 .iter()
670 .any(|suffix| path_suffixes.contains(&Some(suffix.as_str())))
671 })
672 }
673
674 fn get_or_load_language(
675 self: &Arc<Self>,
676 callback: impl Fn(&LanguageConfig) -> bool,
677 ) -> UnwrapFuture<oneshot::Receiver<Result<Arc<Language>>>> {
678 let (tx, rx) = oneshot::channel();
679
680 let mut state = self.state.write();
681 if let Some(language) = state
682 .languages
683 .iter()
684 .find(|language| callback(&language.config))
685 {
686 let _ = tx.send(Ok(language.clone()));
687 } else if let Some(executor) = self.executor.clone() {
688 if let Some(language) = state
689 .available_languages
690 .iter()
691 .find(|l| callback(&l.config))
692 .cloned()
693 {
694 let txs = state
695 .loading_languages
696 .entry(language.id)
697 .or_insert_with(|| {
698 let this = self.clone();
699 executor
700 .spawn(async move {
701 let id = language.id;
702 let queries = (language.get_queries)(&language.path);
703 let language =
704 Language::new(language.config, Some(language.grammar))
705 .with_lsp_adapter(language.lsp_adapter)
706 .await;
707 let name = language.name();
708 match language.with_queries(queries) {
709 Ok(language) => {
710 let language = Arc::new(language);
711 let mut state = this.state.write();
712 state.add(language.clone());
713 state
714 .available_languages
715 .retain(|language| language.id != id);
716 if let Some(mut txs) = state.loading_languages.remove(&id) {
717 for tx in txs.drain(..) {
718 let _ = tx.send(Ok(language.clone()));
719 }
720 }
721 }
722 Err(err) => {
723 let mut state = this.state.write();
724 state
725 .available_languages
726 .retain(|language| language.id != id);
727 if let Some(mut txs) = state.loading_languages.remove(&id) {
728 for tx in txs.drain(..) {
729 let _ = tx.send(Err(anyhow!(
730 "failed to load language {}: {}",
731 name,
732 err
733 )));
734 }
735 }
736 }
737 };
738 })
739 .detach();
740
741 Vec::new()
742 });
743 txs.push(tx);
744 } else {
745 let _ = tx.send(Err(anyhow!("language not found")));
746 }
747 } else {
748 let _ = tx.send(Err(anyhow!("executor does not exist")));
749 }
750
751 rx.unwrap()
752 }
753
754 pub fn to_vec(&self) -> Vec<Arc<Language>> {
755 self.state.read().languages.iter().cloned().collect()
756 }
757
758 pub fn start_language_server(
759 self: &Arc<Self>,
760 server_id: usize,
761 language: Arc<Language>,
762 root_path: Arc<Path>,
763 http_client: Arc<dyn HttpClient>,
764 cx: &mut MutableAppContext,
765 ) -> Option<Task<Result<lsp::LanguageServer>>> {
766 #[cfg(any(test, feature = "test-support"))]
767 if language.fake_adapter.is_some() {
768 let language = language;
769 return Some(cx.spawn(|cx| async move {
770 let (servers_tx, fake_adapter) = language.fake_adapter.as_ref().unwrap();
771 let (server, mut fake_server) = lsp::LanguageServer::fake(
772 fake_adapter.name.to_string(),
773 fake_adapter.capabilities.clone(),
774 cx.clone(),
775 );
776
777 if let Some(initializer) = &fake_adapter.initializer {
778 initializer(&mut fake_server);
779 }
780
781 let servers_tx = servers_tx.clone();
782 cx.background()
783 .spawn(async move {
784 if fake_server
785 .try_receive_notification::<lsp::notification::Initialized>()
786 .await
787 .is_some()
788 {
789 servers_tx.unbounded_send(fake_server).ok();
790 }
791 })
792 .detach();
793 Ok(server)
794 }));
795 }
796
797 let download_dir = self
798 .language_server_download_dir
799 .clone()
800 .ok_or_else(|| anyhow!("language server download directory has not been assigned"))
801 .log_err()?;
802
803 let this = self.clone();
804 let adapter = language.adapter.clone()?;
805 let lsp_binary_statuses = self.lsp_binary_statuses_tx.clone();
806 let login_shell_env_loaded = self.login_shell_env_loaded.clone();
807 let node_path = self.node_path.clone();
808
809 Some(cx.spawn(|cx| async move {
810 login_shell_env_loaded.await;
811 let node_path = node_path.await;
812
813 let server_binary_path = this
814 .lsp_binary_paths
815 .lock()
816 .entry(adapter.name.clone())
817 .or_insert_with(|| {
818 get_server_binary_path(
819 adapter.clone(),
820 language.clone(),
821 http_client,
822 download_dir,
823 lsp_binary_statuses,
824 )
825 .map_err(Arc::new)
826 .boxed()
827 .shared()
828 })
829 .clone()
830 .map_err(|e| anyhow!(e));
831
832 let server_binary_path = server_binary_path.await?;
833 let server_name = server_binary_path
834 .file_name()
835 .map(|name| name.to_string_lossy().to_string());
836
837 let mut command = match adapter.adapter.server_execution_kind().await {
838 ServerExecutionKind::Node => {
839 let node_path = node_path
840 .ok_or(anyhow!("Missing Node path for Node based language server"))?;
841 let node_binary = node_path.join("bin/node");
842 dbg!(&node_binary);
843 let mut command = smol::process::Command::new(node_binary);
844 command.arg(dbg!(server_binary_path));
845 command
846 }
847
848 ServerExecutionKind::Launch => smol::process::Command::new(server_binary_path),
849 };
850
851 command.args(&adapter.server_args);
852 let server = lsp::LanguageServer::new(server_id, server_name, command, &root_path, cx)?;
853
854 Ok(server)
855 }))
856 }
857
858 pub fn language_server_binary_statuses(
859 &self,
860 ) -> async_broadcast::Receiver<(Arc<Language>, LanguageServerBinaryStatus)> {
861 self.lsp_binary_statuses_rx.clone()
862 }
863}
864
865impl LanguageRegistryState {
866 fn add(&mut self, language: Arc<Language>) {
867 if let Some(theme) = self.theme.as_ref() {
868 language.set_theme(&theme.editor.syntax);
869 }
870 self.languages.push(language);
871 self.version += 1;
872 *self.subscription.0.borrow_mut() = ();
873 }
874}
875
876#[cfg(any(test, feature = "test-support"))]
877impl Default for LanguageRegistry {
878 fn default() -> Self {
879 Self::test()
880 }
881}
882
883async fn get_server_binary_path(
884 adapter: Arc<CachedLspAdapter>,
885 language: Arc<Language>,
886 http_client: Arc<dyn HttpClient>,
887 download_dir: Arc<Path>,
888 statuses: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
889) -> Result<PathBuf> {
890 let container_dir = download_dir.join(adapter.name.0.as_ref());
891 if !container_dir.exists() {
892 smol::fs::create_dir_all(&container_dir)
893 .await
894 .context("failed to create container directory")?;
895 }
896
897 let path = fetch_latest_server_binary_path(
898 adapter.clone(),
899 language.clone(),
900 http_client,
901 &container_dir,
902 statuses.clone(),
903 )
904 .await;
905 if let Err(error) = path.as_ref() {
906 if let Some(cached_path) = adapter.cached_server_binary(container_dir).await {
907 statuses
908 .broadcast((language.clone(), LanguageServerBinaryStatus::Cached))
909 .await?;
910 return Ok(cached_path);
911 } else {
912 statuses
913 .broadcast((
914 language.clone(),
915 LanguageServerBinaryStatus::Failed {
916 error: format!("{:?}", error),
917 },
918 ))
919 .await?;
920 }
921 }
922 path
923}
924
925async fn fetch_latest_server_binary_path(
926 adapter: Arc<CachedLspAdapter>,
927 language: Arc<Language>,
928 http_client: Arc<dyn HttpClient>,
929 container_dir: &Path,
930 lsp_binary_statuses_tx: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
931) -> Result<PathBuf> {
932 let container_dir: Arc<Path> = container_dir.into();
933 lsp_binary_statuses_tx
934 .broadcast((
935 language.clone(),
936 LanguageServerBinaryStatus::CheckingForUpdate,
937 ))
938 .await?;
939 let version_info = adapter
940 .fetch_latest_server_version(http_client.clone())
941 .await?;
942 lsp_binary_statuses_tx
943 .broadcast((language.clone(), LanguageServerBinaryStatus::Downloading))
944 .await?;
945 let path = adapter
946 .fetch_server_binary(version_info, http_client, container_dir.to_path_buf())
947 .await?;
948 lsp_binary_statuses_tx
949 .broadcast((language.clone(), LanguageServerBinaryStatus::Downloaded))
950 .await?;
951 Ok(path)
952}
953
954impl Language {
955 pub fn new(config: LanguageConfig, ts_language: Option<tree_sitter::Language>) -> Self {
956 Self {
957 config,
958 grammar: ts_language.map(|ts_language| {
959 Arc::new(Grammar {
960 id: NEXT_GRAMMAR_ID.fetch_add(1, SeqCst),
961 highlights_query: None,
962 brackets_config: None,
963 outline_config: None,
964 indents_config: None,
965 injection_config: None,
966 override_config: None,
967 error_query: Query::new(ts_language, "(ERROR) @error").unwrap(),
968 ts_language,
969 highlight_map: Default::default(),
970 })
971 }),
972 adapter: None,
973
974 #[cfg(any(test, feature = "test-support"))]
975 fake_adapter: None,
976 }
977 }
978
979 pub fn lsp_adapter(&self) -> Option<Arc<CachedLspAdapter>> {
980 self.adapter.clone()
981 }
982
983 pub fn id(&self) -> Option<usize> {
984 self.grammar.as_ref().map(|g| g.id)
985 }
986
987 pub fn with_queries(mut self, queries: LanguageQueries) -> Result<Self> {
988 if let Some(query) = queries.highlights {
989 self = self
990 .with_highlights_query(query.as_ref())
991 .expect("failed to evaluate highlights query");
992 }
993 if let Some(query) = queries.brackets {
994 self = self
995 .with_brackets_query(query.as_ref())
996 .expect("failed to load brackets query");
997 }
998 if let Some(query) = queries.indents {
999 self = self
1000 .with_indents_query(query.as_ref())
1001 .expect("failed to load indents query");
1002 }
1003 if let Some(query) = queries.outline {
1004 self = self
1005 .with_outline_query(query.as_ref())
1006 .expect("failed to load outline query");
1007 }
1008 if let Some(query) = queries.injections {
1009 self = self
1010 .with_injection_query(query.as_ref())
1011 .expect("failed to load injection query");
1012 }
1013 if let Some(query) = queries.overrides {
1014 self = self
1015 .with_override_query(query.as_ref())
1016 .expect("failed to load override query");
1017 }
1018 Ok(self)
1019 }
1020 pub fn with_highlights_query(mut self, source: &str) -> Result<Self> {
1021 let grammar = self.grammar_mut();
1022 grammar.highlights_query = Some(Query::new(grammar.ts_language, source)?);
1023 Ok(self)
1024 }
1025
1026 pub fn with_outline_query(mut self, source: &str) -> Result<Self> {
1027 let grammar = self.grammar_mut();
1028 let query = Query::new(grammar.ts_language, source)?;
1029 let mut item_capture_ix = None;
1030 let mut name_capture_ix = None;
1031 let mut context_capture_ix = None;
1032 get_capture_indices(
1033 &query,
1034 &mut [
1035 ("item", &mut item_capture_ix),
1036 ("name", &mut name_capture_ix),
1037 ("context", &mut context_capture_ix),
1038 ],
1039 );
1040 if let Some((item_capture_ix, name_capture_ix)) = item_capture_ix.zip(name_capture_ix) {
1041 grammar.outline_config = Some(OutlineConfig {
1042 query,
1043 item_capture_ix,
1044 name_capture_ix,
1045 context_capture_ix,
1046 });
1047 }
1048 Ok(self)
1049 }
1050
1051 pub fn with_brackets_query(mut self, source: &str) -> Result<Self> {
1052 let grammar = self.grammar_mut();
1053 let query = Query::new(grammar.ts_language, source)?;
1054 let mut open_capture_ix = None;
1055 let mut close_capture_ix = None;
1056 get_capture_indices(
1057 &query,
1058 &mut [
1059 ("open", &mut open_capture_ix),
1060 ("close", &mut close_capture_ix),
1061 ],
1062 );
1063 if let Some((open_capture_ix, close_capture_ix)) = open_capture_ix.zip(close_capture_ix) {
1064 grammar.brackets_config = Some(BracketConfig {
1065 query,
1066 open_capture_ix,
1067 close_capture_ix,
1068 });
1069 }
1070 Ok(self)
1071 }
1072
1073 pub fn with_indents_query(mut self, source: &str) -> Result<Self> {
1074 let grammar = self.grammar_mut();
1075 let query = Query::new(grammar.ts_language, source)?;
1076 let mut indent_capture_ix = None;
1077 let mut start_capture_ix = None;
1078 let mut end_capture_ix = None;
1079 let mut outdent_capture_ix = None;
1080 get_capture_indices(
1081 &query,
1082 &mut [
1083 ("indent", &mut indent_capture_ix),
1084 ("start", &mut start_capture_ix),
1085 ("end", &mut end_capture_ix),
1086 ("outdent", &mut outdent_capture_ix),
1087 ],
1088 );
1089 if let Some(indent_capture_ix) = indent_capture_ix {
1090 grammar.indents_config = Some(IndentConfig {
1091 query,
1092 indent_capture_ix,
1093 start_capture_ix,
1094 end_capture_ix,
1095 outdent_capture_ix,
1096 });
1097 }
1098 Ok(self)
1099 }
1100
1101 pub fn with_injection_query(mut self, source: &str) -> Result<Self> {
1102 let grammar = self.grammar_mut();
1103 let query = Query::new(grammar.ts_language, source)?;
1104 let mut language_capture_ix = None;
1105 let mut content_capture_ix = None;
1106 get_capture_indices(
1107 &query,
1108 &mut [
1109 ("language", &mut language_capture_ix),
1110 ("content", &mut content_capture_ix),
1111 ],
1112 );
1113 let patterns = (0..query.pattern_count())
1114 .map(|ix| {
1115 let mut config = InjectionPatternConfig::default();
1116 for setting in query.property_settings(ix) {
1117 match setting.key.as_ref() {
1118 "language" => {
1119 config.language = setting.value.clone();
1120 }
1121 "combined" => {
1122 config.combined = true;
1123 }
1124 _ => {}
1125 }
1126 }
1127 config
1128 })
1129 .collect();
1130 if let Some(content_capture_ix) = content_capture_ix {
1131 grammar.injection_config = Some(InjectionConfig {
1132 query,
1133 language_capture_ix,
1134 content_capture_ix,
1135 patterns,
1136 });
1137 }
1138 Ok(self)
1139 }
1140
1141 pub fn with_override_query(mut self, source: &str) -> Result<Self> {
1142 let query = Query::new(self.grammar_mut().ts_language, source)?;
1143
1144 let mut override_configs_by_id = HashMap::default();
1145 for (ix, name) in query.capture_names().iter().enumerate() {
1146 if !name.starts_with('_') {
1147 let value = self.config.overrides.remove(name).unwrap_or_default();
1148 override_configs_by_id.insert(ix as u32, (name.clone(), value));
1149 }
1150 }
1151
1152 if !self.config.overrides.is_empty() {
1153 let keys = self.config.overrides.keys().collect::<Vec<_>>();
1154 Err(anyhow!(
1155 "language {:?} has overrides in config not in query: {keys:?}",
1156 self.config.name
1157 ))?;
1158 }
1159
1160 for disabled_scope_name in self
1161 .config
1162 .brackets
1163 .disabled_scopes_by_bracket_ix
1164 .iter()
1165 .flatten()
1166 {
1167 if !override_configs_by_id
1168 .values()
1169 .any(|(scope_name, _)| scope_name == disabled_scope_name)
1170 {
1171 Err(anyhow!(
1172 "language {:?} has overrides in config not in query: {disabled_scope_name:?}",
1173 self.config.name
1174 ))?;
1175 }
1176 }
1177
1178 for (name, override_config) in override_configs_by_id.values_mut() {
1179 override_config.disabled_bracket_ixs = self
1180 .config
1181 .brackets
1182 .disabled_scopes_by_bracket_ix
1183 .iter()
1184 .enumerate()
1185 .filter_map(|(ix, disabled_scope_names)| {
1186 if disabled_scope_names.contains(name) {
1187 Some(ix as u16)
1188 } else {
1189 None
1190 }
1191 })
1192 .collect();
1193 }
1194
1195 self.config.brackets.disabled_scopes_by_bracket_ix.clear();
1196 self.grammar_mut().override_config = Some(OverrideConfig {
1197 query,
1198 values: override_configs_by_id,
1199 });
1200 Ok(self)
1201 }
1202
1203 fn grammar_mut(&mut self) -> &mut Grammar {
1204 Arc::get_mut(self.grammar.as_mut().unwrap()).unwrap()
1205 }
1206
1207 pub async fn with_lsp_adapter(mut self, lsp_adapter: Option<Arc<dyn LspAdapter>>) -> Self {
1208 if let Some(adapter) = lsp_adapter {
1209 self.adapter = Some(CachedLspAdapter::new(adapter).await);
1210 }
1211 self
1212 }
1213
1214 #[cfg(any(test, feature = "test-support"))]
1215 pub async fn set_fake_lsp_adapter(
1216 &mut self,
1217 fake_lsp_adapter: Arc<FakeLspAdapter>,
1218 ) -> mpsc::UnboundedReceiver<lsp::FakeLanguageServer> {
1219 let (servers_tx, servers_rx) = mpsc::unbounded();
1220 self.fake_adapter = Some((servers_tx, fake_lsp_adapter.clone()));
1221 let adapter = CachedLspAdapter::new(Arc::new(fake_lsp_adapter)).await;
1222 self.adapter = Some(adapter);
1223 servers_rx
1224 }
1225
1226 pub fn name(&self) -> Arc<str> {
1227 self.config.name.clone()
1228 }
1229
1230 pub async fn disk_based_diagnostic_sources(&self) -> &[String] {
1231 match self.adapter.as_ref() {
1232 Some(adapter) => &adapter.disk_based_diagnostic_sources,
1233 None => &[],
1234 }
1235 }
1236
1237 pub async fn disk_based_diagnostics_progress_token(&self) -> Option<&str> {
1238 if let Some(adapter) = self.adapter.as_ref() {
1239 adapter.disk_based_diagnostics_progress_token.as_deref()
1240 } else {
1241 None
1242 }
1243 }
1244
1245 pub async fn process_diagnostics(&self, diagnostics: &mut lsp::PublishDiagnosticsParams) {
1246 if let Some(processor) = self.adapter.as_ref() {
1247 processor.process_diagnostics(diagnostics).await;
1248 }
1249 }
1250
1251 pub async fn process_completion(self: &Arc<Self>, completion: &mut lsp::CompletionItem) {
1252 if let Some(adapter) = self.adapter.as_ref() {
1253 adapter.process_completion(completion).await;
1254 }
1255 }
1256
1257 pub async fn label_for_completion(
1258 self: &Arc<Self>,
1259 completion: &lsp::CompletionItem,
1260 ) -> Option<CodeLabel> {
1261 self.adapter
1262 .as_ref()?
1263 .label_for_completion(completion, self)
1264 .await
1265 }
1266
1267 pub async fn label_for_symbol(
1268 self: &Arc<Self>,
1269 name: &str,
1270 kind: lsp::SymbolKind,
1271 ) -> Option<CodeLabel> {
1272 self.adapter
1273 .as_ref()?
1274 .label_for_symbol(name, kind, self)
1275 .await
1276 }
1277
1278 pub fn highlight_text<'a>(
1279 self: &'a Arc<Self>,
1280 text: &'a Rope,
1281 range: Range<usize>,
1282 ) -> Vec<(Range<usize>, HighlightId)> {
1283 let mut result = Vec::new();
1284 if let Some(grammar) = &self.grammar {
1285 let tree = grammar.parse_text(text, None);
1286 let captures =
1287 SyntaxSnapshot::single_tree_captures(range.clone(), text, &tree, self, |grammar| {
1288 grammar.highlights_query.as_ref()
1289 });
1290 let highlight_maps = vec![grammar.highlight_map()];
1291 let mut offset = 0;
1292 for chunk in BufferChunks::new(text, range, Some((captures, highlight_maps)), vec![]) {
1293 let end_offset = offset + chunk.text.len();
1294 if let Some(highlight_id) = chunk.syntax_highlight_id {
1295 if !highlight_id.is_default() {
1296 result.push((offset..end_offset, highlight_id));
1297 }
1298 }
1299 offset = end_offset;
1300 }
1301 }
1302 result
1303 }
1304
1305 pub fn path_suffixes(&self) -> &[String] {
1306 &self.config.path_suffixes
1307 }
1308
1309 pub fn should_autoclose_before(&self, c: char) -> bool {
1310 c.is_whitespace() || self.config.autoclose_before.contains(c)
1311 }
1312
1313 pub fn set_theme(&self, theme: &SyntaxTheme) {
1314 if let Some(grammar) = self.grammar.as_ref() {
1315 if let Some(highlights_query) = &grammar.highlights_query {
1316 *grammar.highlight_map.lock() =
1317 HighlightMap::new(highlights_query.capture_names(), theme);
1318 }
1319 }
1320 }
1321
1322 pub fn grammar(&self) -> Option<&Arc<Grammar>> {
1323 self.grammar.as_ref()
1324 }
1325}
1326
1327impl LanguageScope {
1328 pub fn line_comment_prefix(&self) -> Option<&Arc<str>> {
1329 Override::as_option(
1330 self.config_override().map(|o| &o.line_comment),
1331 self.language.config.line_comment.as_ref(),
1332 )
1333 }
1334
1335 pub fn block_comment_delimiters(&self) -> Option<(&Arc<str>, &Arc<str>)> {
1336 Override::as_option(
1337 self.config_override().map(|o| &o.block_comment),
1338 self.language.config.block_comment.as_ref(),
1339 )
1340 .map(|e| (&e.0, &e.1))
1341 }
1342
1343 pub fn brackets(&self) -> impl Iterator<Item = (&BracketPair, bool)> {
1344 let mut disabled_ids = self
1345 .config_override()
1346 .map_or(&[] as _, |o| o.disabled_bracket_ixs.as_slice());
1347 self.language
1348 .config
1349 .brackets
1350 .pairs
1351 .iter()
1352 .enumerate()
1353 .map(move |(ix, bracket)| {
1354 let mut is_enabled = true;
1355 if let Some(next_disabled_ix) = disabled_ids.first() {
1356 if ix == *next_disabled_ix as usize {
1357 disabled_ids = &disabled_ids[1..];
1358 is_enabled = false;
1359 }
1360 }
1361 (bracket, is_enabled)
1362 })
1363 }
1364
1365 pub fn should_autoclose_before(&self, c: char) -> bool {
1366 c.is_whitespace() || self.language.config.autoclose_before.contains(c)
1367 }
1368
1369 fn config_override(&self) -> Option<&LanguageConfigOverride> {
1370 let id = self.override_id?;
1371 let grammar = self.language.grammar.as_ref()?;
1372 let override_config = grammar.override_config.as_ref()?;
1373 override_config.values.get(&id).map(|e| &e.1)
1374 }
1375}
1376
1377impl Hash for Language {
1378 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1379 self.id().hash(state)
1380 }
1381}
1382
1383impl PartialEq for Language {
1384 fn eq(&self, other: &Self) -> bool {
1385 self.id().eq(&other.id())
1386 }
1387}
1388
1389impl Eq for Language {}
1390
1391impl Debug for Language {
1392 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1393 f.debug_struct("Language")
1394 .field("name", &self.config.name)
1395 .finish()
1396 }
1397}
1398
1399impl Grammar {
1400 pub fn id(&self) -> usize {
1401 self.id
1402 }
1403
1404 fn parse_text(&self, text: &Rope, old_tree: Option<Tree>) -> Tree {
1405 PARSER.with(|parser| {
1406 let mut parser = parser.borrow_mut();
1407 parser
1408 .set_language(self.ts_language)
1409 .expect("incompatible grammar");
1410 let mut chunks = text.chunks_in_range(0..text.len());
1411 parser
1412 .parse_with(
1413 &mut move |offset, _| {
1414 chunks.seek(offset);
1415 chunks.next().unwrap_or("").as_bytes()
1416 },
1417 old_tree.as_ref(),
1418 )
1419 .unwrap()
1420 })
1421 }
1422
1423 pub fn highlight_map(&self) -> HighlightMap {
1424 self.highlight_map.lock().clone()
1425 }
1426
1427 pub fn highlight_id_for_name(&self, name: &str) -> Option<HighlightId> {
1428 let capture_id = self
1429 .highlights_query
1430 .as_ref()?
1431 .capture_index_for_name(name)?;
1432 Some(self.highlight_map.lock().get(capture_id))
1433 }
1434}
1435
1436impl CodeLabel {
1437 pub fn plain(text: String, filter_text: Option<&str>) -> Self {
1438 let mut result = Self {
1439 runs: Vec::new(),
1440 filter_range: 0..text.len(),
1441 text,
1442 };
1443 if let Some(filter_text) = filter_text {
1444 if let Some(ix) = result.text.find(filter_text) {
1445 result.filter_range = ix..ix + filter_text.len();
1446 }
1447 }
1448 result
1449 }
1450}
1451
1452#[cfg(any(test, feature = "test-support"))]
1453impl Default for FakeLspAdapter {
1454 fn default() -> Self {
1455 Self {
1456 name: "the-fake-language-server",
1457 capabilities: lsp::LanguageServer::full_capabilities(),
1458 initializer: None,
1459 disk_based_diagnostics_progress_token: None,
1460 disk_based_diagnostics_sources: Vec::new(),
1461 }
1462 }
1463}
1464
1465#[cfg(any(test, feature = "test-support"))]
1466#[async_trait]
1467impl LspAdapter for Arc<FakeLspAdapter> {
1468 async fn name(&self) -> LanguageServerName {
1469 LanguageServerName(self.name.into())
1470 }
1471
1472 async fn server_execution_kind(&self) -> ServerExecutionKind {
1473 ServerExecutionKind::Launch
1474 }
1475
1476 async fn fetch_latest_server_version(
1477 &self,
1478 _: Arc<dyn HttpClient>,
1479 ) -> Result<Box<dyn 'static + Send + Any>> {
1480 unreachable!();
1481 }
1482
1483 async fn fetch_server_binary(
1484 &self,
1485 _: Box<dyn 'static + Send + Any>,
1486 _: Arc<dyn HttpClient>,
1487 _: PathBuf,
1488 ) -> Result<PathBuf> {
1489 unreachable!();
1490 }
1491
1492 async fn cached_server_binary(&self, _: PathBuf) -> Option<PathBuf> {
1493 unreachable!();
1494 }
1495
1496 async fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
1497
1498 async fn disk_based_diagnostic_sources(&self) -> Vec<String> {
1499 self.disk_based_diagnostics_sources.clone()
1500 }
1501
1502 async fn disk_based_diagnostics_progress_token(&self) -> Option<String> {
1503 self.disk_based_diagnostics_progress_token.clone()
1504 }
1505}
1506
1507fn get_capture_indices(query: &Query, captures: &mut [(&str, &mut Option<u32>)]) {
1508 for (ix, name) in query.capture_names().iter().enumerate() {
1509 for (capture_name, index) in captures.iter_mut() {
1510 if capture_name == name {
1511 **index = Some(ix as u32);
1512 break;
1513 }
1514 }
1515 }
1516}
1517
1518pub fn point_to_lsp(point: PointUtf16) -> lsp::Position {
1519 lsp::Position::new(point.row, point.column)
1520}
1521
1522pub fn point_from_lsp(point: lsp::Position) -> Unclipped<PointUtf16> {
1523 Unclipped(PointUtf16::new(point.line, point.character))
1524}
1525
1526pub fn range_to_lsp(range: Range<PointUtf16>) -> lsp::Range {
1527 lsp::Range {
1528 start: point_to_lsp(range.start),
1529 end: point_to_lsp(range.end),
1530 }
1531}
1532
1533pub fn range_from_lsp(range: lsp::Range) -> Range<Unclipped<PointUtf16>> {
1534 let mut start = point_from_lsp(range.start);
1535 let mut end = point_from_lsp(range.end);
1536 if start > end {
1537 mem::swap(&mut start, &mut end);
1538 }
1539 start..end
1540}
1541
1542#[cfg(test)]
1543mod tests {
1544 use gpui::TestAppContext;
1545
1546 use super::*;
1547
1548 #[gpui::test(iterations = 10)]
1549 async fn test_language_loading(cx: &mut TestAppContext) {
1550 let mut languages = LanguageRegistry::test();
1551 languages.set_executor(cx.background());
1552 let languages = Arc::new(languages);
1553 languages.register(
1554 "/JSON",
1555 LanguageConfig {
1556 name: "JSON".into(),
1557 path_suffixes: vec!["json".into()],
1558 ..Default::default()
1559 },
1560 tree_sitter_json::language(),
1561 None,
1562 |_| Default::default(),
1563 );
1564 languages.register(
1565 "/rust",
1566 LanguageConfig {
1567 name: "Rust".into(),
1568 path_suffixes: vec!["rs".into()],
1569 ..Default::default()
1570 },
1571 tree_sitter_rust::language(),
1572 None,
1573 |_| Default::default(),
1574 );
1575 assert_eq!(
1576 languages.language_names(),
1577 &[
1578 "JSON".to_string(),
1579 "Plain Text".to_string(),
1580 "Rust".to_string(),
1581 ]
1582 );
1583
1584 let rust1 = languages.language_for_name("Rust");
1585 let rust2 = languages.language_for_name("Rust");
1586
1587 // Ensure language is still listed even if it's being loaded.
1588 assert_eq!(
1589 languages.language_names(),
1590 &[
1591 "JSON".to_string(),
1592 "Plain Text".to_string(),
1593 "Rust".to_string(),
1594 ]
1595 );
1596
1597 let (rust1, rust2) = futures::join!(rust1, rust2);
1598 assert!(Arc::ptr_eq(&rust1.unwrap(), &rust2.unwrap()));
1599
1600 // Ensure language is still listed even after loading it.
1601 assert_eq!(
1602 languages.language_names(),
1603 &[
1604 "JSON".to_string(),
1605 "Plain Text".to_string(),
1606 "Rust".to_string(),
1607 ]
1608 );
1609
1610 // Loading an unknown language returns an error.
1611 assert!(languages.language_for_name("Unknown").await.is_err());
1612 }
1613}