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 dbg!();
797
798 let download_dir = self
799 .language_server_download_dir
800 .clone()
801 .ok_or_else(|| anyhow!("language server download directory has not been assigned"))
802 .log_err()?;
803
804 let this = self.clone();
805 let adapter = language.adapter.clone()?;
806 let lsp_binary_statuses = self.lsp_binary_statuses_tx.clone();
807 let login_shell_env_loaded = self.login_shell_env_loaded.clone();
808 dbg!();
809
810 Some(cx.spawn(|cx| async move {
811 login_shell_env_loaded.await;
812
813 let binary = this
814 .lsp_binary_paths
815 .lock()
816 .entry(adapter.name.clone())
817 .or_insert_with(|| {
818 dbg!();
819 get_binary(
820 adapter.clone(),
821 language.clone(),
822 http_client,
823 download_dir,
824 lsp_binary_statuses,
825 )
826 .map_err(Arc::new)
827 .boxed()
828 .shared()
829 })
830 .clone()
831 .map_err(|e| anyhow!(e))
832 .await?;
833 dbg!();
834
835 let server = lsp::LanguageServer::new(
836 server_id,
837 &binary.path,
838 &binary.arguments,
839 &root_path,
840 cx,
841 )?;
842
843 dbg!();
844 Ok(server)
845 }))
846 }
847
848 pub fn language_server_binary_statuses(
849 &self,
850 ) -> async_broadcast::Receiver<(Arc<Language>, LanguageServerBinaryStatus)> {
851 self.lsp_binary_statuses_rx.clone()
852 }
853}
854
855impl LanguageRegistryState {
856 fn add(&mut self, language: Arc<Language>) {
857 if let Some(theme) = self.theme.as_ref() {
858 language.set_theme(&theme.editor.syntax);
859 }
860 self.languages.push(language);
861 self.version += 1;
862 *self.subscription.0.borrow_mut() = ();
863 }
864}
865
866#[cfg(any(test, feature = "test-support"))]
867impl Default for LanguageRegistry {
868 fn default() -> Self {
869 Self::test()
870 }
871}
872
873async fn get_binary(
874 adapter: Arc<CachedLspAdapter>,
875 language: Arc<Language>,
876 http_client: Arc<dyn HttpClient>,
877 download_dir: Arc<Path>,
878 statuses: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
879) -> Result<LanguageServerBinary> {
880 let container_dir = download_dir.join(adapter.name.0.as_ref());
881 if !container_dir.exists() {
882 smol::fs::create_dir_all(&container_dir)
883 .await
884 .context("failed to create container directory")?;
885 }
886
887 let binary = fetch_latest_binary(
888 adapter.clone(),
889 language.clone(),
890 http_client,
891 &container_dir,
892 statuses.clone(),
893 )
894 .await;
895 if let Err(error) = binary.as_ref() {
896 if let Some(cached) = adapter.cached_server_binary(container_dir).await {
897 statuses
898 .broadcast((language.clone(), LanguageServerBinaryStatus::Cached))
899 .await?;
900 return Ok(cached);
901 } else {
902 statuses
903 .broadcast((
904 language.clone(),
905 LanguageServerBinaryStatus::Failed {
906 error: format!("{:?}", error),
907 },
908 ))
909 .await?;
910 }
911 }
912 binary
913}
914
915async fn fetch_latest_binary(
916 adapter: Arc<CachedLspAdapter>,
917 language: Arc<Language>,
918 http_client: Arc<dyn HttpClient>,
919 container_dir: &Path,
920 lsp_binary_statuses_tx: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
921) -> Result<LanguageServerBinary> {
922 let container_dir: Arc<Path> = container_dir.into();
923 lsp_binary_statuses_tx
924 .broadcast((
925 language.clone(),
926 LanguageServerBinaryStatus::CheckingForUpdate,
927 ))
928 .await?;
929 let version_info = adapter
930 .fetch_latest_server_version(http_client.clone())
931 .await?;
932 lsp_binary_statuses_tx
933 .broadcast((language.clone(), LanguageServerBinaryStatus::Downloading))
934 .await?;
935 let binary = adapter
936 .fetch_server_binary(version_info, http_client, container_dir.to_path_buf())
937 .await?;
938 lsp_binary_statuses_tx
939 .broadcast((language.clone(), LanguageServerBinaryStatus::Downloaded))
940 .await?;
941 Ok(binary)
942}
943
944impl Language {
945 pub fn new(config: LanguageConfig, ts_language: Option<tree_sitter::Language>) -> Self {
946 Self {
947 config,
948 grammar: ts_language.map(|ts_language| {
949 Arc::new(Grammar {
950 id: NEXT_GRAMMAR_ID.fetch_add(1, SeqCst),
951 highlights_query: None,
952 brackets_config: None,
953 outline_config: None,
954 indents_config: None,
955 injection_config: None,
956 override_config: None,
957 error_query: Query::new(ts_language, "(ERROR) @error").unwrap(),
958 ts_language,
959 highlight_map: Default::default(),
960 })
961 }),
962 adapter: None,
963
964 #[cfg(any(test, feature = "test-support"))]
965 fake_adapter: None,
966 }
967 }
968
969 pub fn lsp_adapter(&self) -> Option<Arc<CachedLspAdapter>> {
970 self.adapter.clone()
971 }
972
973 pub fn id(&self) -> Option<usize> {
974 self.grammar.as_ref().map(|g| g.id)
975 }
976
977 pub fn with_queries(mut self, queries: LanguageQueries) -> Result<Self> {
978 if let Some(query) = queries.highlights {
979 self = self
980 .with_highlights_query(query.as_ref())
981 .expect("failed to evaluate highlights query");
982 }
983 if let Some(query) = queries.brackets {
984 self = self
985 .with_brackets_query(query.as_ref())
986 .expect("failed to load brackets query");
987 }
988 if let Some(query) = queries.indents {
989 self = self
990 .with_indents_query(query.as_ref())
991 .expect("failed to load indents query");
992 }
993 if let Some(query) = queries.outline {
994 self = self
995 .with_outline_query(query.as_ref())
996 .expect("failed to load outline query");
997 }
998 if let Some(query) = queries.injections {
999 self = self
1000 .with_injection_query(query.as_ref())
1001 .expect("failed to load injection query");
1002 }
1003 if let Some(query) = queries.overrides {
1004 self = self
1005 .with_override_query(query.as_ref())
1006 .expect("failed to load override query");
1007 }
1008 Ok(self)
1009 }
1010 pub fn with_highlights_query(mut self, source: &str) -> Result<Self> {
1011 let grammar = self.grammar_mut();
1012 grammar.highlights_query = Some(Query::new(grammar.ts_language, source)?);
1013 Ok(self)
1014 }
1015
1016 pub fn with_outline_query(mut self, source: &str) -> Result<Self> {
1017 let grammar = self.grammar_mut();
1018 let query = Query::new(grammar.ts_language, source)?;
1019 let mut item_capture_ix = None;
1020 let mut name_capture_ix = None;
1021 let mut context_capture_ix = None;
1022 get_capture_indices(
1023 &query,
1024 &mut [
1025 ("item", &mut item_capture_ix),
1026 ("name", &mut name_capture_ix),
1027 ("context", &mut context_capture_ix),
1028 ],
1029 );
1030 if let Some((item_capture_ix, name_capture_ix)) = item_capture_ix.zip(name_capture_ix) {
1031 grammar.outline_config = Some(OutlineConfig {
1032 query,
1033 item_capture_ix,
1034 name_capture_ix,
1035 context_capture_ix,
1036 });
1037 }
1038 Ok(self)
1039 }
1040
1041 pub fn with_brackets_query(mut self, source: &str) -> Result<Self> {
1042 let grammar = self.grammar_mut();
1043 let query = Query::new(grammar.ts_language, source)?;
1044 let mut open_capture_ix = None;
1045 let mut close_capture_ix = None;
1046 get_capture_indices(
1047 &query,
1048 &mut [
1049 ("open", &mut open_capture_ix),
1050 ("close", &mut close_capture_ix),
1051 ],
1052 );
1053 if let Some((open_capture_ix, close_capture_ix)) = open_capture_ix.zip(close_capture_ix) {
1054 grammar.brackets_config = Some(BracketConfig {
1055 query,
1056 open_capture_ix,
1057 close_capture_ix,
1058 });
1059 }
1060 Ok(self)
1061 }
1062
1063 pub fn with_indents_query(mut self, source: &str) -> Result<Self> {
1064 let grammar = self.grammar_mut();
1065 let query = Query::new(grammar.ts_language, source)?;
1066 let mut indent_capture_ix = None;
1067 let mut start_capture_ix = None;
1068 let mut end_capture_ix = None;
1069 let mut outdent_capture_ix = None;
1070 get_capture_indices(
1071 &query,
1072 &mut [
1073 ("indent", &mut indent_capture_ix),
1074 ("start", &mut start_capture_ix),
1075 ("end", &mut end_capture_ix),
1076 ("outdent", &mut outdent_capture_ix),
1077 ],
1078 );
1079 if let Some(indent_capture_ix) = indent_capture_ix {
1080 grammar.indents_config = Some(IndentConfig {
1081 query,
1082 indent_capture_ix,
1083 start_capture_ix,
1084 end_capture_ix,
1085 outdent_capture_ix,
1086 });
1087 }
1088 Ok(self)
1089 }
1090
1091 pub fn with_injection_query(mut self, source: &str) -> Result<Self> {
1092 let grammar = self.grammar_mut();
1093 let query = Query::new(grammar.ts_language, source)?;
1094 let mut language_capture_ix = None;
1095 let mut content_capture_ix = None;
1096 get_capture_indices(
1097 &query,
1098 &mut [
1099 ("language", &mut language_capture_ix),
1100 ("content", &mut content_capture_ix),
1101 ],
1102 );
1103 let patterns = (0..query.pattern_count())
1104 .map(|ix| {
1105 let mut config = InjectionPatternConfig::default();
1106 for setting in query.property_settings(ix) {
1107 match setting.key.as_ref() {
1108 "language" => {
1109 config.language = setting.value.clone();
1110 }
1111 "combined" => {
1112 config.combined = true;
1113 }
1114 _ => {}
1115 }
1116 }
1117 config
1118 })
1119 .collect();
1120 if let Some(content_capture_ix) = content_capture_ix {
1121 grammar.injection_config = Some(InjectionConfig {
1122 query,
1123 language_capture_ix,
1124 content_capture_ix,
1125 patterns,
1126 });
1127 }
1128 Ok(self)
1129 }
1130
1131 pub fn with_override_query(mut self, source: &str) -> Result<Self> {
1132 let query = Query::new(self.grammar_mut().ts_language, source)?;
1133
1134 let mut override_configs_by_id = HashMap::default();
1135 for (ix, name) in query.capture_names().iter().enumerate() {
1136 if !name.starts_with('_') {
1137 let value = self.config.overrides.remove(name).unwrap_or_default();
1138 override_configs_by_id.insert(ix as u32, (name.clone(), value));
1139 }
1140 }
1141
1142 if !self.config.overrides.is_empty() {
1143 let keys = self.config.overrides.keys().collect::<Vec<_>>();
1144 Err(anyhow!(
1145 "language {:?} has overrides in config not in query: {keys:?}",
1146 self.config.name
1147 ))?;
1148 }
1149
1150 for disabled_scope_name in self
1151 .config
1152 .brackets
1153 .disabled_scopes_by_bracket_ix
1154 .iter()
1155 .flatten()
1156 {
1157 if !override_configs_by_id
1158 .values()
1159 .any(|(scope_name, _)| scope_name == disabled_scope_name)
1160 {
1161 Err(anyhow!(
1162 "language {:?} has overrides in config not in query: {disabled_scope_name:?}",
1163 self.config.name
1164 ))?;
1165 }
1166 }
1167
1168 for (name, override_config) in override_configs_by_id.values_mut() {
1169 override_config.disabled_bracket_ixs = self
1170 .config
1171 .brackets
1172 .disabled_scopes_by_bracket_ix
1173 .iter()
1174 .enumerate()
1175 .filter_map(|(ix, disabled_scope_names)| {
1176 if disabled_scope_names.contains(name) {
1177 Some(ix as u16)
1178 } else {
1179 None
1180 }
1181 })
1182 .collect();
1183 }
1184
1185 self.config.brackets.disabled_scopes_by_bracket_ix.clear();
1186 self.grammar_mut().override_config = Some(OverrideConfig {
1187 query,
1188 values: override_configs_by_id,
1189 });
1190 Ok(self)
1191 }
1192
1193 fn grammar_mut(&mut self) -> &mut Grammar {
1194 Arc::get_mut(self.grammar.as_mut().unwrap()).unwrap()
1195 }
1196
1197 pub async fn with_lsp_adapter(mut self, lsp_adapter: Option<Arc<dyn LspAdapter>>) -> Self {
1198 if let Some(adapter) = lsp_adapter {
1199 self.adapter = Some(CachedLspAdapter::new(adapter).await);
1200 }
1201 self
1202 }
1203
1204 #[cfg(any(test, feature = "test-support"))]
1205 pub async fn set_fake_lsp_adapter(
1206 &mut self,
1207 fake_lsp_adapter: Arc<FakeLspAdapter>,
1208 ) -> mpsc::UnboundedReceiver<lsp::FakeLanguageServer> {
1209 let (servers_tx, servers_rx) = mpsc::unbounded();
1210 self.fake_adapter = Some((servers_tx, fake_lsp_adapter.clone()));
1211 let adapter = CachedLspAdapter::new(Arc::new(fake_lsp_adapter)).await;
1212 self.adapter = Some(adapter);
1213 servers_rx
1214 }
1215
1216 pub fn name(&self) -> Arc<str> {
1217 self.config.name.clone()
1218 }
1219
1220 pub async fn disk_based_diagnostic_sources(&self) -> &[String] {
1221 match self.adapter.as_ref() {
1222 Some(adapter) => &adapter.disk_based_diagnostic_sources,
1223 None => &[],
1224 }
1225 }
1226
1227 pub async fn disk_based_diagnostics_progress_token(&self) -> Option<&str> {
1228 if let Some(adapter) = self.adapter.as_ref() {
1229 adapter.disk_based_diagnostics_progress_token.as_deref()
1230 } else {
1231 None
1232 }
1233 }
1234
1235 pub async fn process_diagnostics(&self, diagnostics: &mut lsp::PublishDiagnosticsParams) {
1236 if let Some(processor) = self.adapter.as_ref() {
1237 processor.process_diagnostics(diagnostics).await;
1238 }
1239 }
1240
1241 pub async fn process_completion(self: &Arc<Self>, completion: &mut lsp::CompletionItem) {
1242 if let Some(adapter) = self.adapter.as_ref() {
1243 adapter.process_completion(completion).await;
1244 }
1245 }
1246
1247 pub async fn label_for_completion(
1248 self: &Arc<Self>,
1249 completion: &lsp::CompletionItem,
1250 ) -> Option<CodeLabel> {
1251 self.adapter
1252 .as_ref()?
1253 .label_for_completion(completion, self)
1254 .await
1255 }
1256
1257 pub async fn label_for_symbol(
1258 self: &Arc<Self>,
1259 name: &str,
1260 kind: lsp::SymbolKind,
1261 ) -> Option<CodeLabel> {
1262 self.adapter
1263 .as_ref()?
1264 .label_for_symbol(name, kind, self)
1265 .await
1266 }
1267
1268 pub fn highlight_text<'a>(
1269 self: &'a Arc<Self>,
1270 text: &'a Rope,
1271 range: Range<usize>,
1272 ) -> Vec<(Range<usize>, HighlightId)> {
1273 let mut result = Vec::new();
1274 if let Some(grammar) = &self.grammar {
1275 let tree = grammar.parse_text(text, None);
1276 let captures =
1277 SyntaxSnapshot::single_tree_captures(range.clone(), text, &tree, self, |grammar| {
1278 grammar.highlights_query.as_ref()
1279 });
1280 let highlight_maps = vec![grammar.highlight_map()];
1281 let mut offset = 0;
1282 for chunk in BufferChunks::new(text, range, Some((captures, highlight_maps)), vec![]) {
1283 let end_offset = offset + chunk.text.len();
1284 if let Some(highlight_id) = chunk.syntax_highlight_id {
1285 if !highlight_id.is_default() {
1286 result.push((offset..end_offset, highlight_id));
1287 }
1288 }
1289 offset = end_offset;
1290 }
1291 }
1292 result
1293 }
1294
1295 pub fn path_suffixes(&self) -> &[String] {
1296 &self.config.path_suffixes
1297 }
1298
1299 pub fn should_autoclose_before(&self, c: char) -> bool {
1300 c.is_whitespace() || self.config.autoclose_before.contains(c)
1301 }
1302
1303 pub fn set_theme(&self, theme: &SyntaxTheme) {
1304 if let Some(grammar) = self.grammar.as_ref() {
1305 if let Some(highlights_query) = &grammar.highlights_query {
1306 *grammar.highlight_map.lock() =
1307 HighlightMap::new(highlights_query.capture_names(), theme);
1308 }
1309 }
1310 }
1311
1312 pub fn grammar(&self) -> Option<&Arc<Grammar>> {
1313 self.grammar.as_ref()
1314 }
1315}
1316
1317impl LanguageScope {
1318 pub fn line_comment_prefix(&self) -> Option<&Arc<str>> {
1319 Override::as_option(
1320 self.config_override().map(|o| &o.line_comment),
1321 self.language.config.line_comment.as_ref(),
1322 )
1323 }
1324
1325 pub fn block_comment_delimiters(&self) -> Option<(&Arc<str>, &Arc<str>)> {
1326 Override::as_option(
1327 self.config_override().map(|o| &o.block_comment),
1328 self.language.config.block_comment.as_ref(),
1329 )
1330 .map(|e| (&e.0, &e.1))
1331 }
1332
1333 pub fn brackets(&self) -> impl Iterator<Item = (&BracketPair, bool)> {
1334 let mut disabled_ids = self
1335 .config_override()
1336 .map_or(&[] as _, |o| o.disabled_bracket_ixs.as_slice());
1337 self.language
1338 .config
1339 .brackets
1340 .pairs
1341 .iter()
1342 .enumerate()
1343 .map(move |(ix, bracket)| {
1344 let mut is_enabled = true;
1345 if let Some(next_disabled_ix) = disabled_ids.first() {
1346 if ix == *next_disabled_ix as usize {
1347 disabled_ids = &disabled_ids[1..];
1348 is_enabled = false;
1349 }
1350 }
1351 (bracket, is_enabled)
1352 })
1353 }
1354
1355 pub fn should_autoclose_before(&self, c: char) -> bool {
1356 c.is_whitespace() || self.language.config.autoclose_before.contains(c)
1357 }
1358
1359 fn config_override(&self) -> Option<&LanguageConfigOverride> {
1360 let id = self.override_id?;
1361 let grammar = self.language.grammar.as_ref()?;
1362 let override_config = grammar.override_config.as_ref()?;
1363 override_config.values.get(&id).map(|e| &e.1)
1364 }
1365}
1366
1367impl Hash for Language {
1368 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1369 self.id().hash(state)
1370 }
1371}
1372
1373impl PartialEq for Language {
1374 fn eq(&self, other: &Self) -> bool {
1375 self.id().eq(&other.id())
1376 }
1377}
1378
1379impl Eq for Language {}
1380
1381impl Debug for Language {
1382 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1383 f.debug_struct("Language")
1384 .field("name", &self.config.name)
1385 .finish()
1386 }
1387}
1388
1389impl Grammar {
1390 pub fn id(&self) -> usize {
1391 self.id
1392 }
1393
1394 fn parse_text(&self, text: &Rope, old_tree: Option<Tree>) -> Tree {
1395 PARSER.with(|parser| {
1396 let mut parser = parser.borrow_mut();
1397 parser
1398 .set_language(self.ts_language)
1399 .expect("incompatible grammar");
1400 let mut chunks = text.chunks_in_range(0..text.len());
1401 parser
1402 .parse_with(
1403 &mut move |offset, _| {
1404 chunks.seek(offset);
1405 chunks.next().unwrap_or("").as_bytes()
1406 },
1407 old_tree.as_ref(),
1408 )
1409 .unwrap()
1410 })
1411 }
1412
1413 pub fn highlight_map(&self) -> HighlightMap {
1414 self.highlight_map.lock().clone()
1415 }
1416
1417 pub fn highlight_id_for_name(&self, name: &str) -> Option<HighlightId> {
1418 let capture_id = self
1419 .highlights_query
1420 .as_ref()?
1421 .capture_index_for_name(name)?;
1422 Some(self.highlight_map.lock().get(capture_id))
1423 }
1424}
1425
1426impl CodeLabel {
1427 pub fn plain(text: String, filter_text: Option<&str>) -> Self {
1428 let mut result = Self {
1429 runs: Vec::new(),
1430 filter_range: 0..text.len(),
1431 text,
1432 };
1433 if let Some(filter_text) = filter_text {
1434 if let Some(ix) = result.text.find(filter_text) {
1435 result.filter_range = ix..ix + filter_text.len();
1436 }
1437 }
1438 result
1439 }
1440}
1441
1442#[cfg(any(test, feature = "test-support"))]
1443impl Default for FakeLspAdapter {
1444 fn default() -> Self {
1445 Self {
1446 name: "the-fake-language-server",
1447 capabilities: lsp::LanguageServer::full_capabilities(),
1448 initializer: None,
1449 disk_based_diagnostics_progress_token: None,
1450 disk_based_diagnostics_sources: Vec::new(),
1451 }
1452 }
1453}
1454
1455#[cfg(any(test, feature = "test-support"))]
1456#[async_trait]
1457impl LspAdapter for Arc<FakeLspAdapter> {
1458 async fn name(&self) -> LanguageServerName {
1459 LanguageServerName(self.name.into())
1460 }
1461
1462 async fn fetch_latest_server_version(
1463 &self,
1464 _: Arc<dyn HttpClient>,
1465 ) -> Result<Box<dyn 'static + Send + Any>> {
1466 unreachable!();
1467 }
1468
1469 async fn fetch_server_binary(
1470 &self,
1471 _: Box<dyn 'static + Send + Any>,
1472 _: Arc<dyn HttpClient>,
1473 _: PathBuf,
1474 ) -> Result<LanguageServerBinary> {
1475 unreachable!();
1476 }
1477
1478 async fn cached_server_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> {
1479 unreachable!();
1480 }
1481
1482 async fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
1483
1484 async fn disk_based_diagnostic_sources(&self) -> Vec<String> {
1485 self.disk_based_diagnostics_sources.clone()
1486 }
1487
1488 async fn disk_based_diagnostics_progress_token(&self) -> Option<String> {
1489 self.disk_based_diagnostics_progress_token.clone()
1490 }
1491}
1492
1493fn get_capture_indices(query: &Query, captures: &mut [(&str, &mut Option<u32>)]) {
1494 for (ix, name) in query.capture_names().iter().enumerate() {
1495 for (capture_name, index) in captures.iter_mut() {
1496 if capture_name == name {
1497 **index = Some(ix as u32);
1498 break;
1499 }
1500 }
1501 }
1502}
1503
1504pub fn point_to_lsp(point: PointUtf16) -> lsp::Position {
1505 lsp::Position::new(point.row, point.column)
1506}
1507
1508pub fn point_from_lsp(point: lsp::Position) -> Unclipped<PointUtf16> {
1509 Unclipped(PointUtf16::new(point.line, point.character))
1510}
1511
1512pub fn range_to_lsp(range: Range<PointUtf16>) -> lsp::Range {
1513 lsp::Range {
1514 start: point_to_lsp(range.start),
1515 end: point_to_lsp(range.end),
1516 }
1517}
1518
1519pub fn range_from_lsp(range: lsp::Range) -> Range<Unclipped<PointUtf16>> {
1520 let mut start = point_from_lsp(range.start);
1521 let mut end = point_from_lsp(range.end);
1522 if start > end {
1523 mem::swap(&mut start, &mut end);
1524 }
1525 start..end
1526}
1527
1528#[cfg(test)]
1529mod tests {
1530 use gpui::TestAppContext;
1531
1532 use super::*;
1533
1534 #[gpui::test(iterations = 10)]
1535 async fn test_language_loading(cx: &mut TestAppContext) {
1536 let mut languages = LanguageRegistry::test();
1537 languages.set_executor(cx.background());
1538 let languages = Arc::new(languages);
1539 languages.register(
1540 "/JSON",
1541 LanguageConfig {
1542 name: "JSON".into(),
1543 path_suffixes: vec!["json".into()],
1544 ..Default::default()
1545 },
1546 tree_sitter_json::language(),
1547 None,
1548 |_| Default::default(),
1549 );
1550 languages.register(
1551 "/rust",
1552 LanguageConfig {
1553 name: "Rust".into(),
1554 path_suffixes: vec!["rs".into()],
1555 ..Default::default()
1556 },
1557 tree_sitter_rust::language(),
1558 None,
1559 |_| Default::default(),
1560 );
1561 assert_eq!(
1562 languages.language_names(),
1563 &[
1564 "JSON".to_string(),
1565 "Plain Text".to_string(),
1566 "Rust".to_string(),
1567 ]
1568 );
1569
1570 let rust1 = languages.language_for_name("Rust");
1571 let rust2 = languages.language_for_name("Rust");
1572
1573 // Ensure language is still listed even if it's being loaded.
1574 assert_eq!(
1575 languages.language_names(),
1576 &[
1577 "JSON".to_string(),
1578 "Plain Text".to_string(),
1579 "Rust".to_string(),
1580 ]
1581 );
1582
1583 let (rust1, rust2) = futures::join!(rust1, rust2);
1584 assert!(Arc::ptr_eq(&rust1.unwrap(), &rust2.unwrap()));
1585
1586 // Ensure language is still listed even after loading it.
1587 assert_eq!(
1588 languages.language_names(),
1589 &[
1590 "JSON".to_string(),
1591 "Plain Text".to_string(),
1592 "Rust".to_string(),
1593 ]
1594 );
1595
1596 // Loading an unknown language returns an error.
1597 assert!(languages.language_for_name("Unknown").await.is_err());
1598 }
1599}