1mod buffer;
2mod diagnostic_set;
3mod highlight_map;
4mod outline;
5pub mod proto;
6mod syntax_map;
7#[cfg(test)]
8mod tests;
9
10use anyhow::{anyhow, Context, Result};
11use async_trait::async_trait;
12use client::http::HttpClient;
13use collections::HashMap;
14use futures::{
15 future::{BoxFuture, Shared},
16 FutureExt, TryFutureExt,
17};
18use gpui::{MutableAppContext, Task};
19use highlight_map::HighlightMap;
20use lazy_static::lazy_static;
21use parking_lot::{Mutex, RwLock};
22use postage::watch;
23use regex::Regex;
24use serde::{de, Deserialize, Deserializer};
25use serde_json::Value;
26use std::{
27 any::Any,
28 cell::RefCell,
29 mem,
30 ops::Range,
31 path::{Path, PathBuf},
32 str,
33 sync::{
34 atomic::{AtomicUsize, Ordering::SeqCst},
35 Arc,
36 },
37};
38use syntax_map::SyntaxSnapshot;
39use theme::{SyntaxTheme, Theme};
40use tree_sitter::{self, Query};
41use util::ResultExt;
42
43#[cfg(any(test, feature = "test-support"))]
44use futures::channel::mpsc;
45
46pub use buffer::Operation;
47pub use buffer::*;
48pub use diagnostic_set::DiagnosticEntry;
49pub use outline::{Outline, OutlineItem};
50pub use tree_sitter::{Parser, Tree};
51
52thread_local! {
53 static PARSER: RefCell<Parser> = RefCell::new(Parser::new());
54}
55
56lazy_static! {
57 pub static ref NEXT_GRAMMAR_ID: AtomicUsize = Default::default();
58 pub static ref PLAIN_TEXT: Arc<Language> = Arc::new(Language::new(
59 LanguageConfig {
60 name: "Plain Text".into(),
61 ..Default::default()
62 },
63 None,
64 ));
65}
66
67pub trait ToLspPosition {
68 fn to_lsp_position(self) -> lsp::Position;
69}
70
71#[derive(Clone, Debug, PartialEq, Eq, Hash)]
72pub struct LanguageServerName(pub Arc<str>);
73
74/// Represents a Language Server, with certain cached sync properties.
75/// Uses [`LspAdapter`] under the hood, but calls all 'static' methods
76/// once at startup, and caches the results.
77pub struct CachedLspAdapter {
78 pub name: LanguageServerName,
79 pub server_args: Vec<String>,
80 pub initialization_options: Option<Value>,
81 pub disk_based_diagnostic_sources: Vec<String>,
82 pub disk_based_diagnostics_progress_token: Option<String>,
83 pub language_ids: HashMap<String, String>,
84 pub adapter: Box<dyn LspAdapter>,
85}
86
87impl CachedLspAdapter {
88 pub async fn new<T: LspAdapter>(adapter: T) -> Arc<Self> {
89 let adapter = Box::new(adapter);
90 let name = adapter.name().await;
91 let server_args = adapter.server_args().await;
92 let initialization_options = adapter.initialization_options().await;
93 let disk_based_diagnostic_sources = adapter.disk_based_diagnostic_sources().await;
94 let disk_based_diagnostics_progress_token =
95 adapter.disk_based_diagnostics_progress_token().await;
96 let language_ids = adapter.language_ids().await;
97
98 Arc::new(CachedLspAdapter {
99 name,
100 server_args,
101 initialization_options,
102 disk_based_diagnostic_sources,
103 disk_based_diagnostics_progress_token,
104 language_ids,
105 adapter,
106 })
107 }
108
109 pub async fn fetch_latest_server_version(
110 &self,
111 http: Arc<dyn HttpClient>,
112 ) -> Result<Box<dyn 'static + Send + Any>> {
113 self.adapter.fetch_latest_server_version(http).await
114 }
115
116 pub async fn fetch_server_binary(
117 &self,
118 version: Box<dyn 'static + Send + Any>,
119 http: Arc<dyn HttpClient>,
120 container_dir: PathBuf,
121 ) -> Result<PathBuf> {
122 self.adapter
123 .fetch_server_binary(version, http, container_dir)
124 .await
125 }
126
127 pub async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<PathBuf> {
128 self.adapter.cached_server_binary(container_dir).await
129 }
130
131 pub async fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
132 self.adapter.process_diagnostics(params).await
133 }
134
135 pub async fn label_for_completion(
136 &self,
137 completion_item: &lsp::CompletionItem,
138 language: &Language,
139 ) -> Option<CodeLabel> {
140 self.adapter
141 .label_for_completion(completion_item, language)
142 .await
143 }
144
145 pub async fn label_for_symbol(
146 &self,
147 name: &str,
148 kind: lsp::SymbolKind,
149 language: &Language,
150 ) -> Option<CodeLabel> {
151 self.adapter.label_for_symbol(name, kind, language).await
152 }
153}
154
155#[async_trait]
156pub trait LspAdapter: 'static + Send + Sync {
157 async fn name(&self) -> LanguageServerName;
158
159 async fn fetch_latest_server_version(
160 &self,
161 http: Arc<dyn HttpClient>,
162 ) -> Result<Box<dyn 'static + Send + Any>>;
163
164 async fn fetch_server_binary(
165 &self,
166 version: Box<dyn 'static + Send + Any>,
167 http: Arc<dyn HttpClient>,
168 container_dir: PathBuf,
169 ) -> Result<PathBuf>;
170
171 async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<PathBuf>;
172
173 async fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
174
175 async fn label_for_completion(
176 &self,
177 _: &lsp::CompletionItem,
178 _: &Language,
179 ) -> Option<CodeLabel> {
180 None
181 }
182
183 async fn label_for_symbol(
184 &self,
185 _: &str,
186 _: lsp::SymbolKind,
187 _: &Language,
188 ) -> Option<CodeLabel> {
189 None
190 }
191
192 async fn server_args(&self) -> Vec<String> {
193 Vec::new()
194 }
195
196 async fn initialization_options(&self) -> Option<Value> {
197 None
198 }
199
200 async fn disk_based_diagnostic_sources(&self) -> Vec<String> {
201 Default::default()
202 }
203
204 async fn disk_based_diagnostics_progress_token(&self) -> Option<String> {
205 None
206 }
207
208 async fn language_ids(&self) -> HashMap<String, String> {
209 Default::default()
210 }
211}
212
213#[derive(Clone, Debug, PartialEq, Eq)]
214pub struct CodeLabel {
215 pub text: String,
216 pub runs: Vec<(Range<usize>, HighlightId)>,
217 pub filter_range: Range<usize>,
218}
219
220#[derive(Deserialize)]
221pub struct LanguageConfig {
222 pub name: Arc<str>,
223 pub path_suffixes: Vec<String>,
224 pub brackets: Vec<BracketPair>,
225 #[serde(default = "auto_indent_using_last_non_empty_line_default")]
226 pub auto_indent_using_last_non_empty_line: bool,
227 #[serde(default, deserialize_with = "deserialize_regex")]
228 pub increase_indent_pattern: Option<Regex>,
229 #[serde(default, deserialize_with = "deserialize_regex")]
230 pub decrease_indent_pattern: Option<Regex>,
231 #[serde(default)]
232 pub autoclose_before: String,
233 pub line_comment: Option<String>,
234}
235
236impl Default for LanguageConfig {
237 fn default() -> Self {
238 Self {
239 name: "".into(),
240 path_suffixes: Default::default(),
241 brackets: Default::default(),
242 auto_indent_using_last_non_empty_line: auto_indent_using_last_non_empty_line_default(),
243 increase_indent_pattern: Default::default(),
244 decrease_indent_pattern: Default::default(),
245 autoclose_before: Default::default(),
246 line_comment: Default::default(),
247 }
248 }
249}
250
251fn auto_indent_using_last_non_empty_line_default() -> bool {
252 true
253}
254
255fn deserialize_regex<'de, D: Deserializer<'de>>(d: D) -> Result<Option<Regex>, D::Error> {
256 let source = Option::<String>::deserialize(d)?;
257 if let Some(source) = source {
258 Ok(Some(regex::Regex::new(&source).map_err(de::Error::custom)?))
259 } else {
260 Ok(None)
261 }
262}
263
264#[cfg(any(test, feature = "test-support"))]
265pub struct FakeLspAdapter {
266 pub name: &'static str,
267 pub capabilities: lsp::ServerCapabilities,
268 pub initializer: Option<Box<dyn 'static + Send + Sync + Fn(&mut lsp::FakeLanguageServer)>>,
269 pub disk_based_diagnostics_progress_token: Option<String>,
270 pub disk_based_diagnostics_sources: Vec<String>,
271}
272
273#[derive(Clone, Debug, Deserialize)]
274pub struct BracketPair {
275 pub start: String,
276 pub end: String,
277 pub close: bool,
278 pub newline: bool,
279}
280
281pub struct Language {
282 pub(crate) config: LanguageConfig,
283 pub(crate) grammar: Option<Arc<Grammar>>,
284 pub(crate) adapter: Option<Arc<CachedLspAdapter>>,
285
286 #[cfg(any(test, feature = "test-support"))]
287 fake_adapter: Option<(
288 mpsc::UnboundedSender<lsp::FakeLanguageServer>,
289 Arc<FakeLspAdapter>,
290 )>,
291}
292
293pub struct Grammar {
294 id: usize,
295 pub(crate) ts_language: tree_sitter::Language,
296 pub(crate) highlights_query: Option<Query>,
297 pub(crate) brackets_config: Option<BracketConfig>,
298 pub(crate) indents_config: Option<IndentConfig>,
299 pub(crate) outline_config: Option<OutlineConfig>,
300 pub(crate) injection_config: Option<InjectionConfig>,
301 pub(crate) highlight_map: Mutex<HighlightMap>,
302}
303
304struct IndentConfig {
305 query: Query,
306 indent_capture_ix: u32,
307 end_capture_ix: Option<u32>,
308}
309
310struct OutlineConfig {
311 query: Query,
312 item_capture_ix: u32,
313 name_capture_ix: u32,
314 context_capture_ix: Option<u32>,
315}
316
317struct InjectionConfig {
318 query: Query,
319 content_capture_ix: u32,
320 language_capture_ix: Option<u32>,
321 languages_by_pattern_ix: Vec<Option<Box<str>>>,
322}
323
324struct BracketConfig {
325 query: Query,
326 open_capture_ix: u32,
327 close_capture_ix: u32,
328}
329
330#[derive(Clone)]
331pub enum LanguageServerBinaryStatus {
332 CheckingForUpdate,
333 Downloading,
334 Downloaded,
335 Cached,
336 Failed { error: String },
337}
338
339pub struct LanguageRegistry {
340 languages: RwLock<Vec<Arc<Language>>>,
341 language_server_download_dir: Option<Arc<Path>>,
342 lsp_binary_statuses_tx: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
343 lsp_binary_statuses_rx: async_broadcast::Receiver<(Arc<Language>, LanguageServerBinaryStatus)>,
344 login_shell_env_loaded: Shared<Task<()>>,
345 #[allow(clippy::type_complexity)]
346 lsp_binary_paths: Mutex<
347 HashMap<
348 LanguageServerName,
349 Shared<BoxFuture<'static, Result<PathBuf, Arc<anyhow::Error>>>>,
350 >,
351 >,
352 subscription: RwLock<(watch::Sender<()>, watch::Receiver<()>)>,
353 theme: RwLock<Option<Arc<Theme>>>,
354}
355
356impl LanguageRegistry {
357 pub fn new(login_shell_env_loaded: Task<()>) -> Self {
358 let (lsp_binary_statuses_tx, lsp_binary_statuses_rx) = async_broadcast::broadcast(16);
359 Self {
360 language_server_download_dir: None,
361 languages: Default::default(),
362 lsp_binary_statuses_tx,
363 lsp_binary_statuses_rx,
364 login_shell_env_loaded: login_shell_env_loaded.shared(),
365 lsp_binary_paths: Default::default(),
366 subscription: RwLock::new(watch::channel()),
367 theme: Default::default(),
368 }
369 }
370
371 #[cfg(any(test, feature = "test-support"))]
372 pub fn test() -> Self {
373 Self::new(Task::ready(()))
374 }
375
376 pub fn add(&self, language: Arc<Language>) {
377 if let Some(theme) = self.theme.read().clone() {
378 language.set_theme(&theme.editor.syntax);
379 }
380 self.languages.write().push(language);
381 *self.subscription.write().0.borrow_mut() = ();
382 }
383
384 pub fn subscribe(&self) -> watch::Receiver<()> {
385 self.subscription.read().1.clone()
386 }
387
388 pub fn set_theme(&self, theme: Arc<Theme>) {
389 *self.theme.write() = Some(theme.clone());
390 for language in self.languages.read().iter() {
391 language.set_theme(&theme.editor.syntax);
392 }
393 }
394
395 pub fn set_language_server_download_dir(&mut self, path: impl Into<Arc<Path>>) {
396 self.language_server_download_dir = Some(path.into());
397 }
398
399 pub fn get_language(&self, name: &str) -> Option<Arc<Language>> {
400 self.languages
401 .read()
402 .iter()
403 .find(|language| language.name().to_lowercase() == name.to_lowercase())
404 .cloned()
405 }
406
407 pub fn to_vec(&self) -> Vec<Arc<Language>> {
408 self.languages.read().iter().cloned().collect()
409 }
410
411 pub fn language_names(&self) -> Vec<String> {
412 self.languages
413 .read()
414 .iter()
415 .map(|language| language.name().to_string())
416 .collect()
417 }
418
419 pub fn select_language(&self, path: impl AsRef<Path>) -> Option<Arc<Language>> {
420 let path = path.as_ref();
421 let filename = path.file_name().and_then(|name| name.to_str());
422 let extension = path.extension().and_then(|name| name.to_str());
423 let path_suffixes = [extension, filename];
424 self.languages
425 .read()
426 .iter()
427 .find(|language| {
428 language
429 .config
430 .path_suffixes
431 .iter()
432 .any(|suffix| path_suffixes.contains(&Some(suffix.as_str())))
433 })
434 .cloned()
435 }
436
437 pub fn start_language_server(
438 self: &Arc<Self>,
439 server_id: usize,
440 language: Arc<Language>,
441 root_path: Arc<Path>,
442 http_client: Arc<dyn HttpClient>,
443 cx: &mut MutableAppContext,
444 ) -> Option<Task<Result<lsp::LanguageServer>>> {
445 #[cfg(any(test, feature = "test-support"))]
446 if language.fake_adapter.is_some() {
447 let language = language;
448 return Some(cx.spawn(|cx| async move {
449 let (servers_tx, fake_adapter) = language.fake_adapter.as_ref().unwrap();
450 let (server, mut fake_server) = lsp::LanguageServer::fake(
451 fake_adapter.name.to_string(),
452 fake_adapter.capabilities.clone(),
453 cx.clone(),
454 );
455
456 if let Some(initializer) = &fake_adapter.initializer {
457 initializer(&mut fake_server);
458 }
459
460 let servers_tx = servers_tx.clone();
461 cx.background()
462 .spawn(async move {
463 if fake_server
464 .try_receive_notification::<lsp::notification::Initialized>()
465 .await
466 .is_some()
467 {
468 servers_tx.unbounded_send(fake_server).ok();
469 }
470 })
471 .detach();
472 Ok(server)
473 }));
474 }
475
476 let download_dir = self
477 .language_server_download_dir
478 .clone()
479 .ok_or_else(|| anyhow!("language server download directory has not been assigned"))
480 .log_err()?;
481
482 let this = self.clone();
483 let adapter = language.adapter.clone()?;
484 let lsp_binary_statuses = self.lsp_binary_statuses_tx.clone();
485 let login_shell_env_loaded = self.login_shell_env_loaded.clone();
486 Some(cx.spawn(|cx| async move {
487 login_shell_env_loaded.await;
488 let server_binary_path = this
489 .lsp_binary_paths
490 .lock()
491 .entry(adapter.name.clone())
492 .or_insert_with(|| {
493 get_server_binary_path(
494 adapter.clone(),
495 language.clone(),
496 http_client,
497 download_dir,
498 lsp_binary_statuses,
499 )
500 .map_err(Arc::new)
501 .boxed()
502 .shared()
503 })
504 .clone()
505 .map_err(|e| anyhow!(e));
506
507 let server_binary_path = server_binary_path.await?;
508 let server_args = &adapter.server_args;
509 let server = lsp::LanguageServer::new(
510 server_id,
511 &server_binary_path,
512 server_args,
513 &root_path,
514 cx,
515 )?;
516 Ok(server)
517 }))
518 }
519
520 pub fn language_server_binary_statuses(
521 &self,
522 ) -> async_broadcast::Receiver<(Arc<Language>, LanguageServerBinaryStatus)> {
523 self.lsp_binary_statuses_rx.clone()
524 }
525}
526
527#[cfg(any(test, feature = "test-support"))]
528impl Default for LanguageRegistry {
529 fn default() -> Self {
530 Self::test()
531 }
532}
533
534async fn get_server_binary_path(
535 adapter: Arc<CachedLspAdapter>,
536 language: Arc<Language>,
537 http_client: Arc<dyn HttpClient>,
538 download_dir: Arc<Path>,
539 statuses: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
540) -> Result<PathBuf> {
541 let container_dir = download_dir.join(adapter.name.0.as_ref());
542 if !container_dir.exists() {
543 smol::fs::create_dir_all(&container_dir)
544 .await
545 .context("failed to create container directory")?;
546 }
547
548 let path = fetch_latest_server_binary_path(
549 adapter.clone(),
550 language.clone(),
551 http_client,
552 &container_dir,
553 statuses.clone(),
554 )
555 .await;
556 if let Err(error) = path.as_ref() {
557 if let Some(cached_path) = adapter.cached_server_binary(container_dir).await {
558 statuses
559 .broadcast((language.clone(), LanguageServerBinaryStatus::Cached))
560 .await?;
561 return Ok(cached_path);
562 } else {
563 statuses
564 .broadcast((
565 language.clone(),
566 LanguageServerBinaryStatus::Failed {
567 error: format!("{:?}", error),
568 },
569 ))
570 .await?;
571 }
572 }
573 path
574}
575
576async fn fetch_latest_server_binary_path(
577 adapter: Arc<CachedLspAdapter>,
578 language: Arc<Language>,
579 http_client: Arc<dyn HttpClient>,
580 container_dir: &Path,
581 lsp_binary_statuses_tx: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
582) -> Result<PathBuf> {
583 let container_dir: Arc<Path> = container_dir.into();
584 lsp_binary_statuses_tx
585 .broadcast((
586 language.clone(),
587 LanguageServerBinaryStatus::CheckingForUpdate,
588 ))
589 .await?;
590 let version_info = adapter
591 .fetch_latest_server_version(http_client.clone())
592 .await?;
593 lsp_binary_statuses_tx
594 .broadcast((language.clone(), LanguageServerBinaryStatus::Downloading))
595 .await?;
596 let path = adapter
597 .fetch_server_binary(version_info, http_client, container_dir.to_path_buf())
598 .await?;
599 lsp_binary_statuses_tx
600 .broadcast((language.clone(), LanguageServerBinaryStatus::Downloaded))
601 .await?;
602 Ok(path)
603}
604
605impl Language {
606 pub fn new(config: LanguageConfig, ts_language: Option<tree_sitter::Language>) -> Self {
607 Self {
608 config,
609 grammar: ts_language.map(|ts_language| {
610 Arc::new(Grammar {
611 id: NEXT_GRAMMAR_ID.fetch_add(1, SeqCst),
612 highlights_query: None,
613 brackets_config: None,
614 outline_config: None,
615 indents_config: None,
616 injection_config: None,
617 ts_language,
618 highlight_map: Default::default(),
619 })
620 }),
621 adapter: None,
622
623 #[cfg(any(test, feature = "test-support"))]
624 fake_adapter: None,
625 }
626 }
627
628 pub fn lsp_adapter(&self) -> Option<Arc<CachedLspAdapter>> {
629 self.adapter.clone()
630 }
631
632 pub fn with_highlights_query(mut self, source: &str) -> Result<Self> {
633 let grammar = self.grammar_mut();
634 grammar.highlights_query = Some(Query::new(grammar.ts_language, source)?);
635 Ok(self)
636 }
637
638 pub fn with_brackets_query(mut self, source: &str) -> Result<Self> {
639 let grammar = self.grammar_mut();
640 let query = Query::new(grammar.ts_language, source)?;
641 let mut open_capture_ix = None;
642 let mut close_capture_ix = None;
643 get_capture_indices(
644 &query,
645 &mut [
646 ("open", &mut open_capture_ix),
647 ("close", &mut close_capture_ix),
648 ],
649 );
650 if let Some((open_capture_ix, close_capture_ix)) = open_capture_ix.zip(close_capture_ix) {
651 grammar.brackets_config = Some(BracketConfig {
652 query,
653 open_capture_ix,
654 close_capture_ix,
655 });
656 }
657 Ok(self)
658 }
659
660 pub fn with_indents_query(mut self, source: &str) -> Result<Self> {
661 let grammar = self.grammar_mut();
662 let query = Query::new(grammar.ts_language, source)?;
663 let mut indent_capture_ix = None;
664 let mut end_capture_ix = None;
665 get_capture_indices(
666 &query,
667 &mut [
668 ("indent", &mut indent_capture_ix),
669 ("end", &mut end_capture_ix),
670 ],
671 );
672 if let Some(indent_capture_ix) = indent_capture_ix {
673 grammar.indents_config = Some(IndentConfig {
674 query,
675 indent_capture_ix,
676 end_capture_ix,
677 });
678 }
679 Ok(self)
680 }
681
682 pub fn with_outline_query(mut self, source: &str) -> Result<Self> {
683 let grammar = self.grammar_mut();
684 let query = Query::new(grammar.ts_language, source)?;
685 let mut item_capture_ix = None;
686 let mut name_capture_ix = None;
687 let mut context_capture_ix = None;
688 get_capture_indices(
689 &query,
690 &mut [
691 ("item", &mut item_capture_ix),
692 ("name", &mut name_capture_ix),
693 ("context", &mut context_capture_ix),
694 ],
695 );
696 if let Some((item_capture_ix, name_capture_ix)) = item_capture_ix.zip(name_capture_ix) {
697 grammar.outline_config = Some(OutlineConfig {
698 query,
699 item_capture_ix,
700 name_capture_ix,
701 context_capture_ix,
702 });
703 }
704 Ok(self)
705 }
706
707 pub fn with_injection_query(mut self, source: &str) -> Result<Self> {
708 let grammar = self.grammar_mut();
709 let query = Query::new(grammar.ts_language, source)?;
710 let mut language_capture_ix = None;
711 let mut content_capture_ix = None;
712 get_capture_indices(
713 &query,
714 &mut [
715 ("language", &mut language_capture_ix),
716 ("content", &mut content_capture_ix),
717 ],
718 );
719 let languages_by_pattern_ix = (0..query.pattern_count())
720 .map(|ix| {
721 query.property_settings(ix).iter().find_map(|setting| {
722 if setting.key.as_ref() == "language" {
723 return setting.value.clone();
724 } else {
725 None
726 }
727 })
728 })
729 .collect();
730 if let Some(content_capture_ix) = content_capture_ix {
731 grammar.injection_config = Some(InjectionConfig {
732 query,
733 language_capture_ix,
734 content_capture_ix,
735 languages_by_pattern_ix,
736 });
737 }
738 Ok(self)
739 }
740
741 fn grammar_mut(&mut self) -> &mut Grammar {
742 Arc::get_mut(self.grammar.as_mut().unwrap()).unwrap()
743 }
744
745 pub fn with_lsp_adapter(mut self, lsp_adapter: Arc<CachedLspAdapter>) -> Self {
746 self.adapter = Some(lsp_adapter);
747 self
748 }
749
750 #[cfg(any(test, feature = "test-support"))]
751 pub async fn set_fake_lsp_adapter(
752 &mut self,
753 fake_lsp_adapter: Arc<FakeLspAdapter>,
754 ) -> mpsc::UnboundedReceiver<lsp::FakeLanguageServer> {
755 let (servers_tx, servers_rx) = mpsc::unbounded();
756 self.fake_adapter = Some((servers_tx, fake_lsp_adapter.clone()));
757 let adapter = CachedLspAdapter::new(fake_lsp_adapter).await;
758 self.adapter = Some(adapter);
759 servers_rx
760 }
761
762 pub fn name(&self) -> Arc<str> {
763 self.config.name.clone()
764 }
765
766 pub fn line_comment_prefix(&self) -> Option<&str> {
767 self.config.line_comment.as_deref()
768 }
769
770 pub async fn disk_based_diagnostic_sources(&self) -> &[String] {
771 match self.adapter.as_ref() {
772 Some(adapter) => &adapter.disk_based_diagnostic_sources,
773 None => &[],
774 }
775 }
776
777 pub async fn disk_based_diagnostics_progress_token(&self) -> Option<&str> {
778 if let Some(adapter) = self.adapter.as_ref() {
779 adapter.disk_based_diagnostics_progress_token.as_deref()
780 } else {
781 None
782 }
783 }
784
785 pub async fn process_diagnostics(&self, diagnostics: &mut lsp::PublishDiagnosticsParams) {
786 if let Some(processor) = self.adapter.as_ref() {
787 processor.process_diagnostics(diagnostics).await;
788 }
789 }
790
791 pub async fn label_for_completion(
792 &self,
793 completion: &lsp::CompletionItem,
794 ) -> Option<CodeLabel> {
795 self.adapter
796 .as_ref()?
797 .label_for_completion(completion, self)
798 .await
799 }
800
801 pub async fn label_for_symbol(&self, name: &str, kind: lsp::SymbolKind) -> Option<CodeLabel> {
802 self.adapter
803 .as_ref()?
804 .label_for_symbol(name, kind, self)
805 .await
806 }
807
808 pub fn highlight_text<'a>(
809 &'a self,
810 text: &'a Rope,
811 range: Range<usize>,
812 ) -> Vec<(Range<usize>, HighlightId)> {
813 let mut result = Vec::new();
814 if let Some(grammar) = &self.grammar {
815 let tree = grammar.parse_text(text, None);
816 let captures = SyntaxSnapshot::single_tree_captures(
817 range.clone(),
818 text,
819 &tree,
820 grammar,
821 |grammar| grammar.highlights_query.as_ref(),
822 );
823 let highlight_maps = vec![grammar.highlight_map()];
824 let mut offset = 0;
825 for chunk in BufferChunks::new(text, range, Some((captures, highlight_maps)), vec![]) {
826 let end_offset = offset + chunk.text.len();
827 if let Some(highlight_id) = chunk.syntax_highlight_id {
828 if !highlight_id.is_default() {
829 result.push((offset..end_offset, highlight_id));
830 }
831 }
832 offset = end_offset;
833 }
834 }
835 result
836 }
837
838 pub fn brackets(&self) -> &[BracketPair] {
839 &self.config.brackets
840 }
841
842 pub fn path_suffixes(&self) -> &[String] {
843 &self.config.path_suffixes
844 }
845
846 pub fn should_autoclose_before(&self, c: char) -> bool {
847 c.is_whitespace() || self.config.autoclose_before.contains(c)
848 }
849
850 pub fn set_theme(&self, theme: &SyntaxTheme) {
851 if let Some(grammar) = self.grammar.as_ref() {
852 if let Some(highlights_query) = &grammar.highlights_query {
853 *grammar.highlight_map.lock() =
854 HighlightMap::new(highlights_query.capture_names(), theme);
855 }
856 }
857 }
858
859 pub fn grammar(&self) -> Option<&Arc<Grammar>> {
860 self.grammar.as_ref()
861 }
862}
863
864impl Grammar {
865 pub fn id(&self) -> usize {
866 self.id
867 }
868
869 fn parse_text(&self, text: &Rope, old_tree: Option<Tree>) -> Tree {
870 PARSER.with(|parser| {
871 let mut parser = parser.borrow_mut();
872 parser
873 .set_language(self.ts_language)
874 .expect("incompatible grammar");
875 let mut chunks = text.chunks_in_range(0..text.len());
876 parser
877 .parse_with(
878 &mut move |offset, _| {
879 chunks.seek(offset);
880 chunks.next().unwrap_or("").as_bytes()
881 },
882 old_tree.as_ref(),
883 )
884 .unwrap()
885 })
886 }
887
888 pub fn highlight_map(&self) -> HighlightMap {
889 self.highlight_map.lock().clone()
890 }
891
892 pub fn highlight_id_for_name(&self, name: &str) -> Option<HighlightId> {
893 let capture_id = self
894 .highlights_query
895 .as_ref()?
896 .capture_index_for_name(name)?;
897 Some(self.highlight_map.lock().get(capture_id))
898 }
899}
900
901impl CodeLabel {
902 pub fn plain(text: String, filter_text: Option<&str>) -> Self {
903 let mut result = Self {
904 runs: Vec::new(),
905 filter_range: 0..text.len(),
906 text,
907 };
908 if let Some(filter_text) = filter_text {
909 if let Some(ix) = result.text.find(filter_text) {
910 result.filter_range = ix..ix + filter_text.len();
911 }
912 }
913 result
914 }
915}
916
917#[cfg(any(test, feature = "test-support"))]
918impl Default for FakeLspAdapter {
919 fn default() -> Self {
920 Self {
921 name: "the-fake-language-server",
922 capabilities: lsp::LanguageServer::full_capabilities(),
923 initializer: None,
924 disk_based_diagnostics_progress_token: None,
925 disk_based_diagnostics_sources: Vec::new(),
926 }
927 }
928}
929
930#[cfg(any(test, feature = "test-support"))]
931#[async_trait]
932impl LspAdapter for Arc<FakeLspAdapter> {
933 async fn name(&self) -> LanguageServerName {
934 LanguageServerName(self.name.into())
935 }
936
937 async fn fetch_latest_server_version(
938 &self,
939 _: Arc<dyn HttpClient>,
940 ) -> Result<Box<dyn 'static + Send + Any>> {
941 unreachable!();
942 }
943
944 async fn fetch_server_binary(
945 &self,
946 _: Box<dyn 'static + Send + Any>,
947 _: Arc<dyn HttpClient>,
948 _: PathBuf,
949 ) -> Result<PathBuf> {
950 unreachable!();
951 }
952
953 async fn cached_server_binary(&self, _: PathBuf) -> Option<PathBuf> {
954 unreachable!();
955 }
956
957 async fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
958
959 async fn disk_based_diagnostic_sources(&self) -> Vec<String> {
960 self.disk_based_diagnostics_sources.clone()
961 }
962
963 async fn disk_based_diagnostics_progress_token(&self) -> Option<String> {
964 self.disk_based_diagnostics_progress_token.clone()
965 }
966}
967
968fn get_capture_indices(query: &Query, captures: &mut [(&str, &mut Option<u32>)]) {
969 for (ix, name) in query.capture_names().iter().enumerate() {
970 for (capture_name, index) in captures.iter_mut() {
971 if capture_name == name {
972 **index = Some(ix as u32);
973 break;
974 }
975 }
976 }
977}
978
979pub fn point_to_lsp(point: PointUtf16) -> lsp::Position {
980 lsp::Position::new(point.row, point.column)
981}
982
983pub fn point_from_lsp(point: lsp::Position) -> PointUtf16 {
984 PointUtf16::new(point.line, point.character)
985}
986
987pub fn range_to_lsp(range: Range<PointUtf16>) -> lsp::Range {
988 lsp::Range {
989 start: point_to_lsp(range.start),
990 end: point_to_lsp(range.end),
991 }
992}
993
994pub fn range_from_lsp(range: lsp::Range) -> Range<PointUtf16> {
995 let mut start = point_from_lsp(range.start);
996 let mut end = point_from_lsp(range.end);
997 if start > end {
998 mem::swap(&mut start, &mut end);
999 }
1000 start..end
1001}