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_set;
11mod highlight_map;
12mod language_registry;
13pub mod language_settings;
14mod outline;
15pub mod proto;
16mod syntax_map;
17mod task_context;
18mod toolchain;
19
20#[cfg(test)]
21pub mod buffer_tests;
22pub mod markdown;
23
24use crate::language_settings::SoftWrap;
25use anyhow::{anyhow, Context, Result};
26use async_trait::async_trait;
27use collections::{HashMap, HashSet};
28use futures::Future;
29use gpui::{AppContext, AsyncAppContext, Model, SharedString, Task};
30pub use highlight_map::HighlightMap;
31use http_client::HttpClient;
32pub use language_registry::{LanguageName, LoadedLanguage};
33use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerName};
34use parking_lot::Mutex;
35use regex::Regex;
36use schemars::{
37 gen::SchemaGenerator,
38 schema::{InstanceType, Schema, SchemaObject},
39 JsonSchema,
40};
41use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
42use serde_json::Value;
43use settings::WorktreeId;
44use smol::future::FutureExt as _;
45use std::num::NonZeroU32;
46use std::{
47 any::Any,
48 ffi::OsStr,
49 fmt::Debug,
50 hash::Hash,
51 mem,
52 ops::{DerefMut, Range},
53 path::{Path, PathBuf},
54 pin::Pin,
55 str,
56 sync::{
57 atomic::{AtomicU64, AtomicUsize, Ordering::SeqCst},
58 Arc, LazyLock,
59 },
60};
61use syntax_map::{QueryCursorHandle, SyntaxSnapshot};
62use task::RunnableTag;
63pub use task_context::{ContextProvider, RunnableRange};
64use theme::SyntaxTheme;
65pub use toolchain::{LanguageToolchainStore, Toolchain, ToolchainList, ToolchainLister};
66use tree_sitter::{self, wasmtime, Query, QueryCursor, WasmStore};
67use util::serde::default_true;
68
69pub use buffer::Operation;
70pub use buffer::*;
71pub use diagnostic_set::DiagnosticEntry;
72pub use language_registry::{
73 AvailableLanguage, LanguageNotFound, LanguageQueries, LanguageRegistry,
74 LanguageServerBinaryStatus, QUERY_FILENAME_PREFIXES,
75};
76pub use lsp::LanguageServerId;
77pub use outline::*;
78pub use syntax_map::{OwnedSyntaxLayer, SyntaxLayer};
79pub use text::{AnchorRangeExt, LineEnding};
80pub use tree_sitter::{Node, Parser, Tree, TreeCursor};
81
82/// Initializes the `language` crate.
83///
84/// This should be called before making use of items from the create.
85pub fn init(cx: &mut AppContext) {
86 language_settings::init(cx);
87}
88
89static QUERY_CURSORS: Mutex<Vec<QueryCursor>> = Mutex::new(vec![]);
90static PARSERS: Mutex<Vec<Parser>> = Mutex::new(vec![]);
91
92pub fn with_parser<F, R>(func: F) -> R
93where
94 F: FnOnce(&mut Parser) -> R,
95{
96 let mut parser = PARSERS.lock().pop().unwrap_or_else(|| {
97 let mut parser = Parser::new();
98 parser
99 .set_wasm_store(WasmStore::new(&WASM_ENGINE).unwrap())
100 .unwrap();
101 parser
102 });
103 parser.set_included_ranges(&[]).unwrap();
104 let result = func(&mut parser);
105 PARSERS.lock().push(parser);
106 result
107}
108
109pub fn with_query_cursor<F, R>(func: F) -> R
110where
111 F: FnOnce(&mut QueryCursor) -> R,
112{
113 let mut cursor = QueryCursorHandle::new();
114 func(cursor.deref_mut())
115}
116
117static NEXT_LANGUAGE_ID: LazyLock<AtomicUsize> = LazyLock::new(Default::default);
118static NEXT_GRAMMAR_ID: LazyLock<AtomicUsize> = LazyLock::new(Default::default);
119static WASM_ENGINE: LazyLock<wasmtime::Engine> = LazyLock::new(|| {
120 wasmtime::Engine::new(&wasmtime::Config::new()).expect("Failed to create Wasmtime engine")
121});
122
123/// A shared grammar for plain text, exposed for reuse by downstream crates.
124pub static PLAIN_TEXT: LazyLock<Arc<Language>> = LazyLock::new(|| {
125 Arc::new(Language::new(
126 LanguageConfig {
127 name: "Plain Text".into(),
128 soft_wrap: Some(SoftWrap::EditorWidth),
129 ..Default::default()
130 },
131 None,
132 ))
133});
134
135/// Types that represent a position in a buffer, and can be converted into
136/// an LSP position, to send to a language server.
137pub trait ToLspPosition {
138 /// Converts the value into an LSP position.
139 fn to_lsp_position(self) -> lsp::Position;
140}
141
142#[derive(Debug, Clone, PartialEq, Eq, Hash)]
143pub struct Location {
144 pub buffer: Model<Buffer>,
145 pub range: Range<Anchor>,
146}
147
148/// Represents a Language Server, with certain cached sync properties.
149/// Uses [`LspAdapter`] under the hood, but calls all 'static' methods
150/// once at startup, and caches the results.
151pub struct CachedLspAdapter {
152 pub name: LanguageServerName,
153 pub disk_based_diagnostic_sources: Vec<String>,
154 pub disk_based_diagnostics_progress_token: Option<String>,
155 language_ids: HashMap<String, String>,
156 pub adapter: Arc<dyn LspAdapter>,
157 pub reinstall_attempt_count: AtomicU64,
158 cached_binary: futures::lock::Mutex<Option<LanguageServerBinary>>,
159}
160
161impl Debug for CachedLspAdapter {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 f.debug_struct("CachedLspAdapter")
164 .field("name", &self.name)
165 .field(
166 "disk_based_diagnostic_sources",
167 &self.disk_based_diagnostic_sources,
168 )
169 .field(
170 "disk_based_diagnostics_progress_token",
171 &self.disk_based_diagnostics_progress_token,
172 )
173 .field("language_ids", &self.language_ids)
174 .field("reinstall_attempt_count", &self.reinstall_attempt_count)
175 .finish_non_exhaustive()
176 }
177}
178
179impl CachedLspAdapter {
180 pub fn new(adapter: Arc<dyn LspAdapter>) -> Arc<Self> {
181 let name = adapter.name();
182 let disk_based_diagnostic_sources = adapter.disk_based_diagnostic_sources();
183 let disk_based_diagnostics_progress_token = adapter.disk_based_diagnostics_progress_token();
184 let language_ids = adapter.language_ids();
185
186 Arc::new(CachedLspAdapter {
187 name,
188 disk_based_diagnostic_sources,
189 disk_based_diagnostics_progress_token,
190 language_ids,
191 adapter,
192 cached_binary: Default::default(),
193 reinstall_attempt_count: AtomicU64::new(0),
194 })
195 }
196
197 pub fn name(&self) -> LanguageServerName {
198 self.adapter.name().clone()
199 }
200
201 pub async fn get_language_server_command(
202 self: Arc<Self>,
203 delegate: Arc<dyn LspAdapterDelegate>,
204 toolchains: Arc<dyn LanguageToolchainStore>,
205 binary_options: LanguageServerBinaryOptions,
206 cx: &mut AsyncAppContext,
207 ) -> Result<LanguageServerBinary> {
208 let cached_binary = self.cached_binary.lock().await;
209 self.adapter
210 .clone()
211 .get_language_server_command(delegate, toolchains, binary_options, cached_binary, cx)
212 .await
213 }
214
215 pub fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
216 self.adapter.code_action_kinds()
217 }
218
219 pub fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
220 self.adapter.process_diagnostics(params)
221 }
222
223 pub async fn process_completions(&self, completion_items: &mut [lsp::CompletionItem]) {
224 self.adapter.process_completions(completion_items).await
225 }
226
227 pub async fn labels_for_completions(
228 &self,
229 completion_items: &[lsp::CompletionItem],
230 language: &Arc<Language>,
231 ) -> Result<Vec<Option<CodeLabel>>> {
232 self.adapter
233 .clone()
234 .labels_for_completions(completion_items, language)
235 .await
236 }
237
238 pub async fn labels_for_symbols(
239 &self,
240 symbols: &[(String, lsp::SymbolKind)],
241 language: &Arc<Language>,
242 ) -> Result<Vec<Option<CodeLabel>>> {
243 self.adapter
244 .clone()
245 .labels_for_symbols(symbols, language)
246 .await
247 }
248
249 pub fn language_id(&self, language_name: &LanguageName) -> String {
250 self.language_ids
251 .get(language_name.0.as_ref())
252 .cloned()
253 .unwrap_or_else(|| language_name.lsp_id())
254 }
255}
256
257/// [`LspAdapterDelegate`] allows [`LspAdapter]` implementations to interface with the application
258// e.g. to display a notification or fetch data from the web.
259#[async_trait]
260pub trait LspAdapterDelegate: Send + Sync {
261 fn show_notification(&self, message: &str, cx: &mut AppContext);
262 fn http_client(&self) -> Arc<dyn HttpClient>;
263 fn worktree_id(&self) -> WorktreeId;
264 fn worktree_root_path(&self) -> &Path;
265 fn update_status(&self, language: LanguageServerName, status: LanguageServerBinaryStatus);
266 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>>;
267
268 async fn npm_package_installed_version(
269 &self,
270 package_name: &str,
271 ) -> Result<Option<(PathBuf, String)>>;
272 async fn which(&self, command: &OsStr) -> Option<PathBuf>;
273 async fn shell_env(&self) -> HashMap<String, String>;
274 async fn read_text_file(&self, path: PathBuf) -> Result<String>;
275 async fn try_exec(&self, binary: LanguageServerBinary) -> Result<()>;
276}
277
278#[async_trait(?Send)]
279pub trait LspAdapter: 'static + Send + Sync {
280 fn name(&self) -> LanguageServerName;
281
282 fn get_language_server_command<'a>(
283 self: Arc<Self>,
284 delegate: Arc<dyn LspAdapterDelegate>,
285 toolchains: Arc<dyn LanguageToolchainStore>,
286 binary_options: LanguageServerBinaryOptions,
287 mut cached_binary: futures::lock::MutexGuard<'a, Option<LanguageServerBinary>>,
288 cx: &'a mut AsyncAppContext,
289 ) -> Pin<Box<dyn 'a + Future<Output = Result<LanguageServerBinary>>>> {
290 async move {
291 // First we check whether the adapter can give us a user-installed binary.
292 // If so, we do *not* want to cache that, because each worktree might give us a different
293 // binary:
294 //
295 // worktree 1: user-installed at `.bin/gopls`
296 // worktree 2: user-installed at `~/bin/gopls`
297 // worktree 3: no gopls found in PATH -> fallback to Zed installation
298 //
299 // We only want to cache when we fall back to the global one,
300 // because we don't want to download and overwrite our global one
301 // for each worktree we might have open.
302 if binary_options.allow_path_lookup {
303 if let Some(binary) = self.check_if_user_installed(delegate.as_ref(), toolchains, cx).await {
304 log::info!(
305 "found user-installed language server for {}. path: {:?}, arguments: {:?}",
306 self.name().0,
307 binary.path,
308 binary.arguments
309 );
310 return Ok(binary);
311 }
312 }
313
314 if !binary_options.allow_binary_download {
315 return Err(anyhow!("downloading language servers disabled"));
316 }
317
318 if let Some(cached_binary) = cached_binary.as_ref() {
319 return Ok(cached_binary.clone());
320 }
321
322 let Some(container_dir) = delegate.language_server_download_dir(&self.name()).await else {
323 anyhow::bail!("no language server download dir defined")
324 };
325
326 let mut binary = try_fetch_server_binary(self.as_ref(), &delegate, container_dir.to_path_buf(), cx).await;
327
328 if let Err(error) = binary.as_ref() {
329 if let Some(prev_downloaded_binary) = self
330 .cached_server_binary(container_dir.to_path_buf(), delegate.as_ref())
331 .await
332 {
333 log::info!(
334 "failed to fetch newest version of language server {:?}. error: {:?}, falling back to using {:?}",
335 self.name(),
336 error,
337 prev_downloaded_binary.path
338 );
339 binary = Ok(prev_downloaded_binary);
340 } else {
341 delegate.update_status(
342 self.name(),
343 LanguageServerBinaryStatus::Failed {
344 error: format!("{error:?}"),
345 },
346 );
347 }
348 }
349
350 if let Ok(binary) = &binary {
351 *cached_binary = Some(binary.clone());
352 }
353
354 binary
355 }
356 .boxed_local()
357 }
358
359 async fn check_if_user_installed(
360 &self,
361 _: &dyn LspAdapterDelegate,
362 _: Arc<dyn LanguageToolchainStore>,
363 _: &AsyncAppContext,
364 ) -> Option<LanguageServerBinary> {
365 None
366 }
367
368 async fn fetch_latest_server_version(
369 &self,
370 delegate: &dyn LspAdapterDelegate,
371 ) -> Result<Box<dyn 'static + Send + Any>>;
372
373 fn will_fetch_server(
374 &self,
375 _: &Arc<dyn LspAdapterDelegate>,
376 _: &mut AsyncAppContext,
377 ) -> Option<Task<Result<()>>> {
378 None
379 }
380
381 async fn fetch_server_binary(
382 &self,
383 latest_version: Box<dyn 'static + Send + Any>,
384 container_dir: PathBuf,
385 delegate: &dyn LspAdapterDelegate,
386 ) -> Result<LanguageServerBinary>;
387
388 async fn cached_server_binary(
389 &self,
390 container_dir: PathBuf,
391 delegate: &dyn LspAdapterDelegate,
392 ) -> Option<LanguageServerBinary>;
393
394 fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
395
396 /// Post-processes completions provided by the language server.
397 async fn process_completions(&self, _: &mut [lsp::CompletionItem]) {}
398
399 async fn labels_for_completions(
400 self: Arc<Self>,
401 completions: &[lsp::CompletionItem],
402 language: &Arc<Language>,
403 ) -> Result<Vec<Option<CodeLabel>>> {
404 let mut labels = Vec::new();
405 for (ix, completion) in completions.iter().enumerate() {
406 let label = self.label_for_completion(completion, language).await;
407 if let Some(label) = label {
408 labels.resize(ix + 1, None);
409 *labels.last_mut().unwrap() = Some(label);
410 }
411 }
412 Ok(labels)
413 }
414
415 async fn label_for_completion(
416 &self,
417 _: &lsp::CompletionItem,
418 _: &Arc<Language>,
419 ) -> Option<CodeLabel> {
420 None
421 }
422
423 async fn labels_for_symbols(
424 self: Arc<Self>,
425 symbols: &[(String, lsp::SymbolKind)],
426 language: &Arc<Language>,
427 ) -> Result<Vec<Option<CodeLabel>>> {
428 let mut labels = Vec::new();
429 for (ix, (name, kind)) in symbols.iter().enumerate() {
430 let label = self.label_for_symbol(name, *kind, language).await;
431 if let Some(label) = label {
432 labels.resize(ix + 1, None);
433 *labels.last_mut().unwrap() = Some(label);
434 }
435 }
436 Ok(labels)
437 }
438
439 async fn label_for_symbol(
440 &self,
441 _: &str,
442 _: lsp::SymbolKind,
443 _: &Arc<Language>,
444 ) -> Option<CodeLabel> {
445 None
446 }
447
448 /// Returns initialization options that are going to be sent to a LSP server as a part of [`lsp::InitializeParams`]
449 async fn initialization_options(
450 self: Arc<Self>,
451 _: &Arc<dyn LspAdapterDelegate>,
452 ) -> Result<Option<Value>> {
453 Ok(None)
454 }
455
456 async fn workspace_configuration(
457 self: Arc<Self>,
458 _: &Arc<dyn LspAdapterDelegate>,
459 _: Arc<dyn LanguageToolchainStore>,
460 _cx: &mut AsyncAppContext,
461 ) -> Result<Value> {
462 Ok(serde_json::json!({}))
463 }
464
465 /// Returns a list of code actions supported by a given LspAdapter
466 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
467 Some(vec![
468 CodeActionKind::EMPTY,
469 CodeActionKind::QUICKFIX,
470 CodeActionKind::REFACTOR,
471 CodeActionKind::REFACTOR_EXTRACT,
472 CodeActionKind::SOURCE,
473 ])
474 }
475
476 fn disk_based_diagnostic_sources(&self) -> Vec<String> {
477 Default::default()
478 }
479
480 fn disk_based_diagnostics_progress_token(&self) -> Option<String> {
481 None
482 }
483
484 fn language_ids(&self) -> HashMap<String, String> {
485 Default::default()
486 }
487}
488
489async fn try_fetch_server_binary<L: LspAdapter + 'static + Send + Sync + ?Sized>(
490 adapter: &L,
491 delegate: &Arc<dyn LspAdapterDelegate>,
492 container_dir: PathBuf,
493 cx: &mut AsyncAppContext,
494) -> Result<LanguageServerBinary> {
495 if let Some(task) = adapter.will_fetch_server(delegate, cx) {
496 task.await?;
497 }
498
499 let name = adapter.name();
500 log::info!("fetching latest version of language server {:?}", name.0);
501 delegate.update_status(name.clone(), LanguageServerBinaryStatus::CheckingForUpdate);
502
503 let latest_version = adapter
504 .fetch_latest_server_version(delegate.as_ref())
505 .await?;
506
507 log::info!("downloading language server {:?}", name.0);
508 delegate.update_status(adapter.name(), LanguageServerBinaryStatus::Downloading);
509 let binary = adapter
510 .fetch_server_binary(latest_version, container_dir, delegate.as_ref())
511 .await;
512
513 delegate.update_status(name.clone(), LanguageServerBinaryStatus::None);
514 binary
515}
516
517#[derive(Clone, Debug, Default, PartialEq, Eq)]
518pub struct CodeLabel {
519 /// The text to display.
520 pub text: String,
521 /// Syntax highlighting runs.
522 pub runs: Vec<(Range<usize>, HighlightId)>,
523 /// The portion of the text that should be used in fuzzy filtering.
524 pub filter_range: Range<usize>,
525}
526
527#[derive(Clone, Deserialize, JsonSchema)]
528pub struct LanguageConfig {
529 /// Human-readable name of the language.
530 pub name: LanguageName,
531 /// The name of this language for a Markdown code fence block
532 pub code_fence_block_name: Option<Arc<str>>,
533 // The name of the grammar in a WASM bundle (experimental).
534 pub grammar: Option<Arc<str>>,
535 /// The criteria for matching this language to a given file.
536 #[serde(flatten)]
537 pub matcher: LanguageMatcher,
538 /// List of bracket types in a language.
539 #[serde(default)]
540 #[schemars(schema_with = "bracket_pair_config_json_schema")]
541 pub brackets: BracketPairConfig,
542 /// If set to true, auto indentation uses last non empty line to determine
543 /// the indentation level for a new line.
544 #[serde(default = "auto_indent_using_last_non_empty_line_default")]
545 pub auto_indent_using_last_non_empty_line: bool,
546 // Whether indentation of pasted content should be adjusted based on the context.
547 #[serde(default)]
548 pub auto_indent_on_paste: Option<bool>,
549 /// A regex that is used to determine whether the indentation level should be
550 /// increased in the following line.
551 #[serde(default, deserialize_with = "deserialize_regex")]
552 #[schemars(schema_with = "regex_json_schema")]
553 pub increase_indent_pattern: Option<Regex>,
554 /// A regex that is used to determine whether the indentation level should be
555 /// decreased in the following line.
556 #[serde(default, deserialize_with = "deserialize_regex")]
557 #[schemars(schema_with = "regex_json_schema")]
558 pub decrease_indent_pattern: Option<Regex>,
559 /// A list of characters that trigger the automatic insertion of a closing
560 /// bracket when they immediately precede the point where an opening
561 /// bracket is inserted.
562 #[serde(default)]
563 pub autoclose_before: String,
564 /// A placeholder used internally by Semantic Index.
565 #[serde(default)]
566 pub collapsed_placeholder: String,
567 /// A line comment string that is inserted in e.g. `toggle comments` action.
568 /// A language can have multiple flavours of line comments. All of the provided line comments are
569 /// used for comment continuations on the next line, but only the first one is used for Editor::ToggleComments.
570 #[serde(default)]
571 pub line_comments: Vec<Arc<str>>,
572 /// Starting and closing characters of a block comment.
573 #[serde(default)]
574 pub block_comment: Option<(Arc<str>, Arc<str>)>,
575 /// A list of language servers that are allowed to run on subranges of a given language.
576 #[serde(default)]
577 pub scope_opt_in_language_servers: Vec<LanguageServerName>,
578 #[serde(default)]
579 pub overrides: HashMap<String, LanguageConfigOverride>,
580 /// A list of characters that Zed should treat as word characters for the
581 /// purpose of features that operate on word boundaries, like 'move to next word end'
582 /// or a whole-word search in buffer search.
583 #[serde(default)]
584 pub word_characters: HashSet<char>,
585 /// Whether to indent lines using tab characters, as opposed to multiple
586 /// spaces.
587 #[serde(default)]
588 pub hard_tabs: Option<bool>,
589 /// How many columns a tab should occupy.
590 #[serde(default)]
591 pub tab_size: Option<NonZeroU32>,
592 /// How to soft-wrap long lines of text.
593 #[serde(default)]
594 pub soft_wrap: Option<SoftWrap>,
595 /// The name of a Prettier parser that will be used for this language when no file path is available.
596 /// If there's a parser name in the language settings, that will be used instead.
597 #[serde(default)]
598 pub prettier_parser_name: Option<String>,
599 /// If true, this language is only for syntax highlighting via an injection into other
600 /// languages, but should not appear to the user as a distinct language.
601 #[serde(default)]
602 pub hidden: bool,
603}
604
605#[derive(Clone, Debug, Serialize, Deserialize, Default, JsonSchema)]
606pub struct LanguageMatcher {
607 /// Given a list of `LanguageConfig`'s, the language of a file can be determined based on the path extension matching any of the `path_suffixes`.
608 #[serde(default)]
609 pub path_suffixes: Vec<String>,
610 /// A regex pattern that determines whether the language should be assigned to a file or not.
611 #[serde(
612 default,
613 serialize_with = "serialize_regex",
614 deserialize_with = "deserialize_regex"
615 )]
616 #[schemars(schema_with = "regex_json_schema")]
617 pub first_line_pattern: Option<Regex>,
618}
619
620/// Represents a language for the given range. Some languages (e.g. HTML)
621/// interleave several languages together, thus a single buffer might actually contain
622/// several nested scopes.
623#[derive(Clone, Debug)]
624pub struct LanguageScope {
625 language: Arc<Language>,
626 override_id: Option<u32>,
627}
628
629#[derive(Clone, Deserialize, Default, Debug, JsonSchema)]
630pub struct LanguageConfigOverride {
631 #[serde(default)]
632 pub line_comments: Override<Vec<Arc<str>>>,
633 #[serde(default)]
634 pub block_comment: Override<(Arc<str>, Arc<str>)>,
635 #[serde(skip_deserializing)]
636 #[schemars(skip)]
637 pub disabled_bracket_ixs: Vec<u16>,
638 #[serde(default)]
639 pub word_characters: Override<HashSet<char>>,
640 #[serde(default)]
641 pub opt_into_language_servers: Vec<LanguageServerName>,
642}
643
644#[derive(Clone, Deserialize, Debug, Serialize, JsonSchema)]
645#[serde(untagged)]
646pub enum Override<T> {
647 Remove { remove: bool },
648 Set(T),
649}
650
651impl<T> Default for Override<T> {
652 fn default() -> Self {
653 Override::Remove { remove: false }
654 }
655}
656
657impl<T> Override<T> {
658 fn as_option<'a>(this: Option<&'a Self>, original: Option<&'a T>) -> Option<&'a T> {
659 match this {
660 Some(Self::Set(value)) => Some(value),
661 Some(Self::Remove { remove: true }) => None,
662 Some(Self::Remove { remove: false }) | None => original,
663 }
664 }
665}
666
667impl Default for LanguageConfig {
668 fn default() -> Self {
669 Self {
670 name: LanguageName::new(""),
671 code_fence_block_name: None,
672 grammar: None,
673 matcher: LanguageMatcher::default(),
674 brackets: Default::default(),
675 auto_indent_using_last_non_empty_line: auto_indent_using_last_non_empty_line_default(),
676 auto_indent_on_paste: None,
677 increase_indent_pattern: Default::default(),
678 decrease_indent_pattern: Default::default(),
679 autoclose_before: Default::default(),
680 line_comments: Default::default(),
681 block_comment: Default::default(),
682 scope_opt_in_language_servers: Default::default(),
683 overrides: Default::default(),
684 word_characters: Default::default(),
685 collapsed_placeholder: Default::default(),
686 hard_tabs: None,
687 tab_size: None,
688 soft_wrap: None,
689 prettier_parser_name: None,
690 hidden: false,
691 }
692 }
693}
694
695fn auto_indent_using_last_non_empty_line_default() -> bool {
696 true
697}
698
699fn deserialize_regex<'de, D: Deserializer<'de>>(d: D) -> Result<Option<Regex>, D::Error> {
700 let source = Option::<String>::deserialize(d)?;
701 if let Some(source) = source {
702 Ok(Some(regex::Regex::new(&source).map_err(de::Error::custom)?))
703 } else {
704 Ok(None)
705 }
706}
707
708fn regex_json_schema(_: &mut SchemaGenerator) -> Schema {
709 Schema::Object(SchemaObject {
710 instance_type: Some(InstanceType::String.into()),
711 ..Default::default()
712 })
713}
714
715fn serialize_regex<S>(regex: &Option<Regex>, serializer: S) -> Result<S::Ok, S::Error>
716where
717 S: Serializer,
718{
719 match regex {
720 Some(regex) => serializer.serialize_str(regex.as_str()),
721 None => serializer.serialize_none(),
722 }
723}
724
725#[doc(hidden)]
726#[cfg(any(test, feature = "test-support"))]
727pub struct FakeLspAdapter {
728 pub name: &'static str,
729 pub initialization_options: Option<Value>,
730 pub prettier_plugins: Vec<&'static str>,
731 pub disk_based_diagnostics_progress_token: Option<String>,
732 pub disk_based_diagnostics_sources: Vec<String>,
733 pub language_server_binary: LanguageServerBinary,
734
735 pub capabilities: lsp::ServerCapabilities,
736 pub initializer: Option<Box<dyn 'static + Send + Sync + Fn(&mut lsp::FakeLanguageServer)>>,
737}
738
739/// Configuration of handling bracket pairs for a given language.
740///
741/// This struct includes settings for defining which pairs of characters are considered brackets and
742/// also specifies any language-specific scopes where these pairs should be ignored for bracket matching purposes.
743#[derive(Clone, Debug, Default, JsonSchema)]
744pub struct BracketPairConfig {
745 /// A list of character pairs that should be treated as brackets in the context of a given language.
746 pub pairs: Vec<BracketPair>,
747 /// A list of tree-sitter scopes for which a given bracket should not be active.
748 /// N-th entry in `[Self::disabled_scopes_by_bracket_ix]` contains a list of disabled scopes for an n-th entry in `[Self::pairs]`
749 #[schemars(skip)]
750 pub disabled_scopes_by_bracket_ix: Vec<Vec<String>>,
751}
752
753fn bracket_pair_config_json_schema(gen: &mut SchemaGenerator) -> Schema {
754 Option::<Vec<BracketPairContent>>::json_schema(gen)
755}
756
757#[derive(Deserialize, JsonSchema)]
758pub struct BracketPairContent {
759 #[serde(flatten)]
760 pub bracket_pair: BracketPair,
761 #[serde(default)]
762 pub not_in: Vec<String>,
763}
764
765impl<'de> Deserialize<'de> for BracketPairConfig {
766 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
767 where
768 D: Deserializer<'de>,
769 {
770 let result = Vec::<BracketPairContent>::deserialize(deserializer)?;
771 let mut brackets = Vec::with_capacity(result.len());
772 let mut disabled_scopes_by_bracket_ix = Vec::with_capacity(result.len());
773 for entry in result {
774 brackets.push(entry.bracket_pair);
775 disabled_scopes_by_bracket_ix.push(entry.not_in);
776 }
777
778 Ok(BracketPairConfig {
779 pairs: brackets,
780 disabled_scopes_by_bracket_ix,
781 })
782 }
783}
784
785/// Describes a single bracket pair and how an editor should react to e.g. inserting
786/// an opening bracket or to a newline character insertion in between `start` and `end` characters.
787#[derive(Clone, Debug, Default, Deserialize, PartialEq, JsonSchema)]
788pub struct BracketPair {
789 /// Starting substring for a bracket.
790 pub start: String,
791 /// Ending substring for a bracket.
792 pub end: String,
793 /// True if `end` should be automatically inserted right after `start` characters.
794 pub close: bool,
795 /// True if selected text should be surrounded by `start` and `end` characters.
796 #[serde(default = "default_true")]
797 pub surround: bool,
798 /// True if an extra newline should be inserted while the cursor is in the middle
799 /// of that bracket pair.
800 pub newline: bool,
801}
802
803#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
804pub(crate) struct LanguageId(usize);
805
806impl LanguageId {
807 pub(crate) fn new() -> Self {
808 Self(NEXT_LANGUAGE_ID.fetch_add(1, SeqCst))
809 }
810}
811
812pub struct Language {
813 pub(crate) id: LanguageId,
814 pub(crate) config: LanguageConfig,
815 pub(crate) grammar: Option<Arc<Grammar>>,
816 pub(crate) context_provider: Option<Arc<dyn ContextProvider>>,
817 pub(crate) toolchain: Option<Arc<dyn ToolchainLister>>,
818}
819
820#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
821pub struct GrammarId(pub usize);
822
823impl GrammarId {
824 pub(crate) fn new() -> Self {
825 Self(NEXT_GRAMMAR_ID.fetch_add(1, SeqCst))
826 }
827}
828
829pub struct Grammar {
830 id: GrammarId,
831 pub ts_language: tree_sitter::Language,
832 pub(crate) error_query: Query,
833 pub(crate) highlights_query: Option<Query>,
834 pub(crate) brackets_config: Option<BracketConfig>,
835 pub(crate) redactions_config: Option<RedactionConfig>,
836 pub(crate) runnable_config: Option<RunnableConfig>,
837 pub(crate) indents_config: Option<IndentConfig>,
838 pub outline_config: Option<OutlineConfig>,
839 pub embedding_config: Option<EmbeddingConfig>,
840 pub(crate) injection_config: Option<InjectionConfig>,
841 pub(crate) override_config: Option<OverrideConfig>,
842 pub(crate) highlight_map: Mutex<HighlightMap>,
843}
844
845struct IndentConfig {
846 query: Query,
847 indent_capture_ix: u32,
848 start_capture_ix: Option<u32>,
849 end_capture_ix: Option<u32>,
850 outdent_capture_ix: Option<u32>,
851}
852
853pub struct OutlineConfig {
854 pub query: Query,
855 pub item_capture_ix: u32,
856 pub name_capture_ix: u32,
857 pub context_capture_ix: Option<u32>,
858 pub extra_context_capture_ix: Option<u32>,
859 pub open_capture_ix: Option<u32>,
860 pub close_capture_ix: Option<u32>,
861 pub annotation_capture_ix: Option<u32>,
862}
863
864#[derive(Debug)]
865pub struct EmbeddingConfig {
866 pub query: Query,
867 pub item_capture_ix: u32,
868 pub name_capture_ix: Option<u32>,
869 pub context_capture_ix: Option<u32>,
870 pub collapse_capture_ix: Option<u32>,
871 pub keep_capture_ix: Option<u32>,
872}
873
874struct InjectionConfig {
875 query: Query,
876 content_capture_ix: u32,
877 language_capture_ix: Option<u32>,
878 patterns: Vec<InjectionPatternConfig>,
879}
880
881struct RedactionConfig {
882 pub query: Query,
883 pub redaction_capture_ix: u32,
884}
885
886#[derive(Clone, Debug, PartialEq)]
887enum RunnableCapture {
888 Named(SharedString),
889 Run,
890}
891
892struct RunnableConfig {
893 pub query: Query,
894 /// A mapping from capture indice to capture kind
895 pub extra_captures: Vec<RunnableCapture>,
896}
897
898struct OverrideConfig {
899 query: Query,
900 values: HashMap<u32, OverrideEntry>,
901}
902
903#[derive(Debug)]
904struct OverrideEntry {
905 name: String,
906 range_is_inclusive: bool,
907 value: LanguageConfigOverride,
908}
909
910#[derive(Default, Clone)]
911struct InjectionPatternConfig {
912 language: Option<Box<str>>,
913 combined: bool,
914}
915
916struct BracketConfig {
917 query: Query,
918 open_capture_ix: u32,
919 close_capture_ix: u32,
920}
921
922impl Language {
923 pub fn new(config: LanguageConfig, ts_language: Option<tree_sitter::Language>) -> Self {
924 Self::new_with_id(LanguageId::new(), config, ts_language)
925 }
926
927 fn new_with_id(
928 id: LanguageId,
929 config: LanguageConfig,
930 ts_language: Option<tree_sitter::Language>,
931 ) -> Self {
932 Self {
933 id,
934 config,
935 grammar: ts_language.map(|ts_language| {
936 Arc::new(Grammar {
937 id: GrammarId::new(),
938 highlights_query: None,
939 brackets_config: None,
940 outline_config: None,
941 embedding_config: None,
942 indents_config: None,
943 injection_config: None,
944 override_config: None,
945 redactions_config: None,
946 runnable_config: None,
947 error_query: Query::new(&ts_language, "(ERROR) @error").unwrap(),
948 ts_language,
949 highlight_map: Default::default(),
950 })
951 }),
952 context_provider: None,
953 toolchain: None,
954 }
955 }
956
957 pub fn with_context_provider(mut self, provider: Option<Arc<dyn ContextProvider>>) -> Self {
958 self.context_provider = provider;
959 self
960 }
961
962 pub fn with_toolchain_lister(mut self, provider: Option<Arc<dyn ToolchainLister>>) -> Self {
963 self.toolchain = provider;
964 self
965 }
966
967 pub fn with_queries(mut self, queries: LanguageQueries) -> Result<Self> {
968 if let Some(query) = queries.highlights {
969 self = self
970 .with_highlights_query(query.as_ref())
971 .context("Error loading highlights query")?;
972 }
973 if let Some(query) = queries.brackets {
974 self = self
975 .with_brackets_query(query.as_ref())
976 .context("Error loading brackets query")?;
977 }
978 if let Some(query) = queries.indents {
979 self = self
980 .with_indents_query(query.as_ref())
981 .context("Error loading indents query")?;
982 }
983 if let Some(query) = queries.outline {
984 self = self
985 .with_outline_query(query.as_ref())
986 .context("Error loading outline query")?;
987 }
988 if let Some(query) = queries.embedding {
989 self = self
990 .with_embedding_query(query.as_ref())
991 .context("Error loading embedding query")?;
992 }
993 if let Some(query) = queries.injections {
994 self = self
995 .with_injection_query(query.as_ref())
996 .context("Error loading injection query")?;
997 }
998 if let Some(query) = queries.overrides {
999 self = self
1000 .with_override_query(query.as_ref())
1001 .context("Error loading override query")?;
1002 }
1003 if let Some(query) = queries.redactions {
1004 self = self
1005 .with_redaction_query(query.as_ref())
1006 .context("Error loading redaction query")?;
1007 }
1008 if let Some(query) = queries.runnables {
1009 self = self
1010 .with_runnable_query(query.as_ref())
1011 .context("Error loading tests query")?;
1012 }
1013 Ok(self)
1014 }
1015
1016 pub fn with_highlights_query(mut self, source: &str) -> Result<Self> {
1017 let grammar = self
1018 .grammar_mut()
1019 .ok_or_else(|| anyhow!("cannot mutate grammar"))?;
1020 grammar.highlights_query = Some(Query::new(&grammar.ts_language, source)?);
1021 Ok(self)
1022 }
1023
1024 pub fn with_runnable_query(mut self, source: &str) -> Result<Self> {
1025 let grammar = self
1026 .grammar_mut()
1027 .ok_or_else(|| anyhow!("cannot mutate grammar"))?;
1028
1029 let query = Query::new(&grammar.ts_language, source)?;
1030 let mut extra_captures = Vec::with_capacity(query.capture_names().len());
1031
1032 for name in query.capture_names().iter() {
1033 let kind = if *name == "run" {
1034 RunnableCapture::Run
1035 } else {
1036 RunnableCapture::Named(name.to_string().into())
1037 };
1038 extra_captures.push(kind);
1039 }
1040
1041 grammar.runnable_config = Some(RunnableConfig {
1042 extra_captures,
1043 query,
1044 });
1045
1046 Ok(self)
1047 }
1048
1049 pub fn with_outline_query(mut self, source: &str) -> Result<Self> {
1050 let grammar = self
1051 .grammar_mut()
1052 .ok_or_else(|| anyhow!("cannot mutate grammar"))?;
1053 let query = Query::new(&grammar.ts_language, source)?;
1054 let mut item_capture_ix = None;
1055 let mut name_capture_ix = None;
1056 let mut context_capture_ix = None;
1057 let mut extra_context_capture_ix = None;
1058 let mut open_capture_ix = None;
1059 let mut close_capture_ix = None;
1060 let mut annotation_capture_ix = None;
1061 get_capture_indices(
1062 &query,
1063 &mut [
1064 ("item", &mut item_capture_ix),
1065 ("name", &mut name_capture_ix),
1066 ("context", &mut context_capture_ix),
1067 ("context.extra", &mut extra_context_capture_ix),
1068 ("open", &mut open_capture_ix),
1069 ("close", &mut close_capture_ix),
1070 ("annotation", &mut annotation_capture_ix),
1071 ],
1072 );
1073 if let Some((item_capture_ix, name_capture_ix)) = item_capture_ix.zip(name_capture_ix) {
1074 grammar.outline_config = Some(OutlineConfig {
1075 query,
1076 item_capture_ix,
1077 name_capture_ix,
1078 context_capture_ix,
1079 extra_context_capture_ix,
1080 open_capture_ix,
1081 close_capture_ix,
1082 annotation_capture_ix,
1083 });
1084 }
1085 Ok(self)
1086 }
1087
1088 pub fn with_embedding_query(mut self, source: &str) -> Result<Self> {
1089 let grammar = self
1090 .grammar_mut()
1091 .ok_or_else(|| anyhow!("cannot mutate grammar"))?;
1092 let query = Query::new(&grammar.ts_language, source)?;
1093 let mut item_capture_ix = None;
1094 let mut name_capture_ix = None;
1095 let mut context_capture_ix = None;
1096 let mut collapse_capture_ix = None;
1097 let mut keep_capture_ix = None;
1098 get_capture_indices(
1099 &query,
1100 &mut [
1101 ("item", &mut item_capture_ix),
1102 ("name", &mut name_capture_ix),
1103 ("context", &mut context_capture_ix),
1104 ("keep", &mut keep_capture_ix),
1105 ("collapse", &mut collapse_capture_ix),
1106 ],
1107 );
1108 if let Some(item_capture_ix) = item_capture_ix {
1109 grammar.embedding_config = Some(EmbeddingConfig {
1110 query,
1111 item_capture_ix,
1112 name_capture_ix,
1113 context_capture_ix,
1114 collapse_capture_ix,
1115 keep_capture_ix,
1116 });
1117 }
1118 Ok(self)
1119 }
1120
1121 pub fn with_brackets_query(mut self, source: &str) -> Result<Self> {
1122 let grammar = self
1123 .grammar_mut()
1124 .ok_or_else(|| anyhow!("cannot mutate grammar"))?;
1125 let query = Query::new(&grammar.ts_language, source)?;
1126 let mut open_capture_ix = None;
1127 let mut close_capture_ix = None;
1128 get_capture_indices(
1129 &query,
1130 &mut [
1131 ("open", &mut open_capture_ix),
1132 ("close", &mut close_capture_ix),
1133 ],
1134 );
1135 if let Some((open_capture_ix, close_capture_ix)) = open_capture_ix.zip(close_capture_ix) {
1136 grammar.brackets_config = Some(BracketConfig {
1137 query,
1138 open_capture_ix,
1139 close_capture_ix,
1140 });
1141 }
1142 Ok(self)
1143 }
1144
1145 pub fn with_indents_query(mut self, source: &str) -> Result<Self> {
1146 let grammar = self
1147 .grammar_mut()
1148 .ok_or_else(|| anyhow!("cannot mutate grammar"))?;
1149 let query = Query::new(&grammar.ts_language, source)?;
1150 let mut indent_capture_ix = None;
1151 let mut start_capture_ix = None;
1152 let mut end_capture_ix = None;
1153 let mut outdent_capture_ix = None;
1154 get_capture_indices(
1155 &query,
1156 &mut [
1157 ("indent", &mut indent_capture_ix),
1158 ("start", &mut start_capture_ix),
1159 ("end", &mut end_capture_ix),
1160 ("outdent", &mut outdent_capture_ix),
1161 ],
1162 );
1163 if let Some(indent_capture_ix) = indent_capture_ix {
1164 grammar.indents_config = Some(IndentConfig {
1165 query,
1166 indent_capture_ix,
1167 start_capture_ix,
1168 end_capture_ix,
1169 outdent_capture_ix,
1170 });
1171 }
1172 Ok(self)
1173 }
1174
1175 pub fn with_injection_query(mut self, source: &str) -> Result<Self> {
1176 let grammar = self
1177 .grammar_mut()
1178 .ok_or_else(|| anyhow!("cannot mutate grammar"))?;
1179 let query = Query::new(&grammar.ts_language, source)?;
1180 let mut language_capture_ix = None;
1181 let mut content_capture_ix = None;
1182 get_capture_indices(
1183 &query,
1184 &mut [
1185 ("language", &mut language_capture_ix),
1186 ("content", &mut content_capture_ix),
1187 ],
1188 );
1189 let patterns = (0..query.pattern_count())
1190 .map(|ix| {
1191 let mut config = InjectionPatternConfig::default();
1192 for setting in query.property_settings(ix) {
1193 match setting.key.as_ref() {
1194 "language" => {
1195 config.language.clone_from(&setting.value);
1196 }
1197 "combined" => {
1198 config.combined = true;
1199 }
1200 _ => {}
1201 }
1202 }
1203 config
1204 })
1205 .collect();
1206 if let Some(content_capture_ix) = content_capture_ix {
1207 grammar.injection_config = Some(InjectionConfig {
1208 query,
1209 language_capture_ix,
1210 content_capture_ix,
1211 patterns,
1212 });
1213 }
1214 Ok(self)
1215 }
1216
1217 pub fn with_override_query(mut self, source: &str) -> anyhow::Result<Self> {
1218 let query = {
1219 let grammar = self
1220 .grammar
1221 .as_ref()
1222 .ok_or_else(|| anyhow!("no grammar for language"))?;
1223 Query::new(&grammar.ts_language, source)?
1224 };
1225
1226 let mut override_configs_by_id = HashMap::default();
1227 for (ix, mut name) in query.capture_names().iter().copied().enumerate() {
1228 let mut range_is_inclusive = false;
1229 if name.starts_with('_') {
1230 continue;
1231 }
1232 if let Some(prefix) = name.strip_suffix(".inclusive") {
1233 name = prefix;
1234 range_is_inclusive = true;
1235 }
1236
1237 let value = self.config.overrides.get(name).cloned().unwrap_or_default();
1238 for server_name in &value.opt_into_language_servers {
1239 if !self
1240 .config
1241 .scope_opt_in_language_servers
1242 .contains(server_name)
1243 {
1244 util::debug_panic!("Server {server_name:?} has been opted-in by scope {name:?} but has not been marked as an opt-in server");
1245 }
1246 }
1247
1248 override_configs_by_id.insert(
1249 ix as u32,
1250 OverrideEntry {
1251 name: name.to_string(),
1252 range_is_inclusive,
1253 value,
1254 },
1255 );
1256 }
1257
1258 let referenced_override_names = self.config.overrides.keys().chain(
1259 self.config
1260 .brackets
1261 .disabled_scopes_by_bracket_ix
1262 .iter()
1263 .flatten(),
1264 );
1265
1266 for referenced_name in referenced_override_names {
1267 if !override_configs_by_id
1268 .values()
1269 .any(|entry| entry.name == *referenced_name)
1270 {
1271 Err(anyhow!(
1272 "language {:?} has overrides in config not in query: {referenced_name:?}",
1273 self.config.name
1274 ))?;
1275 }
1276 }
1277
1278 for entry in override_configs_by_id.values_mut() {
1279 entry.value.disabled_bracket_ixs = self
1280 .config
1281 .brackets
1282 .disabled_scopes_by_bracket_ix
1283 .iter()
1284 .enumerate()
1285 .filter_map(|(ix, disabled_scope_names)| {
1286 if disabled_scope_names.contains(&entry.name) {
1287 Some(ix as u16)
1288 } else {
1289 None
1290 }
1291 })
1292 .collect();
1293 }
1294
1295 self.config.brackets.disabled_scopes_by_bracket_ix.clear();
1296
1297 let grammar = self
1298 .grammar_mut()
1299 .ok_or_else(|| anyhow!("cannot mutate grammar"))?;
1300 grammar.override_config = Some(OverrideConfig {
1301 query,
1302 values: override_configs_by_id,
1303 });
1304 Ok(self)
1305 }
1306
1307 pub fn with_redaction_query(mut self, source: &str) -> anyhow::Result<Self> {
1308 let grammar = self
1309 .grammar_mut()
1310 .ok_or_else(|| anyhow!("cannot mutate grammar"))?;
1311
1312 let query = Query::new(&grammar.ts_language, source)?;
1313 let mut redaction_capture_ix = None;
1314 get_capture_indices(&query, &mut [("redact", &mut redaction_capture_ix)]);
1315
1316 if let Some(redaction_capture_ix) = redaction_capture_ix {
1317 grammar.redactions_config = Some(RedactionConfig {
1318 query,
1319 redaction_capture_ix,
1320 });
1321 }
1322
1323 Ok(self)
1324 }
1325
1326 fn grammar_mut(&mut self) -> Option<&mut Grammar> {
1327 Arc::get_mut(self.grammar.as_mut()?)
1328 }
1329
1330 pub fn name(&self) -> LanguageName {
1331 self.config.name.clone()
1332 }
1333
1334 pub fn code_fence_block_name(&self) -> Arc<str> {
1335 self.config
1336 .code_fence_block_name
1337 .clone()
1338 .unwrap_or_else(|| self.config.name.0.to_lowercase().into())
1339 }
1340
1341 pub fn context_provider(&self) -> Option<Arc<dyn ContextProvider>> {
1342 self.context_provider.clone()
1343 }
1344
1345 pub fn toolchain_lister(&self) -> Option<Arc<dyn ToolchainLister>> {
1346 self.toolchain.clone()
1347 }
1348
1349 pub fn highlight_text<'a>(
1350 self: &'a Arc<Self>,
1351 text: &'a Rope,
1352 range: Range<usize>,
1353 ) -> Vec<(Range<usize>, HighlightId)> {
1354 let mut result = Vec::new();
1355 if let Some(grammar) = &self.grammar {
1356 let tree = grammar.parse_text(text, None);
1357 let captures =
1358 SyntaxSnapshot::single_tree_captures(range.clone(), text, &tree, self, |grammar| {
1359 grammar.highlights_query.as_ref()
1360 });
1361 let highlight_maps = vec![grammar.highlight_map()];
1362 let mut offset = 0;
1363 for chunk in
1364 BufferChunks::new(text, range, Some((captures, highlight_maps)), false, None)
1365 {
1366 let end_offset = offset + chunk.text.len();
1367 if let Some(highlight_id) = chunk.syntax_highlight_id {
1368 if !highlight_id.is_default() {
1369 result.push((offset..end_offset, highlight_id));
1370 }
1371 }
1372 offset = end_offset;
1373 }
1374 }
1375 result
1376 }
1377
1378 pub fn path_suffixes(&self) -> &[String] {
1379 &self.config.matcher.path_suffixes
1380 }
1381
1382 pub fn should_autoclose_before(&self, c: char) -> bool {
1383 c.is_whitespace() || self.config.autoclose_before.contains(c)
1384 }
1385
1386 pub fn set_theme(&self, theme: &SyntaxTheme) {
1387 if let Some(grammar) = self.grammar.as_ref() {
1388 if let Some(highlights_query) = &grammar.highlights_query {
1389 *grammar.highlight_map.lock() =
1390 HighlightMap::new(highlights_query.capture_names(), theme);
1391 }
1392 }
1393 }
1394
1395 pub fn grammar(&self) -> Option<&Arc<Grammar>> {
1396 self.grammar.as_ref()
1397 }
1398
1399 pub fn default_scope(self: &Arc<Self>) -> LanguageScope {
1400 LanguageScope {
1401 language: self.clone(),
1402 override_id: None,
1403 }
1404 }
1405
1406 pub fn lsp_id(&self) -> String {
1407 self.config.name.lsp_id()
1408 }
1409
1410 pub fn prettier_parser_name(&self) -> Option<&str> {
1411 self.config.prettier_parser_name.as_deref()
1412 }
1413}
1414
1415impl LanguageScope {
1416 pub fn path_suffixes(&self) -> &[String] {
1417 &self.language.path_suffixes()
1418 }
1419
1420 pub fn language_name(&self) -> LanguageName {
1421 self.language.config.name.clone()
1422 }
1423
1424 pub fn collapsed_placeholder(&self) -> &str {
1425 self.language.config.collapsed_placeholder.as_ref()
1426 }
1427
1428 /// Returns line prefix that is inserted in e.g. line continuations or
1429 /// in `toggle comments` action.
1430 pub fn line_comment_prefixes(&self) -> &[Arc<str>] {
1431 Override::as_option(
1432 self.config_override().map(|o| &o.line_comments),
1433 Some(&self.language.config.line_comments),
1434 )
1435 .map_or(&[] as &[_], |e| e.as_slice())
1436 }
1437
1438 pub fn block_comment_delimiters(&self) -> Option<(&Arc<str>, &Arc<str>)> {
1439 Override::as_option(
1440 self.config_override().map(|o| &o.block_comment),
1441 self.language.config.block_comment.as_ref(),
1442 )
1443 .map(|e| (&e.0, &e.1))
1444 }
1445
1446 /// Returns a list of language-specific word characters.
1447 ///
1448 /// By default, Zed treats alphanumeric characters (and '_') as word characters for
1449 /// the purpose of actions like 'move to next word end` or whole-word search.
1450 /// It additionally accounts for language's additional word characters.
1451 pub fn word_characters(&self) -> Option<&HashSet<char>> {
1452 Override::as_option(
1453 self.config_override().map(|o| &o.word_characters),
1454 Some(&self.language.config.word_characters),
1455 )
1456 }
1457
1458 /// Returns a list of bracket pairs for a given language with an additional
1459 /// piece of information about whether the particular bracket pair is currently active for a given language.
1460 pub fn brackets(&self) -> impl Iterator<Item = (&BracketPair, bool)> {
1461 let mut disabled_ids = self
1462 .config_override()
1463 .map_or(&[] as _, |o| o.disabled_bracket_ixs.as_slice());
1464 self.language
1465 .config
1466 .brackets
1467 .pairs
1468 .iter()
1469 .enumerate()
1470 .map(move |(ix, bracket)| {
1471 let mut is_enabled = true;
1472 if let Some(next_disabled_ix) = disabled_ids.first() {
1473 if ix == *next_disabled_ix as usize {
1474 disabled_ids = &disabled_ids[1..];
1475 is_enabled = false;
1476 }
1477 }
1478 (bracket, is_enabled)
1479 })
1480 }
1481
1482 pub fn should_autoclose_before(&self, c: char) -> bool {
1483 c.is_whitespace() || self.language.config.autoclose_before.contains(c)
1484 }
1485
1486 pub fn language_allowed(&self, name: &LanguageServerName) -> bool {
1487 let config = &self.language.config;
1488 let opt_in_servers = &config.scope_opt_in_language_servers;
1489 if opt_in_servers.iter().any(|o| *o == *name) {
1490 if let Some(over) = self.config_override() {
1491 over.opt_into_language_servers.iter().any(|o| *o == *name)
1492 } else {
1493 false
1494 }
1495 } else {
1496 true
1497 }
1498 }
1499
1500 pub fn override_name(&self) -> Option<&str> {
1501 let id = self.override_id?;
1502 let grammar = self.language.grammar.as_ref()?;
1503 let override_config = grammar.override_config.as_ref()?;
1504 override_config.values.get(&id).map(|e| e.name.as_str())
1505 }
1506
1507 fn config_override(&self) -> Option<&LanguageConfigOverride> {
1508 let id = self.override_id?;
1509 let grammar = self.language.grammar.as_ref()?;
1510 let override_config = grammar.override_config.as_ref()?;
1511 override_config.values.get(&id).map(|e| &e.value)
1512 }
1513}
1514
1515impl Hash for Language {
1516 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1517 self.id.hash(state)
1518 }
1519}
1520
1521impl PartialEq for Language {
1522 fn eq(&self, other: &Self) -> bool {
1523 self.id.eq(&other.id)
1524 }
1525}
1526
1527impl Eq for Language {}
1528
1529impl Debug for Language {
1530 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1531 f.debug_struct("Language")
1532 .field("name", &self.config.name)
1533 .finish()
1534 }
1535}
1536
1537impl Grammar {
1538 pub fn id(&self) -> GrammarId {
1539 self.id
1540 }
1541
1542 fn parse_text(&self, text: &Rope, old_tree: Option<Tree>) -> Tree {
1543 with_parser(|parser| {
1544 parser
1545 .set_language(&self.ts_language)
1546 .expect("incompatible grammar");
1547 let mut chunks = text.chunks_in_range(0..text.len());
1548 parser
1549 .parse_with(
1550 &mut move |offset, _| {
1551 chunks.seek(offset);
1552 chunks.next().unwrap_or("").as_bytes()
1553 },
1554 old_tree.as_ref(),
1555 )
1556 .unwrap()
1557 })
1558 }
1559
1560 pub fn highlight_map(&self) -> HighlightMap {
1561 self.highlight_map.lock().clone()
1562 }
1563
1564 pub fn highlight_id_for_name(&self, name: &str) -> Option<HighlightId> {
1565 let capture_id = self
1566 .highlights_query
1567 .as_ref()?
1568 .capture_index_for_name(name)?;
1569 Some(self.highlight_map.lock().get(capture_id))
1570 }
1571}
1572
1573impl CodeLabel {
1574 pub fn plain(text: String, filter_text: Option<&str>) -> Self {
1575 let mut result = Self {
1576 runs: Vec::new(),
1577 filter_range: 0..text.len(),
1578 text,
1579 };
1580 if let Some(filter_text) = filter_text {
1581 if let Some(ix) = result.text.find(filter_text) {
1582 result.filter_range = ix..ix + filter_text.len();
1583 }
1584 }
1585 result
1586 }
1587
1588 pub fn push_str(&mut self, text: &str, highlight: Option<HighlightId>) {
1589 let start_ix = self.text.len();
1590 self.text.push_str(text);
1591 let end_ix = self.text.len();
1592 if let Some(highlight) = highlight {
1593 self.runs.push((start_ix..end_ix, highlight));
1594 }
1595 }
1596
1597 pub fn text(&self) -> &str {
1598 self.text.as_str()
1599 }
1600}
1601
1602impl From<String> for CodeLabel {
1603 fn from(value: String) -> Self {
1604 Self::plain(value, None)
1605 }
1606}
1607
1608impl From<&str> for CodeLabel {
1609 fn from(value: &str) -> Self {
1610 Self::plain(value.to_string(), None)
1611 }
1612}
1613
1614impl Ord for LanguageMatcher {
1615 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1616 self.path_suffixes.cmp(&other.path_suffixes).then_with(|| {
1617 self.first_line_pattern
1618 .as_ref()
1619 .map(Regex::as_str)
1620 .cmp(&other.first_line_pattern.as_ref().map(Regex::as_str))
1621 })
1622 }
1623}
1624
1625impl PartialOrd for LanguageMatcher {
1626 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1627 Some(self.cmp(other))
1628 }
1629}
1630
1631impl Eq for LanguageMatcher {}
1632
1633impl PartialEq for LanguageMatcher {
1634 fn eq(&self, other: &Self) -> bool {
1635 self.path_suffixes == other.path_suffixes
1636 && self.first_line_pattern.as_ref().map(Regex::as_str)
1637 == other.first_line_pattern.as_ref().map(Regex::as_str)
1638 }
1639}
1640
1641#[cfg(any(test, feature = "test-support"))]
1642impl Default for FakeLspAdapter {
1643 fn default() -> Self {
1644 Self {
1645 name: "the-fake-language-server",
1646 capabilities: lsp::LanguageServer::full_capabilities(),
1647 initializer: None,
1648 disk_based_diagnostics_progress_token: None,
1649 initialization_options: None,
1650 disk_based_diagnostics_sources: Vec::new(),
1651 prettier_plugins: Vec::new(),
1652 language_server_binary: LanguageServerBinary {
1653 path: "/the/fake/lsp/path".into(),
1654 arguments: vec![],
1655 env: Default::default(),
1656 },
1657 }
1658 }
1659}
1660
1661#[cfg(any(test, feature = "test-support"))]
1662#[async_trait(?Send)]
1663impl LspAdapter for FakeLspAdapter {
1664 fn name(&self) -> LanguageServerName {
1665 LanguageServerName(self.name.into())
1666 }
1667
1668 async fn check_if_user_installed(
1669 &self,
1670 _: &dyn LspAdapterDelegate,
1671 _: Arc<dyn LanguageToolchainStore>,
1672 _: &AsyncAppContext,
1673 ) -> Option<LanguageServerBinary> {
1674 Some(self.language_server_binary.clone())
1675 }
1676
1677 fn get_language_server_command<'a>(
1678 self: Arc<Self>,
1679 _: Arc<dyn LspAdapterDelegate>,
1680 _: Arc<dyn LanguageToolchainStore>,
1681 _: LanguageServerBinaryOptions,
1682 _: futures::lock::MutexGuard<'a, Option<LanguageServerBinary>>,
1683 _: &'a mut AsyncAppContext,
1684 ) -> Pin<Box<dyn 'a + Future<Output = Result<LanguageServerBinary>>>> {
1685 async move { Ok(self.language_server_binary.clone()) }.boxed_local()
1686 }
1687
1688 async fn fetch_latest_server_version(
1689 &self,
1690 _: &dyn LspAdapterDelegate,
1691 ) -> Result<Box<dyn 'static + Send + Any>> {
1692 unreachable!();
1693 }
1694
1695 async fn fetch_server_binary(
1696 &self,
1697 _: Box<dyn 'static + Send + Any>,
1698 _: PathBuf,
1699 _: &dyn LspAdapterDelegate,
1700 ) -> Result<LanguageServerBinary> {
1701 unreachable!();
1702 }
1703
1704 async fn cached_server_binary(
1705 &self,
1706 _: PathBuf,
1707 _: &dyn LspAdapterDelegate,
1708 ) -> Option<LanguageServerBinary> {
1709 unreachable!();
1710 }
1711
1712 fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
1713
1714 fn disk_based_diagnostic_sources(&self) -> Vec<String> {
1715 self.disk_based_diagnostics_sources.clone()
1716 }
1717
1718 fn disk_based_diagnostics_progress_token(&self) -> Option<String> {
1719 self.disk_based_diagnostics_progress_token.clone()
1720 }
1721
1722 async fn initialization_options(
1723 self: Arc<Self>,
1724 _: &Arc<dyn LspAdapterDelegate>,
1725 ) -> Result<Option<Value>> {
1726 Ok(self.initialization_options.clone())
1727 }
1728}
1729
1730fn get_capture_indices(query: &Query, captures: &mut [(&str, &mut Option<u32>)]) {
1731 for (ix, name) in query.capture_names().iter().enumerate() {
1732 for (capture_name, index) in captures.iter_mut() {
1733 if capture_name == name {
1734 **index = Some(ix as u32);
1735 break;
1736 }
1737 }
1738 }
1739}
1740
1741pub fn point_to_lsp(point: PointUtf16) -> lsp::Position {
1742 lsp::Position::new(point.row, point.column)
1743}
1744
1745pub fn point_from_lsp(point: lsp::Position) -> Unclipped<PointUtf16> {
1746 Unclipped(PointUtf16::new(point.line, point.character))
1747}
1748
1749pub fn range_to_lsp(range: Range<PointUtf16>) -> lsp::Range {
1750 lsp::Range {
1751 start: point_to_lsp(range.start),
1752 end: point_to_lsp(range.end),
1753 }
1754}
1755
1756pub fn range_from_lsp(range: lsp::Range) -> Range<Unclipped<PointUtf16>> {
1757 let mut start = point_from_lsp(range.start);
1758 let mut end = point_from_lsp(range.end);
1759 if start > end {
1760 mem::swap(&mut start, &mut end);
1761 }
1762 start..end
1763}
1764
1765#[cfg(test)]
1766mod tests {
1767 use super::*;
1768 use gpui::TestAppContext;
1769
1770 #[gpui::test(iterations = 10)]
1771 async fn test_language_loading(cx: &mut TestAppContext) {
1772 let languages = LanguageRegistry::test(cx.executor());
1773 let languages = Arc::new(languages);
1774 languages.register_native_grammars([
1775 ("json", tree_sitter_json::LANGUAGE),
1776 ("rust", tree_sitter_rust::LANGUAGE),
1777 ]);
1778 languages.register_test_language(LanguageConfig {
1779 name: "JSON".into(),
1780 grammar: Some("json".into()),
1781 matcher: LanguageMatcher {
1782 path_suffixes: vec!["json".into()],
1783 ..Default::default()
1784 },
1785 ..Default::default()
1786 });
1787 languages.register_test_language(LanguageConfig {
1788 name: "Rust".into(),
1789 grammar: Some("rust".into()),
1790 matcher: LanguageMatcher {
1791 path_suffixes: vec!["rs".into()],
1792 ..Default::default()
1793 },
1794 ..Default::default()
1795 });
1796 assert_eq!(
1797 languages.language_names(),
1798 &[
1799 "JSON".to_string(),
1800 "Plain Text".to_string(),
1801 "Rust".to_string(),
1802 ]
1803 );
1804
1805 let rust1 = languages.language_for_name("Rust");
1806 let rust2 = languages.language_for_name("Rust");
1807
1808 // Ensure language is still listed even if it's being loaded.
1809 assert_eq!(
1810 languages.language_names(),
1811 &[
1812 "JSON".to_string(),
1813 "Plain Text".to_string(),
1814 "Rust".to_string(),
1815 ]
1816 );
1817
1818 let (rust1, rust2) = futures::join!(rust1, rust2);
1819 assert!(Arc::ptr_eq(&rust1.unwrap(), &rust2.unwrap()));
1820
1821 // Ensure language is still listed even after loading it.
1822 assert_eq!(
1823 languages.language_names(),
1824 &[
1825 "JSON".to_string(),
1826 "Plain Text".to_string(),
1827 "Rust".to_string(),
1828 ]
1829 );
1830
1831 // Loading an unknown language returns an error.
1832 assert!(languages.language_for_name("Unknown").await.is_err());
1833 }
1834}