language.rs

   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 manifest;
  15pub mod modeline;
  16mod outline;
  17pub mod proto;
  18mod syntax_map;
  19mod task_context;
  20mod text_diff;
  21mod toolchain;
  22
  23#[cfg(test)]
  24pub mod buffer_tests;
  25
  26use crate::language_settings::SoftWrap;
  27pub use crate::language_settings::{EditPredictionsMode, IndentGuideSettings};
  28use anyhow::{Context as _, Result};
  29use async_trait::async_trait;
  30use collections::{HashMap, HashSet, IndexSet};
  31use futures::Future;
  32use futures::future::LocalBoxFuture;
  33use futures::lock::OwnedMutexGuard;
  34use gpui::{App, AsyncApp, Entity, SharedString};
  35pub use highlight_map::HighlightMap;
  36use http_client::HttpClient;
  37pub use language_registry::{
  38    LanguageName, LanguageServerStatusUpdate, LoadedLanguage, ServerHealth,
  39};
  40use lsp::{
  41    CodeActionKind, InitializeParams, LanguageServerBinary, LanguageServerBinaryOptions, Uri,
  42};
  43pub use manifest::{ManifestDelegate, ManifestName, ManifestProvider, ManifestQuery};
  44pub use modeline::{ModelineSettings, parse_modeline};
  45use parking_lot::Mutex;
  46use regex::Regex;
  47use schemars::{JsonSchema, SchemaGenerator, json_schema};
  48use semver::Version;
  49use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
  50use serde_json::Value;
  51use settings::WorktreeId;
  52use smol::future::FutureExt as _;
  53use std::num::NonZeroU32;
  54use std::{
  55    ffi::OsStr,
  56    fmt::Debug,
  57    hash::Hash,
  58    mem,
  59    ops::{DerefMut, Range},
  60    path::{Path, PathBuf},
  61    str,
  62    sync::{
  63        Arc, LazyLock,
  64        atomic::{AtomicUsize, Ordering::SeqCst},
  65    },
  66};
  67use syntax_map::{QueryCursorHandle, SyntaxSnapshot};
  68use task::RunnableTag;
  69pub use task_context::{ContextLocation, ContextProvider, RunnableRange};
  70pub use text_diff::{
  71    DiffOptions, apply_diff_patch, line_diff, text_diff, text_diff_with_options, unified_diff,
  72    unified_diff_with_offsets, word_diff_ranges,
  73};
  74use theme::SyntaxTheme;
  75pub use toolchain::{
  76    LanguageToolchainStore, LocalLanguageToolchainStore, Toolchain, ToolchainList, ToolchainLister,
  77    ToolchainMetadata, ToolchainScope,
  78};
  79use tree_sitter::{self, Query, QueryCursor, WasmStore, wasmtime};
  80use util::rel_path::RelPath;
  81use util::serde::default_true;
  82
  83pub use buffer::Operation;
  84pub use buffer::*;
  85pub use diagnostic_set::{DiagnosticEntry, DiagnosticEntryRef, DiagnosticGroup};
  86pub use language_registry::{
  87    AvailableLanguage, BinaryStatus, LanguageNotFound, LanguageQueries, LanguageRegistry,
  88    QUERY_FILENAME_PREFIXES,
  89};
  90pub use lsp::{LanguageServerId, LanguageServerName};
  91pub use outline::*;
  92pub use syntax_map::{
  93    OwnedSyntaxLayer, SyntaxLayer, SyntaxMapMatches, ToTreeSitterPoint, TreeSitterOptions,
  94};
  95pub use text::{AnchorRangeExt, LineEnding};
  96pub use tree_sitter::{Node, Parser, Tree, TreeCursor};
  97
  98static QUERY_CURSORS: Mutex<Vec<QueryCursor>> = Mutex::new(vec![]);
  99static PARSERS: Mutex<Vec<Parser>> = Mutex::new(vec![]);
 100
 101pub fn with_parser<F, R>(func: F) -> R
 102where
 103    F: FnOnce(&mut Parser) -> R,
 104{
 105    let mut parser = PARSERS.lock().pop().unwrap_or_else(|| {
 106        let mut parser = Parser::new();
 107        parser
 108            .set_wasm_store(WasmStore::new(&WASM_ENGINE).unwrap())
 109            .unwrap();
 110        parser
 111    });
 112    parser.set_included_ranges(&[]).unwrap();
 113    let result = func(&mut parser);
 114    PARSERS.lock().push(parser);
 115    result
 116}
 117
 118pub fn with_query_cursor<F, R>(func: F) -> R
 119where
 120    F: FnOnce(&mut QueryCursor) -> R,
 121{
 122    let mut cursor = QueryCursorHandle::new();
 123    func(cursor.deref_mut())
 124}
 125
 126static NEXT_LANGUAGE_ID: AtomicUsize = AtomicUsize::new(0);
 127static NEXT_GRAMMAR_ID: AtomicUsize = AtomicUsize::new(0);
 128static WASM_ENGINE: LazyLock<wasmtime::Engine> = LazyLock::new(|| {
 129    wasmtime::Engine::new(&wasmtime::Config::new()).expect("Failed to create Wasmtime engine")
 130});
 131
 132/// A shared grammar for plain text, exposed for reuse by downstream crates.
 133pub static PLAIN_TEXT: LazyLock<Arc<Language>> = LazyLock::new(|| {
 134    Arc::new(Language::new(
 135        LanguageConfig {
 136            name: "Plain Text".into(),
 137            soft_wrap: Some(SoftWrap::EditorWidth),
 138            matcher: LanguageMatcher {
 139                path_suffixes: vec!["txt".to_owned()],
 140                first_line_pattern: None,
 141                modeline_aliases: vec!["text".to_owned(), "txt".to_owned()],
 142            },
 143            brackets: BracketPairConfig {
 144                pairs: vec![
 145                    BracketPair {
 146                        start: "(".to_string(),
 147                        end: ")".to_string(),
 148                        close: true,
 149                        surround: true,
 150                        newline: false,
 151                    },
 152                    BracketPair {
 153                        start: "[".to_string(),
 154                        end: "]".to_string(),
 155                        close: true,
 156                        surround: true,
 157                        newline: false,
 158                    },
 159                    BracketPair {
 160                        start: "{".to_string(),
 161                        end: "}".to_string(),
 162                        close: true,
 163                        surround: true,
 164                        newline: false,
 165                    },
 166                    BracketPair {
 167                        start: "\"".to_string(),
 168                        end: "\"".to_string(),
 169                        close: true,
 170                        surround: true,
 171                        newline: false,
 172                    },
 173                    BracketPair {
 174                        start: "'".to_string(),
 175                        end: "'".to_string(),
 176                        close: true,
 177                        surround: true,
 178                        newline: false,
 179                    },
 180                ],
 181                disabled_scopes_by_bracket_ix: Default::default(),
 182            },
 183            ..Default::default()
 184        },
 185        None,
 186    ))
 187});
 188
 189/// Types that represent a position in a buffer, and can be converted into
 190/// an LSP position, to send to a language server.
 191pub trait ToLspPosition {
 192    /// Converts the value into an LSP position.
 193    fn to_lsp_position(self) -> lsp::Position;
 194}
 195
 196#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 197pub struct Location {
 198    pub buffer: Entity<Buffer>,
 199    pub range: Range<Anchor>,
 200}
 201
 202type ServerBinaryCache = futures::lock::Mutex<Option<(bool, LanguageServerBinary)>>;
 203type DownloadableLanguageServerBinary = LocalBoxFuture<'static, Result<LanguageServerBinary>>;
 204pub type LanguageServerBinaryLocations = LocalBoxFuture<
 205    'static,
 206    (
 207        Result<LanguageServerBinary>,
 208        Option<DownloadableLanguageServerBinary>,
 209    ),
 210>;
 211/// Represents a Language Server, with certain cached sync properties.
 212/// Uses [`LspAdapter`] under the hood, but calls all 'static' methods
 213/// once at startup, and caches the results.
 214pub struct CachedLspAdapter {
 215    pub name: LanguageServerName,
 216    pub disk_based_diagnostic_sources: Vec<String>,
 217    pub disk_based_diagnostics_progress_token: Option<String>,
 218    language_ids: HashMap<LanguageName, String>,
 219    pub adapter: Arc<dyn LspAdapter>,
 220    cached_binary: Arc<ServerBinaryCache>,
 221}
 222
 223impl Debug for CachedLspAdapter {
 224    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 225        f.debug_struct("CachedLspAdapter")
 226            .field("name", &self.name)
 227            .field(
 228                "disk_based_diagnostic_sources",
 229                &self.disk_based_diagnostic_sources,
 230            )
 231            .field(
 232                "disk_based_diagnostics_progress_token",
 233                &self.disk_based_diagnostics_progress_token,
 234            )
 235            .field("language_ids", &self.language_ids)
 236            .finish_non_exhaustive()
 237    }
 238}
 239
 240impl CachedLspAdapter {
 241    pub fn new(adapter: Arc<dyn LspAdapter>) -> Arc<Self> {
 242        let name = adapter.name();
 243        let disk_based_diagnostic_sources = adapter.disk_based_diagnostic_sources();
 244        let disk_based_diagnostics_progress_token = adapter.disk_based_diagnostics_progress_token();
 245        let language_ids = adapter.language_ids();
 246
 247        Arc::new(CachedLspAdapter {
 248            name,
 249            disk_based_diagnostic_sources,
 250            disk_based_diagnostics_progress_token,
 251            language_ids,
 252            adapter,
 253            cached_binary: Default::default(),
 254        })
 255    }
 256
 257    pub fn name(&self) -> LanguageServerName {
 258        self.adapter.name()
 259    }
 260
 261    pub async fn get_language_server_command(
 262        self: Arc<Self>,
 263        delegate: Arc<dyn LspAdapterDelegate>,
 264        toolchains: Option<Toolchain>,
 265        binary_options: LanguageServerBinaryOptions,
 266        cx: &mut AsyncApp,
 267    ) -> LanguageServerBinaryLocations {
 268        let cached_binary = self.cached_binary.clone().lock_owned().await;
 269        self.adapter.clone().get_language_server_command(
 270            delegate,
 271            toolchains,
 272            binary_options,
 273            cached_binary,
 274            cx.clone(),
 275        )
 276    }
 277
 278    pub fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
 279        self.adapter.code_action_kinds()
 280    }
 281
 282    pub fn process_diagnostics(
 283        &self,
 284        params: &mut lsp::PublishDiagnosticsParams,
 285        server_id: LanguageServerId,
 286        existing_diagnostics: Option<&'_ Buffer>,
 287    ) {
 288        self.adapter
 289            .process_diagnostics(params, server_id, existing_diagnostics)
 290    }
 291
 292    pub fn retain_old_diagnostic(&self, previous_diagnostic: &Diagnostic, cx: &App) -> bool {
 293        self.adapter.retain_old_diagnostic(previous_diagnostic, cx)
 294    }
 295
 296    pub fn underline_diagnostic(&self, diagnostic: &lsp::Diagnostic) -> bool {
 297        self.adapter.underline_diagnostic(diagnostic)
 298    }
 299
 300    pub fn diagnostic_message_to_markdown(&self, message: &str) -> Option<String> {
 301        self.adapter.diagnostic_message_to_markdown(message)
 302    }
 303
 304    pub async fn process_completions(&self, completion_items: &mut [lsp::CompletionItem]) {
 305        self.adapter.process_completions(completion_items).await
 306    }
 307
 308    pub async fn labels_for_completions(
 309        &self,
 310        completion_items: &[lsp::CompletionItem],
 311        language: &Arc<Language>,
 312    ) -> Result<Vec<Option<CodeLabel>>> {
 313        self.adapter
 314            .clone()
 315            .labels_for_completions(completion_items, language)
 316            .await
 317    }
 318
 319    pub async fn labels_for_symbols(
 320        &self,
 321        symbols: &[(String, lsp::SymbolKind)],
 322        language: &Arc<Language>,
 323    ) -> Result<Vec<Option<CodeLabel>>> {
 324        self.adapter
 325            .clone()
 326            .labels_for_symbols(symbols, language)
 327            .await
 328    }
 329
 330    pub fn language_id(&self, language_name: &LanguageName) -> String {
 331        self.language_ids
 332            .get(language_name)
 333            .cloned()
 334            .unwrap_or_else(|| language_name.lsp_id())
 335    }
 336
 337    pub async fn initialization_options_schema(
 338        &self,
 339        delegate: &Arc<dyn LspAdapterDelegate>,
 340        cx: &mut AsyncApp,
 341    ) -> Option<serde_json::Value> {
 342        self.adapter
 343            .clone()
 344            .initialization_options_schema(
 345                delegate,
 346                self.cached_binary.clone().lock_owned().await,
 347                cx,
 348            )
 349            .await
 350    }
 351
 352    pub fn process_prompt_response(&self, context: &PromptResponseContext, cx: &mut AsyncApp) {
 353        self.adapter.process_prompt_response(context, cx)
 354    }
 355}
 356
 357/// [`LspAdapterDelegate`] allows [`LspAdapter]` implementations to interface with the application
 358// e.g. to display a notification or fetch data from the web.
 359#[async_trait]
 360pub trait LspAdapterDelegate: Send + Sync {
 361    fn show_notification(&self, message: &str, cx: &mut App);
 362    fn http_client(&self) -> Arc<dyn HttpClient>;
 363    fn worktree_id(&self) -> WorktreeId;
 364    fn worktree_root_path(&self) -> &Path;
 365    fn resolve_executable_path(&self, path: PathBuf) -> PathBuf;
 366    fn update_status(&self, language: LanguageServerName, status: BinaryStatus);
 367    fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>>;
 368    async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>>;
 369
 370    async fn npm_package_installed_version(
 371        &self,
 372        package_name: &str,
 373    ) -> Result<Option<(PathBuf, Version)>>;
 374    async fn which(&self, command: &OsStr) -> Option<PathBuf>;
 375    async fn shell_env(&self) -> HashMap<String, String>;
 376    async fn read_text_file(&self, path: &RelPath) -> Result<String>;
 377    async fn try_exec(&self, binary: LanguageServerBinary) -> Result<()>;
 378}
 379
 380/// Context provided to LSP adapters when a user responds to a ShowMessageRequest prompt.
 381/// This allows adapters to intercept preference selections (like "Always" or "Never")
 382/// and potentially persist them to Zed's settings.
 383#[derive(Debug, Clone)]
 384pub struct PromptResponseContext {
 385    /// The original message shown to the user
 386    pub message: String,
 387    /// The action (button) the user selected
 388    pub selected_action: lsp::MessageActionItem,
 389}
 390
 391#[async_trait(?Send)]
 392pub trait LspAdapter: 'static + Send + Sync + DynLspInstaller {
 393    fn name(&self) -> LanguageServerName;
 394
 395    fn process_diagnostics(
 396        &self,
 397        _: &mut lsp::PublishDiagnosticsParams,
 398        _: LanguageServerId,
 399        _: Option<&'_ Buffer>,
 400    ) {
 401    }
 402
 403    /// When processing new `lsp::PublishDiagnosticsParams` diagnostics, whether to retain previous one(s) or not.
 404    fn retain_old_diagnostic(&self, _previous_diagnostic: &Diagnostic, _cx: &App) -> bool {
 405        false
 406    }
 407
 408    /// Whether to underline a given diagnostic or not, when rendering in the editor.
 409    ///
 410    /// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnosticTag
 411    /// states that
 412    /// > Clients are allowed to render diagnostics with this tag faded out instead of having an error squiggle.
 413    /// for the unnecessary diagnostics, so do not underline them.
 414    fn underline_diagnostic(&self, _diagnostic: &lsp::Diagnostic) -> bool {
 415        true
 416    }
 417
 418    /// Post-processes completions provided by the language server.
 419    async fn process_completions(&self, _: &mut [lsp::CompletionItem]) {}
 420
 421    fn diagnostic_message_to_markdown(&self, _message: &str) -> Option<String> {
 422        None
 423    }
 424
 425    async fn labels_for_completions(
 426        self: Arc<Self>,
 427        completions: &[lsp::CompletionItem],
 428        language: &Arc<Language>,
 429    ) -> Result<Vec<Option<CodeLabel>>> {
 430        let mut labels = Vec::new();
 431        for (ix, completion) in completions.iter().enumerate() {
 432            let label = self.label_for_completion(completion, language).await;
 433            if let Some(label) = label {
 434                labels.resize(ix + 1, None);
 435                *labels.last_mut().unwrap() = Some(label);
 436            }
 437        }
 438        Ok(labels)
 439    }
 440
 441    async fn label_for_completion(
 442        &self,
 443        _: &lsp::CompletionItem,
 444        _: &Arc<Language>,
 445    ) -> Option<CodeLabel> {
 446        None
 447    }
 448
 449    async fn labels_for_symbols(
 450        self: Arc<Self>,
 451        symbols: &[(String, lsp::SymbolKind)],
 452        language: &Arc<Language>,
 453    ) -> Result<Vec<Option<CodeLabel>>> {
 454        let mut labels = Vec::new();
 455        for (ix, (name, kind)) in symbols.iter().enumerate() {
 456            let label = self.label_for_symbol(name, *kind, language).await;
 457            if let Some(label) = label {
 458                labels.resize(ix + 1, None);
 459                *labels.last_mut().unwrap() = Some(label);
 460            }
 461        }
 462        Ok(labels)
 463    }
 464
 465    async fn label_for_symbol(
 466        &self,
 467        _: &str,
 468        _: lsp::SymbolKind,
 469        _: &Arc<Language>,
 470    ) -> Option<CodeLabel> {
 471        None
 472    }
 473
 474    /// Returns initialization options that are going to be sent to a LSP server as a part of [`lsp::InitializeParams`]
 475    async fn initialization_options(
 476        self: Arc<Self>,
 477        _: &Arc<dyn LspAdapterDelegate>,
 478    ) -> Result<Option<Value>> {
 479        Ok(None)
 480    }
 481
 482    /// Returns the JSON schema of the initialization_options for the language server.
 483    async fn initialization_options_schema(
 484        self: Arc<Self>,
 485        _delegate: &Arc<dyn LspAdapterDelegate>,
 486        _cached_binary: OwnedMutexGuard<Option<(bool, LanguageServerBinary)>>,
 487        _cx: &mut AsyncApp,
 488    ) -> Option<serde_json::Value> {
 489        None
 490    }
 491
 492    async fn workspace_configuration(
 493        self: Arc<Self>,
 494        _: &Arc<dyn LspAdapterDelegate>,
 495        _: Option<Toolchain>,
 496        _: Option<Uri>,
 497        _cx: &mut AsyncApp,
 498    ) -> Result<Value> {
 499        Ok(serde_json::json!({}))
 500    }
 501
 502    async fn additional_initialization_options(
 503        self: Arc<Self>,
 504        _target_language_server_id: LanguageServerName,
 505        _: &Arc<dyn LspAdapterDelegate>,
 506    ) -> Result<Option<Value>> {
 507        Ok(None)
 508    }
 509
 510    async fn additional_workspace_configuration(
 511        self: Arc<Self>,
 512        _target_language_server_id: LanguageServerName,
 513        _: &Arc<dyn LspAdapterDelegate>,
 514        _cx: &mut AsyncApp,
 515    ) -> Result<Option<Value>> {
 516        Ok(None)
 517    }
 518
 519    /// Returns a list of code actions supported by a given LspAdapter
 520    fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
 521        None
 522    }
 523
 524    fn disk_based_diagnostic_sources(&self) -> Vec<String> {
 525        Default::default()
 526    }
 527
 528    fn disk_based_diagnostics_progress_token(&self) -> Option<String> {
 529        None
 530    }
 531
 532    fn language_ids(&self) -> HashMap<LanguageName, String> {
 533        HashMap::default()
 534    }
 535
 536    /// Support custom initialize params.
 537    fn prepare_initialize_params(
 538        &self,
 539        original: InitializeParams,
 540        _: &App,
 541    ) -> Result<InitializeParams> {
 542        Ok(original)
 543    }
 544
 545    /// Method only implemented by the default JSON language server adapter.
 546    /// Used to provide dynamic reloading of the JSON schemas used to
 547    /// provide autocompletion and diagnostics in Zed setting and keybind
 548    /// files
 549    fn is_primary_zed_json_schema_adapter(&self) -> bool {
 550        false
 551    }
 552
 553    /// True for the extension adapter and false otherwise.
 554    fn is_extension(&self) -> bool {
 555        false
 556    }
 557
 558    /// Called when a user responds to a ShowMessageRequest from this language server.
 559    /// This allows adapters to intercept preference selections (like "Always" or "Never")
 560    /// for settings that should be persisted to Zed's settings file.
 561    fn process_prompt_response(&self, _context: &PromptResponseContext, _cx: &mut AsyncApp) {}
 562}
 563
 564pub trait LspInstaller {
 565    type BinaryVersion;
 566    fn check_if_user_installed(
 567        &self,
 568        _: &dyn LspAdapterDelegate,
 569        _: Option<Toolchain>,
 570        _: &AsyncApp,
 571    ) -> impl Future<Output = Option<LanguageServerBinary>> {
 572        async { None }
 573    }
 574
 575    fn fetch_latest_server_version(
 576        &self,
 577        delegate: &dyn LspAdapterDelegate,
 578        pre_release: bool,
 579        cx: &mut AsyncApp,
 580    ) -> impl Future<Output = Result<Self::BinaryVersion>>;
 581
 582    fn check_if_version_installed(
 583        &self,
 584        _version: &Self::BinaryVersion,
 585        _container_dir: &PathBuf,
 586        _delegate: &dyn LspAdapterDelegate,
 587    ) -> impl Send + Future<Output = Option<LanguageServerBinary>> {
 588        async { None }
 589    }
 590
 591    fn fetch_server_binary(
 592        &self,
 593        latest_version: Self::BinaryVersion,
 594        container_dir: PathBuf,
 595        delegate: &dyn LspAdapterDelegate,
 596    ) -> impl Send + Future<Output = Result<LanguageServerBinary>>;
 597
 598    fn cached_server_binary(
 599        &self,
 600        container_dir: PathBuf,
 601        delegate: &dyn LspAdapterDelegate,
 602    ) -> impl Future<Output = Option<LanguageServerBinary>>;
 603}
 604
 605#[async_trait(?Send)]
 606pub trait DynLspInstaller {
 607    async fn try_fetch_server_binary(
 608        &self,
 609        delegate: &Arc<dyn LspAdapterDelegate>,
 610        container_dir: PathBuf,
 611        pre_release: bool,
 612        cx: &mut AsyncApp,
 613    ) -> Result<LanguageServerBinary>;
 614
 615    fn get_language_server_command(
 616        self: Arc<Self>,
 617        delegate: Arc<dyn LspAdapterDelegate>,
 618        toolchains: Option<Toolchain>,
 619        binary_options: LanguageServerBinaryOptions,
 620        cached_binary: OwnedMutexGuard<Option<(bool, LanguageServerBinary)>>,
 621        cx: AsyncApp,
 622    ) -> LanguageServerBinaryLocations;
 623}
 624
 625#[async_trait(?Send)]
 626impl<LI, BinaryVersion> DynLspInstaller for LI
 627where
 628    BinaryVersion: Send + Sync,
 629    LI: LspInstaller<BinaryVersion = BinaryVersion> + LspAdapter,
 630{
 631    async fn try_fetch_server_binary(
 632        &self,
 633        delegate: &Arc<dyn LspAdapterDelegate>,
 634        container_dir: PathBuf,
 635        pre_release: bool,
 636        cx: &mut AsyncApp,
 637    ) -> Result<LanguageServerBinary> {
 638        let name = self.name();
 639
 640        log::debug!("fetching latest version of language server {:?}", name.0);
 641        delegate.update_status(name.clone(), BinaryStatus::CheckingForUpdate);
 642
 643        let latest_version = self
 644            .fetch_latest_server_version(delegate.as_ref(), pre_release, cx)
 645            .await?;
 646
 647        if let Some(binary) = cx
 648            .background_executor()
 649            .await_on_background(self.check_if_version_installed(
 650                &latest_version,
 651                &container_dir,
 652                delegate.as_ref(),
 653            ))
 654            .await
 655        {
 656            log::debug!("language server {:?} is already installed", name.0);
 657            delegate.update_status(name.clone(), BinaryStatus::None);
 658            Ok(binary)
 659        } else {
 660            log::debug!("downloading language server {:?}", name.0);
 661            delegate.update_status(name.clone(), BinaryStatus::Downloading);
 662            let binary = cx
 663                .background_executor()
 664                .await_on_background(self.fetch_server_binary(
 665                    latest_version,
 666                    container_dir,
 667                    delegate.as_ref(),
 668                ))
 669                .await;
 670
 671            delegate.update_status(name.clone(), BinaryStatus::None);
 672            binary
 673        }
 674    }
 675    fn get_language_server_command(
 676        self: Arc<Self>,
 677        delegate: Arc<dyn LspAdapterDelegate>,
 678        toolchain: Option<Toolchain>,
 679        binary_options: LanguageServerBinaryOptions,
 680        mut cached_binary: OwnedMutexGuard<Option<(bool, LanguageServerBinary)>>,
 681        mut cx: AsyncApp,
 682    ) -> LanguageServerBinaryLocations {
 683        async move {
 684            let cached_binary_deref = cached_binary.deref_mut();
 685            // First we check whether the adapter can give us a user-installed binary.
 686            // If so, we do *not* want to cache that, because each worktree might give us a different
 687            // binary:
 688            //
 689            //      worktree 1: user-installed at `.bin/gopls`
 690            //      worktree 2: user-installed at `~/bin/gopls`
 691            //      worktree 3: no gopls found in PATH -> fallback to Zed installation
 692            //
 693            // We only want to cache when we fall back to the global one,
 694            // because we don't want to download and overwrite our global one
 695            // for each worktree we might have open.
 696            if binary_options.allow_path_lookup
 697                && let Some(binary) = self
 698                    .check_if_user_installed(delegate.as_ref(), toolchain, &mut cx)
 699                    .await
 700            {
 701                log::info!(
 702                    "found user-installed language server for {}. path: {:?}, arguments: {:?}",
 703                    self.name().0,
 704                    binary.path,
 705                    binary.arguments
 706                );
 707                return (Ok(binary), None);
 708            }
 709
 710            if let Some((pre_release, cached_binary)) = cached_binary_deref
 711                && *pre_release == binary_options.pre_release
 712            {
 713                return (Ok(cached_binary.clone()), None);
 714            }
 715
 716            if !binary_options.allow_binary_download {
 717                return (
 718                    Err(anyhow::anyhow!("downloading language servers disabled")),
 719                    None,
 720                );
 721            }
 722
 723            let Some(container_dir) = delegate.language_server_download_dir(&self.name()).await
 724            else {
 725                return (
 726                    Err(anyhow::anyhow!("no language server download dir defined")),
 727                    None,
 728                );
 729            };
 730
 731            let last_downloaded_binary = self
 732                .cached_server_binary(container_dir.to_path_buf(), delegate.as_ref())
 733                .await
 734                .context(
 735                    "did not find existing language server binary, falling back to downloading",
 736                );
 737            let download_binary = async move {
 738                let mut binary = self
 739                    .try_fetch_server_binary(
 740                        &delegate,
 741                        container_dir.to_path_buf(),
 742                        binary_options.pre_release,
 743                        &mut cx,
 744                    )
 745                    .await;
 746
 747                if let Err(error) = binary.as_ref() {
 748                    if let Some(prev_downloaded_binary) = self
 749                        .cached_server_binary(container_dir.to_path_buf(), delegate.as_ref())
 750                        .await
 751                    {
 752                        log::info!(
 753                            "failed to fetch newest version of language server {:?}. \
 754                            error: {:?}, falling back to using {:?}",
 755                            self.name(),
 756                            error,
 757                            prev_downloaded_binary.path
 758                        );
 759                        binary = Ok(prev_downloaded_binary);
 760                    } else {
 761                        delegate.update_status(
 762                            self.name(),
 763                            BinaryStatus::Failed {
 764                                error: format!("{error:?}"),
 765                            },
 766                        );
 767                    }
 768                }
 769
 770                if let Ok(binary) = &binary {
 771                    *cached_binary = Some((binary_options.pre_release, binary.clone()));
 772                }
 773
 774                binary
 775            }
 776            .boxed_local();
 777            (last_downloaded_binary, Some(download_binary))
 778        }
 779        .boxed_local()
 780    }
 781}
 782
 783#[derive(Clone, Debug, Default, PartialEq, Eq)]
 784pub struct CodeLabel {
 785    /// The text to display.
 786    pub text: String,
 787    /// Syntax highlighting runs.
 788    pub runs: Vec<(Range<usize>, HighlightId)>,
 789    /// The portion of the text that should be used in fuzzy filtering.
 790    pub filter_range: Range<usize>,
 791}
 792
 793#[derive(Clone, Debug, Default, PartialEq, Eq)]
 794pub struct CodeLabelBuilder {
 795    /// The text to display.
 796    text: String,
 797    /// Syntax highlighting runs.
 798    runs: Vec<(Range<usize>, HighlightId)>,
 799    /// The portion of the text that should be used in fuzzy filtering.
 800    filter_range: Range<usize>,
 801}
 802
 803#[derive(Clone, Deserialize, JsonSchema, Debug)]
 804pub struct LanguageConfig {
 805    /// Human-readable name of the language.
 806    pub name: LanguageName,
 807    /// The name of this language for a Markdown code fence block
 808    pub code_fence_block_name: Option<Arc<str>>,
 809    // The name of the grammar in a WASM bundle (experimental).
 810    pub grammar: Option<Arc<str>>,
 811    /// The criteria for matching this language to a given file.
 812    #[serde(flatten)]
 813    pub matcher: LanguageMatcher,
 814    /// List of bracket types in a language.
 815    #[serde(default)]
 816    pub brackets: BracketPairConfig,
 817    /// If set to true, auto indentation uses last non empty line to determine
 818    /// the indentation level for a new line.
 819    #[serde(default = "auto_indent_using_last_non_empty_line_default")]
 820    pub auto_indent_using_last_non_empty_line: bool,
 821    // Whether indentation of pasted content should be adjusted based on the context.
 822    #[serde(default)]
 823    pub auto_indent_on_paste: Option<bool>,
 824    /// A regex that is used to determine whether the indentation level should be
 825    /// increased in the following line.
 826    #[serde(default, deserialize_with = "deserialize_regex")]
 827    #[schemars(schema_with = "regex_json_schema")]
 828    pub increase_indent_pattern: Option<Regex>,
 829    /// A regex that is used to determine whether the indentation level should be
 830    /// decreased in the following line.
 831    #[serde(default, deserialize_with = "deserialize_regex")]
 832    #[schemars(schema_with = "regex_json_schema")]
 833    pub decrease_indent_pattern: Option<Regex>,
 834    /// A list of rules for decreasing indentation. Each rule pairs a regex with a set of valid
 835    /// "block-starting" tokens. When a line matches a pattern, its indentation is aligned with
 836    /// the most recent line that began with a corresponding token. This enables context-aware
 837    /// outdenting, like aligning an `else` with its `if`.
 838    #[serde(default)]
 839    pub decrease_indent_patterns: Vec<DecreaseIndentConfig>,
 840    /// A list of characters that trigger the automatic insertion of a closing
 841    /// bracket when they immediately precede the point where an opening
 842    /// bracket is inserted.
 843    #[serde(default)]
 844    pub autoclose_before: String,
 845    /// A placeholder used internally by Semantic Index.
 846    #[serde(default)]
 847    pub collapsed_placeholder: String,
 848    /// A line comment string that is inserted in e.g. `toggle comments` action.
 849    /// A language can have multiple flavours of line comments. All of the provided line comments are
 850    /// used for comment continuations on the next line, but only the first one is used for Editor::ToggleComments.
 851    #[serde(default)]
 852    pub line_comments: Vec<Arc<str>>,
 853    /// Delimiters and configuration for recognizing and formatting block comments.
 854    #[serde(default)]
 855    pub block_comment: Option<BlockCommentConfig>,
 856    /// Delimiters and configuration for recognizing and formatting documentation comments.
 857    #[serde(default, alias = "documentation")]
 858    pub documentation_comment: Option<BlockCommentConfig>,
 859    /// List markers that are inserted unchanged on newline (e.g., `- `, `* `, `+ `).
 860    #[serde(default)]
 861    pub unordered_list: Vec<Arc<str>>,
 862    /// Configuration for ordered lists with auto-incrementing numbers on newline (e.g., `1. ` becomes `2. `).
 863    #[serde(default)]
 864    pub ordered_list: Vec<OrderedListConfig>,
 865    /// Configuration for task lists where multiple markers map to a single continuation prefix (e.g., `- [x] ` continues as `- [ ] `).
 866    #[serde(default)]
 867    pub task_list: Option<TaskListConfig>,
 868    /// A list of additional regex patterns that should be treated as prefixes
 869    /// for creating boundaries during rewrapping, ensuring content from one
 870    /// prefixed section doesn't merge with another (e.g., markdown list items).
 871    /// By default, Zed treats as paragraph and comment prefixes as boundaries.
 872    #[serde(default, deserialize_with = "deserialize_regex_vec")]
 873    #[schemars(schema_with = "regex_vec_json_schema")]
 874    pub rewrap_prefixes: Vec<Regex>,
 875    /// A list of language servers that are allowed to run on subranges of a given language.
 876    #[serde(default)]
 877    pub scope_opt_in_language_servers: Vec<LanguageServerName>,
 878    #[serde(default)]
 879    pub overrides: HashMap<String, LanguageConfigOverride>,
 880    /// A list of characters that Zed should treat as word characters for the
 881    /// purpose of features that operate on word boundaries, like 'move to next word end'
 882    /// or a whole-word search in buffer search.
 883    #[serde(default)]
 884    pub word_characters: HashSet<char>,
 885    /// Whether to indent lines using tab characters, as opposed to multiple
 886    /// spaces.
 887    #[serde(default)]
 888    pub hard_tabs: Option<bool>,
 889    /// How many columns a tab should occupy.
 890    #[serde(default)]
 891    #[schemars(range(min = 1, max = 128))]
 892    pub tab_size: Option<NonZeroU32>,
 893    /// How to soft-wrap long lines of text.
 894    #[serde(default)]
 895    pub soft_wrap: Option<SoftWrap>,
 896    /// When set, selections can be wrapped using prefix/suffix pairs on both sides.
 897    #[serde(default)]
 898    pub wrap_characters: Option<WrapCharactersConfig>,
 899    /// The name of a Prettier parser that will be used for this language when no file path is available.
 900    /// If there's a parser name in the language settings, that will be used instead.
 901    #[serde(default)]
 902    pub prettier_parser_name: Option<String>,
 903    /// If true, this language is only for syntax highlighting via an injection into other
 904    /// languages, but should not appear to the user as a distinct language.
 905    #[serde(default)]
 906    pub hidden: bool,
 907    /// If configured, this language contains JSX style tags, and should support auto-closing of those tags.
 908    #[serde(default)]
 909    pub jsx_tag_auto_close: Option<JsxTagAutoCloseConfig>,
 910    /// A list of characters that Zed should treat as word characters for completion queries.
 911    #[serde(default)]
 912    pub completion_query_characters: HashSet<char>,
 913    /// A list of characters that Zed should treat as word characters for linked edit operations.
 914    #[serde(default)]
 915    pub linked_edit_characters: HashSet<char>,
 916    /// A list of preferred debuggers for this language.
 917    #[serde(default)]
 918    pub debuggers: IndexSet<SharedString>,
 919    /// A list of import namespace segments that aren't expected to appear in file paths. For
 920    /// example, "super" and "crate" in Rust.
 921    #[serde(default)]
 922    pub ignored_import_segments: HashSet<Arc<str>>,
 923    /// Regular expression that matches substrings to omit from import paths, to make the paths more
 924    /// similar to how they are specified when imported. For example, "/mod\.rs$" or "/__init__\.py$".
 925    #[serde(default, deserialize_with = "deserialize_regex")]
 926    #[schemars(schema_with = "regex_json_schema")]
 927    pub import_path_strip_regex: Option<Regex>,
 928}
 929
 930#[derive(Clone, Debug, Deserialize, Default, JsonSchema)]
 931pub struct DecreaseIndentConfig {
 932    #[serde(default, deserialize_with = "deserialize_regex")]
 933    #[schemars(schema_with = "regex_json_schema")]
 934    pub pattern: Option<Regex>,
 935    #[serde(default)]
 936    pub valid_after: Vec<String>,
 937}
 938
 939/// Configuration for continuing ordered lists with auto-incrementing numbers.
 940#[derive(Clone, Debug, Deserialize, JsonSchema)]
 941pub struct OrderedListConfig {
 942    /// A regex pattern with a capture group for the number portion (e.g., `(\\d+)\\. `).
 943    pub pattern: String,
 944    /// A format string where `{1}` is replaced with the incremented number (e.g., `{1}. `).
 945    pub format: String,
 946}
 947
 948/// Configuration for continuing task lists on newline.
 949#[derive(Clone, Debug, Deserialize, JsonSchema)]
 950pub struct TaskListConfig {
 951    /// The list markers to match (e.g., `- [ ] `, `- [x] `).
 952    pub prefixes: Vec<Arc<str>>,
 953    /// The marker to insert when continuing the list on a new line (e.g., `- [ ] `).
 954    pub continuation: Arc<str>,
 955}
 956
 957#[derive(Clone, Debug, Serialize, Deserialize, Default, JsonSchema)]
 958pub struct LanguageMatcher {
 959    /// 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`.
 960    #[serde(default)]
 961    pub path_suffixes: Vec<String>,
 962    /// A regex pattern that determines whether the language should be assigned to a file or not.
 963    #[serde(
 964        default,
 965        serialize_with = "serialize_regex",
 966        deserialize_with = "deserialize_regex"
 967    )]
 968    #[schemars(schema_with = "regex_json_schema")]
 969    pub first_line_pattern: Option<Regex>,
 970    /// Alternative names for this language used in vim/emacs modelines.
 971    /// These are matched case-insensitively against the `mode` (emacs) or
 972    /// `filetype`/`ft` (vim) specified in the modeline.
 973    #[serde(default)]
 974    pub modeline_aliases: Vec<String>,
 975}
 976
 977/// The configuration for JSX tag auto-closing.
 978#[derive(Clone, Deserialize, JsonSchema, Debug)]
 979pub struct JsxTagAutoCloseConfig {
 980    /// The name of the node for a opening tag
 981    pub open_tag_node_name: String,
 982    /// The name of the node for an closing tag
 983    pub close_tag_node_name: String,
 984    /// The name of the node for a complete element with children for open and close tags
 985    pub jsx_element_node_name: String,
 986    /// The name of the node found within both opening and closing
 987    /// tags that describes the tag name
 988    pub tag_name_node_name: String,
 989    /// Alternate Node names for tag names.
 990    /// Specifically needed as TSX represents the name in `<Foo.Bar>`
 991    /// as `member_expression` rather than `identifier` as usual
 992    #[serde(default)]
 993    pub tag_name_node_name_alternates: Vec<String>,
 994    /// Some grammars are smart enough to detect a closing tag
 995    /// that is not valid i.e. doesn't match it's corresponding
 996    /// opening tag or does not have a corresponding opening tag
 997    /// This should be set to the name of the node for invalid
 998    /// closing tags if the grammar contains such a node, otherwise
 999    /// detecting already closed tags will not work properly
1000    #[serde(default)]
1001    pub erroneous_close_tag_node_name: Option<String>,
1002    /// See above for erroneous_close_tag_node_name for details
1003    /// This should be set if the node used for the tag name
1004    /// within erroneous closing tags is different from the
1005    /// normal tag name node name
1006    #[serde(default)]
1007    pub erroneous_close_tag_name_node_name: Option<String>,
1008}
1009
1010/// The configuration for block comments for this language.
1011#[derive(Clone, Debug, JsonSchema, PartialEq)]
1012pub struct BlockCommentConfig {
1013    /// A start tag of block comment.
1014    pub start: Arc<str>,
1015    /// A end tag of block comment.
1016    pub end: Arc<str>,
1017    /// A character to add as a prefix when a new line is added to a block comment.
1018    pub prefix: Arc<str>,
1019    /// A indent to add for prefix and end line upon new line.
1020    #[schemars(range(min = 1, max = 128))]
1021    pub tab_size: u32,
1022}
1023
1024impl<'de> Deserialize<'de> for BlockCommentConfig {
1025    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1026    where
1027        D: Deserializer<'de>,
1028    {
1029        #[derive(Deserialize)]
1030        #[serde(untagged)]
1031        enum BlockCommentConfigHelper {
1032            New {
1033                start: Arc<str>,
1034                end: Arc<str>,
1035                prefix: Arc<str>,
1036                tab_size: u32,
1037            },
1038            Old([Arc<str>; 2]),
1039        }
1040
1041        match BlockCommentConfigHelper::deserialize(deserializer)? {
1042            BlockCommentConfigHelper::New {
1043                start,
1044                end,
1045                prefix,
1046                tab_size,
1047            } => Ok(BlockCommentConfig {
1048                start,
1049                end,
1050                prefix,
1051                tab_size,
1052            }),
1053            BlockCommentConfigHelper::Old([start, end]) => Ok(BlockCommentConfig {
1054                start,
1055                end,
1056                prefix: "".into(),
1057                tab_size: 0,
1058            }),
1059        }
1060    }
1061}
1062
1063/// Represents a language for the given range. Some languages (e.g. HTML)
1064/// interleave several languages together, thus a single buffer might actually contain
1065/// several nested scopes.
1066#[derive(Clone, Debug)]
1067pub struct LanguageScope {
1068    language: Arc<Language>,
1069    override_id: Option<u32>,
1070}
1071
1072#[derive(Clone, Deserialize, Default, Debug, JsonSchema)]
1073pub struct LanguageConfigOverride {
1074    #[serde(default)]
1075    pub line_comments: Override<Vec<Arc<str>>>,
1076    #[serde(default)]
1077    pub block_comment: Override<BlockCommentConfig>,
1078    #[serde(skip)]
1079    pub disabled_bracket_ixs: Vec<u16>,
1080    #[serde(default)]
1081    pub word_characters: Override<HashSet<char>>,
1082    #[serde(default)]
1083    pub completion_query_characters: Override<HashSet<char>>,
1084    #[serde(default)]
1085    pub linked_edit_characters: Override<HashSet<char>>,
1086    #[serde(default)]
1087    pub opt_into_language_servers: Vec<LanguageServerName>,
1088    #[serde(default)]
1089    pub prefer_label_for_snippet: Option<bool>,
1090}
1091
1092#[derive(Clone, Deserialize, Debug, Serialize, JsonSchema)]
1093#[serde(untagged)]
1094pub enum Override<T> {
1095    Remove { remove: bool },
1096    Set(T),
1097}
1098
1099impl<T> Default for Override<T> {
1100    fn default() -> Self {
1101        Override::Remove { remove: false }
1102    }
1103}
1104
1105impl<T> Override<T> {
1106    fn as_option<'a>(this: Option<&'a Self>, original: Option<&'a T>) -> Option<&'a T> {
1107        match this {
1108            Some(Self::Set(value)) => Some(value),
1109            Some(Self::Remove { remove: true }) => None,
1110            Some(Self::Remove { remove: false }) | None => original,
1111        }
1112    }
1113}
1114
1115impl Default for LanguageConfig {
1116    fn default() -> Self {
1117        Self {
1118            name: LanguageName::new_static(""),
1119            code_fence_block_name: None,
1120            grammar: None,
1121            matcher: LanguageMatcher::default(),
1122            brackets: Default::default(),
1123            auto_indent_using_last_non_empty_line: auto_indent_using_last_non_empty_line_default(),
1124            auto_indent_on_paste: None,
1125            increase_indent_pattern: Default::default(),
1126            decrease_indent_pattern: Default::default(),
1127            decrease_indent_patterns: Default::default(),
1128            autoclose_before: Default::default(),
1129            line_comments: Default::default(),
1130            block_comment: Default::default(),
1131            documentation_comment: Default::default(),
1132            unordered_list: Default::default(),
1133            ordered_list: Default::default(),
1134            task_list: Default::default(),
1135            rewrap_prefixes: Default::default(),
1136            scope_opt_in_language_servers: Default::default(),
1137            overrides: Default::default(),
1138            word_characters: Default::default(),
1139            collapsed_placeholder: Default::default(),
1140            hard_tabs: None,
1141            tab_size: None,
1142            soft_wrap: None,
1143            wrap_characters: None,
1144            prettier_parser_name: None,
1145            hidden: false,
1146            jsx_tag_auto_close: None,
1147            completion_query_characters: Default::default(),
1148            linked_edit_characters: Default::default(),
1149            debuggers: Default::default(),
1150            ignored_import_segments: Default::default(),
1151            import_path_strip_regex: None,
1152        }
1153    }
1154}
1155
1156#[derive(Clone, Debug, Deserialize, JsonSchema)]
1157pub struct WrapCharactersConfig {
1158    /// Opening token split into a prefix and suffix. The first caret goes
1159    /// after the prefix (i.e., between prefix and suffix).
1160    pub start_prefix: String,
1161    pub start_suffix: String,
1162    /// Closing token split into a prefix and suffix. The second caret goes
1163    /// after the prefix (i.e., between prefix and suffix).
1164    pub end_prefix: String,
1165    pub end_suffix: String,
1166}
1167
1168fn auto_indent_using_last_non_empty_line_default() -> bool {
1169    true
1170}
1171
1172fn deserialize_regex<'de, D: Deserializer<'de>>(d: D) -> Result<Option<Regex>, D::Error> {
1173    let source = Option::<String>::deserialize(d)?;
1174    if let Some(source) = source {
1175        Ok(Some(regex::Regex::new(&source).map_err(de::Error::custom)?))
1176    } else {
1177        Ok(None)
1178    }
1179}
1180
1181fn regex_json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
1182    json_schema!({
1183        "type": "string"
1184    })
1185}
1186
1187fn serialize_regex<S>(regex: &Option<Regex>, serializer: S) -> Result<S::Ok, S::Error>
1188where
1189    S: Serializer,
1190{
1191    match regex {
1192        Some(regex) => serializer.serialize_str(regex.as_str()),
1193        None => serializer.serialize_none(),
1194    }
1195}
1196
1197fn deserialize_regex_vec<'de, D: Deserializer<'de>>(d: D) -> Result<Vec<Regex>, D::Error> {
1198    let sources = Vec::<String>::deserialize(d)?;
1199    sources
1200        .into_iter()
1201        .map(|source| regex::Regex::new(&source))
1202        .collect::<Result<_, _>>()
1203        .map_err(de::Error::custom)
1204}
1205
1206fn regex_vec_json_schema(_: &mut SchemaGenerator) -> schemars::Schema {
1207    json_schema!({
1208        "type": "array",
1209        "items": { "type": "string" }
1210    })
1211}
1212
1213#[doc(hidden)]
1214#[cfg(any(test, feature = "test-support"))]
1215pub struct FakeLspAdapter {
1216    pub name: &'static str,
1217    pub initialization_options: Option<Value>,
1218    pub prettier_plugins: Vec<&'static str>,
1219    pub disk_based_diagnostics_progress_token: Option<String>,
1220    pub disk_based_diagnostics_sources: Vec<String>,
1221    pub language_server_binary: LanguageServerBinary,
1222
1223    pub capabilities: lsp::ServerCapabilities,
1224    pub initializer: Option<Box<dyn 'static + Send + Sync + Fn(&mut lsp::FakeLanguageServer)>>,
1225    pub label_for_completion: Option<
1226        Box<
1227            dyn 'static
1228                + Send
1229                + Sync
1230                + Fn(&lsp::CompletionItem, &Arc<Language>) -> Option<CodeLabel>,
1231        >,
1232    >,
1233}
1234
1235/// Configuration of handling bracket pairs for a given language.
1236///
1237/// This struct includes settings for defining which pairs of characters are considered brackets and
1238/// also specifies any language-specific scopes where these pairs should be ignored for bracket matching purposes.
1239#[derive(Clone, Debug, Default, JsonSchema)]
1240#[schemars(with = "Vec::<BracketPairContent>")]
1241pub struct BracketPairConfig {
1242    /// A list of character pairs that should be treated as brackets in the context of a given language.
1243    pub pairs: Vec<BracketPair>,
1244    /// A list of tree-sitter scopes for which a given bracket should not be active.
1245    /// N-th entry in `[Self::disabled_scopes_by_bracket_ix]` contains a list of disabled scopes for an n-th entry in `[Self::pairs]`
1246    pub disabled_scopes_by_bracket_ix: Vec<Vec<String>>,
1247}
1248
1249impl BracketPairConfig {
1250    pub fn is_closing_brace(&self, c: char) -> bool {
1251        self.pairs.iter().any(|pair| pair.end.starts_with(c))
1252    }
1253}
1254
1255#[derive(Deserialize, JsonSchema)]
1256pub struct BracketPairContent {
1257    #[serde(flatten)]
1258    pub bracket_pair: BracketPair,
1259    #[serde(default)]
1260    pub not_in: Vec<String>,
1261}
1262
1263impl<'de> Deserialize<'de> for BracketPairConfig {
1264    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
1265    where
1266        D: Deserializer<'de>,
1267    {
1268        let result = Vec::<BracketPairContent>::deserialize(deserializer)?;
1269        let (brackets, disabled_scopes_by_bracket_ix) = result
1270            .into_iter()
1271            .map(|entry| (entry.bracket_pair, entry.not_in))
1272            .unzip();
1273
1274        Ok(BracketPairConfig {
1275            pairs: brackets,
1276            disabled_scopes_by_bracket_ix,
1277        })
1278    }
1279}
1280
1281/// Describes a single bracket pair and how an editor should react to e.g. inserting
1282/// an opening bracket or to a newline character insertion in between `start` and `end` characters.
1283#[derive(Clone, Debug, Default, Deserialize, PartialEq, JsonSchema)]
1284pub struct BracketPair {
1285    /// Starting substring for a bracket.
1286    pub start: String,
1287    /// Ending substring for a bracket.
1288    pub end: String,
1289    /// True if `end` should be automatically inserted right after `start` characters.
1290    pub close: bool,
1291    /// True if selected text should be surrounded by `start` and `end` characters.
1292    #[serde(default = "default_true")]
1293    pub surround: bool,
1294    /// True if an extra newline should be inserted while the cursor is in the middle
1295    /// of that bracket pair.
1296    pub newline: bool,
1297}
1298
1299#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
1300pub struct LanguageId(usize);
1301
1302impl LanguageId {
1303    pub(crate) fn new() -> Self {
1304        Self(NEXT_LANGUAGE_ID.fetch_add(1, SeqCst))
1305    }
1306}
1307
1308pub struct Language {
1309    pub(crate) id: LanguageId,
1310    pub(crate) config: LanguageConfig,
1311    pub(crate) grammar: Option<Arc<Grammar>>,
1312    pub(crate) context_provider: Option<Arc<dyn ContextProvider>>,
1313    pub(crate) toolchain: Option<Arc<dyn ToolchainLister>>,
1314    pub(crate) manifest_name: Option<ManifestName>,
1315}
1316
1317#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
1318pub struct GrammarId(pub usize);
1319
1320impl GrammarId {
1321    pub(crate) fn new() -> Self {
1322        Self(NEXT_GRAMMAR_ID.fetch_add(1, SeqCst))
1323    }
1324}
1325
1326pub struct Grammar {
1327    id: GrammarId,
1328    pub ts_language: tree_sitter::Language,
1329    pub(crate) error_query: Option<Query>,
1330    pub highlights_config: Option<HighlightsConfig>,
1331    pub(crate) brackets_config: Option<BracketsConfig>,
1332    pub(crate) redactions_config: Option<RedactionConfig>,
1333    pub(crate) runnable_config: Option<RunnableConfig>,
1334    pub(crate) indents_config: Option<IndentConfig>,
1335    pub outline_config: Option<OutlineConfig>,
1336    pub text_object_config: Option<TextObjectConfig>,
1337    pub(crate) injection_config: Option<InjectionConfig>,
1338    pub(crate) override_config: Option<OverrideConfig>,
1339    pub(crate) debug_variables_config: Option<DebugVariablesConfig>,
1340    pub(crate) imports_config: Option<ImportsConfig>,
1341    pub(crate) highlight_map: Mutex<HighlightMap>,
1342}
1343
1344pub struct HighlightsConfig {
1345    pub query: Query,
1346    pub identifier_capture_indices: Vec<u32>,
1347}
1348
1349struct IndentConfig {
1350    query: Query,
1351    indent_capture_ix: u32,
1352    start_capture_ix: Option<u32>,
1353    end_capture_ix: Option<u32>,
1354    outdent_capture_ix: Option<u32>,
1355    suffixed_start_captures: HashMap<u32, SharedString>,
1356}
1357
1358pub struct OutlineConfig {
1359    pub query: Query,
1360    pub item_capture_ix: u32,
1361    pub name_capture_ix: u32,
1362    pub context_capture_ix: Option<u32>,
1363    pub extra_context_capture_ix: Option<u32>,
1364    pub open_capture_ix: Option<u32>,
1365    pub close_capture_ix: Option<u32>,
1366    pub annotation_capture_ix: Option<u32>,
1367}
1368
1369#[derive(Debug, Clone, Copy, PartialEq)]
1370pub enum DebuggerTextObject {
1371    Variable,
1372    Scope,
1373}
1374
1375impl DebuggerTextObject {
1376    pub fn from_capture_name(name: &str) -> Option<DebuggerTextObject> {
1377        match name {
1378            "debug-variable" => Some(DebuggerTextObject::Variable),
1379            "debug-scope" => Some(DebuggerTextObject::Scope),
1380            _ => None,
1381        }
1382    }
1383}
1384
1385#[derive(Debug, Clone, Copy, PartialEq)]
1386pub enum TextObject {
1387    InsideFunction,
1388    AroundFunction,
1389    InsideClass,
1390    AroundClass,
1391    InsideComment,
1392    AroundComment,
1393}
1394
1395impl TextObject {
1396    pub fn from_capture_name(name: &str) -> Option<TextObject> {
1397        match name {
1398            "function.inside" => Some(TextObject::InsideFunction),
1399            "function.around" => Some(TextObject::AroundFunction),
1400            "class.inside" => Some(TextObject::InsideClass),
1401            "class.around" => Some(TextObject::AroundClass),
1402            "comment.inside" => Some(TextObject::InsideComment),
1403            "comment.around" => Some(TextObject::AroundComment),
1404            _ => None,
1405        }
1406    }
1407
1408    pub fn around(&self) -> Option<Self> {
1409        match self {
1410            TextObject::InsideFunction => Some(TextObject::AroundFunction),
1411            TextObject::InsideClass => Some(TextObject::AroundClass),
1412            TextObject::InsideComment => Some(TextObject::AroundComment),
1413            _ => None,
1414        }
1415    }
1416}
1417
1418pub struct TextObjectConfig {
1419    pub query: Query,
1420    pub text_objects_by_capture_ix: Vec<(u32, TextObject)>,
1421}
1422
1423struct InjectionConfig {
1424    query: Query,
1425    content_capture_ix: u32,
1426    language_capture_ix: Option<u32>,
1427    patterns: Vec<InjectionPatternConfig>,
1428}
1429
1430struct RedactionConfig {
1431    pub query: Query,
1432    pub redaction_capture_ix: u32,
1433}
1434
1435#[derive(Clone, Debug, PartialEq)]
1436enum RunnableCapture {
1437    Named(SharedString),
1438    Run,
1439}
1440
1441struct RunnableConfig {
1442    pub query: Query,
1443    /// A mapping from capture indice to capture kind
1444    pub extra_captures: Vec<RunnableCapture>,
1445}
1446
1447struct OverrideConfig {
1448    query: Query,
1449    values: HashMap<u32, OverrideEntry>,
1450}
1451
1452#[derive(Debug)]
1453struct OverrideEntry {
1454    name: String,
1455    range_is_inclusive: bool,
1456    value: LanguageConfigOverride,
1457}
1458
1459#[derive(Default, Clone)]
1460struct InjectionPatternConfig {
1461    language: Option<Box<str>>,
1462    combined: bool,
1463}
1464
1465#[derive(Debug)]
1466struct BracketsConfig {
1467    query: Query,
1468    open_capture_ix: u32,
1469    close_capture_ix: u32,
1470    patterns: Vec<BracketsPatternConfig>,
1471}
1472
1473#[derive(Clone, Debug, Default)]
1474struct BracketsPatternConfig {
1475    newline_only: bool,
1476    rainbow_exclude: bool,
1477}
1478
1479pub struct DebugVariablesConfig {
1480    pub query: Query,
1481    pub objects_by_capture_ix: Vec<(u32, DebuggerTextObject)>,
1482}
1483
1484pub struct ImportsConfig {
1485    pub query: Query,
1486    pub import_ix: u32,
1487    pub name_ix: Option<u32>,
1488    pub namespace_ix: Option<u32>,
1489    pub source_ix: Option<u32>,
1490    pub list_ix: Option<u32>,
1491    pub wildcard_ix: Option<u32>,
1492    pub alias_ix: Option<u32>,
1493}
1494
1495impl Language {
1496    pub fn new(config: LanguageConfig, ts_language: Option<tree_sitter::Language>) -> Self {
1497        Self::new_with_id(LanguageId::new(), config, ts_language)
1498    }
1499
1500    pub fn id(&self) -> LanguageId {
1501        self.id
1502    }
1503
1504    fn new_with_id(
1505        id: LanguageId,
1506        config: LanguageConfig,
1507        ts_language: Option<tree_sitter::Language>,
1508    ) -> Self {
1509        Self {
1510            id,
1511            config,
1512            grammar: ts_language.map(|ts_language| {
1513                Arc::new(Grammar {
1514                    id: GrammarId::new(),
1515                    highlights_config: None,
1516                    brackets_config: None,
1517                    outline_config: None,
1518                    text_object_config: None,
1519                    indents_config: None,
1520                    injection_config: None,
1521                    override_config: None,
1522                    redactions_config: None,
1523                    runnable_config: None,
1524                    error_query: Query::new(&ts_language, "(ERROR) @error").ok(),
1525                    debug_variables_config: None,
1526                    imports_config: None,
1527                    ts_language,
1528                    highlight_map: Default::default(),
1529                })
1530            }),
1531            context_provider: None,
1532            toolchain: None,
1533            manifest_name: None,
1534        }
1535    }
1536
1537    pub fn with_context_provider(mut self, provider: Option<Arc<dyn ContextProvider>>) -> Self {
1538        self.context_provider = provider;
1539        self
1540    }
1541
1542    pub fn with_toolchain_lister(mut self, provider: Option<Arc<dyn ToolchainLister>>) -> Self {
1543        self.toolchain = provider;
1544        self
1545    }
1546
1547    pub fn with_manifest(mut self, name: Option<ManifestName>) -> Self {
1548        self.manifest_name = name;
1549        self
1550    }
1551
1552    pub fn with_queries(mut self, queries: LanguageQueries) -> Result<Self> {
1553        if let Some(query) = queries.highlights {
1554            self = self
1555                .with_highlights_query(query.as_ref())
1556                .context("Error loading highlights query")?;
1557        }
1558        if let Some(query) = queries.brackets {
1559            self = self
1560                .with_brackets_query(query.as_ref())
1561                .context("Error loading brackets query")?;
1562        }
1563        if let Some(query) = queries.indents {
1564            self = self
1565                .with_indents_query(query.as_ref())
1566                .context("Error loading indents query")?;
1567        }
1568        if let Some(query) = queries.outline {
1569            self = self
1570                .with_outline_query(query.as_ref())
1571                .context("Error loading outline query")?;
1572        }
1573        if let Some(query) = queries.injections {
1574            self = self
1575                .with_injection_query(query.as_ref())
1576                .context("Error loading injection query")?;
1577        }
1578        if let Some(query) = queries.overrides {
1579            self = self
1580                .with_override_query(query.as_ref())
1581                .context("Error loading override query")?;
1582        }
1583        if let Some(query) = queries.redactions {
1584            self = self
1585                .with_redaction_query(query.as_ref())
1586                .context("Error loading redaction query")?;
1587        }
1588        if let Some(query) = queries.runnables {
1589            self = self
1590                .with_runnable_query(query.as_ref())
1591                .context("Error loading runnables query")?;
1592        }
1593        if let Some(query) = queries.text_objects {
1594            self = self
1595                .with_text_object_query(query.as_ref())
1596                .context("Error loading textobject query")?;
1597        }
1598        if let Some(query) = queries.debugger {
1599            self = self
1600                .with_debug_variables_query(query.as_ref())
1601                .context("Error loading debug variables query")?;
1602        }
1603        if let Some(query) = queries.imports {
1604            self = self
1605                .with_imports_query(query.as_ref())
1606                .context("Error loading imports query")?;
1607        }
1608        Ok(self)
1609    }
1610
1611    pub fn with_highlights_query(mut self, source: &str) -> Result<Self> {
1612        let grammar = self.grammar_mut()?;
1613        let query = Query::new(&grammar.ts_language, source)?;
1614
1615        let mut identifier_capture_indices = Vec::new();
1616        for name in [
1617            "variable",
1618            "constant",
1619            "constructor",
1620            "function",
1621            "function.method",
1622            "function.method.call",
1623            "function.special",
1624            "property",
1625            "type",
1626            "type.interface",
1627        ] {
1628            identifier_capture_indices.extend(query.capture_index_for_name(name));
1629        }
1630
1631        grammar.highlights_config = Some(HighlightsConfig {
1632            query,
1633            identifier_capture_indices,
1634        });
1635
1636        Ok(self)
1637    }
1638
1639    pub fn with_runnable_query(mut self, source: &str) -> Result<Self> {
1640        let grammar = self.grammar_mut()?;
1641
1642        let query = Query::new(&grammar.ts_language, source)?;
1643        let extra_captures: Vec<_> = query
1644            .capture_names()
1645            .iter()
1646            .map(|&name| match name {
1647                "run" => RunnableCapture::Run,
1648                name => RunnableCapture::Named(name.to_string().into()),
1649            })
1650            .collect();
1651
1652        grammar.runnable_config = Some(RunnableConfig {
1653            extra_captures,
1654            query,
1655        });
1656
1657        Ok(self)
1658    }
1659
1660    pub fn with_outline_query(mut self, source: &str) -> Result<Self> {
1661        let query = Query::new(&self.expect_grammar()?.ts_language, source)?;
1662        let mut item_capture_ix = 0;
1663        let mut name_capture_ix = 0;
1664        let mut context_capture_ix = None;
1665        let mut extra_context_capture_ix = None;
1666        let mut open_capture_ix = None;
1667        let mut close_capture_ix = None;
1668        let mut annotation_capture_ix = None;
1669        if populate_capture_indices(
1670            &query,
1671            &self.config.name,
1672            "outline",
1673            &[],
1674            &mut [
1675                Capture::Required("item", &mut item_capture_ix),
1676                Capture::Required("name", &mut name_capture_ix),
1677                Capture::Optional("context", &mut context_capture_ix),
1678                Capture::Optional("context.extra", &mut extra_context_capture_ix),
1679                Capture::Optional("open", &mut open_capture_ix),
1680                Capture::Optional("close", &mut close_capture_ix),
1681                Capture::Optional("annotation", &mut annotation_capture_ix),
1682            ],
1683        ) {
1684            self.grammar_mut()?.outline_config = Some(OutlineConfig {
1685                query,
1686                item_capture_ix,
1687                name_capture_ix,
1688                context_capture_ix,
1689                extra_context_capture_ix,
1690                open_capture_ix,
1691                close_capture_ix,
1692                annotation_capture_ix,
1693            });
1694        }
1695        Ok(self)
1696    }
1697
1698    pub fn with_text_object_query(mut self, source: &str) -> Result<Self> {
1699        let query = Query::new(&self.expect_grammar()?.ts_language, source)?;
1700
1701        let mut text_objects_by_capture_ix = Vec::new();
1702        for (ix, name) in query.capture_names().iter().enumerate() {
1703            if let Some(text_object) = TextObject::from_capture_name(name) {
1704                text_objects_by_capture_ix.push((ix as u32, text_object));
1705            } else {
1706                log::warn!(
1707                    "unrecognized capture name '{}' in {} textobjects TreeSitter query",
1708                    name,
1709                    self.config.name,
1710                );
1711            }
1712        }
1713
1714        self.grammar_mut()?.text_object_config = Some(TextObjectConfig {
1715            query,
1716            text_objects_by_capture_ix,
1717        });
1718        Ok(self)
1719    }
1720
1721    pub fn with_debug_variables_query(mut self, source: &str) -> Result<Self> {
1722        let query = Query::new(&self.expect_grammar()?.ts_language, source)?;
1723
1724        let mut objects_by_capture_ix = Vec::new();
1725        for (ix, name) in query.capture_names().iter().enumerate() {
1726            if let Some(text_object) = DebuggerTextObject::from_capture_name(name) {
1727                objects_by_capture_ix.push((ix as u32, text_object));
1728            } else {
1729                log::warn!(
1730                    "unrecognized capture name '{}' in {} debugger TreeSitter query",
1731                    name,
1732                    self.config.name,
1733                );
1734            }
1735        }
1736
1737        self.grammar_mut()?.debug_variables_config = Some(DebugVariablesConfig {
1738            query,
1739            objects_by_capture_ix,
1740        });
1741        Ok(self)
1742    }
1743
1744    pub fn with_imports_query(mut self, source: &str) -> Result<Self> {
1745        let query = Query::new(&self.expect_grammar()?.ts_language, source)?;
1746
1747        let mut import_ix = 0;
1748        let mut name_ix = None;
1749        let mut namespace_ix = None;
1750        let mut source_ix = None;
1751        let mut list_ix = None;
1752        let mut wildcard_ix = None;
1753        let mut alias_ix = None;
1754        if populate_capture_indices(
1755            &query,
1756            &self.config.name,
1757            "imports",
1758            &[],
1759            &mut [
1760                Capture::Required("import", &mut import_ix),
1761                Capture::Optional("name", &mut name_ix),
1762                Capture::Optional("namespace", &mut namespace_ix),
1763                Capture::Optional("source", &mut source_ix),
1764                Capture::Optional("list", &mut list_ix),
1765                Capture::Optional("wildcard", &mut wildcard_ix),
1766                Capture::Optional("alias", &mut alias_ix),
1767            ],
1768        ) {
1769            self.grammar_mut()?.imports_config = Some(ImportsConfig {
1770                query,
1771                import_ix,
1772                name_ix,
1773                namespace_ix,
1774                source_ix,
1775                list_ix,
1776                wildcard_ix,
1777                alias_ix,
1778            });
1779        }
1780        return Ok(self);
1781    }
1782
1783    pub fn with_brackets_query(mut self, source: &str) -> Result<Self> {
1784        let query = Query::new(&self.expect_grammar()?.ts_language, source)?;
1785        let mut open_capture_ix = 0;
1786        let mut close_capture_ix = 0;
1787        if populate_capture_indices(
1788            &query,
1789            &self.config.name,
1790            "brackets",
1791            &[],
1792            &mut [
1793                Capture::Required("open", &mut open_capture_ix),
1794                Capture::Required("close", &mut close_capture_ix),
1795            ],
1796        ) {
1797            let patterns = (0..query.pattern_count())
1798                .map(|ix| {
1799                    let mut config = BracketsPatternConfig::default();
1800                    for setting in query.property_settings(ix) {
1801                        let setting_key = setting.key.as_ref();
1802                        if setting_key == "newline.only" {
1803                            config.newline_only = true
1804                        }
1805                        if setting_key == "rainbow.exclude" {
1806                            config.rainbow_exclude = true
1807                        }
1808                    }
1809                    config
1810                })
1811                .collect();
1812            self.grammar_mut()?.brackets_config = Some(BracketsConfig {
1813                query,
1814                open_capture_ix,
1815                close_capture_ix,
1816                patterns,
1817            });
1818        }
1819        Ok(self)
1820    }
1821
1822    pub fn with_indents_query(mut self, source: &str) -> Result<Self> {
1823        let query = Query::new(&self.expect_grammar()?.ts_language, source)?;
1824        let mut indent_capture_ix = 0;
1825        let mut start_capture_ix = None;
1826        let mut end_capture_ix = None;
1827        let mut outdent_capture_ix = None;
1828        if populate_capture_indices(
1829            &query,
1830            &self.config.name,
1831            "indents",
1832            &["start."],
1833            &mut [
1834                Capture::Required("indent", &mut indent_capture_ix),
1835                Capture::Optional("start", &mut start_capture_ix),
1836                Capture::Optional("end", &mut end_capture_ix),
1837                Capture::Optional("outdent", &mut outdent_capture_ix),
1838            ],
1839        ) {
1840            let mut suffixed_start_captures = HashMap::default();
1841            for (ix, name) in query.capture_names().iter().enumerate() {
1842                if let Some(suffix) = name.strip_prefix("start.") {
1843                    suffixed_start_captures.insert(ix as u32, suffix.to_owned().into());
1844                }
1845            }
1846
1847            self.grammar_mut()?.indents_config = Some(IndentConfig {
1848                query,
1849                indent_capture_ix,
1850                start_capture_ix,
1851                end_capture_ix,
1852                outdent_capture_ix,
1853                suffixed_start_captures,
1854            });
1855        }
1856        Ok(self)
1857    }
1858
1859    pub fn with_injection_query(mut self, source: &str) -> Result<Self> {
1860        let query = Query::new(&self.expect_grammar()?.ts_language, source)?;
1861        let mut language_capture_ix = None;
1862        let mut injection_language_capture_ix = None;
1863        let mut content_capture_ix = None;
1864        let mut injection_content_capture_ix = None;
1865        if populate_capture_indices(
1866            &query,
1867            &self.config.name,
1868            "injections",
1869            &[],
1870            &mut [
1871                Capture::Optional("language", &mut language_capture_ix),
1872                Capture::Optional("injection.language", &mut injection_language_capture_ix),
1873                Capture::Optional("content", &mut content_capture_ix),
1874                Capture::Optional("injection.content", &mut injection_content_capture_ix),
1875            ],
1876        ) {
1877            language_capture_ix = match (language_capture_ix, injection_language_capture_ix) {
1878                (None, Some(ix)) => Some(ix),
1879                (Some(_), Some(_)) => {
1880                    anyhow::bail!("both language and injection.language captures are present");
1881                }
1882                _ => language_capture_ix,
1883            };
1884            content_capture_ix = match (content_capture_ix, injection_content_capture_ix) {
1885                (None, Some(ix)) => Some(ix),
1886                (Some(_), Some(_)) => {
1887                    anyhow::bail!("both content and injection.content captures are present")
1888                }
1889                _ => content_capture_ix,
1890            };
1891            let patterns = (0..query.pattern_count())
1892                .map(|ix| {
1893                    let mut config = InjectionPatternConfig::default();
1894                    for setting in query.property_settings(ix) {
1895                        match setting.key.as_ref() {
1896                            "language" | "injection.language" => {
1897                                config.language.clone_from(&setting.value);
1898                            }
1899                            "combined" | "injection.combined" => {
1900                                config.combined = true;
1901                            }
1902                            _ => {}
1903                        }
1904                    }
1905                    config
1906                })
1907                .collect();
1908            if let Some(content_capture_ix) = content_capture_ix {
1909                self.grammar_mut()?.injection_config = Some(InjectionConfig {
1910                    query,
1911                    language_capture_ix,
1912                    content_capture_ix,
1913                    patterns,
1914                });
1915            } else {
1916                log::error!(
1917                    "missing required capture in injections {} TreeSitter query: \
1918                    content or injection.content",
1919                    &self.config.name,
1920                );
1921            }
1922        }
1923        Ok(self)
1924    }
1925
1926    pub fn with_override_query(mut self, source: &str) -> anyhow::Result<Self> {
1927        let query = Query::new(&self.expect_grammar()?.ts_language, source)?;
1928
1929        let mut override_configs_by_id = HashMap::default();
1930        for (ix, mut name) in query.capture_names().iter().copied().enumerate() {
1931            let mut range_is_inclusive = false;
1932            if name.starts_with('_') {
1933                continue;
1934            }
1935            if let Some(prefix) = name.strip_suffix(".inclusive") {
1936                name = prefix;
1937                range_is_inclusive = true;
1938            }
1939
1940            let value = self.config.overrides.get(name).cloned().unwrap_or_default();
1941            for server_name in &value.opt_into_language_servers {
1942                if !self
1943                    .config
1944                    .scope_opt_in_language_servers
1945                    .contains(server_name)
1946                {
1947                    util::debug_panic!(
1948                        "Server {server_name:?} has been opted-in by scope {name:?} but has not been marked as an opt-in server"
1949                    );
1950                }
1951            }
1952
1953            override_configs_by_id.insert(
1954                ix as u32,
1955                OverrideEntry {
1956                    name: name.to_string(),
1957                    range_is_inclusive,
1958                    value,
1959                },
1960            );
1961        }
1962
1963        let referenced_override_names = self.config.overrides.keys().chain(
1964            self.config
1965                .brackets
1966                .disabled_scopes_by_bracket_ix
1967                .iter()
1968                .flatten(),
1969        );
1970
1971        for referenced_name in referenced_override_names {
1972            if !override_configs_by_id
1973                .values()
1974                .any(|entry| entry.name == *referenced_name)
1975            {
1976                anyhow::bail!(
1977                    "language {:?} has overrides in config not in query: {referenced_name:?}",
1978                    self.config.name
1979                );
1980            }
1981        }
1982
1983        for entry in override_configs_by_id.values_mut() {
1984            entry.value.disabled_bracket_ixs = self
1985                .config
1986                .brackets
1987                .disabled_scopes_by_bracket_ix
1988                .iter()
1989                .enumerate()
1990                .filter_map(|(ix, disabled_scope_names)| {
1991                    if disabled_scope_names.contains(&entry.name) {
1992                        Some(ix as u16)
1993                    } else {
1994                        None
1995                    }
1996                })
1997                .collect();
1998        }
1999
2000        self.config.brackets.disabled_scopes_by_bracket_ix.clear();
2001
2002        let grammar = self.grammar_mut()?;
2003        grammar.override_config = Some(OverrideConfig {
2004            query,
2005            values: override_configs_by_id,
2006        });
2007        Ok(self)
2008    }
2009
2010    pub fn with_redaction_query(mut self, source: &str) -> anyhow::Result<Self> {
2011        let query = Query::new(&self.expect_grammar()?.ts_language, source)?;
2012        let mut redaction_capture_ix = 0;
2013        if populate_capture_indices(
2014            &query,
2015            &self.config.name,
2016            "redactions",
2017            &[],
2018            &mut [Capture::Required("redact", &mut redaction_capture_ix)],
2019        ) {
2020            self.grammar_mut()?.redactions_config = Some(RedactionConfig {
2021                query,
2022                redaction_capture_ix,
2023            });
2024        }
2025        Ok(self)
2026    }
2027
2028    fn expect_grammar(&self) -> Result<&Grammar> {
2029        self.grammar
2030            .as_ref()
2031            .map(|grammar| grammar.as_ref())
2032            .context("no grammar for language")
2033    }
2034
2035    fn grammar_mut(&mut self) -> Result<&mut Grammar> {
2036        Arc::get_mut(self.grammar.as_mut().context("no grammar for language")?)
2037            .context("cannot mutate grammar")
2038    }
2039
2040    pub fn name(&self) -> LanguageName {
2041        self.config.name.clone()
2042    }
2043    pub fn manifest(&self) -> Option<&ManifestName> {
2044        self.manifest_name.as_ref()
2045    }
2046
2047    pub fn code_fence_block_name(&self) -> Arc<str> {
2048        self.config
2049            .code_fence_block_name
2050            .clone()
2051            .unwrap_or_else(|| self.config.name.as_ref().to_lowercase().into())
2052    }
2053
2054    pub fn context_provider(&self) -> Option<Arc<dyn ContextProvider>> {
2055        self.context_provider.clone()
2056    }
2057
2058    pub fn toolchain_lister(&self) -> Option<Arc<dyn ToolchainLister>> {
2059        self.toolchain.clone()
2060    }
2061
2062    pub fn highlight_text<'a>(
2063        self: &'a Arc<Self>,
2064        text: &'a Rope,
2065        range: Range<usize>,
2066    ) -> Vec<(Range<usize>, HighlightId)> {
2067        let mut result = Vec::new();
2068        if let Some(grammar) = &self.grammar {
2069            let tree = grammar.parse_text(text, None);
2070            let captures =
2071                SyntaxSnapshot::single_tree_captures(range.clone(), text, &tree, self, |grammar| {
2072                    grammar
2073                        .highlights_config
2074                        .as_ref()
2075                        .map(|config| &config.query)
2076                });
2077            let highlight_maps = vec![grammar.highlight_map()];
2078            let mut offset = 0;
2079            for chunk in
2080                BufferChunks::new(text, range, Some((captures, highlight_maps)), false, None)
2081            {
2082                let end_offset = offset + chunk.text.len();
2083                if let Some(highlight_id) = chunk.syntax_highlight_id
2084                    && !highlight_id.is_default()
2085                {
2086                    result.push((offset..end_offset, highlight_id));
2087                }
2088                offset = end_offset;
2089            }
2090        }
2091        result
2092    }
2093
2094    pub fn path_suffixes(&self) -> &[String] {
2095        &self.config.matcher.path_suffixes
2096    }
2097
2098    pub fn should_autoclose_before(&self, c: char) -> bool {
2099        c.is_whitespace() || self.config.autoclose_before.contains(c)
2100    }
2101
2102    pub fn set_theme(&self, theme: &SyntaxTheme) {
2103        if let Some(grammar) = self.grammar.as_ref()
2104            && let Some(highlights_config) = &grammar.highlights_config
2105        {
2106            *grammar.highlight_map.lock() =
2107                HighlightMap::new(highlights_config.query.capture_names(), theme);
2108        }
2109    }
2110
2111    pub fn grammar(&self) -> Option<&Arc<Grammar>> {
2112        self.grammar.as_ref()
2113    }
2114
2115    pub fn default_scope(self: &Arc<Self>) -> LanguageScope {
2116        LanguageScope {
2117            language: self.clone(),
2118            override_id: None,
2119        }
2120    }
2121
2122    pub fn lsp_id(&self) -> String {
2123        self.config.name.lsp_id()
2124    }
2125
2126    pub fn prettier_parser_name(&self) -> Option<&str> {
2127        self.config.prettier_parser_name.as_deref()
2128    }
2129
2130    pub fn config(&self) -> &LanguageConfig {
2131        &self.config
2132    }
2133}
2134
2135impl LanguageScope {
2136    pub fn path_suffixes(&self) -> &[String] {
2137        self.language.path_suffixes()
2138    }
2139
2140    pub fn language_name(&self) -> LanguageName {
2141        self.language.config.name.clone()
2142    }
2143
2144    pub fn collapsed_placeholder(&self) -> &str {
2145        self.language.config.collapsed_placeholder.as_ref()
2146    }
2147
2148    /// Returns line prefix that is inserted in e.g. line continuations or
2149    /// in `toggle comments` action.
2150    pub fn line_comment_prefixes(&self) -> &[Arc<str>] {
2151        Override::as_option(
2152            self.config_override().map(|o| &o.line_comments),
2153            Some(&self.language.config.line_comments),
2154        )
2155        .map_or([].as_slice(), |e| e.as_slice())
2156    }
2157
2158    /// Config for block comments for this language.
2159    pub fn block_comment(&self) -> Option<&BlockCommentConfig> {
2160        Override::as_option(
2161            self.config_override().map(|o| &o.block_comment),
2162            self.language.config.block_comment.as_ref(),
2163        )
2164    }
2165
2166    /// Config for documentation-style block comments for this language.
2167    pub fn documentation_comment(&self) -> Option<&BlockCommentConfig> {
2168        self.language.config.documentation_comment.as_ref()
2169    }
2170
2171    /// Returns list markers that are inserted unchanged on newline (e.g., `- `, `* `, `+ `).
2172    pub fn unordered_list(&self) -> &[Arc<str>] {
2173        &self.language.config.unordered_list
2174    }
2175
2176    /// Returns configuration for ordered lists with auto-incrementing numbers (e.g., `1. ` becomes `2. `).
2177    pub fn ordered_list(&self) -> &[OrderedListConfig] {
2178        &self.language.config.ordered_list
2179    }
2180
2181    /// Returns configuration for task list continuation, if any (e.g., `- [x] ` continues as `- [ ] `).
2182    pub fn task_list(&self) -> Option<&TaskListConfig> {
2183        self.language.config.task_list.as_ref()
2184    }
2185
2186    /// Returns additional regex patterns that act as prefix markers for creating
2187    /// boundaries during rewrapping.
2188    ///
2189    /// By default, Zed treats as paragraph and comment prefixes as boundaries.
2190    pub fn rewrap_prefixes(&self) -> &[Regex] {
2191        &self.language.config.rewrap_prefixes
2192    }
2193
2194    /// Returns a list of language-specific word characters.
2195    ///
2196    /// By default, Zed treats alphanumeric characters (and '_') as word characters for
2197    /// the purpose of actions like 'move to next word end` or whole-word search.
2198    /// It additionally accounts for language's additional word characters.
2199    pub fn word_characters(&self) -> Option<&HashSet<char>> {
2200        Override::as_option(
2201            self.config_override().map(|o| &o.word_characters),
2202            Some(&self.language.config.word_characters),
2203        )
2204    }
2205
2206    /// Returns a list of language-specific characters that are considered part of
2207    /// a completion query.
2208    pub fn completion_query_characters(&self) -> Option<&HashSet<char>> {
2209        Override::as_option(
2210            self.config_override()
2211                .map(|o| &o.completion_query_characters),
2212            Some(&self.language.config.completion_query_characters),
2213        )
2214    }
2215
2216    /// Returns a list of language-specific characters that are considered part of
2217    /// identifiers during linked editing operations.
2218    pub fn linked_edit_characters(&self) -> Option<&HashSet<char>> {
2219        Override::as_option(
2220            self.config_override().map(|o| &o.linked_edit_characters),
2221            Some(&self.language.config.linked_edit_characters),
2222        )
2223    }
2224
2225    /// Returns whether to prefer snippet `label` over `new_text` to replace text when
2226    /// completion is accepted.
2227    ///
2228    /// In cases like when cursor is in string or renaming existing function,
2229    /// you don't want to expand function signature instead just want function name
2230    /// to replace existing one.
2231    pub fn prefers_label_for_snippet_in_completion(&self) -> bool {
2232        self.config_override()
2233            .and_then(|o| o.prefer_label_for_snippet)
2234            .unwrap_or(false)
2235    }
2236
2237    /// Returns a list of bracket pairs for a given language with an additional
2238    /// piece of information about whether the particular bracket pair is currently active for a given language.
2239    pub fn brackets(&self) -> impl Iterator<Item = (&BracketPair, bool)> {
2240        let mut disabled_ids = self
2241            .config_override()
2242            .map_or(&[] as _, |o| o.disabled_bracket_ixs.as_slice());
2243        self.language
2244            .config
2245            .brackets
2246            .pairs
2247            .iter()
2248            .enumerate()
2249            .map(move |(ix, bracket)| {
2250                let mut is_enabled = true;
2251                if let Some(next_disabled_ix) = disabled_ids.first()
2252                    && ix == *next_disabled_ix as usize
2253                {
2254                    disabled_ids = &disabled_ids[1..];
2255                    is_enabled = false;
2256                }
2257                (bracket, is_enabled)
2258            })
2259    }
2260
2261    pub fn should_autoclose_before(&self, c: char) -> bool {
2262        c.is_whitespace() || self.language.config.autoclose_before.contains(c)
2263    }
2264
2265    pub fn language_allowed(&self, name: &LanguageServerName) -> bool {
2266        let config = &self.language.config;
2267        let opt_in_servers = &config.scope_opt_in_language_servers;
2268        if opt_in_servers.contains(name) {
2269            if let Some(over) = self.config_override() {
2270                over.opt_into_language_servers.contains(name)
2271            } else {
2272                false
2273            }
2274        } else {
2275            true
2276        }
2277    }
2278
2279    pub fn override_name(&self) -> Option<&str> {
2280        let id = self.override_id?;
2281        let grammar = self.language.grammar.as_ref()?;
2282        let override_config = grammar.override_config.as_ref()?;
2283        override_config.values.get(&id).map(|e| e.name.as_str())
2284    }
2285
2286    fn config_override(&self) -> Option<&LanguageConfigOverride> {
2287        let id = self.override_id?;
2288        let grammar = self.language.grammar.as_ref()?;
2289        let override_config = grammar.override_config.as_ref()?;
2290        override_config.values.get(&id).map(|e| &e.value)
2291    }
2292}
2293
2294impl Hash for Language {
2295    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
2296        self.id.hash(state)
2297    }
2298}
2299
2300impl PartialEq for Language {
2301    fn eq(&self, other: &Self) -> bool {
2302        self.id.eq(&other.id)
2303    }
2304}
2305
2306impl Eq for Language {}
2307
2308impl Debug for Language {
2309    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2310        f.debug_struct("Language")
2311            .field("name", &self.config.name)
2312            .finish()
2313    }
2314}
2315
2316impl Grammar {
2317    pub fn id(&self) -> GrammarId {
2318        self.id
2319    }
2320
2321    fn parse_text(&self, text: &Rope, old_tree: Option<Tree>) -> Tree {
2322        with_parser(|parser| {
2323            parser
2324                .set_language(&self.ts_language)
2325                .expect("incompatible grammar");
2326            let mut chunks = text.chunks_in_range(0..text.len());
2327            parser
2328                .parse_with_options(
2329                    &mut move |offset, _| {
2330                        chunks.seek(offset);
2331                        chunks.next().unwrap_or("").as_bytes()
2332                    },
2333                    old_tree.as_ref(),
2334                    None,
2335                )
2336                .unwrap()
2337        })
2338    }
2339
2340    pub fn highlight_map(&self) -> HighlightMap {
2341        self.highlight_map.lock().clone()
2342    }
2343
2344    pub fn highlight_id_for_name(&self, name: &str) -> Option<HighlightId> {
2345        let capture_id = self
2346            .highlights_config
2347            .as_ref()?
2348            .query
2349            .capture_index_for_name(name)?;
2350        Some(self.highlight_map.lock().get(capture_id))
2351    }
2352
2353    pub fn debug_variables_config(&self) -> Option<&DebugVariablesConfig> {
2354        self.debug_variables_config.as_ref()
2355    }
2356
2357    pub fn imports_config(&self) -> Option<&ImportsConfig> {
2358        self.imports_config.as_ref()
2359    }
2360}
2361
2362impl CodeLabelBuilder {
2363    pub fn respan_filter_range(&mut self, filter_text: Option<&str>) {
2364        self.filter_range = filter_text
2365            .and_then(|filter| self.text.find(filter).map(|ix| ix..ix + filter.len()))
2366            .unwrap_or(0..self.text.len());
2367    }
2368
2369    pub fn push_str(&mut self, text: &str, highlight: Option<HighlightId>) {
2370        let start_ix = self.text.len();
2371        self.text.push_str(text);
2372        if let Some(highlight) = highlight {
2373            let end_ix = self.text.len();
2374            self.runs.push((start_ix..end_ix, highlight));
2375        }
2376    }
2377
2378    pub fn build(mut self) -> CodeLabel {
2379        if self.filter_range.end == 0 {
2380            self.respan_filter_range(None);
2381        }
2382        CodeLabel {
2383            text: self.text,
2384            runs: self.runs,
2385            filter_range: self.filter_range,
2386        }
2387    }
2388}
2389
2390impl CodeLabel {
2391    pub fn fallback_for_completion(
2392        item: &lsp::CompletionItem,
2393        language: Option<&Language>,
2394    ) -> Self {
2395        let highlight_id = item.kind.and_then(|kind| {
2396            let grammar = language?.grammar()?;
2397            use lsp::CompletionItemKind as Kind;
2398            match kind {
2399                Kind::CLASS => grammar.highlight_id_for_name("type"),
2400                Kind::CONSTANT => grammar.highlight_id_for_name("constant"),
2401                Kind::CONSTRUCTOR => grammar.highlight_id_for_name("constructor"),
2402                Kind::ENUM => grammar
2403                    .highlight_id_for_name("enum")
2404                    .or_else(|| grammar.highlight_id_for_name("type")),
2405                Kind::ENUM_MEMBER => grammar
2406                    .highlight_id_for_name("variant")
2407                    .or_else(|| grammar.highlight_id_for_name("property")),
2408                Kind::FIELD => grammar.highlight_id_for_name("property"),
2409                Kind::FUNCTION => grammar.highlight_id_for_name("function"),
2410                Kind::INTERFACE => grammar.highlight_id_for_name("type"),
2411                Kind::METHOD => grammar
2412                    .highlight_id_for_name("function.method")
2413                    .or_else(|| grammar.highlight_id_for_name("function")),
2414                Kind::OPERATOR => grammar.highlight_id_for_name("operator"),
2415                Kind::PROPERTY => grammar.highlight_id_for_name("property"),
2416                Kind::STRUCT => grammar.highlight_id_for_name("type"),
2417                Kind::VARIABLE => grammar.highlight_id_for_name("variable"),
2418                Kind::KEYWORD => grammar.highlight_id_for_name("keyword"),
2419                _ => None,
2420            }
2421        });
2422
2423        let label = &item.label;
2424        let label_length = label.len();
2425        let runs = highlight_id
2426            .map(|highlight_id| vec![(0..label_length, highlight_id)])
2427            .unwrap_or_default();
2428        let text = if let Some(detail) = item.detail.as_deref().filter(|detail| detail != label) {
2429            format!("{label} {detail}")
2430        } else if let Some(description) = item
2431            .label_details
2432            .as_ref()
2433            .and_then(|label_details| label_details.description.as_deref())
2434            .filter(|description| description != label)
2435        {
2436            format!("{label} {description}")
2437        } else {
2438            label.clone()
2439        };
2440        let filter_range = item
2441            .filter_text
2442            .as_deref()
2443            .and_then(|filter| text.find(filter).map(|ix| ix..ix + filter.len()))
2444            .unwrap_or(0..label_length);
2445        Self {
2446            text,
2447            runs,
2448            filter_range,
2449        }
2450    }
2451
2452    pub fn plain(text: String, filter_text: Option<&str>) -> Self {
2453        Self::filtered(text.clone(), text.len(), filter_text, Vec::new())
2454    }
2455
2456    pub fn filtered(
2457        text: String,
2458        label_len: usize,
2459        filter_text: Option<&str>,
2460        runs: Vec<(Range<usize>, HighlightId)>,
2461    ) -> Self {
2462        assert!(label_len <= text.len());
2463        let filter_range = filter_text
2464            .and_then(|filter| text.find(filter).map(|ix| ix..ix + filter.len()))
2465            .unwrap_or(0..label_len);
2466        Self::new(text, filter_range, runs)
2467    }
2468
2469    pub fn new(
2470        text: String,
2471        filter_range: Range<usize>,
2472        runs: Vec<(Range<usize>, HighlightId)>,
2473    ) -> Self {
2474        assert!(
2475            text.get(filter_range.clone()).is_some(),
2476            "invalid filter range"
2477        );
2478        runs.iter().for_each(|(range, _)| {
2479            assert!(
2480                text.get(range.clone()).is_some(),
2481                "invalid run range with inputs. Requested range {range:?} in text '{text}'",
2482            );
2483        });
2484        Self {
2485            runs,
2486            filter_range,
2487            text,
2488        }
2489    }
2490
2491    pub fn text(&self) -> &str {
2492        self.text.as_str()
2493    }
2494
2495    pub fn filter_text(&self) -> &str {
2496        &self.text[self.filter_range.clone()]
2497    }
2498}
2499
2500impl From<String> for CodeLabel {
2501    fn from(value: String) -> Self {
2502        Self::plain(value, None)
2503    }
2504}
2505
2506impl From<&str> for CodeLabel {
2507    fn from(value: &str) -> Self {
2508        Self::plain(value.to_string(), None)
2509    }
2510}
2511
2512impl Ord for LanguageMatcher {
2513    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
2514        self.path_suffixes.cmp(&other.path_suffixes).then_with(|| {
2515            self.first_line_pattern
2516                .as_ref()
2517                .map(Regex::as_str)
2518                .cmp(&other.first_line_pattern.as_ref().map(Regex::as_str))
2519        })
2520    }
2521}
2522
2523impl PartialOrd for LanguageMatcher {
2524    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
2525        Some(self.cmp(other))
2526    }
2527}
2528
2529impl Eq for LanguageMatcher {}
2530
2531impl PartialEq for LanguageMatcher {
2532    fn eq(&self, other: &Self) -> bool {
2533        self.path_suffixes == other.path_suffixes
2534            && self.first_line_pattern.as_ref().map(Regex::as_str)
2535                == other.first_line_pattern.as_ref().map(Regex::as_str)
2536    }
2537}
2538
2539#[cfg(any(test, feature = "test-support"))]
2540impl Default for FakeLspAdapter {
2541    fn default() -> Self {
2542        Self {
2543            name: "the-fake-language-server",
2544            capabilities: lsp::LanguageServer::full_capabilities(),
2545            initializer: None,
2546            disk_based_diagnostics_progress_token: None,
2547            initialization_options: None,
2548            disk_based_diagnostics_sources: Vec::new(),
2549            prettier_plugins: Vec::new(),
2550            language_server_binary: LanguageServerBinary {
2551                path: "/the/fake/lsp/path".into(),
2552                arguments: vec![],
2553                env: Default::default(),
2554            },
2555            label_for_completion: None,
2556        }
2557    }
2558}
2559
2560#[cfg(any(test, feature = "test-support"))]
2561impl LspInstaller for FakeLspAdapter {
2562    type BinaryVersion = ();
2563
2564    async fn fetch_latest_server_version(
2565        &self,
2566        _: &dyn LspAdapterDelegate,
2567        _: bool,
2568        _: &mut AsyncApp,
2569    ) -> Result<Self::BinaryVersion> {
2570        unreachable!()
2571    }
2572
2573    async fn check_if_user_installed(
2574        &self,
2575        _: &dyn LspAdapterDelegate,
2576        _: Option<Toolchain>,
2577        _: &AsyncApp,
2578    ) -> Option<LanguageServerBinary> {
2579        Some(self.language_server_binary.clone())
2580    }
2581
2582    async fn fetch_server_binary(
2583        &self,
2584        _: (),
2585        _: PathBuf,
2586        _: &dyn LspAdapterDelegate,
2587    ) -> Result<LanguageServerBinary> {
2588        unreachable!();
2589    }
2590
2591    async fn cached_server_binary(
2592        &self,
2593        _: PathBuf,
2594        _: &dyn LspAdapterDelegate,
2595    ) -> Option<LanguageServerBinary> {
2596        unreachable!();
2597    }
2598}
2599
2600#[cfg(any(test, feature = "test-support"))]
2601#[async_trait(?Send)]
2602impl LspAdapter for FakeLspAdapter {
2603    fn name(&self) -> LanguageServerName {
2604        LanguageServerName(self.name.into())
2605    }
2606
2607    fn disk_based_diagnostic_sources(&self) -> Vec<String> {
2608        self.disk_based_diagnostics_sources.clone()
2609    }
2610
2611    fn disk_based_diagnostics_progress_token(&self) -> Option<String> {
2612        self.disk_based_diagnostics_progress_token.clone()
2613    }
2614
2615    async fn initialization_options(
2616        self: Arc<Self>,
2617        _: &Arc<dyn LspAdapterDelegate>,
2618    ) -> Result<Option<Value>> {
2619        Ok(self.initialization_options.clone())
2620    }
2621
2622    async fn label_for_completion(
2623        &self,
2624        item: &lsp::CompletionItem,
2625        language: &Arc<Language>,
2626    ) -> Option<CodeLabel> {
2627        let label_for_completion = self.label_for_completion.as_ref()?;
2628        label_for_completion(item, language)
2629    }
2630
2631    fn is_extension(&self) -> bool {
2632        false
2633    }
2634}
2635
2636enum Capture<'a> {
2637    Required(&'static str, &'a mut u32),
2638    Optional(&'static str, &'a mut Option<u32>),
2639}
2640
2641fn populate_capture_indices(
2642    query: &Query,
2643    language_name: &LanguageName,
2644    query_type: &str,
2645    expected_prefixes: &[&str],
2646    captures: &mut [Capture<'_>],
2647) -> bool {
2648    let mut found_required_indices = Vec::new();
2649    'outer: for (ix, name) in query.capture_names().iter().enumerate() {
2650        for (required_ix, capture) in captures.iter_mut().enumerate() {
2651            match capture {
2652                Capture::Required(capture_name, index) if capture_name == name => {
2653                    **index = ix as u32;
2654                    found_required_indices.push(required_ix);
2655                    continue 'outer;
2656                }
2657                Capture::Optional(capture_name, index) if capture_name == name => {
2658                    **index = Some(ix as u32);
2659                    continue 'outer;
2660                }
2661                _ => {}
2662            }
2663        }
2664        if !name.starts_with("_")
2665            && !expected_prefixes
2666                .iter()
2667                .any(|&prefix| name.starts_with(prefix))
2668        {
2669            log::warn!(
2670                "unrecognized capture name '{}' in {} {} TreeSitter query \
2671                (suppress this warning by prefixing with '_')",
2672                name,
2673                language_name,
2674                query_type
2675            );
2676        }
2677    }
2678    let mut missing_required_captures = Vec::new();
2679    for (capture_ix, capture) in captures.iter().enumerate() {
2680        if let Capture::Required(capture_name, _) = capture
2681            && !found_required_indices.contains(&capture_ix)
2682        {
2683            missing_required_captures.push(*capture_name);
2684        }
2685    }
2686    let success = missing_required_captures.is_empty();
2687    if !success {
2688        log::error!(
2689            "missing required capture(s) in {} {} TreeSitter query: {}",
2690            language_name,
2691            query_type,
2692            missing_required_captures.join(", ")
2693        );
2694    }
2695    success
2696}
2697
2698pub fn point_to_lsp(point: PointUtf16) -> lsp::Position {
2699    lsp::Position::new(point.row, point.column)
2700}
2701
2702pub fn point_from_lsp(point: lsp::Position) -> Unclipped<PointUtf16> {
2703    Unclipped(PointUtf16::new(point.line, point.character))
2704}
2705
2706pub fn range_to_lsp(range: Range<PointUtf16>) -> Result<lsp::Range> {
2707    anyhow::ensure!(
2708        range.start <= range.end,
2709        "Inverted range provided to an LSP request: {:?}-{:?}",
2710        range.start,
2711        range.end
2712    );
2713    Ok(lsp::Range {
2714        start: point_to_lsp(range.start),
2715        end: point_to_lsp(range.end),
2716    })
2717}
2718
2719pub fn range_from_lsp(range: lsp::Range) -> Range<Unclipped<PointUtf16>> {
2720    let mut start = point_from_lsp(range.start);
2721    let mut end = point_from_lsp(range.end);
2722    if start > end {
2723        // We debug instead of warn so that this is not logged by default unless explicitly requested.
2724        // Using warn would write to the log file, and since we receive an enormous amount of
2725        // range_from_lsp calls (especially during completions), that can hang the main thread.
2726        //
2727        // See issue #36223.
2728        zlog::debug!("range_from_lsp called with inverted range {start:?}-{end:?}");
2729        mem::swap(&mut start, &mut end);
2730    }
2731    start..end
2732}
2733
2734#[doc(hidden)]
2735#[cfg(any(test, feature = "test-support"))]
2736pub fn rust_lang() -> Arc<Language> {
2737    use std::borrow::Cow;
2738
2739    let language = Language::new(
2740        LanguageConfig {
2741            name: "Rust".into(),
2742            matcher: LanguageMatcher {
2743                path_suffixes: vec!["rs".to_string()],
2744                ..Default::default()
2745            },
2746            line_comments: vec!["// ".into(), "/// ".into(), "//! ".into()],
2747            ..Default::default()
2748        },
2749        Some(tree_sitter_rust::LANGUAGE.into()),
2750    )
2751    .with_queries(LanguageQueries {
2752        outline: Some(Cow::from(include_str!(
2753            "../../languages/src/rust/outline.scm"
2754        ))),
2755        indents: Some(Cow::from(include_str!(
2756            "../../languages/src/rust/indents.scm"
2757        ))),
2758        brackets: Some(Cow::from(include_str!(
2759            "../../languages/src/rust/brackets.scm"
2760        ))),
2761        text_objects: Some(Cow::from(include_str!(
2762            "../../languages/src/rust/textobjects.scm"
2763        ))),
2764        highlights: Some(Cow::from(include_str!(
2765            "../../languages/src/rust/highlights.scm"
2766        ))),
2767        injections: Some(Cow::from(include_str!(
2768            "../../languages/src/rust/injections.scm"
2769        ))),
2770        overrides: Some(Cow::from(include_str!(
2771            "../../languages/src/rust/overrides.scm"
2772        ))),
2773        redactions: None,
2774        runnables: Some(Cow::from(include_str!(
2775            "../../languages/src/rust/runnables.scm"
2776        ))),
2777        debugger: Some(Cow::from(include_str!(
2778            "../../languages/src/rust/debugger.scm"
2779        ))),
2780        imports: Some(Cow::from(include_str!(
2781            "../../languages/src/rust/imports.scm"
2782        ))),
2783    })
2784    .expect("Could not parse queries");
2785    Arc::new(language)
2786}
2787
2788#[doc(hidden)]
2789#[cfg(any(test, feature = "test-support"))]
2790pub fn markdown_lang() -> Arc<Language> {
2791    use std::borrow::Cow;
2792
2793    let language = Language::new(
2794        LanguageConfig {
2795            name: "Markdown".into(),
2796            matcher: LanguageMatcher {
2797                path_suffixes: vec!["md".into()],
2798                ..Default::default()
2799            },
2800            ..LanguageConfig::default()
2801        },
2802        Some(tree_sitter_md::LANGUAGE.into()),
2803    )
2804    .with_queries(LanguageQueries {
2805        brackets: Some(Cow::from(include_str!(
2806            "../../languages/src/markdown/brackets.scm"
2807        ))),
2808        injections: Some(Cow::from(include_str!(
2809            "../../languages/src/markdown/injections.scm"
2810        ))),
2811        highlights: Some(Cow::from(include_str!(
2812            "../../languages/src/markdown/highlights.scm"
2813        ))),
2814        indents: Some(Cow::from(include_str!(
2815            "../../languages/src/markdown/indents.scm"
2816        ))),
2817        outline: Some(Cow::from(include_str!(
2818            "../../languages/src/markdown/outline.scm"
2819        ))),
2820        ..LanguageQueries::default()
2821    })
2822    .expect("Could not parse markdown queries");
2823    Arc::new(language)
2824}
2825
2826#[cfg(test)]
2827mod tests {
2828    use super::*;
2829    use gpui::TestAppContext;
2830    use pretty_assertions::assert_matches;
2831
2832    #[gpui::test(iterations = 10)]
2833    async fn test_language_loading(cx: &mut TestAppContext) {
2834        let languages = LanguageRegistry::test(cx.executor());
2835        let languages = Arc::new(languages);
2836        languages.register_native_grammars([
2837            ("json", tree_sitter_json::LANGUAGE),
2838            ("rust", tree_sitter_rust::LANGUAGE),
2839        ]);
2840        languages.register_test_language(LanguageConfig {
2841            name: "JSON".into(),
2842            grammar: Some("json".into()),
2843            matcher: LanguageMatcher {
2844                path_suffixes: vec!["json".into()],
2845                ..Default::default()
2846            },
2847            ..Default::default()
2848        });
2849        languages.register_test_language(LanguageConfig {
2850            name: "Rust".into(),
2851            grammar: Some("rust".into()),
2852            matcher: LanguageMatcher {
2853                path_suffixes: vec!["rs".into()],
2854                ..Default::default()
2855            },
2856            ..Default::default()
2857        });
2858        assert_eq!(
2859            languages.language_names(),
2860            &[
2861                LanguageName::new_static("JSON"),
2862                LanguageName::new_static("Plain Text"),
2863                LanguageName::new_static("Rust"),
2864            ]
2865        );
2866
2867        let rust1 = languages.language_for_name("Rust");
2868        let rust2 = languages.language_for_name("Rust");
2869
2870        // Ensure language is still listed even if it's being loaded.
2871        assert_eq!(
2872            languages.language_names(),
2873            &[
2874                LanguageName::new_static("JSON"),
2875                LanguageName::new_static("Plain Text"),
2876                LanguageName::new_static("Rust"),
2877            ]
2878        );
2879
2880        let (rust1, rust2) = futures::join!(rust1, rust2);
2881        assert!(Arc::ptr_eq(&rust1.unwrap(), &rust2.unwrap()));
2882
2883        // Ensure language is still listed even after loading it.
2884        assert_eq!(
2885            languages.language_names(),
2886            &[
2887                LanguageName::new_static("JSON"),
2888                LanguageName::new_static("Plain Text"),
2889                LanguageName::new_static("Rust"),
2890            ]
2891        );
2892
2893        // Loading an unknown language returns an error.
2894        assert!(languages.language_for_name("Unknown").await.is_err());
2895    }
2896
2897    #[gpui::test]
2898    async fn test_completion_label_omits_duplicate_data() {
2899        let regular_completion_item_1 = lsp::CompletionItem {
2900            label: "regular1".to_string(),
2901            detail: Some("detail1".to_string()),
2902            label_details: Some(lsp::CompletionItemLabelDetails {
2903                detail: None,
2904                description: Some("description 1".to_string()),
2905            }),
2906            ..lsp::CompletionItem::default()
2907        };
2908
2909        let regular_completion_item_2 = lsp::CompletionItem {
2910            label: "regular2".to_string(),
2911            label_details: Some(lsp::CompletionItemLabelDetails {
2912                detail: None,
2913                description: Some("description 2".to_string()),
2914            }),
2915            ..lsp::CompletionItem::default()
2916        };
2917
2918        let completion_item_with_duplicate_detail_and_proper_description = lsp::CompletionItem {
2919            detail: Some(regular_completion_item_1.label.clone()),
2920            ..regular_completion_item_1.clone()
2921        };
2922
2923        let completion_item_with_duplicate_detail = lsp::CompletionItem {
2924            detail: Some(regular_completion_item_1.label.clone()),
2925            label_details: None,
2926            ..regular_completion_item_1.clone()
2927        };
2928
2929        let completion_item_with_duplicate_description = lsp::CompletionItem {
2930            label_details: Some(lsp::CompletionItemLabelDetails {
2931                detail: None,
2932                description: Some(regular_completion_item_2.label.clone()),
2933            }),
2934            ..regular_completion_item_2.clone()
2935        };
2936
2937        assert_eq!(
2938            CodeLabel::fallback_for_completion(&regular_completion_item_1, None).text,
2939            format!(
2940                "{} {}",
2941                regular_completion_item_1.label,
2942                regular_completion_item_1.detail.unwrap()
2943            ),
2944            "LSP completion items with both detail and label_details.description should prefer detail"
2945        );
2946        assert_eq!(
2947            CodeLabel::fallback_for_completion(&regular_completion_item_2, None).text,
2948            format!(
2949                "{} {}",
2950                regular_completion_item_2.label,
2951                regular_completion_item_2
2952                    .label_details
2953                    .as_ref()
2954                    .unwrap()
2955                    .description
2956                    .as_ref()
2957                    .unwrap()
2958            ),
2959            "LSP completion items without detail but with label_details.description should use that"
2960        );
2961        assert_eq!(
2962            CodeLabel::fallback_for_completion(
2963                &completion_item_with_duplicate_detail_and_proper_description,
2964                None
2965            )
2966            .text,
2967            format!(
2968                "{} {}",
2969                regular_completion_item_1.label,
2970                regular_completion_item_1
2971                    .label_details
2972                    .as_ref()
2973                    .unwrap()
2974                    .description
2975                    .as_ref()
2976                    .unwrap()
2977            ),
2978            "LSP completion items with both detail and label_details.description should prefer description only if the detail duplicates the completion label"
2979        );
2980        assert_eq!(
2981            CodeLabel::fallback_for_completion(&completion_item_with_duplicate_detail, None).text,
2982            regular_completion_item_1.label,
2983            "LSP completion items with duplicate label and detail, should omit the detail"
2984        );
2985        assert_eq!(
2986            CodeLabel::fallback_for_completion(&completion_item_with_duplicate_description, None)
2987                .text,
2988            regular_completion_item_2.label,
2989            "LSP completion items with duplicate label and detail, should omit the detail"
2990        );
2991    }
2992
2993    #[test]
2994    fn test_deserializing_comments_backwards_compat() {
2995        // current version of `block_comment` and `documentation_comment` work
2996        {
2997            let config: LanguageConfig = ::toml::from_str(
2998                r#"
2999                name = "Foo"
3000                block_comment = { start = "a", end = "b", prefix = "c", tab_size = 1 }
3001                documentation_comment = { start = "d", end = "e", prefix = "f", tab_size = 2 }
3002                "#,
3003            )
3004            .unwrap();
3005            assert_matches!(config.block_comment, Some(BlockCommentConfig { .. }));
3006            assert_matches!(
3007                config.documentation_comment,
3008                Some(BlockCommentConfig { .. })
3009            );
3010
3011            let block_config = config.block_comment.unwrap();
3012            assert_eq!(block_config.start.as_ref(), "a");
3013            assert_eq!(block_config.end.as_ref(), "b");
3014            assert_eq!(block_config.prefix.as_ref(), "c");
3015            assert_eq!(block_config.tab_size, 1);
3016
3017            let doc_config = config.documentation_comment.unwrap();
3018            assert_eq!(doc_config.start.as_ref(), "d");
3019            assert_eq!(doc_config.end.as_ref(), "e");
3020            assert_eq!(doc_config.prefix.as_ref(), "f");
3021            assert_eq!(doc_config.tab_size, 2);
3022        }
3023
3024        // former `documentation` setting is read into `documentation_comment`
3025        {
3026            let config: LanguageConfig = ::toml::from_str(
3027                r#"
3028                name = "Foo"
3029                documentation = { start = "a", end = "b", prefix = "c", tab_size = 1}
3030                "#,
3031            )
3032            .unwrap();
3033            assert_matches!(
3034                config.documentation_comment,
3035                Some(BlockCommentConfig { .. })
3036            );
3037
3038            let config = config.documentation_comment.unwrap();
3039            assert_eq!(config.start.as_ref(), "a");
3040            assert_eq!(config.end.as_ref(), "b");
3041            assert_eq!(config.prefix.as_ref(), "c");
3042            assert_eq!(config.tab_size, 1);
3043        }
3044
3045        // old block_comment format is read into BlockCommentConfig
3046        {
3047            let config: LanguageConfig = ::toml::from_str(
3048                r#"
3049                name = "Foo"
3050                block_comment = ["a", "b"]
3051                "#,
3052            )
3053            .unwrap();
3054            assert_matches!(config.block_comment, Some(BlockCommentConfig { .. }));
3055
3056            let config = config.block_comment.unwrap();
3057            assert_eq!(config.start.as_ref(), "a");
3058            assert_eq!(config.end.as_ref(), "b");
3059            assert_eq!(config.prefix.as_ref(), "");
3060            assert_eq!(config.tab_size, 0);
3061        }
3062    }
3063}