1237 lines · 45.6 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 gpui::{AsyncApp, BorrowAppContext, Context, Entity, EventEmitter, Subscription, Task};use lsp::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::DirenvSettings;pub use settings::LspSettings;use settings::{    DapSettingsContent, InvalidSettingsError, LocalSettingsKind, RegisterSetting, Settings,    SettingsLocation, SettingsStore, parse_json_with_comments, watch_config_file,};use std::{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},    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>,     /// 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,} #[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)]pub struct GlobalLspSettings {    /// Whether to show the LSP servers button in the status bar.    ///    /// Default: `true`    pub button: bool,} #[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,         #[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>,    },    Extension {        /// Whether the context server is enabled.        #[serde(default = "default_true")]        enabled: 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, command } => {                ContextServerSettings::Stdio { enabled, command }            }            settings::ContextServerSettingsContent::Extension { enabled, settings } => {                ContextServerSettings::Extension { enabled, settings }            }            settings::ContextServerSettingsContent::Http {                enabled,                url,                headers,            } => ContextServerSettings::Http {                enabled,                url,                headers,            },        }    }}impl Into<settings::ContextServerSettingsContent> for ContextServerSettings {    fn into(self) -> settings::ContextServerSettingsContent {        match self {            ContextServerSettings::Stdio { enabled, command } => {                settings::ContextServerSettingsContent::Stdio { enabled, command }            }            ContextServerSettings::Extension { enabled, settings } => {                settings::ContextServerSettingsContent::Extension { enabled, settings }            }            ContextServerSettings::Http {                enabled,                url,                headers,            } => settings::ContextServerSettingsContent::Http {                enabled,                url,                headers,            },        }    }} impl ContextServerSettings {    pub fn default_extension() -> Self {        Self::Extension {            enabled: true,            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(Copy, Clone, Debug)]pub struct GitSettings {    /// 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,} #[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    pub enabled: bool,    /// Whether to only show the inline blame information    /// after a delay once the cursor stops moving.    ///    /// Default: 0    pub delay_ms: settings::DelayMs,    /// The amount of padding between the end of the source line and the start    /// of the inline blame in units of columns.    ///    /// Default: 7    pub padding: u32,    /// The minimum column number to show the inline blame information at    ///    /// Default: 0    pub min_column: u32,    /// Whether to show commit summary as part of the inline blame.    ///    /// Default: false    pub show_commit_summary: bool,} #[derive(Clone, Copy, Debug)]pub struct BlameSettings {    /// Whether to show the avatar of the author of the commit.    ///    /// Default: true    pub show_avatar: bool,} impl GitSettings {    pub fn inline_blame_delay(&self) -> Option<Duration> {        if self.inline_blame.delay_ms.0 > 0 {            Some(Duration::from_millis(self.inline_blame.delay_ms.0))        } else {            None        }    }} #[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema)]#[serde(rename_all = "snake_case")]pub struct BranchPickerSettings {    /// Whether to show author name as part of the commit information.    ///    /// Default: false    #[serde(default)]    pub show_author_name: bool,} impl Default for BranchPickerSettings {    fn default() -> Self {        Self {            show_author_name: true,        }    }} #[derive(Clone, Debug)]pub struct DiagnosticsSettings {    /// Whether to show the project diagnostics button in the status bar.    pub button: bool,     /// Whether or not to include warning diagnostics.    pub include_warnings: bool,     /// Settings for using LSP pull diagnostics mechanism in Zed.    pub lsp_pull_diagnostics: LspPullDiagnosticsSettings,     /// Settings for showing inline diagnostics.    pub inline: InlineDiagnosticsSettings,} #[derive(Clone, Copy, Debug, PartialEq, Eq)]pub struct InlineDiagnosticsSettings {    /// Whether or not to show inline diagnostics    ///    /// Default: false    pub enabled: bool,    /// Whether to only show the inline diagnostics after a delay after the    /// last editor event.    ///    /// Default: 150    pub update_debounce_ms: u64,    /// The amount of padding between the end of the source line and the start    /// of the inline diagnostic in units of columns.    ///    /// Default: 4    pub padding: u32,    /// The minimum column to display inline diagnostics. This setting can be    /// used to horizontally align inline diagnostics at some position. Lines    /// longer than this value will still push diagnostics further to the right.    ///    /// Default: 0    pub min_column: u32,     pub max_severity: Option<DiagnosticSeverity>,} #[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]pub struct LspPullDiagnosticsSettings {    /// Whether to pull for diagnostics or not.    ///    /// Default: true    pub enabled: bool,    /// Minimum time to wait before pulling diagnostics from the language server(s).    /// 0 turns the debounce off.    ///    /// Default: 50    pub debounce_ms: u64,} impl Settings for ProjectSettings {    fn from_settings(content: &settings::SettingsContent) -> Self {        let project = &content.project.clone();        let diagnostics = content.diagnostics.as_ref().unwrap();        let lsp_pull_diagnostics = diagnostics.lsp_pull_diagnostics.as_ref().unwrap();        let inline_diagnostics = diagnostics.inline.as_ref().unwrap();         let git = content.git.as_ref().unwrap();        let git_settings = GitSettings {            git_gutter: git.git_gutter.unwrap(),            gutter_debounce: git.gutter_debounce.unwrap_or_default(),

Lines 1–500 of 1237.