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