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