1589 lines · 59.8 KB · Rust
RawDownload
use anyhow::Context as _;use collections::HashMap;use context_server::ContextServerCommand;use dap::adapters::DebugAdapterName;use fs::Fs;use futures::StreamExt as _;use git::repository::DEFAULT_WORKTREE_DIRECTORY;use gpui::{AsyncApp, BorrowAppContext, Context, Entity, EventEmitter, Subscription, Task};use lsp::{DEFAULT_LSP_REQUEST_TIMEOUT_SECS, LanguageServerName};use paths::{    EDITORCONFIG_NAME, local_debug_file_relative_path, local_settings_file_relative_path,    local_tasks_file_relative_path, local_vscode_launch_file_relative_path,    local_vscode_tasks_file_relative_path, task_file_name,};use rpc::{    AnyProtoClient, TypedEnvelope,    proto::{self, REMOTE_SERVER_PROJECT_ID},};use schemars::JsonSchema;use serde::{Deserialize, Serialize};pub use settings::BinarySettings;pub use settings::DirenvSettings;pub use settings::LspSettings;use settings::{    DapSettingsContent, EditorconfigEvent, InvalidSettingsError, LocalSettingsKind,    LocalSettingsPath, RegisterSetting, SemanticTokenRules, Settings, SettingsLocation,    SettingsStore, parse_json_with_comments, watch_config_file,};use std::{cell::OnceCell, collections::BTreeMap, path::PathBuf, sync::Arc, time::Duration};use task::{DebugTaskFile, TaskTemplates, VsCodeDebugTaskFile, VsCodeTaskFile};use util::{ResultExt, rel_path::RelPath, serde::default_true};use worktree::{PathChange, UpdatedEntriesSet, Worktree, WorktreeId}; use crate::{    task_store::{TaskSettingsLocation, TaskStore},    trusted_worktrees::{PathTrust, TrustedWorktrees, TrustedWorktreesEvent},    worktree_store::{WorktreeStore, WorktreeStoreEvent},}; #[derive(Debug, Clone, RegisterSetting)]pub struct ProjectSettings {    /// Configuration for language servers.    ///    /// The following settings can be overridden for specific language servers:    /// - initialization_options    ///    /// To override settings for a language, add an entry for that language server's    /// name to the lsp value.    /// Default: null    // todo(settings-follow-up)    // We should change to use a non content type (settings::LspSettings is a content type)    // Note: Will either require merging with defaults, which also requires deciding where the defaults come from,    //       or case by case deciding which fields are optional and which are actually required.    pub lsp: HashMap<LanguageServerName, settings::LspSettings>,     /// Common language server settings.    pub global_lsp_settings: GlobalLspSettings,     /// Configuration for Debugger-related features    pub dap: HashMap<DebugAdapterName, DapSettings>,     /// Settings for context servers used for AI-related features.    pub context_servers: HashMap<Arc<str>, ContextServerSettings>,     /// Default timeout for context server requests in seconds.    pub context_server_timeout: u64,     /// Configuration for Diagnostics-related features.    pub diagnostics: DiagnosticsSettings,     /// Configuration for Git-related features    pub git: GitSettings,     /// Configuration for Node-related features    pub node: NodeBinarySettings,     /// Configuration for how direnv configuration should be loaded    pub load_direnv: DirenvSettings,     /// Configuration for session-related features    pub session: SessionSettings,} #[derive(Copy, Clone, Debug)]pub struct SessionSettings {    /// Whether or not to restore unsaved buffers on restart.    ///    /// If this is true, user won't be prompted whether to save/discard    /// dirty files when closing the application.    ///    /// Default: true    pub restore_unsaved_buffers: bool,    /// Whether or not to skip worktree trust checks.    /// When trusted, project settings are synchronized automatically,    /// language and MCP servers are downloaded and started automatically.    ///    /// Default: false    pub trust_all_worktrees: bool,} #[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]pub struct NodeBinarySettings {    /// The path to the Node binary.    pub path: Option<String>,    /// The path to the npm binary Zed should use (defaults to `.path/../npm`).    pub npm_path: Option<String>,    /// If enabled, Zed will download its own copy of Node.    pub ignore_system_version: bool,} impl From<settings::NodeBinarySettings> for NodeBinarySettings {    fn from(settings: settings::NodeBinarySettings) -> Self {        Self {            path: settings.path,            npm_path: settings.npm_path,            ignore_system_version: settings.ignore_system_version.unwrap_or(false),        }    }} /// Common language server settings.#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]#[serde(default)]pub struct GlobalLspSettings {    /// Whether to show the LSP servers button in the status bar.    ///    /// Default: `true`    pub button: bool,    /// The maximum amount of time to wait for responses from language servers, in seconds.    /// A value of `0` will result in no timeout being applied (causing all LSP responses to wait    /// indefinitely until completed).    /// This should not be used outside of serialization/de-serialization in favor of get_request_timeout.    ///    /// Default: `120`    pub request_timeout: u64,    pub notifications: LspNotificationSettings,     /// Rules for highlighting semantic tokens.    pub semantic_token_rules: SemanticTokenRules,} impl Default for GlobalLspSettings {    fn default() -> Self {        Self {            button: true,            request_timeout: DEFAULT_LSP_REQUEST_TIMEOUT_SECS,            notifications: LspNotificationSettings::default(),            semantic_token_rules: SemanticTokenRules::default(),        }    }} impl GlobalLspSettings {    /// Returns the timeout duration for LSP-related interactions, or Duration::ZERO if no timeout should be applied.    /// Zero durations are treated as no timeout by language servers, so code using this in an async context can    /// simply call unwrap_or_default.    pub const fn get_request_timeout(&self) -> Duration {        Duration::from_secs(self.request_timeout)    }} #[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, Debug)]#[serde(tag = "source", rename_all = "snake_case")]pub struct LspNotificationSettings {    /// Timeout in milliseconds for automatically dismissing language server notifications.    /// Set to 0 to disable auto-dismiss.    ///    /// Default: 5000    pub dismiss_timeout_ms: Option<u64>,} impl Default for LspNotificationSettings {    fn default() -> Self {        Self {            dismiss_timeout_ms: Some(5000),        }    }} #[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, Debug)]#[serde(tag = "source", rename_all = "snake_case")]pub enum ContextServerSettings {    Stdio {        /// Whether the context server is enabled.        #[serde(default = "default_true")]        enabled: bool,        /// If true, run this server on the remote server when using remote development.        #[serde(default)]        remote: bool,        #[serde(flatten)]        command: ContextServerCommand,    },    Http {        /// Whether the context server is enabled.        #[serde(default = "default_true")]        enabled: bool,        /// The URL of the remote context server.        url: String,        /// Optional authentication configuration for the remote server.        #[serde(skip_serializing_if = "HashMap::is_empty", default)]        headers: HashMap<String, String>,        /// Timeout for tool calls in milliseconds.        timeout: Option<u64>,    },    Extension {        /// Whether the context server is enabled.        #[serde(default = "default_true")]        enabled: bool,        /// If true, run this server on the remote server when using remote development.        #[serde(default)]        remote: bool,        /// The settings for this context server specified by the extension.        ///        /// Consult the documentation for the context server to see what settings        /// are supported.        settings: serde_json::Value,    },} impl From<settings::ContextServerSettingsContent> for ContextServerSettings {    fn from(value: settings::ContextServerSettingsContent) -> Self {        match value {            settings::ContextServerSettingsContent::Stdio {                enabled,                remote,                command,            } => ContextServerSettings::Stdio {                enabled,                remote,                command,            },            settings::ContextServerSettingsContent::Extension {                enabled,                remote,                settings,            } => ContextServerSettings::Extension {                enabled,                remote,                settings,            },            settings::ContextServerSettingsContent::Http {                enabled,                url,                headers,                timeout,            } => ContextServerSettings::Http {                enabled,                url,                headers,                timeout,            },        }    }}impl Into<settings::ContextServerSettingsContent> for ContextServerSettings {    fn into(self) -> settings::ContextServerSettingsContent {        match self {            ContextServerSettings::Stdio {                enabled,                remote,                command,            } => settings::ContextServerSettingsContent::Stdio {                enabled,                remote,                command,            },            ContextServerSettings::Extension {                enabled,                remote,                settings,            } => settings::ContextServerSettingsContent::Extension {                enabled,                remote,                settings,            },            ContextServerSettings::Http {                enabled,                url,                headers,                timeout,            } => settings::ContextServerSettingsContent::Http {                enabled,                url,                headers,                timeout,            },        }    }} impl ContextServerSettings {    pub fn default_extension() -> Self {        Self::Extension {            enabled: true,            remote: false,            settings: serde_json::json!({}),        }    }     pub fn enabled(&self) -> bool {        match self {            ContextServerSettings::Stdio { enabled, .. } => *enabled,            ContextServerSettings::Http { enabled, .. } => *enabled,            ContextServerSettings::Extension { enabled, .. } => *enabled,        }    }     pub fn set_enabled(&mut self, enabled: bool) {        match self {            ContextServerSettings::Stdio { enabled: e, .. } => *e = enabled,            ContextServerSettings::Http { enabled: e, .. } => *e = enabled,            ContextServerSettings::Extension { enabled: e, .. } => *e = enabled,        }    }} #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]pub enum DiagnosticSeverity {    // No diagnostics are shown.    Off,    Error,    Warning,    Info,    Hint,} impl DiagnosticSeverity {    pub fn into_lsp(self) -> Option<lsp::DiagnosticSeverity> {        match self {            DiagnosticSeverity::Off => None,            DiagnosticSeverity::Error => Some(lsp::DiagnosticSeverity::ERROR),            DiagnosticSeverity::Warning => Some(lsp::DiagnosticSeverity::WARNING),            DiagnosticSeverity::Info => Some(lsp::DiagnosticSeverity::INFORMATION),            DiagnosticSeverity::Hint => Some(lsp::DiagnosticSeverity::HINT),        }    }} impl From<settings::DiagnosticSeverityContent> for DiagnosticSeverity {    fn from(severity: settings::DiagnosticSeverityContent) -> Self {        match severity {            settings::DiagnosticSeverityContent::Off => DiagnosticSeverity::Off,            settings::DiagnosticSeverityContent::Error => DiagnosticSeverity::Error,            settings::DiagnosticSeverityContent::Warning => DiagnosticSeverity::Warning,            settings::DiagnosticSeverityContent::Info => DiagnosticSeverity::Info,            settings::DiagnosticSeverityContent::Hint => DiagnosticSeverity::Hint,            settings::DiagnosticSeverityContent::All => DiagnosticSeverity::Hint,        }    }} /// Determines the severity of the diagnostic that should be moved to.#[derive(PartialEq, PartialOrd, Clone, Copy, Debug, Eq, Deserialize, JsonSchema)]#[serde(rename_all = "snake_case")]pub enum GoToDiagnosticSeverity {    /// Errors    Error = 3,    /// Warnings    Warning = 2,    /// Information    Information = 1,    /// Hints    Hint = 0,} impl From<lsp::DiagnosticSeverity> for GoToDiagnosticSeverity {    fn from(severity: lsp::DiagnosticSeverity) -> Self {        match severity {            lsp::DiagnosticSeverity::ERROR => Self::Error,            lsp::DiagnosticSeverity::WARNING => Self::Warning,            lsp::DiagnosticSeverity::INFORMATION => Self::Information,            lsp::DiagnosticSeverity::HINT => Self::Hint,            _ => Self::Error,        }    }} impl GoToDiagnosticSeverity {    pub fn min() -> Self {        Self::Hint    }     pub fn max() -> Self {        Self::Error    }} /// Allows filtering diagnostics that should be moved to.#[derive(PartialEq, Clone, Copy, Debug, Deserialize, JsonSchema)]#[serde(untagged)]pub enum GoToDiagnosticSeverityFilter {    /// Move to diagnostics of a specific severity.    Only(GoToDiagnosticSeverity),     /// Specify a range of severities to include.    Range {        /// Minimum severity to move to. Defaults no "error".        #[serde(default = "GoToDiagnosticSeverity::min")]        min: GoToDiagnosticSeverity,        /// Maximum severity to move to. Defaults to "hint".        #[serde(default = "GoToDiagnosticSeverity::max")]        max: GoToDiagnosticSeverity,    },} impl Default for GoToDiagnosticSeverityFilter {    fn default() -> Self {        Self::Range {            min: GoToDiagnosticSeverity::min(),            max: GoToDiagnosticSeverity::max(),        }    }} impl GoToDiagnosticSeverityFilter {    pub fn matches(&self, severity: lsp::DiagnosticSeverity) -> bool {        let severity: GoToDiagnosticSeverity = severity.into();        match self {            Self::Only(target) => *target == severity,            Self::Range { min, max } => severity >= *min && severity <= *max,        }    }} #[derive(Clone, Debug)]pub struct GitSettings {    /// Whether or not git integration is enabled.    ///    /// Default: true    pub enabled: GitEnabledSettings,    /// Whether or not to show the git gutter.    ///    /// Default: tracked_files    pub git_gutter: settings::GitGutterSetting,    /// Sets the debounce threshold (in milliseconds) after which changes are reflected in the git gutter.    ///    /// Default: 0    pub gutter_debounce: u64,    /// Whether or not to show git blame data inline in    /// the currently focused line.    ///    /// Default: on    pub inline_blame: InlineBlameSettings,    /// Git blame settings.    pub blame: BlameSettings,    /// Which information to show in the branch picker.    ///    /// Default: on    pub branch_picker: BranchPickerSettings,    /// How hunks are displayed visually in the editor.    ///    /// Default: staged_hollow    pub hunk_style: settings::GitHunkStyleSetting,    /// How file paths are displayed in the git gutter.    ///    /// Default: file_name_first    pub path_style: GitPathStyle,    /// Directory where git worktrees are created, relative to the repository    /// working directory. When the resolved directory is outside the project    /// root, the project's directory name is automatically appended so that    /// sibling repos don't collide.    ///    /// Default: ../worktrees    pub worktree_directory: String,} #[derive(Clone, Copy, Debug)]pub struct GitEnabledSettings {    /// Whether git integration is enabled for showing git status.    ///    /// Default: true    pub status: bool,    /// Whether git integration is enabled for showing diffs.    ///    /// Default: true    pub diff: bool,} #[derive(Clone, Copy, Debug, PartialEq, Default)]pub enum GitPathStyle {    #[default]    FileNameFirst,    FilePathFirst,} impl From<settings::GitPathStyle> for GitPathStyle {    fn from(style: settings::GitPathStyle) -> Self {        match style {            settings::GitPathStyle::FileNameFirst => GitPathStyle::FileNameFirst,            settings::GitPathStyle::FilePathFirst => GitPathStyle::FilePathFirst,        }    }} #[derive(Clone, Copy, Debug)]pub struct InlineBlameSettings {    /// Whether or not to show git blame data inline in    /// the currently focused line.    ///    /// Default: true

Lines 1–500 of 1589.