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