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