1//! The `language` crate provides a large chunk of Zed's language-related
2//! features (the other big contributors being project and lsp crates that revolve around LSP features).
3//! Namely, this crate:
4//! - Provides [`Language`], [`Grammar`] and [`LanguageRegistry`] types that
5//! use Tree-sitter to provide syntax highlighting to the editor; note though that `language` doesn't perform the highlighting by itself. It only maps ranges in a buffer to colors. Treesitter is also used for buffer outlines (lists of symbols in a buffer)
6//! - Exposes [`LanguageConfig`] that describes how constructs (like brackets or line comments) should be handled by the editor for a source file of a particular language.
7//!
8//! Notably we do *not* assign a single language to a single file; in real world a single file can consist of multiple programming languages - HTML is a good example of that - and `language` crate tends to reflect that status quo in its API.
9mod buffer;
10mod diagnostic;
11mod diagnostic_set;
12mod language_registry;
13
14pub mod language_settings;
15mod manifest;
16pub mod modeline;
17mod outline;
18pub mod proto;
19mod syntax_map;
20mod task_context;
21mod text_diff;
22mod toolchain;
23
24#[cfg(test)]
25pub mod buffer_tests;
26
27pub use crate::language_settings::{AutoIndentMode, EditPredictionsMode, IndentGuideSettings};
28use anyhow::{Context as _, Result};
29use async_trait::async_trait;
30use collections::{HashMap, HashSet};
31use futures::Future;
32use futures::future::LocalBoxFuture;
33use futures::lock::OwnedMutexGuard;
34use gpui::{App, AsyncApp, Entity};
35use http_client::HttpClient;
36
37pub use language_core::highlight_map::{HighlightId, HighlightMap};
38
39pub use language_core::{
40 BlockCommentConfig, BracketPair, BracketPairConfig, BracketPairContent, BracketsConfig,
41 BracketsPatternConfig, CodeLabel, CodeLabelBuilder, DebugVariablesConfig, DebuggerTextObject,
42 DecreaseIndentConfig, Grammar, GrammarId, HighlightsConfig, ImportsConfig, IndentConfig,
43 InjectionConfig, InjectionPatternConfig, JsxTagAutoCloseConfig, LanguageConfig,
44 LanguageConfigOverride, LanguageId, LanguageMatcher, OrderedListConfig, OutlineConfig,
45 Override, OverrideConfig, OverrideEntry, PromptResponseContext, RedactionConfig,
46 RunnableCapture, RunnableConfig, SoftWrap, Symbol, TaskListConfig, TextObject,
47 TextObjectConfig, ToLspPosition, WrapCharactersConfig,
48 auto_indent_using_last_non_empty_line_default, deserialize_regex, deserialize_regex_vec,
49 regex_json_schema, regex_vec_json_schema, serialize_regex,
50};
51pub use language_registry::{
52 LanguageName, LanguageServerStatusUpdate, LoadedLanguage, ServerHealth,
53};
54use lsp::{
55 CodeActionKind, InitializeParams, LanguageServerBinary, LanguageServerBinaryOptions, Uri,
56};
57pub use manifest::{ManifestDelegate, ManifestName, ManifestProvider, ManifestQuery};
58pub use modeline::{ModelineSettings, parse_modeline};
59use parking_lot::Mutex;
60use regex::Regex;
61use semver::Version;
62use serde_json::Value;
63use settings::WorktreeId;
64use smol::future::FutureExt as _;
65use std::{
66 ffi::OsStr,
67 fmt::Debug,
68 hash::Hash,
69 mem,
70 ops::{DerefMut, Range},
71 path::{Path, PathBuf},
72 str,
73 sync::{Arc, LazyLock},
74};
75use syntax_map::{QueryCursorHandle, SyntaxSnapshot};
76use task::RunnableTag;
77pub use task_context::{ContextLocation, ContextProvider, RunnableRange};
78pub use text_diff::{
79 DiffOptions, apply_diff_patch, apply_reversed_diff_patch, char_diff, line_diff, text_diff,
80 text_diff_with_options, unified_diff, unified_diff_with_context, unified_diff_with_offsets,
81 word_diff_ranges,
82};
83use theme::SyntaxTheme;
84pub use toolchain::{
85 LanguageToolchainStore, LocalLanguageToolchainStore, Toolchain, ToolchainList, ToolchainLister,
86 ToolchainMetadata, ToolchainScope,
87};
88use tree_sitter::{self, QueryCursor, WasmStore, wasmtime};
89use util::rel_path::RelPath;
90
91pub use buffer::Operation;
92pub use buffer::*;
93pub use diagnostic::{Diagnostic, DiagnosticSourceKind};
94pub use diagnostic_set::{DiagnosticEntry, DiagnosticEntryRef, DiagnosticGroup};
95pub use language_registry::{
96 AvailableLanguage, BinaryStatus, LanguageNotFound, LanguageQueries, LanguageRegistry,
97 QUERY_FILENAME_PREFIXES,
98};
99pub use lsp::{LanguageServerId, LanguageServerName};
100pub use outline::*;
101pub use syntax_map::{
102 OwnedSyntaxLayer, SyntaxLayer, SyntaxMapMatches, ToTreeSitterPoint, TreeSitterOptions,
103};
104pub use text::{AnchorRangeExt, LineEnding};
105pub use tree_sitter::{Node, Parser, Tree, TreeCursor};
106
107pub(crate) fn to_settings_soft_wrap(value: language_core::SoftWrap) -> settings::SoftWrap {
108 match value {
109 language_core::SoftWrap::None => settings::SoftWrap::None,
110 language_core::SoftWrap::PreferLine => settings::SoftWrap::PreferLine,
111 language_core::SoftWrap::EditorWidth => settings::SoftWrap::EditorWidth,
112 language_core::SoftWrap::PreferredLineLength => settings::SoftWrap::PreferredLineLength,
113 language_core::SoftWrap::Bounded => settings::SoftWrap::Bounded,
114 }
115}
116
117static QUERY_CURSORS: Mutex<Vec<QueryCursor>> = Mutex::new(vec![]);
118static PARSERS: Mutex<Vec<Parser>> = Mutex::new(vec![]);
119
120#[ztracing::instrument(skip_all)]
121pub fn with_parser<F, R>(func: F) -> R
122where
123 F: FnOnce(&mut Parser) -> R,
124{
125 let mut parser = PARSERS.lock().pop().unwrap_or_else(|| {
126 let mut parser = Parser::new();
127 parser
128 .set_wasm_store(WasmStore::new(&WASM_ENGINE).unwrap())
129 .unwrap();
130 parser
131 });
132 parser.set_included_ranges(&[]).unwrap();
133 let result = func(&mut parser);
134 PARSERS.lock().push(parser);
135 result
136}
137
138pub fn with_query_cursor<F, R>(func: F) -> R
139where
140 F: FnOnce(&mut QueryCursor) -> R,
141{
142 let mut cursor = QueryCursorHandle::new();
143 func(cursor.deref_mut())
144}
145
146static WASM_ENGINE: LazyLock<wasmtime::Engine> = LazyLock::new(|| {
147 wasmtime::Engine::new(&wasmtime::Config::new()).expect("Failed to create Wasmtime engine")
148});
149
150/// A shared grammar for plain text, exposed for reuse by downstream crates.
151pub static PLAIN_TEXT: LazyLock<Arc<Language>> = LazyLock::new(|| {
152 Arc::new(Language::new(
153 LanguageConfig {
154 name: "Plain Text".into(),
155 soft_wrap: Some(SoftWrap::EditorWidth),
156 matcher: LanguageMatcher {
157 path_suffixes: vec!["txt".to_owned()],
158 first_line_pattern: None,
159 modeline_aliases: vec!["text".to_owned(), "txt".to_owned()],
160 },
161 brackets: BracketPairConfig {
162 pairs: vec![
163 BracketPair {
164 start: "(".to_string(),
165 end: ")".to_string(),
166 close: true,
167 surround: true,
168 newline: false,
169 },
170 BracketPair {
171 start: "[".to_string(),
172 end: "]".to_string(),
173 close: true,
174 surround: true,
175 newline: false,
176 },
177 BracketPair {
178 start: "{".to_string(),
179 end: "}".to_string(),
180 close: true,
181 surround: true,
182 newline: false,
183 },
184 BracketPair {
185 start: "\"".to_string(),
186 end: "\"".to_string(),
187 close: true,
188 surround: true,
189 newline: false,
190 },
191 BracketPair {
192 start: "'".to_string(),
193 end: "'".to_string(),
194 close: true,
195 surround: true,
196 newline: false,
197 },
198 ],
199 disabled_scopes_by_bracket_ix: Default::default(),
200 },
201 ..Default::default()
202 },
203 None,
204 ))
205});
206
207#[derive(Debug, Clone, PartialEq, Eq, Hash)]
208pub struct Location {
209 pub buffer: Entity<Buffer>,
210 pub range: Range<Anchor>,
211}
212
213type ServerBinaryCache = futures::lock::Mutex<Option<(bool, LanguageServerBinary)>>;
214type DownloadableLanguageServerBinary = LocalBoxFuture<'static, Result<LanguageServerBinary>>;
215pub type LanguageServerBinaryLocations = LocalBoxFuture<
216 'static,
217 (
218 Result<LanguageServerBinary>,
219 Option<DownloadableLanguageServerBinary>,
220 ),
221>;
222/// Represents a Language Server, with certain cached sync properties.
223/// Uses [`LspAdapter`] under the hood, but calls all 'static' methods
224/// once at startup, and caches the results.
225pub struct CachedLspAdapter {
226 pub name: LanguageServerName,
227 pub disk_based_diagnostic_sources: Vec<String>,
228 pub disk_based_diagnostics_progress_token: Option<String>,
229 language_ids: HashMap<LanguageName, String>,
230 pub adapter: Arc<dyn LspAdapter>,
231 cached_binary: Arc<ServerBinaryCache>,
232}
233
234impl Debug for CachedLspAdapter {
235 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236 f.debug_struct("CachedLspAdapter")
237 .field("name", &self.name)
238 .field(
239 "disk_based_diagnostic_sources",
240 &self.disk_based_diagnostic_sources,
241 )
242 .field(
243 "disk_based_diagnostics_progress_token",
244 &self.disk_based_diagnostics_progress_token,
245 )
246 .field("language_ids", &self.language_ids)
247 .finish_non_exhaustive()
248 }
249}
250
251impl CachedLspAdapter {
252 pub fn new(adapter: Arc<dyn LspAdapter>) -> Arc<Self> {
253 let name = adapter.name();
254 let disk_based_diagnostic_sources = adapter.disk_based_diagnostic_sources();
255 let disk_based_diagnostics_progress_token = adapter.disk_based_diagnostics_progress_token();
256 let language_ids = adapter.language_ids();
257
258 Arc::new(CachedLspAdapter {
259 name,
260 disk_based_diagnostic_sources,
261 disk_based_diagnostics_progress_token,
262 language_ids,
263 adapter,
264 cached_binary: Default::default(),
265 })
266 }
267
268 pub fn name(&self) -> LanguageServerName {
269 self.adapter.name()
270 }
271
272 pub async fn get_language_server_command(
273 self: Arc<Self>,
274 delegate: Arc<dyn LspAdapterDelegate>,
275 toolchains: Option<Toolchain>,
276 binary_options: LanguageServerBinaryOptions,
277 cx: &mut AsyncApp,
278 ) -> LanguageServerBinaryLocations {
279 let cached_binary = self.cached_binary.clone().lock_owned().await;
280 self.adapter.clone().get_language_server_command(
281 delegate,
282 toolchains,
283 binary_options,
284 cached_binary,
285 cx.clone(),
286 )
287 }
288
289 pub fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
290 self.adapter.code_action_kinds()
291 }
292
293 pub fn process_diagnostics(
294 &self,
295 params: &mut lsp::PublishDiagnosticsParams,
296 server_id: LanguageServerId,
297 ) {
298 self.adapter.process_diagnostics(params, server_id)
299 }
300
301 pub fn retain_old_diagnostic(&self, previous_diagnostic: &Diagnostic) -> bool {
302 self.adapter.retain_old_diagnostic(previous_diagnostic)
303 }
304
305 pub fn underline_diagnostic(&self, diagnostic: &lsp::Diagnostic) -> bool {
306 self.adapter.underline_diagnostic(diagnostic)
307 }
308
309 pub fn diagnostic_message_to_markdown(&self, message: &str) -> Option<String> {
310 self.adapter.diagnostic_message_to_markdown(message)
311 }
312
313 pub async fn process_completions(&self, completion_items: &mut [lsp::CompletionItem]) {
314 self.adapter.process_completions(completion_items).await
315 }
316
317 pub async fn labels_for_completions(
318 &self,
319 completion_items: &[lsp::CompletionItem],
320 language: &Arc<Language>,
321 ) -> Result<Vec<Option<CodeLabel>>> {
322 self.adapter
323 .clone()
324 .labels_for_completions(completion_items, language)
325 .await
326 }
327
328 pub async fn labels_for_symbols(
329 &self,
330 symbols: &[Symbol],
331 language: &Arc<Language>,
332 ) -> Result<Vec<Option<CodeLabel>>> {
333 self.adapter
334 .clone()
335 .labels_for_symbols(symbols, language)
336 .await
337 }
338
339 pub fn language_id(&self, language_name: &LanguageName) -> String {
340 self.language_ids
341 .get(language_name)
342 .cloned()
343 .unwrap_or_else(|| language_name.lsp_id())
344 }
345
346 pub async fn initialization_options_schema(
347 &self,
348 delegate: &Arc<dyn LspAdapterDelegate>,
349 cx: &mut AsyncApp,
350 ) -> Option<serde_json::Value> {
351 self.adapter
352 .clone()
353 .initialization_options_schema(
354 delegate,
355 self.cached_binary.clone().lock_owned().await,
356 cx,
357 )
358 .await
359 }
360
361 pub async fn settings_schema(
362 &self,
363 delegate: &Arc<dyn LspAdapterDelegate>,
364 cx: &mut AsyncApp,
365 ) -> Option<serde_json::Value> {
366 self.adapter
367 .clone()
368 .settings_schema(delegate, self.cached_binary.clone().lock_owned().await, cx)
369 .await
370 }
371
372 pub fn process_prompt_response(&self, context: &PromptResponseContext, cx: &mut AsyncApp) {
373 self.adapter.process_prompt_response(context, cx)
374 }
375}
376
377/// [`LspAdapterDelegate`] allows [`LspAdapter]` implementations to interface with the application
378// e.g. to display a notification or fetch data from the web.
379#[async_trait]
380pub trait LspAdapterDelegate: Send + Sync {
381 fn show_notification(&self, message: &str, cx: &mut App);
382 fn http_client(&self) -> Arc<dyn HttpClient>;
383 fn worktree_id(&self) -> WorktreeId;
384 fn worktree_root_path(&self) -> &Path;
385 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf;
386 fn update_status(&self, language: LanguageServerName, status: BinaryStatus);
387 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>>;
388 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>>;
389
390 async fn npm_package_installed_version(
391 &self,
392 package_name: &str,
393 ) -> Result<Option<(PathBuf, Version)>>;
394 async fn which(&self, command: &OsStr) -> Option<PathBuf>;
395 async fn shell_env(&self) -> HashMap<String, String>;
396 async fn read_text_file(&self, path: &RelPath) -> Result<String>;
397 async fn try_exec(&self, binary: LanguageServerBinary) -> Result<()>;
398}
399
400#[async_trait(?Send)]
401pub trait LspAdapter: 'static + Send + Sync + DynLspInstaller {
402 fn name(&self) -> LanguageServerName;
403
404 fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams, _: LanguageServerId) {}
405
406 /// When processing new `lsp::PublishDiagnosticsParams` diagnostics, whether to retain previous one(s) or not.
407 fn retain_old_diagnostic(&self, _previous_diagnostic: &Diagnostic) -> bool {
408 false
409 }
410
411 /// Whether to underline a given diagnostic or not, when rendering in the editor.
412 ///
413 /// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnosticTag
414 /// states that
415 /// > Clients are allowed to render diagnostics with this tag faded out instead of having an error squiggle.
416 /// for the unnecessary diagnostics, so do not underline them.
417 fn underline_diagnostic(&self, _diagnostic: &lsp::Diagnostic) -> bool {
418 true
419 }
420
421 /// Post-processes completions provided by the language server.
422 async fn process_completions(&self, _: &mut [lsp::CompletionItem]) {}
423
424 fn diagnostic_message_to_markdown(&self, _message: &str) -> Option<String> {
425 None
426 }
427
428 async fn labels_for_completions(
429 self: Arc<Self>,
430 completions: &[lsp::CompletionItem],
431 language: &Arc<Language>,
432 ) -> Result<Vec<Option<CodeLabel>>> {
433 let mut labels = Vec::new();
434 for (ix, completion) in completions.iter().enumerate() {
435 let label = self.label_for_completion(completion, language).await;
436 if let Some(label) = label {
437 labels.resize(ix + 1, None);
438 *labels.last_mut().unwrap() = Some(label);
439 }
440 }
441 Ok(labels)
442 }
443
444 async fn label_for_completion(
445 &self,
446 _: &lsp::CompletionItem,
447 _: &Arc<Language>,
448 ) -> Option<CodeLabel> {
449 None
450 }
451
452 async fn labels_for_symbols(
453 self: Arc<Self>,
454 symbols: &[Symbol],
455 language: &Arc<Language>,
456 ) -> Result<Vec<Option<CodeLabel>>> {
457 let mut labels = Vec::new();
458 for (ix, symbol) in symbols.iter().enumerate() {
459 let label = self.label_for_symbol(symbol, language).await;
460 if let Some(label) = label {
461 labels.resize(ix + 1, None);
462 *labels.last_mut().unwrap() = Some(label);
463 }
464 }
465 Ok(labels)
466 }
467
468 async fn label_for_symbol(
469 &self,
470 _symbol: &Symbol,
471 _language: &Arc<Language>,
472 ) -> Option<CodeLabel> {
473 None
474 }
475
476 /// Returns initialization options that are going to be sent to a LSP server as a part of [`lsp::InitializeParams`]
477 async fn initialization_options(
478 self: Arc<Self>,
479 _: &Arc<dyn LspAdapterDelegate>,
480 _cx: &mut AsyncApp,
481 ) -> Result<Option<Value>> {
482 Ok(None)
483 }
484
485 /// Returns the JSON schema of the initialization_options for the language server.
486 async fn initialization_options_schema(
487 self: Arc<Self>,
488 _delegate: &Arc<dyn LspAdapterDelegate>,
489 _cached_binary: OwnedMutexGuard<Option<(bool, LanguageServerBinary)>>,
490 _cx: &mut AsyncApp,
491 ) -> Option<serde_json::Value> {
492 None
493 }
494
495 /// Returns the JSON schema of the settings for the language server.
496 /// This corresponds to the `settings` field in `LspSettings`, which is used
497 /// to respond to `workspace/configuration` requests from the language server.
498 async fn settings_schema(
499 self: Arc<Self>,
500 _delegate: &Arc<dyn LspAdapterDelegate>,
501 _cached_binary: OwnedMutexGuard<Option<(bool, LanguageServerBinary)>>,
502 _cx: &mut AsyncApp,
503 ) -> Option<serde_json::Value> {
504 None
505 }
506
507 async fn workspace_configuration(
508 self: Arc<Self>,
509 _: &Arc<dyn LspAdapterDelegate>,
510 _: Option<Toolchain>,
511 _: Option<Uri>,
512 _cx: &mut AsyncApp,
513 ) -> Result<Value> {
514 Ok(serde_json::json!({}))
515 }
516
517 async fn additional_initialization_options(
518 self: Arc<Self>,
519 _target_language_server_id: LanguageServerName,
520 _: &Arc<dyn LspAdapterDelegate>,
521 ) -> Result<Option<Value>> {
522 Ok(None)
523 }
524
525 async fn additional_workspace_configuration(
526 self: Arc<Self>,
527 _target_language_server_id: LanguageServerName,
528 _: &Arc<dyn LspAdapterDelegate>,
529 _cx: &mut AsyncApp,
530 ) -> Result<Option<Value>> {
531 Ok(None)
532 }
533
534 /// Returns a list of code actions supported by a given LspAdapter
535 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
536 None
537 }
538
539 fn disk_based_diagnostic_sources(&self) -> Vec<String> {
540 Default::default()
541 }
542
543 fn disk_based_diagnostics_progress_token(&self) -> Option<String> {
544 None
545 }
546
547 fn language_ids(&self) -> HashMap<LanguageName, String> {
548 HashMap::default()
549 }
550
551 /// Support custom initialize params.
552 fn prepare_initialize_params(
553 &self,
554 original: InitializeParams,
555 _: &App,
556 ) -> Result<InitializeParams> {
557 Ok(original)
558 }
559
560 /// Method only implemented by the default JSON language server adapter.
561 /// Used to provide dynamic reloading of the JSON schemas used to
562 /// provide autocompletion and diagnostics in Zed setting and keybind
563 /// files
564 fn is_primary_zed_json_schema_adapter(&self) -> bool {
565 false
566 }
567
568 /// True for the extension adapter and false otherwise.
569 fn is_extension(&self) -> bool {
570 false
571 }
572
573 /// Called when a user responds to a ShowMessageRequest from this language server.
574 /// This allows adapters to intercept preference selections (like "Always" or "Never")
575 /// for settings that should be persisted to Zed's settings file.
576 fn process_prompt_response(&self, _context: &PromptResponseContext, _cx: &mut AsyncApp) {}
577}
578
579pub trait LspInstaller {
580 type BinaryVersion;
581 fn check_if_user_installed(
582 &self,
583 _: &dyn LspAdapterDelegate,
584 _: Option<Toolchain>,
585 _: &AsyncApp,
586 ) -> impl Future<Output = Option<LanguageServerBinary>> {
587 async { None }
588 }
589
590 fn fetch_latest_server_version(
591 &self,
592 delegate: &dyn LspAdapterDelegate,
593 pre_release: bool,
594 cx: &mut AsyncApp,
595 ) -> impl Future<Output = Result<Self::BinaryVersion>>;
596
597 fn check_if_version_installed(
598 &self,
599 _version: &Self::BinaryVersion,
600 _container_dir: &PathBuf,
601 _delegate: &dyn LspAdapterDelegate,
602 ) -> impl Send + Future<Output = Option<LanguageServerBinary>> {
603 async { None }
604 }
605
606 fn fetch_server_binary(
607 &self,
608 latest_version: Self::BinaryVersion,
609 container_dir: PathBuf,
610 delegate: &dyn LspAdapterDelegate,
611 ) -> impl Send + Future<Output = Result<LanguageServerBinary>>;
612
613 fn cached_server_binary(
614 &self,
615 container_dir: PathBuf,
616 delegate: &dyn LspAdapterDelegate,
617 ) -> impl Future<Output = Option<LanguageServerBinary>>;
618}
619
620#[async_trait(?Send)]
621pub trait DynLspInstaller {
622 async fn try_fetch_server_binary(
623 &self,
624 delegate: &Arc<dyn LspAdapterDelegate>,
625 container_dir: PathBuf,
626 pre_release: bool,
627 cx: &mut AsyncApp,
628 ) -> Result<LanguageServerBinary>;
629
630 fn get_language_server_command(
631 self: Arc<Self>,
632 delegate: Arc<dyn LspAdapterDelegate>,
633 toolchains: Option<Toolchain>,
634 binary_options: LanguageServerBinaryOptions,
635 cached_binary: OwnedMutexGuard<Option<(bool, LanguageServerBinary)>>,
636 cx: AsyncApp,
637 ) -> LanguageServerBinaryLocations;
638}
639
640#[async_trait(?Send)]
641impl<LI, BinaryVersion> DynLspInstaller for LI
642where
643 BinaryVersion: Send + Sync,
644 LI: LspInstaller<BinaryVersion = BinaryVersion> + LspAdapter,
645{
646 async fn try_fetch_server_binary(
647 &self,
648 delegate: &Arc<dyn LspAdapterDelegate>,
649 container_dir: PathBuf,
650 pre_release: bool,
651 cx: &mut AsyncApp,
652 ) -> Result<LanguageServerBinary> {
653 let name = self.name();
654
655 log::debug!("fetching latest version of language server {:?}", name.0);
656 delegate.update_status(name.clone(), BinaryStatus::CheckingForUpdate);
657
658 let latest_version = self
659 .fetch_latest_server_version(delegate.as_ref(), pre_release, cx)
660 .await?;
661
662 if let Some(binary) = cx
663 .background_executor()
664 .await_on_background(self.check_if_version_installed(
665 &latest_version,
666 &container_dir,
667 delegate.as_ref(),
668 ))
669 .await
670 {
671 log::debug!("language server {:?} is already installed", name.0);
672 delegate.update_status(name.clone(), BinaryStatus::None);
673 Ok(binary)
674 } else {
675 log::debug!("downloading language server {:?}", name.0);
676 delegate.update_status(name.clone(), BinaryStatus::Downloading);
677 let binary = cx
678 .background_executor()
679 .await_on_background(self.fetch_server_binary(
680 latest_version,
681 container_dir,
682 delegate.as_ref(),
683 ))
684 .await;
685
686 delegate.update_status(name.clone(), BinaryStatus::None);
687 binary
688 }
689 }
690 fn get_language_server_command(
691 self: Arc<Self>,
692 delegate: Arc<dyn LspAdapterDelegate>,
693 toolchain: Option<Toolchain>,
694 binary_options: LanguageServerBinaryOptions,
695 mut cached_binary: OwnedMutexGuard<Option<(bool, LanguageServerBinary)>>,
696 mut cx: AsyncApp,
697 ) -> LanguageServerBinaryLocations {
698 async move {
699 let cached_binary_deref = cached_binary.deref_mut();
700 // First we check whether the adapter can give us a user-installed binary.
701 // If so, we do *not* want to cache that, because each worktree might give us a different
702 // binary:
703 //
704 // worktree 1: user-installed at `.bin/gopls`
705 // worktree 2: user-installed at `~/bin/gopls`
706 // worktree 3: no gopls found in PATH -> fallback to Zed installation
707 //
708 // We only want to cache when we fall back to the global one,
709 // because we don't want to download and overwrite our global one
710 // for each worktree we might have open.
711 if binary_options.allow_path_lookup
712 && let Some(binary) = self
713 .check_if_user_installed(delegate.as_ref(), toolchain, &mut cx)
714 .await
715 {
716 log::info!(
717 "found user-installed language server for {}. path: {:?}, arguments: {:?}",
718 self.name().0,
719 binary.path,
720 binary.arguments
721 );
722 return (Ok(binary), None);
723 }
724
725 if let Some((pre_release, cached_binary)) = cached_binary_deref
726 && *pre_release == binary_options.pre_release
727 {
728 return (Ok(cached_binary.clone()), None);
729 }
730
731 if !binary_options.allow_binary_download {
732 return (
733 Err(anyhow::anyhow!("downloading language servers disabled")),
734 None,
735 );
736 }
737
738 let Some(container_dir) = delegate.language_server_download_dir(&self.name()).await
739 else {
740 return (
741 Err(anyhow::anyhow!("no language server download dir defined")),
742 None,
743 );
744 };
745
746 let last_downloaded_binary = self
747 .cached_server_binary(container_dir.to_path_buf(), delegate.as_ref())
748 .await
749 .context(
750 "did not find existing language server binary, falling back to downloading",
751 );
752 let download_binary = async move {
753 let mut binary = self
754 .try_fetch_server_binary(
755 &delegate,
756 container_dir.to_path_buf(),
757 binary_options.pre_release,
758 &mut cx,
759 )
760 .await;
761
762 if let Err(error) = binary.as_ref() {
763 if let Some(prev_downloaded_binary) = self
764 .cached_server_binary(container_dir.to_path_buf(), delegate.as_ref())
765 .await
766 {
767 log::info!(
768 "failed to fetch newest version of language server {:?}. \
769 error: {:?}, falling back to using {:?}",
770 self.name(),
771 error,
772 prev_downloaded_binary.path
773 );
774 binary = Ok(prev_downloaded_binary);
775 } else {
776 delegate.update_status(
777 self.name(),
778 BinaryStatus::Failed {
779 error: format!("{error:?}"),
780 },
781 );
782 }
783 }
784
785 if let Ok(binary) = &binary {
786 *cached_binary = Some((binary_options.pre_release, binary.clone()));
787 }
788
789 binary
790 }
791 .boxed_local();
792 (last_downloaded_binary, Some(download_binary))
793 }
794 .boxed_local()
795 }
796}
797
798/// Represents a language for the given range. Some languages (e.g. HTML)
799/// interleave several languages together, thus a single buffer might actually contain
800/// several nested scopes.
801#[derive(Clone, Debug)]
802pub struct LanguageScope {
803 language: Arc<Language>,
804 override_id: Option<u32>,
805}
806
807#[doc(hidden)]
808#[cfg(any(test, feature = "test-support"))]
809pub struct FakeLspAdapter {
810 pub name: &'static str,
811 pub initialization_options: Option<Value>,
812 pub prettier_plugins: Vec<&'static str>,
813 pub disk_based_diagnostics_progress_token: Option<String>,
814 pub disk_based_diagnostics_sources: Vec<String>,
815 pub language_server_binary: LanguageServerBinary,
816
817 pub capabilities: lsp::ServerCapabilities,
818 pub initializer: Option<Box<dyn 'static + Send + Sync + Fn(&mut lsp::FakeLanguageServer)>>,
819 pub label_for_completion: Option<
820 Box<
821 dyn 'static
822 + Send
823 + Sync
824 + Fn(&lsp::CompletionItem, &Arc<Language>) -> Option<CodeLabel>,
825 >,
826 >,
827}
828
829pub struct Language {
830 pub(crate) id: LanguageId,
831 pub(crate) config: LanguageConfig,
832 pub(crate) grammar: Option<Arc<Grammar>>,
833 pub(crate) context_provider: Option<Arc<dyn ContextProvider>>,
834 pub(crate) toolchain: Option<Arc<dyn ToolchainLister>>,
835 pub(crate) manifest_name: Option<ManifestName>,
836}
837
838impl Language {
839 pub fn new(config: LanguageConfig, ts_language: Option<tree_sitter::Language>) -> Self {
840 Self::new_with_id(LanguageId::new(), config, ts_language)
841 }
842
843 pub fn id(&self) -> LanguageId {
844 self.id
845 }
846
847 fn new_with_id(
848 id: LanguageId,
849 config: LanguageConfig,
850 ts_language: Option<tree_sitter::Language>,
851 ) -> Self {
852 Self {
853 id,
854 config,
855 grammar: ts_language.map(|ts_language| Arc::new(Grammar::new(ts_language))),
856 context_provider: None,
857 toolchain: None,
858 manifest_name: None,
859 }
860 }
861
862 pub fn with_context_provider(mut self, provider: Option<Arc<dyn ContextProvider>>) -> Self {
863 self.context_provider = provider;
864 self
865 }
866
867 pub fn with_toolchain_lister(mut self, provider: Option<Arc<dyn ToolchainLister>>) -> Self {
868 self.toolchain = provider;
869 self
870 }
871
872 pub fn with_manifest(mut self, name: Option<ManifestName>) -> Self {
873 self.manifest_name = name;
874 self
875 }
876
877 pub fn with_queries(mut self, queries: LanguageQueries) -> Result<Self> {
878 if let Some(grammar) = self.grammar.take() {
879 let grammar =
880 Arc::try_unwrap(grammar).map_err(|_| anyhow::anyhow!("cannot mutate grammar"))?;
881 let grammar = grammar.with_queries(queries, &mut self.config)?;
882 self.grammar = Some(Arc::new(grammar));
883 }
884 Ok(self)
885 }
886
887 pub fn with_highlights_query(self, source: &str) -> Result<Self> {
888 self.with_grammar_query(|grammar| grammar.with_highlights_query(source))
889 }
890
891 pub fn with_runnable_query(self, source: &str) -> Result<Self> {
892 self.with_grammar_query(|grammar| grammar.with_runnable_query(source))
893 }
894
895 pub fn with_outline_query(self, source: &str) -> Result<Self> {
896 self.with_grammar_query_and_name(|grammar, name| grammar.with_outline_query(source, name))
897 }
898
899 pub fn with_text_object_query(self, source: &str) -> Result<Self> {
900 self.with_grammar_query_and_name(|grammar, name| {
901 grammar.with_text_object_query(source, name)
902 })
903 }
904
905 pub fn with_debug_variables_query(self, source: &str) -> Result<Self> {
906 self.with_grammar_query_and_name(|grammar, name| {
907 grammar.with_debug_variables_query(source, name)
908 })
909 }
910
911 pub fn with_imports_query(self, source: &str) -> Result<Self> {
912 self.with_grammar_query_and_name(|grammar, name| grammar.with_imports_query(source, name))
913 }
914
915 pub fn with_brackets_query(self, source: &str) -> Result<Self> {
916 self.with_grammar_query_and_name(|grammar, name| grammar.with_brackets_query(source, name))
917 }
918
919 pub fn with_indents_query(self, source: &str) -> Result<Self> {
920 self.with_grammar_query_and_name(|grammar, name| grammar.with_indents_query(source, name))
921 }
922
923 pub fn with_injection_query(self, source: &str) -> Result<Self> {
924 self.with_grammar_query_and_name(|grammar, name| grammar.with_injection_query(source, name))
925 }
926
927 pub fn with_override_query(mut self, source: &str) -> Result<Self> {
928 if let Some(grammar_arc) = self.grammar.take() {
929 let grammar = Arc::try_unwrap(grammar_arc)
930 .map_err(|_| anyhow::anyhow!("cannot mutate grammar"))?;
931 let grammar = grammar.with_override_query(
932 source,
933 &self.config.name,
934 &self.config.overrides,
935 &mut self.config.brackets,
936 &self.config.scope_opt_in_language_servers,
937 )?;
938 self.grammar = Some(Arc::new(grammar));
939 }
940 Ok(self)
941 }
942
943 pub fn with_redaction_query(self, source: &str) -> Result<Self> {
944 self.with_grammar_query_and_name(|grammar, name| grammar.with_redaction_query(source, name))
945 }
946
947 fn with_grammar_query(
948 mut self,
949 build: impl FnOnce(Grammar) -> Result<Grammar>,
950 ) -> Result<Self> {
951 if let Some(grammar_arc) = self.grammar.take() {
952 let grammar = Arc::try_unwrap(grammar_arc)
953 .map_err(|_| anyhow::anyhow!("cannot mutate grammar"))?;
954 self.grammar = Some(Arc::new(build(grammar)?));
955 }
956 Ok(self)
957 }
958
959 fn with_grammar_query_and_name(
960 mut self,
961 build: impl FnOnce(Grammar, &LanguageName) -> Result<Grammar>,
962 ) -> Result<Self> {
963 if let Some(grammar_arc) = self.grammar.take() {
964 let grammar = Arc::try_unwrap(grammar_arc)
965 .map_err(|_| anyhow::anyhow!("cannot mutate grammar"))?;
966 self.grammar = Some(Arc::new(build(grammar, &self.config.name)?));
967 }
968 Ok(self)
969 }
970
971 pub fn name(&self) -> LanguageName {
972 self.config.name.clone()
973 }
974 pub fn manifest(&self) -> Option<&ManifestName> {
975 self.manifest_name.as_ref()
976 }
977
978 pub fn code_fence_block_name(&self) -> Arc<str> {
979 self.config
980 .code_fence_block_name
981 .clone()
982 .unwrap_or_else(|| self.config.name.as_ref().to_lowercase().into())
983 }
984
985 pub fn matches_kernel_language(&self, kernel_language: &str) -> bool {
986 let kernel_language_lower = kernel_language.to_lowercase();
987
988 if self.code_fence_block_name().to_lowercase() == kernel_language_lower {
989 return true;
990 }
991
992 if self.config.name.as_ref().to_lowercase() == kernel_language_lower {
993 return true;
994 }
995
996 self.config
997 .kernel_language_names
998 .iter()
999 .any(|name| name.to_lowercase() == kernel_language_lower)
1000 }
1001
1002 pub fn context_provider(&self) -> Option<Arc<dyn ContextProvider>> {
1003 self.context_provider.clone()
1004 }
1005
1006 pub fn toolchain_lister(&self) -> Option<Arc<dyn ToolchainLister>> {
1007 self.toolchain.clone()
1008 }
1009
1010 pub fn highlight_text<'a>(
1011 self: &'a Arc<Self>,
1012 text: &'a Rope,
1013 range: Range<usize>,
1014 ) -> Vec<(Range<usize>, HighlightId)> {
1015 let mut result = Vec::new();
1016 if let Some(grammar) = &self.grammar {
1017 let tree = parse_text(grammar, text, None);
1018 let captures =
1019 SyntaxSnapshot::single_tree_captures(range.clone(), text, &tree, self, |grammar| {
1020 grammar
1021 .highlights_config
1022 .as_ref()
1023 .map(|config| &config.query)
1024 });
1025 let highlight_maps = vec![grammar.highlight_map()];
1026 let mut offset = 0;
1027 for chunk in
1028 BufferChunks::new(text, range, Some((captures, highlight_maps)), false, None)
1029 {
1030 let end_offset = offset + chunk.text.len();
1031 if let Some(highlight_id) = chunk.syntax_highlight_id
1032 && !highlight_id.is_default()
1033 {
1034 result.push((offset..end_offset, highlight_id));
1035 }
1036 offset = end_offset;
1037 }
1038 }
1039 result
1040 }
1041
1042 pub fn path_suffixes(&self) -> &[String] {
1043 &self.config.matcher.path_suffixes
1044 }
1045
1046 pub fn should_autoclose_before(&self, c: char) -> bool {
1047 c.is_whitespace() || self.config.autoclose_before.contains(c)
1048 }
1049
1050 pub fn set_theme(&self, theme: &SyntaxTheme) {
1051 if let Some(grammar) = self.grammar.as_ref()
1052 && let Some(highlights_config) = &grammar.highlights_config
1053 {
1054 *grammar.highlight_map.lock() =
1055 build_highlight_map(highlights_config.query.capture_names(), theme);
1056 }
1057 }
1058
1059 pub fn grammar(&self) -> Option<&Arc<Grammar>> {
1060 self.grammar.as_ref()
1061 }
1062
1063 pub fn default_scope(self: &Arc<Self>) -> LanguageScope {
1064 LanguageScope {
1065 language: self.clone(),
1066 override_id: None,
1067 }
1068 }
1069
1070 pub fn lsp_id(&self) -> String {
1071 self.config.name.lsp_id()
1072 }
1073
1074 pub fn prettier_parser_name(&self) -> Option<&str> {
1075 self.config.prettier_parser_name.as_deref()
1076 }
1077
1078 pub fn config(&self) -> &LanguageConfig {
1079 &self.config
1080 }
1081}
1082
1083#[inline]
1084pub fn build_highlight_map(capture_names: &[&str], theme: &SyntaxTheme) -> HighlightMap {
1085 HighlightMap::from_ids(capture_names.iter().map(|capture_name| {
1086 theme
1087 .highlight_id(capture_name)
1088 .map_or(HighlightId::default(), HighlightId)
1089 }))
1090}
1091
1092impl LanguageScope {
1093 pub fn path_suffixes(&self) -> &[String] {
1094 self.language.path_suffixes()
1095 }
1096
1097 pub fn language_name(&self) -> LanguageName {
1098 self.language.config.name.clone()
1099 }
1100
1101 pub fn collapsed_placeholder(&self) -> &str {
1102 self.language.config.collapsed_placeholder.as_ref()
1103 }
1104
1105 /// Returns line prefix that is inserted in e.g. line continuations or
1106 /// in `toggle comments` action.
1107 pub fn line_comment_prefixes(&self) -> &[Arc<str>] {
1108 Override::as_option(
1109 self.config_override().map(|o| &o.line_comments),
1110 Some(&self.language.config.line_comments),
1111 )
1112 .map_or([].as_slice(), |e| e.as_slice())
1113 }
1114
1115 /// Config for block comments for this language.
1116 pub fn block_comment(&self) -> Option<&BlockCommentConfig> {
1117 Override::as_option(
1118 self.config_override().map(|o| &o.block_comment),
1119 self.language.config.block_comment.as_ref(),
1120 )
1121 }
1122
1123 /// Config for documentation-style block comments for this language.
1124 pub fn documentation_comment(&self) -> Option<&BlockCommentConfig> {
1125 self.language.config.documentation_comment.as_ref()
1126 }
1127
1128 /// Returns list markers that are inserted unchanged on newline (e.g., `- `, `* `, `+ `).
1129 pub fn unordered_list(&self) -> &[Arc<str>] {
1130 &self.language.config.unordered_list
1131 }
1132
1133 /// Returns configuration for ordered lists with auto-incrementing numbers (e.g., `1. ` becomes `2. `).
1134 pub fn ordered_list(&self) -> &[OrderedListConfig] {
1135 &self.language.config.ordered_list
1136 }
1137
1138 /// Returns configuration for task list continuation, if any (e.g., `- [x] ` continues as `- [ ] `).
1139 pub fn task_list(&self) -> Option<&TaskListConfig> {
1140 self.language.config.task_list.as_ref()
1141 }
1142
1143 /// Returns additional regex patterns that act as prefix markers for creating
1144 /// boundaries during rewrapping.
1145 ///
1146 /// By default, Zed treats as paragraph and comment prefixes as boundaries.
1147 pub fn rewrap_prefixes(&self) -> &[Regex] {
1148 &self.language.config.rewrap_prefixes
1149 }
1150
1151 /// Returns a list of language-specific word characters.
1152 ///
1153 /// By default, Zed treats alphanumeric characters (and '_') as word characters for
1154 /// the purpose of actions like 'move to next word end` or whole-word search.
1155 /// It additionally accounts for language's additional word characters.
1156 pub fn word_characters(&self) -> Option<&HashSet<char>> {
1157 Override::as_option(
1158 self.config_override().map(|o| &o.word_characters),
1159 Some(&self.language.config.word_characters),
1160 )
1161 }
1162
1163 /// Returns a list of language-specific characters that are considered part of
1164 /// a completion query.
1165 pub fn completion_query_characters(&self) -> Option<&HashSet<char>> {
1166 Override::as_option(
1167 self.config_override()
1168 .map(|o| &o.completion_query_characters),
1169 Some(&self.language.config.completion_query_characters),
1170 )
1171 }
1172
1173 /// Returns a list of language-specific characters that are considered part of
1174 /// identifiers during linked editing operations.
1175 pub fn linked_edit_characters(&self) -> Option<&HashSet<char>> {
1176 Override::as_option(
1177 self.config_override().map(|o| &o.linked_edit_characters),
1178 Some(&self.language.config.linked_edit_characters),
1179 )
1180 }
1181
1182 /// Returns whether to prefer snippet `label` over `new_text` to replace text when
1183 /// completion is accepted.
1184 ///
1185 /// In cases like when cursor is in string or renaming existing function,
1186 /// you don't want to expand function signature instead just want function name
1187 /// to replace existing one.
1188 pub fn prefers_label_for_snippet_in_completion(&self) -> bool {
1189 self.config_override()
1190 .and_then(|o| o.prefer_label_for_snippet)
1191 .unwrap_or(false)
1192 }
1193
1194 /// Returns a list of bracket pairs for a given language with an additional
1195 /// piece of information about whether the particular bracket pair is currently active for a given language.
1196 pub fn brackets(&self) -> impl Iterator<Item = (&BracketPair, bool)> {
1197 let mut disabled_ids = self
1198 .config_override()
1199 .map_or(&[] as _, |o| o.disabled_bracket_ixs.as_slice());
1200 self.language
1201 .config
1202 .brackets
1203 .pairs
1204 .iter()
1205 .enumerate()
1206 .map(move |(ix, bracket)| {
1207 let mut is_enabled = true;
1208 if let Some(next_disabled_ix) = disabled_ids.first()
1209 && ix == *next_disabled_ix as usize
1210 {
1211 disabled_ids = &disabled_ids[1..];
1212 is_enabled = false;
1213 }
1214 (bracket, is_enabled)
1215 })
1216 }
1217
1218 pub fn should_autoclose_before(&self, c: char) -> bool {
1219 c.is_whitespace() || self.language.config.autoclose_before.contains(c)
1220 }
1221
1222 pub fn language_allowed(&self, name: &LanguageServerName) -> bool {
1223 let config = &self.language.config;
1224 let opt_in_servers = &config.scope_opt_in_language_servers;
1225 if opt_in_servers.contains(name) {
1226 if let Some(over) = self.config_override() {
1227 over.opt_into_language_servers.contains(name)
1228 } else {
1229 false
1230 }
1231 } else {
1232 true
1233 }
1234 }
1235
1236 pub fn override_name(&self) -> Option<&str> {
1237 let id = self.override_id?;
1238 let grammar = self.language.grammar.as_ref()?;
1239 let override_config = grammar.override_config.as_ref()?;
1240 override_config.values.get(&id).map(|e| e.name.as_str())
1241 }
1242
1243 fn config_override(&self) -> Option<&LanguageConfigOverride> {
1244 let id = self.override_id?;
1245 let grammar = self.language.grammar.as_ref()?;
1246 let override_config = grammar.override_config.as_ref()?;
1247 override_config.values.get(&id).map(|e| &e.value)
1248 }
1249}
1250
1251impl Hash for Language {
1252 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1253 self.id.hash(state)
1254 }
1255}
1256
1257impl PartialEq for Language {
1258 fn eq(&self, other: &Self) -> bool {
1259 self.id.eq(&other.id)
1260 }
1261}
1262
1263impl Eq for Language {}
1264
1265impl Debug for Language {
1266 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1267 f.debug_struct("Language")
1268 .field("name", &self.config.name)
1269 .finish()
1270 }
1271}
1272
1273pub(crate) fn parse_text(grammar: &Grammar, text: &Rope, old_tree: Option<Tree>) -> Tree {
1274 with_parser(|parser| {
1275 parser
1276 .set_language(&grammar.ts_language)
1277 .expect("incompatible grammar");
1278 let mut chunks = text.chunks_in_range(0..text.len());
1279 parser
1280 .parse_with_options(
1281 &mut move |offset, _| {
1282 chunks.seek(offset);
1283 chunks.next().unwrap_or("").as_bytes()
1284 },
1285 old_tree.as_ref(),
1286 None,
1287 )
1288 .unwrap()
1289 })
1290}
1291
1292pub trait CodeLabelExt {
1293 fn fallback_for_completion(
1294 item: &lsp::CompletionItem,
1295 language: Option<&Language>,
1296 ) -> CodeLabel;
1297}
1298
1299impl CodeLabelExt for CodeLabel {
1300 fn fallback_for_completion(
1301 item: &lsp::CompletionItem,
1302 language: Option<&Language>,
1303 ) -> CodeLabel {
1304 let highlight_id = item.kind.and_then(|kind| {
1305 let grammar = language?.grammar()?;
1306 use lsp::CompletionItemKind as Kind;
1307 match kind {
1308 Kind::CLASS => grammar.highlight_id_for_name("type"),
1309 Kind::CONSTANT => grammar.highlight_id_for_name("constant"),
1310 Kind::CONSTRUCTOR => grammar.highlight_id_for_name("constructor"),
1311 Kind::ENUM => grammar
1312 .highlight_id_for_name("enum")
1313 .or_else(|| grammar.highlight_id_for_name("type")),
1314 Kind::ENUM_MEMBER => grammar
1315 .highlight_id_for_name("variant")
1316 .or_else(|| grammar.highlight_id_for_name("property")),
1317 Kind::FIELD => grammar.highlight_id_for_name("property"),
1318 Kind::FUNCTION => grammar.highlight_id_for_name("function"),
1319 Kind::INTERFACE => grammar.highlight_id_for_name("type"),
1320 Kind::METHOD => grammar
1321 .highlight_id_for_name("function.method")
1322 .or_else(|| grammar.highlight_id_for_name("function")),
1323 Kind::OPERATOR => grammar.highlight_id_for_name("operator"),
1324 Kind::PROPERTY => grammar.highlight_id_for_name("property"),
1325 Kind::STRUCT => grammar.highlight_id_for_name("type"),
1326 Kind::VARIABLE => grammar.highlight_id_for_name("variable"),
1327 Kind::KEYWORD => grammar.highlight_id_for_name("keyword"),
1328 _ => None,
1329 }
1330 });
1331
1332 let label = &item.label;
1333 let label_length = label.len();
1334 let runs = highlight_id
1335 .map(|highlight_id| vec![(0..label_length, highlight_id)])
1336 .unwrap_or_default();
1337 let text = if let Some(detail) = item.detail.as_deref().filter(|detail| detail != label) {
1338 format!("{label} {detail}")
1339 } else if let Some(description) = item
1340 .label_details
1341 .as_ref()
1342 .and_then(|label_details| label_details.description.as_deref())
1343 .filter(|description| description != label)
1344 {
1345 format!("{label} {description}")
1346 } else {
1347 label.clone()
1348 };
1349 let filter_range = item
1350 .filter_text
1351 .as_deref()
1352 .and_then(|filter| text.find(filter).map(|ix| ix..ix + filter.len()))
1353 .unwrap_or(0..label_length);
1354 CodeLabel {
1355 text,
1356 runs,
1357 filter_range,
1358 }
1359 }
1360}
1361
1362#[cfg(any(test, feature = "test-support"))]
1363impl Default for FakeLspAdapter {
1364 fn default() -> Self {
1365 Self {
1366 name: "the-fake-language-server",
1367 capabilities: lsp::LanguageServer::full_capabilities(),
1368 initializer: None,
1369 disk_based_diagnostics_progress_token: None,
1370 initialization_options: None,
1371 disk_based_diagnostics_sources: Vec::new(),
1372 prettier_plugins: Vec::new(),
1373 language_server_binary: LanguageServerBinary {
1374 path: "/the/fake/lsp/path".into(),
1375 arguments: vec![],
1376 env: Default::default(),
1377 },
1378 label_for_completion: None,
1379 }
1380 }
1381}
1382
1383#[cfg(any(test, feature = "test-support"))]
1384impl LspInstaller for FakeLspAdapter {
1385 type BinaryVersion = ();
1386
1387 async fn fetch_latest_server_version(
1388 &self,
1389 _: &dyn LspAdapterDelegate,
1390 _: bool,
1391 _: &mut AsyncApp,
1392 ) -> Result<Self::BinaryVersion> {
1393 unreachable!()
1394 }
1395
1396 async fn check_if_user_installed(
1397 &self,
1398 _: &dyn LspAdapterDelegate,
1399 _: Option<Toolchain>,
1400 _: &AsyncApp,
1401 ) -> Option<LanguageServerBinary> {
1402 Some(self.language_server_binary.clone())
1403 }
1404
1405 async fn fetch_server_binary(
1406 &self,
1407 _: (),
1408 _: PathBuf,
1409 _: &dyn LspAdapterDelegate,
1410 ) -> Result<LanguageServerBinary> {
1411 unreachable!();
1412 }
1413
1414 async fn cached_server_binary(
1415 &self,
1416 _: PathBuf,
1417 _: &dyn LspAdapterDelegate,
1418 ) -> Option<LanguageServerBinary> {
1419 unreachable!();
1420 }
1421}
1422
1423#[cfg(any(test, feature = "test-support"))]
1424#[async_trait(?Send)]
1425impl LspAdapter for FakeLspAdapter {
1426 fn name(&self) -> LanguageServerName {
1427 LanguageServerName(self.name.into())
1428 }
1429
1430 fn disk_based_diagnostic_sources(&self) -> Vec<String> {
1431 self.disk_based_diagnostics_sources.clone()
1432 }
1433
1434 fn disk_based_diagnostics_progress_token(&self) -> Option<String> {
1435 self.disk_based_diagnostics_progress_token.clone()
1436 }
1437
1438 async fn initialization_options(
1439 self: Arc<Self>,
1440 _: &Arc<dyn LspAdapterDelegate>,
1441 _cx: &mut AsyncApp,
1442 ) -> Result<Option<Value>> {
1443 Ok(self.initialization_options.clone())
1444 }
1445
1446 async fn label_for_completion(
1447 &self,
1448 item: &lsp::CompletionItem,
1449 language: &Arc<Language>,
1450 ) -> Option<CodeLabel> {
1451 let label_for_completion = self.label_for_completion.as_ref()?;
1452 label_for_completion(item, language)
1453 }
1454
1455 fn is_extension(&self) -> bool {
1456 false
1457 }
1458}
1459
1460pub fn point_to_lsp(point: PointUtf16) -> lsp::Position {
1461 lsp::Position::new(point.row, point.column)
1462}
1463
1464pub fn point_from_lsp(point: lsp::Position) -> Unclipped<PointUtf16> {
1465 Unclipped(PointUtf16::new(point.line, point.character))
1466}
1467
1468pub fn range_to_lsp(range: Range<PointUtf16>) -> Result<lsp::Range> {
1469 anyhow::ensure!(
1470 range.start <= range.end,
1471 "Inverted range provided to an LSP request: {:?}-{:?}",
1472 range.start,
1473 range.end
1474 );
1475 Ok(lsp::Range {
1476 start: point_to_lsp(range.start),
1477 end: point_to_lsp(range.end),
1478 })
1479}
1480
1481pub fn range_from_lsp(range: lsp::Range) -> Range<Unclipped<PointUtf16>> {
1482 let mut start = point_from_lsp(range.start);
1483 let mut end = point_from_lsp(range.end);
1484 if start > end {
1485 // We debug instead of warn so that this is not logged by default unless explicitly requested.
1486 // Using warn would write to the log file, and since we receive an enormous amount of
1487 // range_from_lsp calls (especially during completions), that can hang the main thread.
1488 //
1489 // See issue #36223.
1490 zlog::debug!("range_from_lsp called with inverted range {start:?}-{end:?}");
1491 mem::swap(&mut start, &mut end);
1492 }
1493 start..end
1494}
1495
1496#[doc(hidden)]
1497#[cfg(any(test, feature = "test-support"))]
1498pub fn rust_lang() -> Arc<Language> {
1499 use std::borrow::Cow;
1500
1501 let language = Language::new(
1502 LanguageConfig {
1503 name: "Rust".into(),
1504 matcher: LanguageMatcher {
1505 path_suffixes: vec!["rs".to_string()],
1506 ..Default::default()
1507 },
1508 line_comments: vec!["// ".into(), "/// ".into(), "//! ".into()],
1509 brackets: BracketPairConfig {
1510 pairs: vec![
1511 BracketPair {
1512 start: "{".into(),
1513 end: "}".into(),
1514 close: true,
1515 surround: false,
1516 newline: true,
1517 },
1518 BracketPair {
1519 start: "[".into(),
1520 end: "]".into(),
1521 close: true,
1522 surround: false,
1523 newline: true,
1524 },
1525 BracketPair {
1526 start: "(".into(),
1527 end: ")".into(),
1528 close: true,
1529 surround: false,
1530 newline: true,
1531 },
1532 BracketPair {
1533 start: "<".into(),
1534 end: ">".into(),
1535 close: false,
1536 surround: false,
1537 newline: true,
1538 },
1539 BracketPair {
1540 start: "\"".into(),
1541 end: "\"".into(),
1542 close: true,
1543 surround: false,
1544 newline: false,
1545 },
1546 ],
1547 ..Default::default()
1548 },
1549 ..Default::default()
1550 },
1551 Some(tree_sitter_rust::LANGUAGE.into()),
1552 )
1553 .with_queries(LanguageQueries {
1554 outline: Some(Cow::from(include_str!(
1555 "../../grammars/src/rust/outline.scm"
1556 ))),
1557 indents: Some(Cow::from(include_str!(
1558 "../../grammars/src/rust/indents.scm"
1559 ))),
1560 brackets: Some(Cow::from(include_str!(
1561 "../../grammars/src/rust/brackets.scm"
1562 ))),
1563 text_objects: Some(Cow::from(include_str!(
1564 "../../grammars/src/rust/textobjects.scm"
1565 ))),
1566 highlights: Some(Cow::from(include_str!(
1567 "../../grammars/src/rust/highlights.scm"
1568 ))),
1569 injections: Some(Cow::from(include_str!(
1570 "../../grammars/src/rust/injections.scm"
1571 ))),
1572 overrides: Some(Cow::from(include_str!(
1573 "../../grammars/src/rust/overrides.scm"
1574 ))),
1575 redactions: None,
1576 runnables: Some(Cow::from(include_str!(
1577 "../../grammars/src/rust/runnables.scm"
1578 ))),
1579 debugger: Some(Cow::from(include_str!(
1580 "../../grammars/src/rust/debugger.scm"
1581 ))),
1582 imports: Some(Cow::from(include_str!(
1583 "../../grammars/src/rust/imports.scm"
1584 ))),
1585 })
1586 .expect("Could not parse queries");
1587 Arc::new(language)
1588}
1589
1590#[doc(hidden)]
1591#[cfg(any(test, feature = "test-support"))]
1592pub fn markdown_lang() -> Arc<Language> {
1593 use std::borrow::Cow;
1594
1595 let language = Language::new(
1596 LanguageConfig {
1597 name: "Markdown".into(),
1598 matcher: LanguageMatcher {
1599 path_suffixes: vec!["md".into()],
1600 ..Default::default()
1601 },
1602 ..LanguageConfig::default()
1603 },
1604 Some(tree_sitter_md::LANGUAGE.into()),
1605 )
1606 .with_queries(LanguageQueries {
1607 brackets: Some(Cow::from(include_str!(
1608 "../../grammars/src/markdown/brackets.scm"
1609 ))),
1610 injections: Some(Cow::from(include_str!(
1611 "../../grammars/src/markdown/injections.scm"
1612 ))),
1613 highlights: Some(Cow::from(include_str!(
1614 "../../grammars/src/markdown/highlights.scm"
1615 ))),
1616 indents: Some(Cow::from(include_str!(
1617 "../../grammars/src/markdown/indents.scm"
1618 ))),
1619 outline: Some(Cow::from(include_str!(
1620 "../../grammars/src/markdown/outline.scm"
1621 ))),
1622 ..LanguageQueries::default()
1623 })
1624 .expect("Could not parse markdown queries");
1625 Arc::new(language)
1626}
1627
1628#[cfg(test)]
1629mod tests {
1630 use super::*;
1631 use gpui::{TestAppContext, rgba};
1632 use pretty_assertions::assert_matches;
1633
1634 #[test]
1635 fn test_highlight_map() {
1636 let theme = SyntaxTheme::new(
1637 [
1638 ("function", rgba(0x100000ff)),
1639 ("function.method", rgba(0x200000ff)),
1640 ("function.async", rgba(0x300000ff)),
1641 ("variable.builtin.self.rust", rgba(0x400000ff)),
1642 ("variable.builtin", rgba(0x500000ff)),
1643 ("variable", rgba(0x600000ff)),
1644 ]
1645 .iter()
1646 .map(|(name, color)| (name.to_string(), (*color).into())),
1647 );
1648
1649 let capture_names = &[
1650 "function.special",
1651 "function.async.rust",
1652 "variable.builtin.self",
1653 ];
1654
1655 let map = build_highlight_map(capture_names, &theme);
1656 assert_eq!(theme.get_capture_name(map.get(0)), Some("function"));
1657 assert_eq!(theme.get_capture_name(map.get(1)), Some("function.async"));
1658 assert_eq!(theme.get_capture_name(map.get(2)), Some("variable.builtin"));
1659 }
1660
1661 #[gpui::test(iterations = 10)]
1662
1663 async fn test_language_loading(cx: &mut TestAppContext) {
1664 let languages = LanguageRegistry::test(cx.executor());
1665 let languages = Arc::new(languages);
1666 languages.register_native_grammars([
1667 ("json", tree_sitter_json::LANGUAGE),
1668 ("rust", tree_sitter_rust::LANGUAGE),
1669 ]);
1670 languages.register_test_language(LanguageConfig {
1671 name: "JSON".into(),
1672 grammar: Some("json".into()),
1673 matcher: LanguageMatcher {
1674 path_suffixes: vec!["json".into()],
1675 ..Default::default()
1676 },
1677 ..Default::default()
1678 });
1679 languages.register_test_language(LanguageConfig {
1680 name: "Rust".into(),
1681 grammar: Some("rust".into()),
1682 matcher: LanguageMatcher {
1683 path_suffixes: vec!["rs".into()],
1684 ..Default::default()
1685 },
1686 ..Default::default()
1687 });
1688 assert_eq!(
1689 languages.language_names(),
1690 &[
1691 LanguageName::new_static("JSON"),
1692 LanguageName::new_static("Plain Text"),
1693 LanguageName::new_static("Rust"),
1694 ]
1695 );
1696
1697 let rust1 = languages.language_for_name("Rust");
1698 let rust2 = languages.language_for_name("Rust");
1699
1700 // Ensure language is still listed even if it's being loaded.
1701 assert_eq!(
1702 languages.language_names(),
1703 &[
1704 LanguageName::new_static("JSON"),
1705 LanguageName::new_static("Plain Text"),
1706 LanguageName::new_static("Rust"),
1707 ]
1708 );
1709
1710 let (rust1, rust2) = futures::join!(rust1, rust2);
1711 assert!(Arc::ptr_eq(&rust1.unwrap(), &rust2.unwrap()));
1712
1713 // Ensure language is still listed even after loading it.
1714 assert_eq!(
1715 languages.language_names(),
1716 &[
1717 LanguageName::new_static("JSON"),
1718 LanguageName::new_static("Plain Text"),
1719 LanguageName::new_static("Rust"),
1720 ]
1721 );
1722
1723 // Loading an unknown language returns an error.
1724 assert!(languages.language_for_name("Unknown").await.is_err());
1725 }
1726
1727 #[gpui::test]
1728 async fn test_completion_label_omits_duplicate_data() {
1729 let regular_completion_item_1 = lsp::CompletionItem {
1730 label: "regular1".to_string(),
1731 detail: Some("detail1".to_string()),
1732 label_details: Some(lsp::CompletionItemLabelDetails {
1733 detail: None,
1734 description: Some("description 1".to_string()),
1735 }),
1736 ..lsp::CompletionItem::default()
1737 };
1738
1739 let regular_completion_item_2 = lsp::CompletionItem {
1740 label: "regular2".to_string(),
1741 label_details: Some(lsp::CompletionItemLabelDetails {
1742 detail: None,
1743 description: Some("description 2".to_string()),
1744 }),
1745 ..lsp::CompletionItem::default()
1746 };
1747
1748 let completion_item_with_duplicate_detail_and_proper_description = lsp::CompletionItem {
1749 detail: Some(regular_completion_item_1.label.clone()),
1750 ..regular_completion_item_1.clone()
1751 };
1752
1753 let completion_item_with_duplicate_detail = lsp::CompletionItem {
1754 detail: Some(regular_completion_item_1.label.clone()),
1755 label_details: None,
1756 ..regular_completion_item_1.clone()
1757 };
1758
1759 let completion_item_with_duplicate_description = lsp::CompletionItem {
1760 label_details: Some(lsp::CompletionItemLabelDetails {
1761 detail: None,
1762 description: Some(regular_completion_item_2.label.clone()),
1763 }),
1764 ..regular_completion_item_2.clone()
1765 };
1766
1767 assert_eq!(
1768 CodeLabel::fallback_for_completion(®ular_completion_item_1, None).text,
1769 format!(
1770 "{} {}",
1771 regular_completion_item_1.label,
1772 regular_completion_item_1.detail.unwrap()
1773 ),
1774 "LSP completion items with both detail and label_details.description should prefer detail"
1775 );
1776 assert_eq!(
1777 CodeLabel::fallback_for_completion(®ular_completion_item_2, None).text,
1778 format!(
1779 "{} {}",
1780 regular_completion_item_2.label,
1781 regular_completion_item_2
1782 .label_details
1783 .as_ref()
1784 .unwrap()
1785 .description
1786 .as_ref()
1787 .unwrap()
1788 ),
1789 "LSP completion items without detail but with label_details.description should use that"
1790 );
1791 assert_eq!(
1792 CodeLabel::fallback_for_completion(
1793 &completion_item_with_duplicate_detail_and_proper_description,
1794 None
1795 )
1796 .text,
1797 format!(
1798 "{} {}",
1799 regular_completion_item_1.label,
1800 regular_completion_item_1
1801 .label_details
1802 .as_ref()
1803 .unwrap()
1804 .description
1805 .as_ref()
1806 .unwrap()
1807 ),
1808 "LSP completion items with both detail and label_details.description should prefer description only if the detail duplicates the completion label"
1809 );
1810 assert_eq!(
1811 CodeLabel::fallback_for_completion(&completion_item_with_duplicate_detail, None).text,
1812 regular_completion_item_1.label,
1813 "LSP completion items with duplicate label and detail, should omit the detail"
1814 );
1815 assert_eq!(
1816 CodeLabel::fallback_for_completion(&completion_item_with_duplicate_description, None)
1817 .text,
1818 regular_completion_item_2.label,
1819 "LSP completion items with duplicate label and detail, should omit the detail"
1820 );
1821 }
1822
1823 #[test]
1824 fn test_deserializing_comments_backwards_compat() {
1825 // current version of `block_comment` and `documentation_comment` work
1826 {
1827 let config: LanguageConfig = ::toml::from_str(
1828 r#"
1829 name = "Foo"
1830 block_comment = { start = "a", end = "b", prefix = "c", tab_size = 1 }
1831 documentation_comment = { start = "d", end = "e", prefix = "f", tab_size = 2 }
1832 "#,
1833 )
1834 .unwrap();
1835 assert_matches!(config.block_comment, Some(BlockCommentConfig { .. }));
1836 assert_matches!(
1837 config.documentation_comment,
1838 Some(BlockCommentConfig { .. })
1839 );
1840
1841 let block_config = config.block_comment.unwrap();
1842 assert_eq!(block_config.start.as_ref(), "a");
1843 assert_eq!(block_config.end.as_ref(), "b");
1844 assert_eq!(block_config.prefix.as_ref(), "c");
1845 assert_eq!(block_config.tab_size, 1);
1846
1847 let doc_config = config.documentation_comment.unwrap();
1848 assert_eq!(doc_config.start.as_ref(), "d");
1849 assert_eq!(doc_config.end.as_ref(), "e");
1850 assert_eq!(doc_config.prefix.as_ref(), "f");
1851 assert_eq!(doc_config.tab_size, 2);
1852 }
1853
1854 // former `documentation` setting is read into `documentation_comment`
1855 {
1856 let config: LanguageConfig = ::toml::from_str(
1857 r#"
1858 name = "Foo"
1859 documentation = { start = "a", end = "b", prefix = "c", tab_size = 1}
1860 "#,
1861 )
1862 .unwrap();
1863 assert_matches!(
1864 config.documentation_comment,
1865 Some(BlockCommentConfig { .. })
1866 );
1867
1868 let config = config.documentation_comment.unwrap();
1869 assert_eq!(config.start.as_ref(), "a");
1870 assert_eq!(config.end.as_ref(), "b");
1871 assert_eq!(config.prefix.as_ref(), "c");
1872 assert_eq!(config.tab_size, 1);
1873 }
1874
1875 // old block_comment format is read into BlockCommentConfig
1876 {
1877 let config: LanguageConfig = ::toml::from_str(
1878 r#"
1879 name = "Foo"
1880 block_comment = ["a", "b"]
1881 "#,
1882 )
1883 .unwrap();
1884 assert_matches!(config.block_comment, Some(BlockCommentConfig { .. }));
1885
1886 let config = config.block_comment.unwrap();
1887 assert_eq!(config.start.as_ref(), "a");
1888 assert_eq!(config.end.as_ref(), "b");
1889 assert_eq!(config.prefix.as_ref(), "");
1890 assert_eq!(config.tab_size, 0);
1891 }
1892 }
1893}