1use std::num::NonZeroUsize;
2
3use crate::DockPosition;
4use collections::HashMap;
5use gpui::App;
6use serde::Deserialize;
7pub use settings::AutosaveSetting;
8use settings::Settings;
9pub use settings::{
10 BottomDockLayout, PaneSplitDirectionHorizontal, PaneSplitDirectionVertical,
11 RestoreOnStartupBehavior,
12};
13
14pub struct WorkspaceSettings {
15 pub active_pane_modifiers: ActivePanelModifiers,
16 pub bottom_dock_layout: settings::BottomDockLayout,
17 pub pane_split_direction_horizontal: settings::PaneSplitDirectionHorizontal,
18 pub pane_split_direction_vertical: settings::PaneSplitDirectionVertical,
19 pub centered_layout: settings::CenteredLayoutSettings,
20 pub confirm_quit: bool,
21 pub show_call_status_icon: bool,
22 pub autosave: AutosaveSetting,
23 pub restore_on_startup: settings::RestoreOnStartupBehavior,
24 pub restore_on_file_reopen: bool,
25 pub drop_target_size: f32,
26 pub use_system_path_prompts: bool,
27 pub use_system_prompts: bool,
28 pub command_aliases: HashMap<String, String>,
29 pub max_tabs: Option<NonZeroUsize>,
30 pub when_closing_with_no_tabs: settings::CloseWindowWhenNoItems,
31 pub on_last_window_closed: settings::OnLastWindowClosed,
32 pub resize_all_panels_in_dock: Vec<DockPosition>,
33 pub close_on_file_delete: bool,
34 pub use_system_window_tabs: bool,
35 pub zoomed_padding: bool,
36}
37
38#[derive(Copy, Clone, PartialEq, Debug, Default)]
39pub struct ActivePanelModifiers {
40 /// Size of the border surrounding the active pane.
41 /// When set to 0, the active pane doesn't have any border.
42 /// The border is drawn inset.
43 ///
44 /// Default: `0.0`
45 // TODO: make this not an option, it is never None
46 pub border_size: Option<f32>,
47 /// Opacity of inactive panels.
48 /// When set to 1.0, the inactive panes have the same opacity as the active one.
49 /// If set to 0, the inactive panes content will not be visible at all.
50 /// Values are clamped to the [0.0, 1.0] range.
51 ///
52 /// Default: `1.0`
53 // TODO: make this not an option, it is never None
54 pub inactive_opacity: Option<f32>,
55}
56
57#[derive(Deserialize)]
58pub struct TabBarSettings {
59 pub show: bool,
60 pub show_nav_history_buttons: bool,
61 pub show_tab_bar_buttons: bool,
62}
63
64impl Settings for WorkspaceSettings {
65 fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self {
66 let workspace = &content.workspace;
67 Self {
68 active_pane_modifiers: ActivePanelModifiers {
69 border_size: Some(
70 workspace
71 .active_pane_modifiers
72 .unwrap()
73 .border_size
74 .unwrap(),
75 ),
76 inactive_opacity: Some(
77 workspace
78 .active_pane_modifiers
79 .unwrap()
80 .inactive_opacity
81 .unwrap(),
82 ),
83 },
84 bottom_dock_layout: workspace.bottom_dock_layout.unwrap(),
85 pane_split_direction_horizontal: workspace.pane_split_direction_horizontal.unwrap(),
86 pane_split_direction_vertical: workspace.pane_split_direction_vertical.unwrap(),
87 centered_layout: workspace.centered_layout.unwrap(),
88 confirm_quit: workspace.confirm_quit.unwrap(),
89 show_call_status_icon: workspace.show_call_status_icon.unwrap(),
90 autosave: workspace.autosave.unwrap(),
91 restore_on_startup: workspace.restore_on_startup.unwrap(),
92 restore_on_file_reopen: workspace.restore_on_file_reopen.unwrap(),
93 drop_target_size: workspace.drop_target_size.unwrap(),
94 use_system_path_prompts: workspace.use_system_path_prompts.unwrap(),
95 use_system_prompts: workspace.use_system_prompts.unwrap(),
96 command_aliases: workspace.command_aliases.clone(),
97 max_tabs: workspace.max_tabs,
98 when_closing_with_no_tabs: workspace.when_closing_with_no_tabs.unwrap(),
99 on_last_window_closed: workspace.on_last_window_closed.unwrap(),
100 resize_all_panels_in_dock: workspace
101 .resize_all_panels_in_dock
102 .clone()
103 .unwrap()
104 .into_iter()
105 .map(Into::into)
106 .collect(),
107 close_on_file_delete: workspace.close_on_file_delete.unwrap(),
108 use_system_window_tabs: workspace.use_system_window_tabs.unwrap(),
109 zoomed_padding: workspace.zoomed_padding.unwrap(),
110 }
111 }
112
113 fn import_from_vscode(
114 vscode: &settings::VsCodeSettings,
115 current: &mut settings::SettingsContent,
116 ) {
117 if vscode
118 .read_bool("accessibility.dimUnfocused.enabled")
119 .unwrap_or_default()
120 && let Some(opacity) = vscode
121 .read_value("accessibility.dimUnfocused.opacity")
122 .and_then(|v| v.as_f64())
123 {
124 current
125 .workspace
126 .active_pane_modifiers
127 .get_or_insert_default()
128 .inactive_opacity = Some(opacity as f32);
129 }
130
131 vscode.enum_setting(
132 "window.confirmBeforeClose",
133 &mut current.workspace.confirm_quit,
134 |s| match s {
135 "always" | "keyboardOnly" => Some(true),
136 "never" => Some(false),
137 _ => None,
138 },
139 );
140
141 vscode.bool_setting(
142 "workbench.editor.restoreViewState",
143 &mut current.workspace.restore_on_file_reopen,
144 );
145
146 if let Some(b) = vscode.read_bool("window.closeWhenEmpty") {
147 current.workspace.when_closing_with_no_tabs = Some(if b {
148 settings::CloseWindowWhenNoItems::CloseWindow
149 } else {
150 settings::CloseWindowWhenNoItems::KeepWindowOpen
151 });
152 }
153
154 if let Some(b) = vscode.read_bool("files.simpleDialog.enable") {
155 current.workspace.use_system_path_prompts = Some(!b);
156 }
157
158 if let Some(v) = vscode.read_enum("files.autoSave", |s| match s {
159 "off" => Some(AutosaveSetting::Off),
160 "afterDelay" => Some(AutosaveSetting::AfterDelay {
161 milliseconds: vscode
162 .read_value("files.autoSaveDelay")
163 .and_then(|v| v.as_u64())
164 .unwrap_or(1000),
165 }),
166 "onFocusChange" => Some(AutosaveSetting::OnFocusChange),
167 "onWindowChange" => Some(AutosaveSetting::OnWindowChange),
168 _ => None,
169 }) {
170 current.workspace.autosave = Some(v);
171 }
172
173 // workbench.editor.limit contains "enabled", "value", and "perEditorGroup"
174 // our semantics match if those are set to true, some N, and true respectively.
175 // we'll ignore "perEditorGroup" for now since we only support a global max
176 if let Some(n) = vscode
177 .read_value("workbench.editor.limit.value")
178 .and_then(|v| v.as_u64())
179 .and_then(|n| NonZeroUsize::new(n as usize))
180 && vscode
181 .read_bool("workbench.editor.limit.enabled")
182 .unwrap_or_default()
183 {
184 current.workspace.max_tabs = Some(n)
185 }
186
187 if let Some(b) = vscode.read_bool("window.nativeTabs") {
188 current.workspace.use_system_window_tabs = Some(b);
189 }
190
191 // some combination of "window.restoreWindows" and "workbench.startupEditor" might
192 // map to our "restore_on_startup"
193
194 // there doesn't seem to be a way to read whether the bottom dock's "justified"
195 // setting is enabled in vscode. that'd be our equivalent to "bottom_dock_layout"
196 }
197}
198
199impl Settings for TabBarSettings {
200 fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self {
201 let tab_bar = content.tab_bar.clone().unwrap();
202 TabBarSettings {
203 show: tab_bar.show.unwrap(),
204 show_nav_history_buttons: tab_bar.show_nav_history_buttons.unwrap(),
205 show_tab_bar_buttons: tab_bar.show_tab_bar_buttons.unwrap(),
206 }
207 }
208
209 fn import_from_vscode(
210 vscode: &settings::VsCodeSettings,
211 current: &mut settings::SettingsContent,
212 ) {
213 if let Some(b) = vscode.read_enum("workbench.editor.showTabs", |s| match s {
214 "multiple" => Some(true),
215 "single" | "none" => Some(false),
216 _ => None,
217 }) {
218 current.tab_bar.get_or_insert_default().show = Some(b);
219 }
220 if Some("hidden") == vscode.read_string("workbench.editor.editorActionsLocation") {
221 current.tab_bar.get_or_insert_default().show_tab_bar_buttons = Some(false)
222 }
223 }
224}
225
226#[derive(Deserialize)]
227pub struct StatusBarSettings {
228 pub show: bool,
229 pub active_language_button: bool,
230 pub cursor_position_button: bool,
231}
232
233impl Settings for StatusBarSettings {
234 fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self {
235 let status_bar = content.status_bar.clone().unwrap();
236 StatusBarSettings {
237 show: status_bar.show.unwrap(),
238 active_language_button: status_bar.active_language_button.unwrap(),
239 cursor_position_button: status_bar.cursor_position_button.unwrap(),
240 }
241 }
242
243 fn import_from_vscode(
244 vscode: &settings::VsCodeSettings,
245 current: &mut settings::SettingsContent,
246 ) {
247 if let Some(show) = vscode.read_bool("workbench.statusBar.visible") {
248 current.status_bar.get_or_insert_default().show = Some(show);
249 }
250 }
251}