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 result.push((offset..end_offset, highlight_id));
1028 }
1029 offset = end_offset;
1030 }
1031 }
1032 result
1033 }
1034
1035 pub fn path_suffixes(&self) -> &[String] {
1036 &self.config.matcher.path_suffixes
1037 }
1038
1039 pub fn should_autoclose_before(&self, c: char) -> bool {
1040 c.is_whitespace() || self.config.autoclose_before.contains(c)
1041 }
1042
1043 pub fn set_theme(&self, theme: &SyntaxTheme) {
1044 if let Some(grammar) = self.grammar.as_ref()
1045 && let Some(highlights_config) = &grammar.highlights_config
1046 {
1047 *grammar.highlight_map.lock() =
1048 build_highlight_map(highlights_config.query.capture_names(), theme);
1049 }
1050 }
1051
1052 pub fn grammar(&self) -> Option<&Arc<Grammar>> {
1053 self.grammar.as_ref()
1054 }
1055
1056 pub fn default_scope(self: &Arc<Self>) -> LanguageScope {
1057 LanguageScope {
1058 language: self.clone(),
1059 override_id: None,
1060 }
1061 }
1062
1063 pub fn lsp_id(&self) -> String {
1064 self.config.name.lsp_id()
1065 }
1066
1067 pub fn prettier_parser_name(&self) -> Option<&str> {
1068 self.config.prettier_parser_name.as_deref()
1069 }
1070
1071 pub fn config(&self) -> &LanguageConfig {
1072 &self.config
1073 }
1074}
1075
1076#[inline]
1077pub fn build_highlight_map(capture_names: &[&str], theme: &SyntaxTheme) -> HighlightMap {
1078 HighlightMap::from_ids(
1079 capture_names
1080 .iter()
1081 .map(|capture_name| theme.highlight_id(capture_name).map(HighlightId::new)),
1082 )
1083}
1084
1085impl LanguageScope {
1086 pub fn path_suffixes(&self) -> &[String] {
1087 self.language.path_suffixes()
1088 }
1089
1090 pub fn language_name(&self) -> LanguageName {
1091 self.language.config.name.clone()
1092 }
1093
1094 pub fn collapsed_placeholder(&self) -> &str {
1095 self.language.config.collapsed_placeholder.as_ref()
1096 }
1097
1098 /// Returns line prefix that is inserted in e.g. line continuations or
1099 /// in `toggle comments` action.
1100 pub fn line_comment_prefixes(&self) -> &[Arc<str>] {
1101 Override::as_option(
1102 self.config_override().map(|o| &o.line_comments),
1103 Some(&self.language.config.line_comments),
1104 )
1105 .map_or([].as_slice(), |e| e.as_slice())
1106 }
1107
1108 /// Config for block comments for this language.
1109 pub fn block_comment(&self) -> Option<&BlockCommentConfig> {
1110 Override::as_option(
1111 self.config_override().map(|o| &o.block_comment),
1112 self.language.config.block_comment.as_ref(),
1113 )
1114 }
1115
1116 /// Config for documentation-style block comments for this language.
1117 pub fn documentation_comment(&self) -> Option<&BlockCommentConfig> {
1118 self.language.config.documentation_comment.as_ref()
1119 }
1120
1121 /// Returns list markers that are inserted unchanged on newline (e.g., `- `, `* `, `+ `).
1122 pub fn unordered_list(&self) -> &[Arc<str>] {
1123 &self.language.config.unordered_list
1124 }
1125
1126 /// Returns configuration for ordered lists with auto-incrementing numbers (e.g., `1. ` becomes `2. `).
1127 pub fn ordered_list(&self) -> &[OrderedListConfig] {
1128 &self.language.config.ordered_list
1129 }
1130
1131 /// Returns configuration for task list continuation, if any (e.g., `- [x] ` continues as `- [ ] `).
1132 pub fn task_list(&self) -> Option<&TaskListConfig> {
1133 self.language.config.task_list.as_ref()
1134 }
1135
1136 /// Returns additional regex patterns that act as prefix markers for creating
1137 /// boundaries during rewrapping.
1138 ///
1139 /// By default, Zed treats as paragraph and comment prefixes as boundaries.
1140 pub fn rewrap_prefixes(&self) -> &[Regex] {
1141 &self.language.config.rewrap_prefixes
1142 }
1143
1144 /// Returns a list of language-specific word characters.
1145 ///
1146 /// By default, Zed treats alphanumeric characters (and '_') as word characters for
1147 /// the purpose of actions like 'move to next word end` or whole-word search.
1148 /// It additionally accounts for language's additional word characters.
1149 pub fn word_characters(&self) -> Option<&HashSet<char>> {
1150 Override::as_option(
1151 self.config_override().map(|o| &o.word_characters),
1152 Some(&self.language.config.word_characters),
1153 )
1154 }
1155
1156 /// Returns a list of language-specific characters that are considered part of
1157 /// a completion query.
1158 pub fn completion_query_characters(&self) -> Option<&HashSet<char>> {
1159 Override::as_option(
1160 self.config_override()
1161 .map(|o| &o.completion_query_characters),
1162 Some(&self.language.config.completion_query_characters),
1163 )
1164 }
1165
1166 /// Returns a list of language-specific characters that are considered part of
1167 /// identifiers during linked editing operations.
1168 pub fn linked_edit_characters(&self) -> Option<&HashSet<char>> {
1169 Override::as_option(
1170 self.config_override().map(|o| &o.linked_edit_characters),
1171 Some(&self.language.config.linked_edit_characters),
1172 )
1173 }
1174
1175 /// Returns whether to prefer snippet `label` over `new_text` to replace text when
1176 /// completion is accepted.
1177 ///
1178 /// In cases like when cursor is in string or renaming existing function,
1179 /// you don't want to expand function signature instead just want function name
1180 /// to replace existing one.
1181 pub fn prefers_label_for_snippet_in_completion(&self) -> bool {
1182 self.config_override()
1183 .and_then(|o| o.prefer_label_for_snippet)
1184 .unwrap_or(false)
1185 }
1186
1187 /// Returns a list of bracket pairs for a given language with an additional
1188 /// piece of information about whether the particular bracket pair is currently active for a given language.
1189 pub fn brackets(&self) -> impl Iterator<Item = (&BracketPair, bool)> {
1190 let mut disabled_ids = self
1191 .config_override()
1192 .map_or(&[] as _, |o| o.disabled_bracket_ixs.as_slice());
1193 self.language
1194 .config
1195 .brackets
1196 .pairs
1197 .iter()
1198 .enumerate()
1199 .map(move |(ix, bracket)| {
1200 let mut is_enabled = true;
1201 if let Some(next_disabled_ix) = disabled_ids.first()
1202 && ix == *next_disabled_ix as usize
1203 {
1204 disabled_ids = &disabled_ids[1..];
1205 is_enabled = false;
1206 }
1207 (bracket, is_enabled)
1208 })
1209 }
1210
1211 pub fn should_autoclose_before(&self, c: char) -> bool {
1212 c.is_whitespace() || self.language.config.autoclose_before.contains(c)
1213 }
1214
1215 pub fn language_allowed(&self, name: &LanguageServerName) -> bool {
1216 let config = &self.language.config;
1217 let opt_in_servers = &config.scope_opt_in_language_servers;
1218 if opt_in_servers.contains(name) {
1219 if let Some(over) = self.config_override() {
1220 over.opt_into_language_servers.contains(name)
1221 } else {
1222 false
1223 }
1224 } else {
1225 true
1226 }
1227 }
1228
1229 pub fn override_name(&self) -> Option<&str> {
1230 let id = self.override_id?;
1231 let grammar = self.language.grammar.as_ref()?;
1232 let override_config = grammar.override_config.as_ref()?;
1233 override_config.values.get(&id).map(|e| e.name.as_str())
1234 }
1235
1236 fn config_override(&self) -> Option<&LanguageConfigOverride> {
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.value)
1241 }
1242}
1243
1244impl Hash for Language {
1245 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1246 self.id.hash(state)
1247 }
1248}
1249
1250impl PartialEq for Language {
1251 fn eq(&self, other: &Self) -> bool {
1252 self.id.eq(&other.id)
1253 }
1254}
1255
1256impl Eq for Language {}
1257
1258impl Debug for Language {
1259 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1260 f.debug_struct("Language")
1261 .field("name", &self.config.name)
1262 .finish()
1263 }
1264}
1265
1266pub(crate) fn parse_text(grammar: &Grammar, text: &Rope, old_tree: Option<Tree>) -> Tree {
1267 with_parser(|parser| {
1268 parser
1269 .set_language(&grammar.ts_language)
1270 .expect("incompatible grammar");
1271 let mut chunks = text.chunks_in_range(0..text.len());
1272 parser
1273 .parse_with_options(
1274 &mut move |offset, _| {
1275 chunks.seek(offset);
1276 chunks.next().unwrap_or("").as_bytes()
1277 },
1278 old_tree.as_ref(),
1279 None,
1280 )
1281 .unwrap()
1282 })
1283}
1284
1285pub trait CodeLabelExt {
1286 fn fallback_for_completion(
1287 item: &lsp::CompletionItem,
1288 language: Option<&Language>,
1289 ) -> CodeLabel;
1290}
1291
1292impl CodeLabelExt for CodeLabel {
1293 fn fallback_for_completion(
1294 item: &lsp::CompletionItem,
1295 language: Option<&Language>,
1296 ) -> CodeLabel {
1297 let highlight_id = item.kind.and_then(|kind| {
1298 let grammar = language?.grammar()?;
1299 use lsp::CompletionItemKind as Kind;
1300 match kind {
1301 Kind::CLASS => grammar.highlight_id_for_name("type"),
1302 Kind::CONSTANT => grammar.highlight_id_for_name("constant"),
1303 Kind::CONSTRUCTOR => grammar.highlight_id_for_name("constructor"),
1304 Kind::ENUM => grammar
1305 .highlight_id_for_name("enum")
1306 .or_else(|| grammar.highlight_id_for_name("type")),
1307 Kind::ENUM_MEMBER => grammar
1308 .highlight_id_for_name("variant")
1309 .or_else(|| grammar.highlight_id_for_name("property")),
1310 Kind::FIELD => grammar.highlight_id_for_name("property"),
1311 Kind::FUNCTION => grammar.highlight_id_for_name("function"),
1312 Kind::INTERFACE => grammar.highlight_id_for_name("type"),
1313 Kind::METHOD => grammar
1314 .highlight_id_for_name("function.method")
1315 .or_else(|| grammar.highlight_id_for_name("function")),
1316 Kind::OPERATOR => grammar.highlight_id_for_name("operator"),
1317 Kind::PROPERTY => grammar.highlight_id_for_name("property"),
1318 Kind::STRUCT => grammar.highlight_id_for_name("type"),
1319 Kind::VARIABLE => grammar.highlight_id_for_name("variable"),
1320 Kind::KEYWORD => grammar.highlight_id_for_name("keyword"),
1321 _ => None,
1322 }
1323 });
1324
1325 let label = &item.label;
1326 let label_length = label.len();
1327 let runs = highlight_id
1328 .map(|highlight_id| vec![(0..label_length, highlight_id)])
1329 .unwrap_or_default();
1330 let text = if let Some(detail) = item.detail.as_deref().filter(|detail| detail != label) {
1331 format!("{label} {detail}")
1332 } else if let Some(description) = item
1333 .label_details
1334 .as_ref()
1335 .and_then(|label_details| label_details.description.as_deref())
1336 .filter(|description| description != label)
1337 {
1338 format!("{label} {description}")
1339 } else {
1340 label.clone()
1341 };
1342 let filter_range = item
1343 .filter_text
1344 .as_deref()
1345 .and_then(|filter| text.find(filter).map(|ix| ix..ix + filter.len()))
1346 .unwrap_or(0..label_length);
1347 CodeLabel {
1348 text,
1349 runs,
1350 filter_range,
1351 }
1352 }
1353}
1354
1355#[cfg(any(test, feature = "test-support"))]
1356impl Default for FakeLspAdapter {
1357 fn default() -> Self {
1358 Self {
1359 name: "the-fake-language-server",
1360 capabilities: lsp::LanguageServer::full_capabilities(),
1361 initializer: None,
1362 disk_based_diagnostics_progress_token: None,
1363 initialization_options: None,
1364 disk_based_diagnostics_sources: Vec::new(),
1365 prettier_plugins: Vec::new(),
1366 language_server_binary: LanguageServerBinary {
1367 path: "/the/fake/lsp/path".into(),
1368 arguments: vec![],
1369 env: Default::default(),
1370 },
1371 label_for_completion: None,
1372 }
1373 }
1374}
1375
1376#[cfg(any(test, feature = "test-support"))]
1377impl LspInstaller for FakeLspAdapter {
1378 type BinaryVersion = ();
1379
1380 async fn fetch_latest_server_version(
1381 &self,
1382 _: &dyn LspAdapterDelegate,
1383 _: bool,
1384 _: &mut AsyncApp,
1385 ) -> Result<Self::BinaryVersion> {
1386 unreachable!()
1387 }
1388
1389 async fn check_if_user_installed(
1390 &self,
1391 _: &dyn LspAdapterDelegate,
1392 _: Option<Toolchain>,
1393 _: &AsyncApp,
1394 ) -> Option<LanguageServerBinary> {
1395 Some(self.language_server_binary.clone())
1396 }
1397
1398 async fn fetch_server_binary(
1399 &self,
1400 _: (),
1401 _: PathBuf,
1402 _: &dyn LspAdapterDelegate,
1403 ) -> Result<LanguageServerBinary> {
1404 unreachable!();
1405 }
1406
1407 async fn cached_server_binary(
1408 &self,
1409 _: PathBuf,
1410 _: &dyn LspAdapterDelegate,
1411 ) -> Option<LanguageServerBinary> {
1412 unreachable!();
1413 }
1414}
1415
1416#[cfg(any(test, feature = "test-support"))]
1417#[async_trait(?Send)]
1418impl LspAdapter for FakeLspAdapter {
1419 fn name(&self) -> LanguageServerName {
1420 LanguageServerName(self.name.into())
1421 }
1422
1423 fn disk_based_diagnostic_sources(&self) -> Vec<String> {
1424 self.disk_based_diagnostics_sources.clone()
1425 }
1426
1427 fn disk_based_diagnostics_progress_token(&self) -> Option<String> {
1428 self.disk_based_diagnostics_progress_token.clone()
1429 }
1430
1431 async fn initialization_options(
1432 self: Arc<Self>,
1433 _: &Arc<dyn LspAdapterDelegate>,
1434 _cx: &mut AsyncApp,
1435 ) -> Result<Option<Value>> {
1436 Ok(self.initialization_options.clone())
1437 }
1438
1439 async fn label_for_completion(
1440 &self,
1441 item: &lsp::CompletionItem,
1442 language: &Arc<Language>,
1443 ) -> Option<CodeLabel> {
1444 let label_for_completion = self.label_for_completion.as_ref()?;
1445 label_for_completion(item, language)
1446 }
1447
1448 fn is_extension(&self) -> bool {
1449 false
1450 }
1451}
1452
1453pub fn point_to_lsp(point: PointUtf16) -> lsp::Position {
1454 lsp::Position::new(point.row, point.column)
1455}
1456
1457pub fn point_from_lsp(point: lsp::Position) -> Unclipped<PointUtf16> {
1458 Unclipped(PointUtf16::new(point.line, point.character))
1459}
1460
1461pub fn range_to_lsp(range: Range<PointUtf16>) -> Result<lsp::Range> {
1462 anyhow::ensure!(
1463 range.start <= range.end,
1464 "Inverted range provided to an LSP request: {:?}-{:?}",
1465 range.start,
1466 range.end
1467 );
1468 Ok(lsp::Range {
1469 start: point_to_lsp(range.start),
1470 end: point_to_lsp(range.end),
1471 })
1472}
1473
1474pub fn range_from_lsp(range: lsp::Range) -> Range<Unclipped<PointUtf16>> {
1475 let mut start = point_from_lsp(range.start);
1476 let mut end = point_from_lsp(range.end);
1477 if start > end {
1478 // We debug instead of warn so that this is not logged by default unless explicitly requested.
1479 // Using warn would write to the log file, and since we receive an enormous amount of
1480 // range_from_lsp calls (especially during completions), that can hang the main thread.
1481 //
1482 // See issue #36223.
1483 zlog::debug!("range_from_lsp called with inverted range {start:?}-{end:?}");
1484 mem::swap(&mut start, &mut end);
1485 }
1486 start..end
1487}
1488
1489#[doc(hidden)]
1490#[cfg(any(test, feature = "test-support"))]
1491pub fn rust_lang() -> Arc<Language> {
1492 use std::borrow::Cow;
1493
1494 let language = Language::new(
1495 LanguageConfig {
1496 name: "Rust".into(),
1497 matcher: LanguageMatcher {
1498 path_suffixes: vec!["rs".to_string()],
1499 ..Default::default()
1500 },
1501 line_comments: vec!["// ".into(), "/// ".into(), "//! ".into()],
1502 brackets: BracketPairConfig {
1503 pairs: vec![
1504 BracketPair {
1505 start: "{".into(),
1506 end: "}".into(),
1507 close: true,
1508 surround: false,
1509 newline: true,
1510 },
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: false,
1529 surround: false,
1530 newline: true,
1531 },
1532 BracketPair {
1533 start: "\"".into(),
1534 end: "\"".into(),
1535 close: true,
1536 surround: false,
1537 newline: false,
1538 },
1539 ],
1540 ..Default::default()
1541 },
1542 ..Default::default()
1543 },
1544 Some(tree_sitter_rust::LANGUAGE.into()),
1545 )
1546 .with_queries(LanguageQueries {
1547 outline: Some(Cow::from(include_str!(
1548 "../../grammars/src/rust/outline.scm"
1549 ))),
1550 indents: Some(Cow::from(include_str!(
1551 "../../grammars/src/rust/indents.scm"
1552 ))),
1553 brackets: Some(Cow::from(include_str!(
1554 "../../grammars/src/rust/brackets.scm"
1555 ))),
1556 text_objects: Some(Cow::from(include_str!(
1557 "../../grammars/src/rust/textobjects.scm"
1558 ))),
1559 highlights: Some(Cow::from(include_str!(
1560 "../../grammars/src/rust/highlights.scm"
1561 ))),
1562 injections: Some(Cow::from(include_str!(
1563 "../../grammars/src/rust/injections.scm"
1564 ))),
1565 overrides: Some(Cow::from(include_str!(
1566 "../../grammars/src/rust/overrides.scm"
1567 ))),
1568 redactions: None,
1569 runnables: Some(Cow::from(include_str!(
1570 "../../grammars/src/rust/runnables.scm"
1571 ))),
1572 debugger: Some(Cow::from(include_str!(
1573 "../../grammars/src/rust/debugger.scm"
1574 ))),
1575 })
1576 .expect("Could not parse queries");
1577 Arc::new(language)
1578}
1579
1580#[doc(hidden)]
1581#[cfg(any(test, feature = "test-support"))]
1582pub fn markdown_lang() -> Arc<Language> {
1583 use std::borrow::Cow;
1584
1585 let language = Language::new(
1586 LanguageConfig {
1587 name: "Markdown".into(),
1588 matcher: LanguageMatcher {
1589 path_suffixes: vec!["md".into()],
1590 ..Default::default()
1591 },
1592 ..LanguageConfig::default()
1593 },
1594 Some(tree_sitter_md::LANGUAGE.into()),
1595 )
1596 .with_queries(LanguageQueries {
1597 brackets: Some(Cow::from(include_str!(
1598 "../../grammars/src/markdown/brackets.scm"
1599 ))),
1600 injections: Some(Cow::from(include_str!(
1601 "../../grammars/src/markdown/injections.scm"
1602 ))),
1603 highlights: Some(Cow::from(include_str!(
1604 "../../grammars/src/markdown/highlights.scm"
1605 ))),
1606 indents: Some(Cow::from(include_str!(
1607 "../../grammars/src/markdown/indents.scm"
1608 ))),
1609 outline: Some(Cow::from(include_str!(
1610 "../../grammars/src/markdown/outline.scm"
1611 ))),
1612 ..LanguageQueries::default()
1613 })
1614 .expect("Could not parse markdown queries");
1615 Arc::new(language)
1616}
1617
1618#[cfg(test)]
1619mod tests {
1620 use super::*;
1621 use gpui::{TestAppContext, rgba};
1622 use pretty_assertions::assert_matches;
1623
1624 #[test]
1625 fn test_highlight_map() {
1626 let theme = SyntaxTheme::new(
1627 [
1628 ("function", rgba(0x100000ff)),
1629 ("function.method", rgba(0x200000ff)),
1630 ("function.async", rgba(0x300000ff)),
1631 ("variable.builtin.self.rust", rgba(0x400000ff)),
1632 ("variable.builtin", rgba(0x500000ff)),
1633 ("variable", rgba(0x600000ff)),
1634 ]
1635 .iter()
1636 .map(|(name, color)| (name.to_string(), (*color).into())),
1637 );
1638
1639 let capture_names = &[
1640 "function.special",
1641 "function.async.rust",
1642 "variable.builtin.self",
1643 ];
1644
1645 let map = build_highlight_map(capture_names, &theme);
1646 assert_eq!(
1647 theme.get_capture_name(map.get(0).unwrap()),
1648 Some("function")
1649 );
1650 assert_eq!(
1651 theme.get_capture_name(map.get(1).unwrap()),
1652 Some("function.async")
1653 );
1654 assert_eq!(
1655 theme.get_capture_name(map.get(2).unwrap()),
1656 Some("variable.builtin")
1657 );
1658 }
1659
1660 #[gpui::test(iterations = 10)]
1661
1662 async fn test_language_loading(cx: &mut TestAppContext) {
1663 let languages = LanguageRegistry::test(cx.executor());
1664 let languages = Arc::new(languages);
1665 languages.register_native_grammars([
1666 ("json", tree_sitter_json::LANGUAGE),
1667 ("rust", tree_sitter_rust::LANGUAGE),
1668 ]);
1669 languages.register_test_language(LanguageConfig {
1670 name: "JSON".into(),
1671 grammar: Some("json".into()),
1672 matcher: LanguageMatcher {
1673 path_suffixes: vec!["json".into()],
1674 ..Default::default()
1675 },
1676 ..Default::default()
1677 });
1678 languages.register_test_language(LanguageConfig {
1679 name: "Rust".into(),
1680 grammar: Some("rust".into()),
1681 matcher: LanguageMatcher {
1682 path_suffixes: vec!["rs".into()],
1683 ..Default::default()
1684 },
1685 ..Default::default()
1686 });
1687 assert_eq!(
1688 languages.language_names(),
1689 &[
1690 LanguageName::new_static("JSON"),
1691 LanguageName::new_static("Plain Text"),
1692 LanguageName::new_static("Rust"),
1693 ]
1694 );
1695
1696 let rust1 = languages.language_for_name("Rust");
1697 let rust2 = languages.language_for_name("Rust");
1698
1699 // Ensure language is still listed even if it's being loaded.
1700 assert_eq!(
1701 languages.language_names(),
1702 &[
1703 LanguageName::new_static("JSON"),
1704 LanguageName::new_static("Plain Text"),
1705 LanguageName::new_static("Rust"),
1706 ]
1707 );
1708
1709 let (rust1, rust2) = futures::join!(rust1, rust2);
1710 assert!(Arc::ptr_eq(&rust1.unwrap(), &rust2.unwrap()));
1711
1712 // Ensure language is still listed even after loading it.
1713 assert_eq!(
1714 languages.language_names(),
1715 &[
1716 LanguageName::new_static("JSON"),
1717 LanguageName::new_static("Plain Text"),
1718 LanguageName::new_static("Rust"),
1719 ]
1720 );
1721
1722 // Loading an unknown language returns an error.
1723 assert!(languages.language_for_name("Unknown").await.is_err());
1724 }
1725
1726 #[gpui::test]
1727 async fn test_completion_label_omits_duplicate_data() {
1728 let regular_completion_item_1 = lsp::CompletionItem {
1729 label: "regular1".to_string(),
1730 detail: Some("detail1".to_string()),
1731 label_details: Some(lsp::CompletionItemLabelDetails {
1732 detail: None,
1733 description: Some("description 1".to_string()),
1734 }),
1735 ..lsp::CompletionItem::default()
1736 };
1737
1738 let regular_completion_item_2 = lsp::CompletionItem {
1739 label: "regular2".to_string(),
1740 label_details: Some(lsp::CompletionItemLabelDetails {
1741 detail: None,
1742 description: Some("description 2".to_string()),
1743 }),
1744 ..lsp::CompletionItem::default()
1745 };
1746
1747 let completion_item_with_duplicate_detail_and_proper_description = lsp::CompletionItem {
1748 detail: Some(regular_completion_item_1.label.clone()),
1749 ..regular_completion_item_1.clone()
1750 };
1751
1752 let completion_item_with_duplicate_detail = lsp::CompletionItem {
1753 detail: Some(regular_completion_item_1.label.clone()),
1754 label_details: None,
1755 ..regular_completion_item_1.clone()
1756 };
1757
1758 let completion_item_with_duplicate_description = lsp::CompletionItem {
1759 label_details: Some(lsp::CompletionItemLabelDetails {
1760 detail: None,
1761 description: Some(regular_completion_item_2.label.clone()),
1762 }),
1763 ..regular_completion_item_2.clone()
1764 };
1765
1766 assert_eq!(
1767 CodeLabel::fallback_for_completion(®ular_completion_item_1, None).text,
1768 format!(
1769 "{} {}",
1770 regular_completion_item_1.label,
1771 regular_completion_item_1.detail.unwrap()
1772 ),
1773 "LSP completion items with both detail and label_details.description should prefer detail"
1774 );
1775 assert_eq!(
1776 CodeLabel::fallback_for_completion(®ular_completion_item_2, None).text,
1777 format!(
1778 "{} {}",
1779 regular_completion_item_2.label,
1780 regular_completion_item_2
1781 .label_details
1782 .as_ref()
1783 .unwrap()
1784 .description
1785 .as_ref()
1786 .unwrap()
1787 ),
1788 "LSP completion items without detail but with label_details.description should use that"
1789 );
1790 assert_eq!(
1791 CodeLabel::fallback_for_completion(
1792 &completion_item_with_duplicate_detail_and_proper_description,
1793 None
1794 )
1795 .text,
1796 format!(
1797 "{} {}",
1798 regular_completion_item_1.label,
1799 regular_completion_item_1
1800 .label_details
1801 .as_ref()
1802 .unwrap()
1803 .description
1804 .as_ref()
1805 .unwrap()
1806 ),
1807 "LSP completion items with both detail and label_details.description should prefer description only if the detail duplicates the completion label"
1808 );
1809 assert_eq!(
1810 CodeLabel::fallback_for_completion(&completion_item_with_duplicate_detail, None).text,
1811 regular_completion_item_1.label,
1812 "LSP completion items with duplicate label and detail, should omit the detail"
1813 );
1814 assert_eq!(
1815 CodeLabel::fallback_for_completion(&completion_item_with_duplicate_description, None)
1816 .text,
1817 regular_completion_item_2.label,
1818 "LSP completion items with duplicate label and detail, should omit the detail"
1819 );
1820 }
1821
1822 #[test]
1823 fn test_deserializing_comments_backwards_compat() {
1824 // current version of `block_comment` and `documentation_comment` work
1825 {
1826 let config: LanguageConfig = ::toml::from_str(
1827 r#"
1828 name = "Foo"
1829 block_comment = { start = "a", end = "b", prefix = "c", tab_size = 1 }
1830 documentation_comment = { start = "d", end = "e", prefix = "f", tab_size = 2 }
1831 "#,
1832 )
1833 .unwrap();
1834 assert_matches!(config.block_comment, Some(BlockCommentConfig { .. }));
1835 assert_matches!(
1836 config.documentation_comment,
1837 Some(BlockCommentConfig { .. })
1838 );
1839
1840 let block_config = config.block_comment.unwrap();
1841 assert_eq!(block_config.start.as_ref(), "a");
1842 assert_eq!(block_config.end.as_ref(), "b");
1843 assert_eq!(block_config.prefix.as_ref(), "c");
1844 assert_eq!(block_config.tab_size, 1);
1845
1846 let doc_config = config.documentation_comment.unwrap();
1847 assert_eq!(doc_config.start.as_ref(), "d");
1848 assert_eq!(doc_config.end.as_ref(), "e");
1849 assert_eq!(doc_config.prefix.as_ref(), "f");
1850 assert_eq!(doc_config.tab_size, 2);
1851 }
1852
1853 // former `documentation` setting is read into `documentation_comment`
1854 {
1855 let config: LanguageConfig = ::toml::from_str(
1856 r#"
1857 name = "Foo"
1858 documentation = { start = "a", end = "b", prefix = "c", tab_size = 1}
1859 "#,
1860 )
1861 .unwrap();
1862 assert_matches!(
1863 config.documentation_comment,
1864 Some(BlockCommentConfig { .. })
1865 );
1866
1867 let config = config.documentation_comment.unwrap();
1868 assert_eq!(config.start.as_ref(), "a");
1869 assert_eq!(config.end.as_ref(), "b");
1870 assert_eq!(config.prefix.as_ref(), "c");
1871 assert_eq!(config.tab_size, 1);
1872 }
1873
1874 // old block_comment format is read into BlockCommentConfig
1875 {
1876 let config: LanguageConfig = ::toml::from_str(
1877 r#"
1878 name = "Foo"
1879 block_comment = ["a", "b"]
1880 "#,
1881 )
1882 .unwrap();
1883 assert_matches!(config.block_comment, Some(BlockCommentConfig { .. }));
1884
1885 let config = config.block_comment.unwrap();
1886 assert_eq!(config.start.as_ref(), "a");
1887 assert_eq!(config.end.as_ref(), "b");
1888 assert_eq!(config.prefix.as_ref(), "");
1889 assert_eq!(config.tab_size, 0);
1890 }
1891 }
1892}