Define workspace settings in workspace crate

This commit is contained in:
Max Brunsfeld 2023-05-16 20:25:18 -07:00
parent cbd4771f10
commit 6403bb86e1
22 changed files with 253 additions and 243 deletions

1
Cargo.lock generated
View file

@ -8676,6 +8676,7 @@ dependencies = [
"parking_lot 0.11.2", "parking_lot 0.11.2",
"postage", "postage",
"project", "project",
"schemars",
"serde", "serde",
"serde_derive", "serde_derive",
"serde_json", "serde_json",

View file

@ -6,7 +6,7 @@ use gpui::{
platform::{Appearance, MouseButton}, platform::{Appearance, MouseButton},
AnyElement, AppContext, Element, Entity, View, ViewContext, AnyElement, AppContext, Element, Entity, View, ViewContext,
}; };
use settings::Settings; use workspace::WorkspaceSettings;
pub fn init(cx: &mut AppContext) { pub fn init(cx: &mut AppContext) {
let active_call = ActiveCall::global(cx); let active_call = ActiveCall::global(cx);
@ -15,7 +15,9 @@ pub fn init(cx: &mut AppContext) {
cx.observe(&active_call, move |call, cx| { cx.observe(&active_call, move |call, cx| {
if let Some(room) = call.read(cx).room() { if let Some(room) = call.read(cx).room() {
if room.read(cx).is_screen_sharing() { if room.read(cx).is_screen_sharing() {
if status_indicator.is_none() && cx.global::<Settings>().show_call_status_icon { if status_indicator.is_none()
&& settings::get_setting::<WorkspaceSettings>(None, cx).show_call_status_icon
{
status_indicator = Some(cx.add_status_bar_item(|_| SharingStatusIndicator)); status_indicator = Some(cx.add_status_bar_item(|_| SharingStatusIndicator));
} }
} else if let Some((window_id, _)) = status_indicator.take() { } else if let Some((window_id, _)) = status_indicator.take() {

View file

@ -1499,6 +1499,7 @@ mod tests {
cx.set_global(Settings::test(cx)); cx.set_global(Settings::test(cx));
cx.set_global(SettingsStore::test(cx)); cx.set_global(SettingsStore::test(cx));
language::init(cx); language::init(cx);
workspace::init_settings(cx);
}); });
} }

View file

@ -6685,6 +6685,7 @@ pub(crate) fn init_test(cx: &mut TestAppContext, f: fn(&mut AllLanguageSettingsC
language::init(cx); language::init(cx);
crate::init(cx); crate::init(cx);
Project::init_settings(cx); Project::init_settings(cx);
workspace::init_settings(cx);
}); });
update_test_settings(cx, f); update_test_settings(cx, f);

View file

@ -40,7 +40,7 @@ use language::{
Selection, Selection,
}; };
use project::ProjectPath; use project::ProjectPath;
use settings::{GitGutter, Settings}; use settings::Settings;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{ use std::{
borrow::Cow, borrow::Cow,
@ -50,7 +50,7 @@ use std::{
ops::Range, ops::Range,
sync::Arc, sync::Arc,
}; };
use workspace::item::Item; use workspace::{item::Item, GitGutterSetting, WorkspaceSettings};
enum FoldMarkers {} enum FoldMarkers {}
@ -550,11 +550,11 @@ impl EditorElement {
let scroll_top = scroll_position.y() * line_height; let scroll_top = scroll_position.y() * line_height;
let show_gutter = matches!( let show_gutter = matches!(
&cx.global::<Settings>() settings::get_setting::<WorkspaceSettings>(None, cx)
.git_overrides .git
.git_gutter .git_gutter
.unwrap_or_default(), .unwrap_or_default(),
GitGutter::TrackedFiles GitGutterSetting::TrackedFiles
); );
if show_gutter { if show_gutter {

View file

@ -41,6 +41,7 @@ impl<'a> EditorLspTestContext<'a> {
crate::init(cx); crate::init(cx);
pane::init(cx); pane::init(cx);
Project::init_settings(cx); Project::init_settings(cx);
workspace::init_settings(cx);
}); });
let file_name = format!( let file_name = format!(

View file

@ -658,6 +658,7 @@ mod tests {
language::init(cx); language::init(cx);
super::init(cx); super::init(cx);
editor::init(cx); editor::init(cx);
workspace::init_settings(cx);
state state
}) })
} }

View file

@ -1936,6 +1936,7 @@ mod tests {
cx.set_global(SettingsStore::test(cx)); cx.set_global(SettingsStore::test(cx));
language::init(cx); language::init(cx);
editor::init_settings(cx); editor::init_settings(cx);
workspace::init_settings(cx);
}); });
} }
} }

View file

@ -375,6 +375,7 @@ mod tests {
cx.set_global(SettingsStore::test(cx)); cx.set_global(SettingsStore::test(cx));
language::init(cx); language::init(cx);
Project::init_settings(cx); Project::init_settings(cx);
workspace::init_settings(cx);
}); });
} }

View file

@ -1288,6 +1288,7 @@ pub mod tests {
language::init(cx); language::init(cx);
editor::init_settings(cx); editor::init_settings(cx);
workspace::init_settings(cx);
}); });
} }
} }

View file

