1use collections::HashMap;
2use gpui::AppContext;
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5use settings::{Settings, SettingsSources};
6use std::{sync::Arc, time::Duration};
7
8#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
9pub struct ProjectSettings {
10 /// Configuration for language servers.
11 ///
12 /// The following settings can be overridden for specific language servers:
13 /// - initialization_options
14 /// To override settings for a language, add an entry for that language server's
15 /// name to the lsp value.
16 /// Default: null
17 #[serde(default)]
18 pub lsp: HashMap<Arc<str>, LspSettings>,
19
20 /// Configuration for Git-related features
21 #[serde(default)]
22 pub git: GitSettings,
23}
24
25#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
26pub struct GitSettings {
27 /// Whether or not to show the git gutter.
28 ///
29 /// Default: tracked_files
30 pub git_gutter: Option<GitGutterSetting>,
31 pub gutter_debounce: Option<u64>,
32 /// Whether or not to show git blame data inline in
33 /// the currently focused line.
34 ///
35 /// Default: on
36 pub inline_blame: Option<InlineBlameSettings>,
37}
38
39impl GitSettings {
40 pub fn inline_blame_enabled(&self) -> bool {
41 #[allow(unknown_lints, clippy::manual_unwrap_or_default)]
42 match self.inline_blame {
43 Some(InlineBlameSettings { enabled, .. }) => enabled,
44 _ => false,
45 }
46 }
47
48 pub fn inline_blame_delay(&self) -> Option<Duration> {
49 match self.inline_blame {
50 Some(InlineBlameSettings {
51 delay_ms: Some(delay_ms),
52 ..
53 }) if delay_ms > 0 => Some(Duration::from_millis(delay_ms)),
54 _ => None,
55 }
56 }
57}
58
59#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
60#[serde(rename_all = "snake_case")]
61pub enum GitGutterSetting {
62 /// Show git gutter in tracked files.
63 #[default]
64 TrackedFiles,
65 /// Hide git gutter
66 Hide,
67}
68
69#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
70#[serde(rename_all = "snake_case")]
71pub struct InlineBlameSettings {
72 /// Whether or not to show git blame data inline in
73 /// the currently focused line.
74 ///
75 /// Default: true
76 #[serde(default = "true_value")]
77 pub enabled: bool,
78 /// Whether to only show the inline blame information
79 /// after a delay once the cursor stops moving.
80 ///
81 /// Default: 0
82 pub delay_ms: Option<u64>,
83 /// The minimum column number to show the inline blame information at
84 ///
85 /// Default: 0
86 pub min_column: Option<u32>,
87}
88
89const fn true_value() -> bool {
90 true
91}
92
93#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
94pub struct BinarySettings {
95 pub path: Option<String>,
96 pub arguments: Option<Vec<String>>,
97 pub path_lookup: Option<bool>,
98}
99
100#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
101#[serde(rename_all = "snake_case")]
102pub struct LspSettings {
103 pub binary: Option<BinarySettings>,
104 pub initialization_options: Option<serde_json::Value>,
105 pub settings: Option<serde_json::Value>,
106}
107
108impl Settings for ProjectSettings {
109 const KEY: Option<&'static str> = None;
110
111 type FileContent = Self;
112
113 fn load(
114 sources: SettingsSources<Self::FileContent>,
115 _: &mut AppContext,
116 ) -> anyhow::Result<Self> {
117 sources.json_merge()
118 }
119}