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