@ -3,7 +3,7 @@ mod keymap_file;
mod settings_file; mod settings_file;
mod settings_store; mod settings_store;
use anyhow::{bail, Result}; use anyhow::Result;
use gpui::{ use gpui::{
font_cache::{FamilyId, FontCache}, font_cache::{FamilyId, FontCache},
fonts, AppContext, AssetSource, fonts, AppContext, AssetSource,
@ -15,10 +15,6 @@ use schemars::{
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
use sqlez::{
bindable::{Bind, Column, StaticColumnCount},
statement::Statement,
};
use std::{borrow::Cow, str, sync::Arc}; use std::{borrow::Cow, str, sync::Arc};
use theme::{Theme, ThemeRegistry}; use theme::{Theme, ThemeRegistry};
use util::ResultExt as _; use util::ResultExt as _;
@ -37,13 +33,6 @@ pub struct Settings {
pub buffer_font_features: fonts::Features, pub buffer_font_features: fonts::Features,
pub buffer_font_family: FamilyId, pub buffer_font_family: FamilyId,
pub buffer_font_size: f32, pub buffer_font_size: f32,
pub active_pane_magnification: f32,
pub confirm_quit: bool,
pub show_call_status_icon: bool,
pub autosave: Autosave,
pub default_dock_anchor: DockAnchor,
pub git: GitSettings,
pub git_overrides: GitSettings,
pub theme: Arc<Theme>, pub theme: Arc<Theme>,
pub base_keymap: BaseKeymap, pub base_keymap: BaseKeymap,
} }
@ -72,13 +61,6 @@ impl Setting for Settings {
buffer_font_family_name: defaults.buffer_font_family.clone().unwrap(), buffer_font_family_name: defaults.buffer_font_family.clone().unwrap(),
buffer_font_features, buffer_font_features,
buffer_font_size: defaults.buffer_font_size.unwrap(), buffer_font_size: defaults.buffer_font_size.unwrap(),
active_pane_magnification: defaults.active_pane_magnification.unwrap(),
confirm_quit: defaults.confirm_quit.unwrap(),
show_call_status_icon: defaults.show_call_status_icon.unwrap(),
autosave: defaults.autosave.unwrap(),
default_dock_anchor: defaults.default_dock_anchor.unwrap(),
git: defaults.git.unwrap(),
git_overrides: Default::default(),
theme: themes.get(defaults.theme.as_ref().unwrap()).unwrap(), theme: themes.get(defaults.theme.as_ref().unwrap()).unwrap(),
base_keymap: Default::default(), base_keymap: Default::default(),
}; };
@ -201,65 +183,6 @@ impl BaseKeymap {
.unwrap_or_default() .unwrap_or_default()
} }
} }
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
pub struct GitSettings {
pub git_gutter: Option<GitGutter>,
pub gutter_debounce: Option<u64>,
}
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum GitGutter {
#[default]
TrackedFiles,
Hide,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum Autosave {
Off,
AfterDelay { milliseconds: u64 },
OnFocusChange,
OnWindowChange,
}
#[derive(PartialEq, Eq, Debug, Default, Copy, Clone, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum DockAnchor {
#[default]
Bottom,
Right,
Expanded,
}
impl StaticColumnCount for DockAnchor {}
impl Bind for DockAnchor {
fn bind(&self, statement: &Statement, start_index: i32) -> anyhow::Result<i32> {
match self {
DockAnchor::Bottom => "Bottom",
DockAnchor::Right => "Right",
DockAnchor::Expanded => "Expanded",
}
.bind(statement, start_index)
}
}
impl Column for DockAnchor {
fn column(statement: &mut Statement, start_index: i32) -> anyhow::Result<(Self, i32)> {
String::column(statement, start_index).and_then(|(anchor_text, next_index)| {
Ok((
match anchor_text.as_ref() {
"Bottom" => DockAnchor::Bottom,
"Right" => DockAnchor::Right,
"Expanded" => DockAnchor::Expanded,
_ => bail!("Stored dock anchor is incorrect"),
},
next_index,
))
})
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] #[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
pub struct SettingsFileContent { pub struct SettingsFileContent {
@ -270,24 +193,6 @@ pub struct SettingsFileContent {
#[serde(default)] #[serde(default)]
pub buffer_font_features: Option<fonts::Features>, pub buffer_font_features: Option<fonts::Features>,
#[serde(default)] #[serde(default)]
pub active_pane_magnification: Option<f32>,
#[serde(default)]
pub cursor_blink: Option<bool>,
#[serde(default)]
pub confirm_quit: Option<bool>,
#[serde(default)]
pub hover_popover_enabled: Option<bool>,
#[serde(default)]
pub show_completions_on_input: Option<bool>,
#[serde(default)]
pub show_call_status_icon: Option<bool>,
#[serde(default)]
pub autosave: Option<Autosave>,
#[serde(default)]
pub default_dock_anchor: Option<DockAnchor>,
#[serde(default)]
pub git: Option<GitSettings>,
#[serde(default)]
pub theme: Option<String>, pub theme: Option<String>,
#[serde(default)] #[serde(default)]
pub base_keymap: Option<BaseKeymap>, pub base_keymap: Option<BaseKeymap>,
@ -323,13 +228,6 @@ impl Settings {
buffer_font_family_name: defaults.buffer_font_family.unwrap(), buffer_font_family_name: defaults.buffer_font_family.unwrap(),
buffer_font_features, buffer_font_features,
buffer_font_size: defaults.buffer_font_size.unwrap(), buffer_font_size: defaults.buffer_font_size.unwrap(),
active_pane_magnification: defaults.active_pane_magnification.unwrap(),
confirm_quit: defaults.confirm_quit.unwrap(),
show_call_status_icon: defaults.show_call_status_icon.unwrap(),
autosave: defaults.autosave.unwrap(),
default_dock_anchor: defaults.default_dock_anchor.unwrap(),
git: defaults.git.unwrap(),
git_overrides: Default::default(),
theme: themes.get(&defaults.theme.unwrap()).unwrap(), theme: themes.get(&defaults.theme.unwrap()).unwrap(),
base_keymap: Default::default(), base_keymap: Default::default(),
} }
@ -367,24 +265,7 @@ impl Settings {
} }
merge(&mut self.buffer_font_size, data.buffer_font_size); merge(&mut self.buffer_font_size, data.buffer_font_size);
merge(
&mut self.active_pane_magnification,
data.active_pane_magnification,
);
merge(&mut self.confirm_quit, data.confirm_quit);
merge(&mut self.autosave, data.autosave);
merge(&mut self.default_dock_anchor, data.default_dock_anchor);
merge(&mut self.base_keymap, data.base_keymap); merge(&mut self.base_keymap, data.base_keymap);
self.git_overrides = data.git.unwrap_or_default();
}
pub fn git_gutter(&self) -> GitGutter {
self.git_overrides.git_gutter.unwrap_or_else(|| {
self.git
.git_gutter
.expect("git_gutter should be some by setting setup")
})
} }
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
@ -397,13 +278,6 @@ impl Settings {
.load_family(&["Monaco"], &Default::default()) .load_family(&["Monaco"], &Default::default())
.unwrap(), .unwrap(),
buffer_font_size: 14., buffer_font_size: 14.,
active_pane_magnification: 1.,
confirm_quit: false,
show_call_status_icon: true,
autosave: Autosave::Off,
default_dock_anchor: DockAnchor::Bottom,
git: Default::default(),
git_overrides: Default::default(),
theme: gpui::fonts::with_font_cache(cx.font_cache().clone(), Default::default), theme: gpui::fonts::with_font_cache(cx.font_cache().clone(), Default::default),
base_keymap: Default::default(), base_keymap: Default::default(),
} }

