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