1use std::{collections::HashMap, path::PathBuf};
2
3use gpui::{fonts, AppContext};
4use schemars::JsonSchema;
5use serde_derive::{Deserialize, Serialize};
6
7#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
8#[serde(rename_all = "snake_case")]
9pub enum TerminalDockPosition {
10 Left,
11 Bottom,
12 Right,
13}
14
15#[derive(Deserialize)]
16pub struct TerminalSettings {
17 pub shell: Shell,
18 pub working_directory: WorkingDirectory,
19 font_size: Option<f32>,
20 pub font_family: Option<String>,
21 pub line_height: TerminalLineHeight,
22 pub font_features: Option<fonts::Features>,
23 pub env: HashMap<String, String>,
24 pub blinking: TerminalBlink,
25 pub alternate_scroll: AlternateScroll,
26 pub option_as_meta: bool,
27 pub copy_on_select: bool,
28 pub dock: TerminalDockPosition,
29 pub default_width: f32,
30 pub default_height: f32,
31 pub detect_venv: VenvSettings,
32}
33
34#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
35#[serde(rename_all = "snake_case")]
36pub enum VenvSettings {
37 #[default]
38 Off,
39 On {
40 activate_script: Option<ActivateScript>,
41 directories: Option<Vec<PathBuf>>,
42 },
43}
44
45pub struct VenvSettingsContent<'a> {
46 pub activate_script: ActivateScript,
47 pub directories: &'a [PathBuf],
48}
49
50impl VenvSettings {
51 pub fn as_option(&self) -> Option<VenvSettingsContent> {
52 match self {
53 VenvSettings::Off => None,
54 VenvSettings::On {
55 activate_script,
56 directories,
57 } => Some(VenvSettingsContent {
58 activate_script: activate_script.unwrap_or(ActivateScript::Default),
59 directories: directories.as_deref().unwrap_or(&[]),
60 }),
61 }
62 }
63}
64
65#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
66#[serde(rename_all = "snake_case")]
67pub enum ActivateScript {
68 #[default]
69 Default,
70 Csh,
71 Fish,
72}
73
74#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
75pub struct TerminalSettingsContent {
76 pub shell: Option<Shell>,
77 pub working_directory: Option<WorkingDirectory>,
78 pub font_size: Option<f32>,
79 pub font_family: Option<String>,
80 pub line_height: Option<TerminalLineHeight>,
81 pub font_features: Option<fonts::Features>,
82 pub env: Option<HashMap<String, String>>,
83 pub blinking: Option<TerminalBlink>,
84 pub alternate_scroll: Option<AlternateScroll>,
85 pub option_as_meta: Option<bool>,
86 pub copy_on_select: Option<bool>,
87 pub dock: Option<TerminalDockPosition>,
88 pub default_width: Option<f32>,
89 pub default_height: Option<f32>,
90 pub detect_venv: Option<VenvSettings>,
91}
92
93impl TerminalSettings {
94 pub fn font_size(&self, cx: &AppContext) -> Option<f32> {
95 self.font_size
96 .map(|size| theme::adjusted_font_size(size, cx))
97 }
98}
99
100impl settings::Setting for TerminalSettings {
101 const KEY: Option<&'static str> = Some("terminal");
102
103 type FileContent = TerminalSettingsContent;
104
105 fn load(
106 default_value: &Self::FileContent,
107 user_values: &[&Self::FileContent],
108 _: &AppContext,
109 ) -> anyhow::Result<Self> {
110 Self::load_via_json_merge(default_value, user_values)
111 }
112}
113
114#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema, Default)]
115#[serde(rename_all = "snake_case")]
116pub enum TerminalLineHeight {
117 #[default]
118 Comfortable,
119 Standard,
120 Custom(f32),
121}
122
123impl TerminalLineHeight {
124 pub fn value(&self) -> f32 {
125 match self {
126 TerminalLineHeight::Comfortable => 1.618,
127 TerminalLineHeight::Standard => 1.3,
128 TerminalLineHeight::Custom(line_height) => f32::max(*line_height, 1.),
129 }
130 }
131}
132
133#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
134#[serde(rename_all = "snake_case")]
135pub enum TerminalBlink {
136 Off,
137 TerminalControlled,
138 On,
139}
140
141#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
142#[serde(rename_all = "snake_case")]
143pub enum Shell {
144 System,
145 Program(String),
146 WithArguments { program: String, args: Vec<String> },
147}
148
149#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
150#[serde(rename_all = "snake_case")]
151pub enum AlternateScroll {
152 On,
153 Off,
154}
155
156#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
157#[serde(rename_all = "snake_case")]
158pub enum WorkingDirectory {
159 CurrentProjectDirectory,
160 FirstProjectDirectory,
161 AlwaysHome,
162 Always { directory: String },
163}