View file

@ -787,22 +787,18 @@ fn get_path_from_wt(wt: &LocalWorktree) -> Option<PathBuf> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use gpui::TestAppContext; use gpui::TestAppContext;
use project::{Entry, Project, ProjectPath, Worktree}; use project::{Entry, Project, ProjectPath, Worktree};
use std::path::Path;
use workspace::AppState; use workspace::AppState;
use std::path::Path; // Working directory calculation tests
///Working directory calculation tests // No Worktrees in project -> home_dir()
///No Worktrees in project -> home_dir()
#[gpui::test] #[gpui::test]
async fn no_worktree(cx: &mut TestAppContext) { async fn no_worktree(cx: &mut TestAppContext) {
//Setup variables let (project, workspace) = init_test(cx).await;
let (project, workspace) = blank_workspace(cx).await;
//Test
cx.read(|cx| { cx.read(|cx| {
let workspace = workspace.read(cx); let workspace = workspace.read(cx);
let active_entry = project.read(cx).active_entry(); let active_entry = project.read(cx).active_entry();
@ -818,14 +814,12 @@ mod tests {
}); });
} }
///No active entry, but a worktree, worktree is a file -> home_dir() // No active entry, but a worktree, worktree is a file -> home_dir()
#[gpui::test] #[gpui::test]
async fn no_active_entry_worktree_is_file(cx: &mut TestAppContext) { async fn no_active_entry_worktree_is_file(cx: &mut TestAppContext) {
//Setup variables let (project, workspace) = init_test(cx).await;
let (project, workspace) = blank_workspace(cx).await;
create_file_wt(project.clone(), "/root.txt", cx).await; create_file_wt(project.clone(), "/root.txt", cx).await;
cx.read(|cx| { cx.read(|cx| {
let workspace = workspace.read(cx); let workspace = workspace.read(cx);
let active_entry = project.read(cx).active_entry(); let active_entry = project.read(cx).active_entry();
@ -844,11 +838,9 @@ mod tests {
// No active entry, but a worktree, worktree is a folder -> worktree_folder // No active entry, but a worktree, worktree is a folder -> worktree_folder
#[gpui::test] #[gpui::test]
async fn no_active_entry_worktree_is_dir(cx: &mut TestAppContext) { async fn no_active_entry_worktree_is_dir(cx: &mut TestAppContext) {
//Setup variables let (project, workspace) = init_test(cx).await;
let (project, workspace) = blank_workspace(cx).await;
let (_wt, _entry) = create_folder_wt(project.clone(), "/root/", cx).await;
//Test let (_wt, _entry) = create_folder_wt(project.clone(), "/root/", cx).await;
cx.update(|cx| { cx.update(|cx| {
let workspace = workspace.read(cx); let workspace = workspace.read(cx);
let active_entry = project.read(cx).active_entry(); let active_entry = project.read(cx).active_entry();
@ -866,14 +858,12 @@ mod tests {
// Active entry with a work tree, worktree is a file -> home_dir() // Active entry with a work tree, worktree is a file -> home_dir()
#[gpui::test] #[gpui::test]
async fn active_entry_worktree_is_file(cx: &mut TestAppContext) { async fn active_entry_worktree_is_file(cx: &mut TestAppContext) {
//Setup variables let (project, workspace) = init_test(cx).await;
let (project, workspace) = blank_workspace(cx).await;
let (_wt, _entry) = create_folder_wt(project.clone(), "/root1/", cx).await; let (_wt, _entry) = create_folder_wt(project.clone(), "/root1/", cx).await;
let (wt2, entry2) = create_file_wt(project.clone(), "/root2.txt", cx).await; let (wt2, entry2) = create_file_wt(project.clone(), "/root2.txt", cx).await;
insert_active_entry_for(wt2, entry2, project.clone(), cx); insert_active_entry_for(wt2, entry2, project.clone(), cx);
//Test
cx.update(|cx| { cx.update(|cx| {
let workspace = workspace.read(cx); let workspace = workspace.read(cx);
let active_entry = project.read(cx).active_entry(); let active_entry = project.read(cx).active_entry();
@ -890,13 +880,12 @@ mod tests {
// Active entry, with a worktree, worktree is a folder -> worktree_folder // Active entry, with a worktree, worktree is a folder -> worktree_folder
#[gpui::test] #[gpui::test]
async fn active_entry_worktree_is_dir(cx: &mut TestAppContext) { async fn active_entry_worktree_is_dir(cx: &mut TestAppContext) {
//Setup variables let (project, workspace) = init_test(cx).await;
let (project, workspace) = blank_workspace(cx).await;
let (_wt, _entry) = create_folder_wt(project.clone(), "/root1/", cx).await; let (_wt, _entry) = create_folder_wt(project.clone(), "/root1/", cx).await;
let (wt2, entry2) = create_folder_wt(project.clone(), "/root2/", cx).await; let (wt2, entry2) = create_folder_wt(project.clone(), "/root2/", cx).await;
insert_active_entry_for(wt2, entry2, project.clone(), cx); insert_active_entry_for(wt2, entry2, project.clone(), cx);
//Test
cx.update(|cx| { cx.update(|cx| {
let workspace = workspace.read(cx); let workspace = workspace.read(cx);
let active_entry = project.read(cx).active_entry(); let active_entry = project.read(cx).active_entry();
@ -911,7 +900,7 @@ mod tests {
} }
/// Creates a worktree with 1 file: /root.txt /// Creates a worktree with 1 file: /root.txt
pub async fn blank_workspace( pub async fn init_test(
cx: &mut TestAppContext, cx: &mut TestAppContext,
) -> (ModelHandle<Project>, ViewHandle<Workspace>) { ) -> (ModelHandle<Project>, ViewHandle<Workspace>) {
let params = cx.update(AppState::test); let params = cx.update(AppState::test);

View file

@ -45,6 +45,7 @@ lazy_static.workspace = true
log.workspace = true log.workspace = true
parking_lot.workspace = true parking_lot.workspace = true
postage.workspace = true postage.workspace = true
schemars.workspace = true
serde.workspace = true serde.workspace = true
serde_derive.workspace = true serde_derive.workspace = true
serde_json.workspace = true serde_json.workspace = true

View file

@ -1,5 +1,9 @@
mod toggle_dock_button; mod toggle_dock_button;
use crate::{
sidebar::SidebarSide, BackgroundActions, DockAnchor, ItemHandle, Pane, Workspace,
WorkspaceSettings,
};
use collections::HashMap; use collections::HashMap;
use gpui::{ use gpui::{
actions, actions,
@ -8,10 +12,7 @@ use gpui::{
platform::{CursorStyle, MouseButton}, platform::{CursorStyle, MouseButton},
AnyElement, AppContext, Border, Element, SizeConstraint, ViewContext, ViewHandle, AnyElement, AppContext, Border, Element, SizeConstraint, ViewContext, ViewHandle,
}; };
use settings::{DockAnchor, Settings};
use theme::Theme; use theme::Theme;
use crate::{sidebar::SidebarSide, BackgroundActions, ItemHandle, Pane, Workspace};
pub use toggle_dock_button::ToggleDockButton; pub use toggle_dock_button::ToggleDockButton;
actions!( actions!(
@ -171,7 +172,9 @@ impl Dock {
background_actions: BackgroundActions, background_actions: BackgroundActions,
cx: &mut ViewContext<Workspace>, cx: &mut ViewContext<Workspace>,
) -> Self { ) -> Self {
let position = DockPosition::Hidden(cx.global::<Settings>().default_dock_anchor); let position = DockPosition::Hidden(
settings::get_setting::<WorkspaceSettings>(None, cx).default_dock_anchor,
);
let workspace = cx.weak_handle(); let workspace = cx.weak_handle();
let pane = let pane =
cx.add_view(|cx| Pane::new(workspace, Some(position.anchor()), background_actions, cx)); cx.add_view(|cx| Pane::new(workspace, Some(position.anchor()), background_actions, cx));
@ -405,7 +408,6 @@ mod tests {
use gpui::{AppContext, BorrowWindowContext, TestAppContext, ViewContext, WindowContext}; use gpui::{AppContext, BorrowWindowContext, TestAppContext, ViewContext, WindowContext};
use project::{FakeFs, Project}; use project::{FakeFs, Project};
use settings::Settings;
use theme::ThemeRegistry; use theme::ThemeRegistry;
use super::*; use super::*;
@ -417,6 +419,7 @@ mod tests {
}, },
register_deserializable_item, register_deserializable_item,
sidebar::Sidebar, sidebar::Sidebar,
tests::init_test,
AppState, ItemHandle, Workspace, AppState, ItemHandle, Workspace,
}; };
@ -429,8 +432,7 @@ mod tests {
#[gpui::test] #[gpui::test]
async fn test_dock_workspace_infinite_loop(cx: &mut TestAppContext) { async fn test_dock_workspace_infinite_loop(cx: &mut TestAppContext) {
cx.foreground().forbid_parking(); init_test(cx);
Settings::test_async(cx);
cx.update(|cx| { cx.update(|cx| {
register_deserializable_item::<item::test::TestItem>(cx); register_deserializable_item::<item::test::TestItem>(cx);
@ -598,7 +600,7 @@ mod tests {
impl<'a> DockTestContext<'a> { impl<'a> DockTestContext<'a> {
pub async fn new(cx: &'a mut TestAppContext) -> DockTestContext<'a> { pub async fn new(cx: &'a mut TestAppContext) -> DockTestContext<'a> {
Settings::test_async(cx); init_test(cx);
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
cx.update(|cx| init(cx)); cx.update(|cx| init(cx));

View file

@ -3,6 +3,7 @@ use crate::{
FollowableItemBuilders, ItemNavHistory, Pane, ToolbarItemLocation, ViewId, Workspace, FollowableItemBuilders, ItemNavHistory, Pane, ToolbarItemLocation, ViewId, Workspace,
WorkspaceId, WorkspaceId,
}; };
use crate::{AutosaveSetting, WorkspaceSettings};
use anyhow::Result; use anyhow::Result;
use client::{proto, Client}; use client::{proto, Client};
use gpui::{ use gpui::{
@ -10,7 +11,6 @@ use gpui::{
ViewContext, ViewHandle, WeakViewHandle, WindowContext, ViewContext, ViewHandle, WeakViewHandle, WindowContext,
}; };
use project::{Project, ProjectEntryId, ProjectPath}; use project::{Project, ProjectEntryId, ProjectPath};
use settings::{Autosave, Settings};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{ use std::{
any::{Any, TypeId}, any::{Any, TypeId},
@ -450,8 +450,11 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
} }
ItemEvent::Edit => { ItemEvent::Edit => {
if let Autosave::AfterDelay { milliseconds } = let settings = settings::get_setting::<WorkspaceSettings>(None, cx);
cx.global::<Settings>().autosave let debounce_delay = settings.git.gutter_debounce;
if let AutosaveSetting::AfterDelay { milliseconds } =
settings.autosave
{ {
let delay = Duration::from_millis(milliseconds); let delay = Duration::from_millis(milliseconds);
let item = item.clone(); let item = item.clone();
@ -460,9 +463,6 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
}); });
} }
let settings = cx.global::<Settings>();
let debounce_delay = settings.git_overrides.gutter_debounce;
let item = item.clone(); let item = item.clone();
if let Some(delay) = debounce_delay { if let Some(delay) = debounce_delay {
@ -500,7 +500,10 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
})); }));
cx.observe_focus(self, move |workspace, item, focused, cx| { cx.observe_focus(self, move |workspace, item, focused, cx| {
if !focused && cx.global::<Settings>().autosave == Autosave::OnFocusChange { if !focused
&& settings::get_setting::<WorkspaceSettings>(None, cx).autosave
== AutosaveSetting::OnFocusChange
{
Pane::autosave_item(&item, workspace.project.clone(), cx) Pane::autosave_item(&item, workspace.project.clone(), cx)
.detach_and_log_err(cx); .detach_and_log_err(cx);
} }

View file

@ -5,7 +5,8 @@ use crate::{
dock::{icon_for_dock_anchor, AnchorDockBottom, AnchorDockRight, Dock, ExpandDock}, dock::{icon_for_dock_anchor, AnchorDockBottom, AnchorDockRight, Dock, ExpandDock},
item::WeakItemHandle, item::WeakItemHandle,
toolbar::Toolbar, toolbar::Toolbar,
Item, NewFile, NewSearch, NewTerminal, Workspace, AutosaveSetting, DockAnchor, Item, NewFile, NewSearch, NewTerminal, Workspace,
WorkspaceSettings,
}; };
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use collections::{HashMap, HashSet, VecDeque}; use collections::{HashMap, HashSet, VecDeque};
@ -29,7 +30,7 @@ use gpui::{
}; };
use project::{Project, ProjectEntryId, ProjectPath}; use project::{Project, ProjectEntryId, ProjectPath};
use serde::Deserialize; use serde::Deserialize;
use settings::{Autosave, DockAnchor, Settings}; use settings::Settings;
use std::{any::Any, cell::RefCell, cmp, mem, path::Path, rc::Rc}; use std::{any::Any, cell::RefCell, cmp, mem, path::Path, rc::Rc};
use theme::Theme; use theme::Theme;
use util::ResultExt; use util::ResultExt;
@ -1024,8 +1025,8 @@ impl Pane {
} else if is_dirty && (can_save || is_singleton) { } else if is_dirty && (can_save || is_singleton) {
let will_autosave = cx.read(|cx| { let will_autosave = cx.read(|cx| {
matches!( matches!(
cx.global::<Settings>().autosave, settings::get_setting::<WorkspaceSettings>(None, cx).autosave,
Autosave::OnFocusChange | Autosave::OnWindowChange AutosaveSetting::OnFocusChange | AutosaveSetting::OnWindowChange
) && Self::can_autosave_item(&*item, cx) ) && Self::can_autosave_item(&*item, cx)
}); });
let should_save = if should_prompt_for_save && !will_autosave { let should_save = if should_prompt_for_save && !will_autosave {
@ -2087,10 +2088,11 @@ mod tests {
use crate::item::test::{TestItem, TestProjectItem}; use crate::item::test::{TestItem, TestProjectItem};
use gpui::{executor::Deterministic, TestAppContext}; use gpui::{executor::Deterministic, TestAppContext};
use project::FakeFs; use project::FakeFs;
use settings::SettingsStore;
#[gpui::test] #[gpui::test]
async fn test_remove_active_empty(cx: &mut TestAppContext) { async fn test_remove_active_empty(cx: &mut TestAppContext) {
Settings::test_async(cx); init_test(cx);
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
let project = Project::test(fs, None, cx).await; let project = Project::test(fs, None, cx).await;
@ -2104,7 +2106,7 @@ mod tests {
#[gpui::test] #[gpui::test]
async fn test_add_item_with_new_item(cx: &mut TestAppContext) { async fn test_add_item_with_new_item(cx: &mut TestAppContext) {
cx.foreground().forbid_parking(); cx.foreground().forbid_parking();
Settings::test_async(cx); init_test(cx);
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
let project = Project::test(fs, None, cx).await; let project = Project::test(fs, None, cx).await;
@ -2192,7 +2194,7 @@ mod tests {
#[gpui::test] #[gpui::test]
async fn test_add_item_with_existing_item(cx: &mut TestAppContext) { async fn test_add_item_with_existing_item(cx: &mut TestAppContext) {
cx.foreground().forbid_parking(); cx.foreground().forbid_parking();
Settings::test_async(cx); init_test(cx);
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
let project = Project::test(fs, None, cx).await; let project = Project::test(fs, None, cx).await;
@ -2268,7 +2270,7 @@ mod tests {
#[gpui::test] #[gpui::test]
async fn test_add_item_with_same_project_entries(cx: &mut TestAppContext) { async fn test_add_item_with_same_project_entries(cx: &mut TestAppContext) {
cx.foreground().forbid_parking(); cx.foreground().forbid_parking();
Settings::test_async(cx); init_test(cx);
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
let project = Project::test(fs, None, cx).await; let project = Project::test(fs, None, cx).await;
@ -2377,7 +2379,7 @@ mod tests {
#[gpui::test] #[gpui::test]
async fn test_remove_item_ordering(deterministic: Arc<Deterministic>, cx: &mut TestAppContext) { async fn test_remove_item_ordering(deterministic: Arc<Deterministic>, cx: &mut TestAppContext) {
Settings::test_async(cx); init_test(cx);
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
let project = Project::test(fs, None, cx).await; let project = Project::test(fs, None, cx).await;
@ -2424,7 +2426,7 @@ mod tests {
#[gpui::test] #[gpui::test]
async fn test_close_inactive_items(deterministic: Arc<Deterministic>, cx: &mut TestAppContext) { async fn test_close_inactive_items(deterministic: Arc<Deterministic>, cx: &mut TestAppContext) {
Settings::test_async(cx); init_test(cx);
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
let project = Project::test(fs, None, cx).await; let project = Project::test(fs, None, cx).await;
@ -2443,7 +2445,7 @@ mod tests {
#[gpui::test] #[gpui::test]
async fn test_close_clean_items(deterministic: Arc<Deterministic>, cx: &mut TestAppContext) { async fn test_close_clean_items(deterministic: Arc<Deterministic>, cx: &mut TestAppContext) {
Settings::test_async(cx); init_test(cx);
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
let project = Project::test(fs, None, cx).await; let project = Project::test(fs, None, cx).await;
@ -2470,7 +2472,7 @@ mod tests {
deterministic: Arc<Deterministic>, deterministic: Arc<Deterministic>,
cx: &mut TestAppContext, cx: &mut TestAppContext,
) { ) {
Settings::test_async(cx); init_test(cx);
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
let project = Project::test(fs, None, cx).await; let project = Project::test(fs, None, cx).await;
@ -2492,7 +2494,7 @@ mod tests {
deterministic: Arc<Deterministic>, deterministic: Arc<Deterministic>,
cx: &mut TestAppContext, cx: &mut TestAppContext,
) { ) {
Settings::test_async(cx); init_test(cx);
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
let project = Project::test(fs, None, cx).await; let project = Project::test(fs, None, cx).await;
@ -2511,7 +2513,7 @@ mod tests {
#[gpui::test] #[gpui::test]
async fn test_close_all_items(deterministic: Arc<Deterministic>, cx: &mut TestAppContext) { async fn test_close_all_items(deterministic: Arc<Deterministic>, cx: &mut TestAppContext) {
Settings::test_async(cx); init_test(cx);
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
let project = Project::test(fs, None, cx).await; let project = Project::test(fs, None, cx).await;
@ -2531,6 +2533,14 @@ mod tests {
assert_item_labels(&pane, [], cx); assert_item_labels(&pane, [], cx);
} }
fn init_test(cx: &mut TestAppContext) {
cx.update(|cx| {
cx.set_global(SettingsStore::test(cx));
cx.set_global(settings::Settings::test(cx));
crate::init_settings(cx);
});
}
fn add_labeled_item( fn add_labeled_item(
workspace: &ViewHandle<Workspace>, workspace: &ViewHandle<Workspace>,
pane: &ViewHandle<Pane>, pane: &ViewHandle<Pane>,

View file

@ -1,6 +1,6 @@
use std::sync::Arc; use std::sync::Arc;
use crate::{AppState, FollowerStatesByLeader, Pane, Workspace}; use crate::{AppState, FollowerStatesByLeader, Pane, Workspace, WorkspaceSettings};
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use call::{ActiveCall, ParticipantLocation}; use call::{ActiveCall, ParticipantLocation};
use gpui::{ use gpui::{
@ -11,7 +11,6 @@ use gpui::{
}; };
use project::Project; use project::Project;
use serde::Deserialize; use serde::Deserialize;
use settings::Settings;
use theme::Theme; use theme::Theme;
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
@ -380,7 +379,8 @@ impl PaneAxis {
.with_children(self.members.iter().enumerate().map(|(ix, member)| { .with_children(self.members.iter().enumerate().map(|(ix, member)| {
let mut flex = 1.0; let mut flex = 1.0;
if member.contains(active_pane) { if member.contains(active_pane) {
flex = cx.global::<Settings>().active_pane_magnification; flex = settings::get_setting::<WorkspaceSettings>(None, cx)
.active_pane_magnification;
} }
let mut member = member.render( let mut member = member.render(

View file

@ -497,13 +497,10 @@ impl WorkspaceDb {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::sync::Arc;
use db::open_test_db;
use settings::DockAnchor;
use super::*; use super::*;
use crate::DockAnchor;
use db::open_test_db;
use std::sync::Arc;
#[gpui::test] #[gpui::test]
async fn test_next_id_stability() { async fn test_next_id_stability() {

View file

@ -1,5 +1,6 @@
use crate::{ use crate::{
dock::DockPosition, ItemDeserializers, Member, Pane, PaneAxis, Workspace, WorkspaceId, dock::DockPosition, DockAnchor, ItemDeserializers, Member, Pane, PaneAxis, Workspace,
WorkspaceId,
}; };
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use async_recursion::async_recursion; use async_recursion::async_recursion;
@ -11,7 +12,6 @@ use gpui::{
platform::WindowBounds, AsyncAppContext, Axis, ModelHandle, Task, ViewHandle, WeakViewHandle, platform::WindowBounds, AsyncAppContext, Axis, ModelHandle, Task, ViewHandle, WeakViewHandle,
}; };
use project::Project; use project::Project;
use settings::DockAnchor;
use std::{ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Arc, sync::Arc,
@ -305,10 +305,9 @@ impl Column for DockPosition {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use db::sqlez::connection::Connection;
use settings::DockAnchor;
use super::WorkspaceLocation; use super::WorkspaceLocation;
use crate::DockAnchor;
use db::sqlez::connection::Connection;
#[test] #[test]
fn test_workspace_round_trips() { fn test_workspace_round_trips() {

View file

@ -13,6 +13,7 @@ pub mod shared_screen;
pub mod sidebar; pub mod sidebar;
mod status_bar; mod status_bar;
mod toolbar; mod toolbar;
mod workspace_settings;
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use assets::Assets; use assets::Assets;
@ -75,7 +76,7 @@ pub use persistence::{
use postage::prelude::Stream; use postage::prelude::Stream;
use project::{Project, ProjectEntryId, ProjectPath, Worktree, WorktreeId}; use project::{Project, ProjectEntryId, ProjectPath, Worktree, WorktreeId};
use serde::Deserialize; use serde::Deserialize;
use settings::{Autosave, DockAnchor, Settings}; use settings::Settings;
use shared_screen::SharedScreen; use shared_screen::SharedScreen;
use sidebar::{Sidebar, SidebarButtons, SidebarSide, ToggleSidebarItem}; use sidebar::{Sidebar, SidebarButtons, SidebarSide, ToggleSidebarItem};
use status_bar::StatusBar; use status_bar::StatusBar;
@ -83,6 +84,7 @@ pub use status_bar::StatusItemView;
use theme::{Theme, ThemeRegistry}; use theme::{Theme, ThemeRegistry};
pub use toolbar::{ToolbarItemLocation, ToolbarItemView}; pub use toolbar::{ToolbarItemLocation, ToolbarItemView};
use util::{paths, ResultExt}; use util::{paths, ResultExt};
pub use workspace_settings::{AutosaveSetting, DockAnchor, GitGutterSetting, WorkspaceSettings};
lazy_static! { lazy_static! {
static ref ZED_WINDOW_SIZE: Option<Vector2F> = env::var("ZED_WINDOW_SIZE") static ref ZED_WINDOW_SIZE: Option<Vector2F> = env::var("ZED_WINDOW_SIZE")
@ -183,7 +185,12 @@ pub type WorkspaceId = i64;
impl_actions!(workspace, [ActivatePane]); impl_actions!(workspace, [ActivatePane]);
pub fn init_settings(cx: &mut AppContext) {
settings::register_setting::<WorkspaceSettings>(cx);
}
pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) { pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
init_settings(cx);
pane::init(cx); pane::init(cx);
dock::init(cx); dock::init(cx);
notifications::init(cx); notifications::init(cx);
@ -384,6 +391,7 @@ impl AppState {
let themes = ThemeRegistry::new((), cx.font_cache().clone()); let themes = ThemeRegistry::new((), cx.font_cache().clone());
client::init(&client, cx); client::init(&client, cx);
crate::init_settings(cx);
Arc::new(Self { Arc::new(Self {
client, client,
@ -672,7 +680,9 @@ impl Workspace {
Self::load_from_serialized_workspace(weak_handle, serialized_workspace, cx) Self::load_from_serialized_workspace(weak_handle, serialized_workspace, cx)
}); });
} else if project.read(cx).is_local() { } else if project.read(cx).is_local() {
if cx.global::<Settings>().default_dock_anchor != DockAnchor::Expanded { if settings::get_setting::<WorkspaceSettings>(None, cx).default_dock_anchor
!= DockAnchor::Expanded
{
Dock::show(&mut this, false, cx); Dock::show(&mut this, false, cx);
} }
} }
@ -2406,8 +2416,8 @@ impl Workspace {
item.workspace_deactivated(cx); item.workspace_deactivated(cx);
} }
if matches!( if matches!(
cx.global::<Settings>().autosave, settings::get_setting::<WorkspaceSettings>(None, cx).autosave,
Autosave::OnWindowChange | Autosave::OnFocusChange AutosaveSetting::OnWindowChange | AutosaveSetting::OnFocusChange
) { ) {
for item in pane.items() { for item in pane.items() {
Pane::autosave_item(item.as_ref(), self.project.clone(), cx) Pane::autosave_item(item.as_ref(), self.project.clone(), cx)
@ -3067,7 +3077,7 @@ pub fn join_remote_project(
} }
pub fn restart(_: &Restart, cx: &mut AppContext) { pub fn restart(_: &Restart, cx: &mut AppContext) {
let should_confirm = cx.global::<Settings>().confirm_quit; let should_confirm = settings::get_setting::<WorkspaceSettings>(None, cx).confirm_quit;
cx.spawn(|mut cx| async move { cx.spawn(|mut cx| async move {
let mut workspaces = cx let mut workspaces = cx
.window_ids() .window_ids()
@ -3128,20 +3138,18 @@ fn parse_pixel_position_env_var(value: &str) -> Option<Vector2F> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::{cell::RefCell, rc::Rc};
use crate::item::test::{TestItem, TestItemEvent, TestProjectItem};
use super::*; use super::*;
use crate::item::test::{TestItem, TestItemEvent, TestProjectItem};
use fs::FakeFs; use fs::FakeFs;
use gpui::{executor::Deterministic, TestAppContext}; use gpui::{executor::Deterministic, TestAppContext};
use project::{Project, ProjectEntryId}; use project::{Project, ProjectEntryId};
use serde_json::json; use serde_json::json;
use settings::SettingsStore;
use std::{cell::RefCell, rc::Rc};
#[gpui::test] #[gpui::test]
async fn test_tab_disambiguation(cx: &mut TestAppContext) { async fn test_tab_disambiguation(cx: &mut TestAppContext) {
cx.foreground().forbid_parking(); init_test(cx);
Settings::test_async(cx);
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
let project = Project::test(fs, [], cx).await; let project = Project::test(fs, [], cx).await;
@ -3189,8 +3197,8 @@ mod tests {
#[gpui::test] #[gpui::test]
async fn test_tracking_active_path(cx: &mut TestAppContext) { async fn test_tracking_active_path(cx: &mut TestAppContext) {
cx.foreground().forbid_parking(); init_test(cx);
Settings::test_async(cx);
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
fs.insert_tree( fs.insert_tree(
"/root1", "/root1",
@ -3293,8 +3301,8 @@ mod tests {
#[gpui::test] #[gpui::test]
async fn test_close_window(cx: &mut TestAppContext) { async fn test_close_window(cx: &mut TestAppContext) {
cx.foreground().forbid_parking(); init_test(cx);
Settings::test_async(cx);
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
fs.insert_tree("/root", json!({ "one": "" })).await; fs.insert_tree("/root", json!({ "one": "" })).await;
@ -3329,8 +3337,8 @@ mod tests {
#[gpui::test] #[gpui::test]
async fn test_close_pane_items(cx: &mut TestAppContext) { async fn test_close_pane_items(cx: &mut TestAppContext) {
cx.foreground().forbid_parking(); init_test(cx);
Settings::test_async(cx);
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
let project = Project::test(fs, None, cx).await; let project = Project::test(fs, None, cx).await;
@ -3436,8 +3444,8 @@ mod tests {
#[gpui::test] #[gpui::test]
async fn test_prompting_to_save_only_on_last_item_for_entry(cx: &mut TestAppContext) { async fn test_prompting_to_save_only_on_last_item_for_entry(cx: &mut TestAppContext) {
cx.foreground().forbid_parking(); init_test(cx);
Settings::test_async(cx);
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
let project = Project::test(fs, [], cx).await; let project = Project::test(fs, [], cx).await;
@ -3542,9 +3550,8 @@ mod tests {
#[gpui::test] #[gpui::test]
async fn test_autosave(deterministic: Arc<Deterministic>, cx: &mut gpui::TestAppContext) { async fn test_autosave(deterministic: Arc<Deterministic>, cx: &mut gpui::TestAppContext) {
deterministic.forbid_parking(); init_test(cx);
Settings::test_async(cx);
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
let project = Project::test(fs, [], cx).await; let project = Project::test(fs, [], cx).await;
@ -3560,8 +3567,10 @@ mod tests {
// Autosave on window change. // Autosave on window change.
item.update(cx, |item, cx| { item.update(cx, |item, cx| {
cx.update_global(|settings: &mut Settings, _| { cx.update_global(|settings: &mut SettingsStore, cx| {
settings.autosave = Autosave::OnWindowChange; settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
settings.autosave = Some(AutosaveSetting::OnWindowChange);
})
}); });
item.is_dirty = true; item.is_dirty = true;
}); });
@ -3574,8 +3583,10 @@ mod tests {
// Autosave on focus change. // Autosave on focus change.
item.update(cx, |item, cx| { item.update(cx, |item, cx| {
cx.focus_self(); cx.focus_self();
cx.update_global(|settings: &mut Settings, _| { cx.update_global(|settings: &mut SettingsStore, cx| {
settings.autosave = Autosave::OnFocusChange; settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
settings.autosave = Some(AutosaveSetting::OnFocusChange);
})
}); });
item.is_dirty = true; item.is_dirty = true;
}); });
@ -3598,8 +3609,10 @@ mod tests {
// Autosave after delay. // Autosave after delay.
item.update(cx, |item, cx| { item.update(cx, |item, cx| {
cx.update_global(|settings: &mut Settings, _| { cx.update_global(|settings: &mut SettingsStore, cx| {
settings.autosave = Autosave::AfterDelay { milliseconds: 500 }; settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
settings.autosave = Some(AutosaveSetting::AfterDelay { milliseconds: 500 });
})
}); });
item.is_dirty = true; item.is_dirty = true;
cx.emit(TestItemEvent::Edit); cx.emit(TestItemEvent::Edit);
@ -3615,8 +3628,10 @@ mod tests {
// Autosave on focus change, ensuring closing the tab counts as such. // Autosave on focus change, ensuring closing the tab counts as such.
item.update(cx, |item, cx| { item.update(cx, |item, cx| {
cx.update_global(|settings: &mut Settings, _| { cx.update_global(|settings: &mut SettingsStore, cx| {
settings.autosave = Autosave::OnFocusChange; settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
settings.autosave = Some(AutosaveSetting::OnFocusChange);
})
}); });
item.is_dirty = true; item.is_dirty = true;
}); });
@ -3656,12 +3671,9 @@ mod tests {
} }
#[gpui::test] #[gpui::test]
async fn test_pane_navigation( async fn test_pane_navigation(cx: &mut gpui::TestAppContext) {
deterministic: Arc<Deterministic>, init_test(cx);
cx: &mut gpui::TestAppContext,
) {
deterministic.forbid_parking();
Settings::test_async(cx);
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
let project = Project::test(fs, [], cx).await; let project = Project::test(fs, [], cx).await;
@ -3713,4 +3725,14 @@ mod tests {
assert!(pane.can_navigate_forward()); assert!(pane.can_navigate_forward());
}); });
} }
pub fn init_test(cx: &mut TestAppContext) {
cx.foreground().forbid_parking();
cx.update(|cx| {
cx.set_global(SettingsStore::test(cx));
cx.set_global(Settings::test(cx));
language::init(cx);
crate::init_settings(cx);
});
}
} }

View file

@ -0,0 +1,103 @@
use anyhow::bail;
use db::sqlez::{
bindable::{Bind, Column, StaticColumnCount},
statement::Statement,
};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::Setting;
#[derive(Deserialize)]
pub struct WorkspaceSettings {
pub active_pane_magnification: f32,
pub confirm_quit: bool,
pub show_call_status_icon: bool,
pub autosave: AutosaveSetting,
pub default_dock_anchor: DockAnchor,
pub git: GitSettings,
}
#[derive(Clone, Serialize, Deserialize, JsonSchema)]
pub struct WorkspaceSettingsContent {
pub active_pane_magnification: Option<f32>,
pub confirm_quit: Option<bool>,
pub show_call_status_icon: Option<bool>,
pub autosave: Option<AutosaveSetting>,
pub default_dock_anchor: Option<DockAnchor>,
pub git: Option<GitSettings>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum AutosaveSetting {
Off,
AfterDelay { milliseconds: u64 },
OnFocusChange,
OnWindowChange,
}
#[derive(PartialEq, Eq, Debug, Default, Copy, Clone, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum DockAnchor {
#[default]
Bottom,
Right,
Expanded,
}
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
pub struct GitSettings {
pub git_gutter: Option<GitGutterSetting>,
pub gutter_debounce: Option<u64>,
}
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum GitGutterSetting {
#[default]
TrackedFiles,
Hide,
}
impl StaticColumnCount for DockAnchor {}
impl Bind for DockAnchor {
fn bind(&self, statement: &Statement, start_index: i32) -> anyhow::Result<i32> {
match self {
DockAnchor::Bottom => "Bottom",
DockAnchor::Right => "Right",
DockAnchor::Expanded => "Expanded",
}
.bind(statement, start_index)
}
}
impl Column for DockAnchor {
fn column(statement: &mut Statement, start_index: i32) -> anyhow::Result<(Self, i32)> {
String::column(statement, start_index).and_then(|(anchor_text, next_index)| {
Ok((
match anchor_text.as_ref() {
"Bottom" => DockAnchor::Bottom,
"Right" => DockAnchor::Right,
"Expanded" => DockAnchor::Expanded,
_ => bail!("Stored dock anchor is incorrect"),
},
next_index,
))
})
}
}
impl Setting for WorkspaceSettings {
const KEY: Option<&'static str> = None;
type FileContent = WorkspaceSettingsContent;
fn load(
default_value: &Self::FileContent,
user_values: &[&Self::FileContent],
_: &gpui::AppContext,
) -> anyhow::Result<Self> {
Self::load_via_json_merge(default_value, user_values)
}
}

View file

@ -37,7 +37,7 @@ use uuid::Uuid;
pub use workspace; pub use workspace;
use workspace::{ use workspace::{
create_and_open_local_file, open_new, sidebar::SidebarSide, AppState, NewFile, NewWindow, create_and_open_local_file, open_new, sidebar::SidebarSide, AppState, NewFile, NewWindow,
Workspace, Workspace, WorkspaceSettings,
}; };
#[derive(Deserialize, Clone, PartialEq)] #[derive(Deserialize, Clone, PartialEq)]
@ -367,7 +367,7 @@ pub fn build_window_options(
} }
fn quit(_: &Quit, cx: &mut gpui::AppContext) { fn quit(_: &Quit, cx: &mut gpui::AppContext) {
let should_confirm = cx.global::<Settings>().confirm_quit; let should_confirm = settings::get_setting::<WorkspaceSettings>(None, cx).confirm_quit;
cx.spawn(|mut cx| async move { cx.spawn(|mut cx| async move {
let mut workspaces = cx let mut workspaces = cx
.window_ids() .window_ids()