Settings refactor (#38367)

Co-Authored-By: Ben K <ben@zed.dev>
Co-Authored-By: Anthony <anthony@zed.dev>
Co-Authored-By: Mikayla <mikayla@zed.dev>

Release Notes:

- settings: Major internal changes to settings. The primary user-facing
effect is that some settings which did not make sense in project
settings files are no-longer read from there. (For example the inline
blame settings)

---------

Co-authored-by: Ben Kunkle <ben@zed.dev>
Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com>
Co-authored-by: Anthony <anthony@zed.dev>
This commit is contained in:
Conrad Irwin
2025-09-18 16:47:23 +00:00
committed by GitHub
co-authored by Ben Kunkle Mikayla Maki Anthony
parent 0a9023bce0
commit fcdab160f9
219 changed files with 11697 additions and 11894 deletions
+2 -3
View File
@@ -224,7 +224,6 @@ mod test {
use settings::SettingsStore;
use crate::{
VimSettings,
state::Mode,
test::{NeovimBackedTestContext, VimTestContext},
};
@@ -294,11 +293,11 @@ mod test {
let mut cx: VimTestContext = VimTestContext::new(cx, true).await;
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<VimSettings>(cx, |s| {
store.update_user_settings(cx, |s| {
let mut custom_digraphs = HashMap::default();
custom_digraphs.insert("|-".into(), "".into());
custom_digraphs.insert(":)".into(), "👨‍💻".into());
s.custom_digraphs = Some(custom_digraphs);
s.vim.get_or_insert_default().custom_digraphs = Some(custom_digraphs);
});
});
+9 -6
View File
@@ -989,11 +989,10 @@ impl Vim {
mod test {
use gpui::{KeyBinding, TestAppContext, UpdateGlobal};
use indoc::indoc;
use language::language_settings::AllLanguageSettings;
use settings::SettingsStore;
use crate::{
VimSettings, motion,
motion,
state::Mode::{self},
test::{NeovimBackedTestContext, VimTestContext},
};
@@ -1724,8 +1723,8 @@ mod test {
async fn test_f_and_t_smartcase(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await;
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<VimSettings>(cx, |s| {
s.use_smartcase_find = Some(true);
store.update_user_settings(cx, |s| {
s.vim.get_or_insert_default().use_smartcase_find = Some(true);
});
});
@@ -1891,8 +1890,12 @@ mod test {
cx.update(|_, cx| {
SettingsStore::update_global(cx, |settings, cx| {
settings.update_user_settings::<AllLanguageSettings>(cx, |settings| {
settings.defaults.preferred_line_length = Some(5);
settings.update_user_settings(cx, |settings| {
settings
.project
.all_languages
.defaults
.preferred_line_length = Some(5);
});
})
});
+18 -21
View File
@@ -311,17 +311,13 @@ impl Vim {
#[cfg(test)]
mod test {
use crate::{
UseSystemClipboard, VimSettings,
state::{Mode, Register},
test::{NeovimBackedTestContext, VimTestContext},
};
use gpui::ClipboardItem;
use indoc::indoc;
use language::{
LanguageName,
language_settings::{AllLanguageSettings, LanguageSettingsContent},
};
use settings::SettingsStore;
use language::{LanguageName, language_settings::LanguageSettingsContent};
use settings::{SettingsStore, UseSystemClipboard};
#[gpui::test]
async fn test_paste(cx: &mut gpui::TestAppContext) {
@@ -408,8 +404,8 @@ mod test {
let mut cx = VimTestContext::new(cx, true).await;
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<VimSettings>(cx, |s| {
s.use_system_clipboard = Some(UseSystemClipboard::Never)
store.update_user_settings(cx, |s| {
s.vim.get_or_insert_default().use_system_clipboard = Some(UseSystemClipboard::Never)
});
});
@@ -444,8 +440,9 @@ mod test {
let mut cx = VimTestContext::new(cx, true).await;
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<VimSettings>(cx, |s| {
s.use_system_clipboard = Some(UseSystemClipboard::OnYank)
store.update_user_settings(cx, |s| {
s.vim.get_or_insert_default().use_system_clipboard =
Some(UseSystemClipboard::OnYank)
});
});
@@ -709,9 +706,9 @@ mod test {
Mode::Normal,
);
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<AllLanguageSettings>(cx, |settings| {
settings.languages.0.insert(
LanguageName::new("Rust"),
store.update_user_settings(cx, |settings| {
settings.project.all_languages.languages.0.insert(
LanguageName::new("Rust").0,
LanguageSettingsContent {
auto_indent_on_paste: Some(false),
..Default::default()
@@ -772,8 +769,8 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await;
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<VimSettings>(cx, |s| {
s.use_system_clipboard = Some(UseSystemClipboard::Never)
store.update_user_settings(cx, |s| {
s.vim.get_or_insert_default().use_system_clipboard = Some(UseSystemClipboard::Never)
});
});
@@ -818,8 +815,8 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await;
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<VimSettings>(cx, |s| {
s.use_system_clipboard = Some(UseSystemClipboard::Never)
store.update_user_settings(cx, |s| {
s.vim.get_or_insert_default().use_system_clipboard = Some(UseSystemClipboard::Never)
});
});
@@ -847,8 +844,8 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await;
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<VimSettings>(cx, |s| {
s.use_system_clipboard = Some(UseSystemClipboard::Never)
store.update_user_settings(cx, |s| {
s.vim.get_or_insert_default().use_system_clipboard = Some(UseSystemClipboard::Never)
});
});
@@ -906,8 +903,8 @@ mod test {
let mut cx = VimTestContext::new(cx, true).await;
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<VimSettings>(cx, |s| {
s.use_system_clipboard = Some(UseSystemClipboard::Never)
store.update_user_settings(cx, |s| {
s.vim.get_or_insert_default().use_system_clipboard = Some(UseSystemClipboard::Never)
});
});
+5 -10
View File
@@ -271,7 +271,7 @@ mod test {
state::Mode,
test::{NeovimBackedTestContext, VimTestContext},
};
use editor::{EditorSettings, ScrollBeyondLastLine};
use editor::ScrollBeyondLastLine;
use gpui::{AppContext as _, point, px, size};
use indoc::indoc;
use language::Point;
@@ -427,9 +427,7 @@ mod test {
// First test without vertical scroll margin
cx.neovim.set_option(&format!("scrolloff={}", 0)).await;
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<EditorSettings>(cx, |s| {
s.vertical_scroll_margin = Some(0.0)
});
store.update_user_settings(cx, |s| s.editor.vertical_scroll_margin = Some(0.0));
});
let content = "ˇ".to_owned() + &sample_text(26, 2, 'a');
@@ -455,9 +453,7 @@ mod test {
cx.neovim.set_option(&format!("scrolloff={}", 3)).await;
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<EditorSettings>(cx, |s| {
s.vertical_scroll_margin = Some(3.0)
});
store.update_user_settings(cx, |s| s.editor.vertical_scroll_margin = Some(3.0));
});
// scroll down: ctrl-f
@@ -485,9 +481,8 @@ mod test {
cx.set_shared_state(&content).await;
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<EditorSettings>(cx, |s| {
s.scroll_beyond_last_line = Some(ScrollBeyondLastLine::Off);
// s.vertical_scroll_margin = Some(0.);
store.update_user_settings(cx, |s| {
s.editor.scroll_beyond_last_line = Some(ScrollBeyondLastLine::Off);
});
});
+2 -3
View File
@@ -645,7 +645,6 @@ mod test {
state::Mode,
test::{NeovimBackedTestContext, VimTestContext},
};
use editor::EditorSettings;
use editor::{DisplayPoint, display_map::DisplayRow};
use indoc::indoc;
@@ -694,7 +693,7 @@ mod test {
let mut cx = VimTestContext::new(cx, true).await;
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<EditorSettings>(cx, |s| s.search_wrap = Some(false));
store.update_user_settings(cx, |s| s.editor.search_wrap = Some(false));
});
cx.set_state("ˇhi\nhigh\nhi\n", Mode::Normal);
@@ -815,7 +814,7 @@ mod test {
// check that searching with unable search wrap
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<EditorSettings>(cx, |s| s.search_wrap = Some(false));
store.update_user_settings(cx, |s| s.editor.search_wrap = Some(false));
});
cx.set_state("aa\nbˇb\ncc\ncc\ncc\n", Mode::Normal);
cx.simulate_keystrokes("/ c c enter");
+2 -3
View File
@@ -22,7 +22,6 @@ pub use vim_test_context::*;
use indoc::indoc;
use search::BufferSearchBar;
use workspace::WorkspaceSettings;
use crate::{PushSneak, PushSneakBackward, insert::NormalBefore, motion, state::Mode};
@@ -1562,10 +1561,10 @@ async fn test_plus_minus(cx: &mut gpui::TestAppContext) {
async fn test_command_alias(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await;
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<WorkspaceSettings>(cx, |s| {
store.update_user_settings(cx, |s| {
let mut aliases = HashMap::default();
aliases.insert("Q".to_string(), "upper".to_string());
s.command_aliases = Some(aliases)
s.workspace.command_aliases = aliases
});
});
@@ -6,7 +6,7 @@ use std::{
panic, thread,
};
use language::language_settings::{AllLanguageSettings, SoftWrap};
use language::language_settings::SoftWrap;
use util::test::marked_text_offsets;
use super::{VimTestContext, neovim_connection::NeovimConnection};
@@ -245,9 +245,14 @@ impl NeovimBackedTestContext {
self.update(|_, cx| {
SettingsStore::update_global(cx, |settings, cx| {
settings.update_user_settings::<AllLanguageSettings>(cx, |settings| {
settings.defaults.soft_wrap = Some(SoftWrap::PreferredLineLength);
settings.defaults.preferred_line_length = Some(columns);
settings.update_user_settings(cx, |settings| {
settings.project.all_languages.defaults.soft_wrap =
Some(SoftWrap::PreferredLineLength);
settings
.project
.all_languages
.defaults
.preferred_line_length = Some(columns);
});
})
})
+4 -6
View File
@@ -68,7 +68,7 @@ impl VimTestContext {
pub fn init_keybindings(enabled: bool, cx: &mut App) {
SettingsStore::update_global(cx, |store, cx| {
store.update_user_settings::<VimModeSetting>(cx, |s| s.vim_mode = Some(enabled));
store.update_user_settings(cx, |s| s.vim_mode = Some(enabled));
});
let mut default_key_bindings = settings::KeymapFile::load_asset_allow_partial_failure(
"keymaps/default-macos.json",
@@ -137,7 +137,7 @@ impl VimTestContext {
pub fn enable_vim(&mut self) {
self.cx.update(|_, cx| {
SettingsStore::update_global(cx, |store, cx| {
store.update_user_settings::<VimModeSetting>(cx, |s| s.vim_mode = Some(true));
store.update_user_settings(cx, |s| s.vim_mode = Some(true));
});
})
}
@@ -145,7 +145,7 @@ impl VimTestContext {
pub fn disable_vim(&mut self) {
self.cx.update(|_, cx| {
SettingsStore::update_global(cx, |store, cx| {
store.update_user_settings::<VimModeSetting>(cx, |s| s.vim_mode = Some(false));
store.update_user_settings(cx, |s| s.vim_mode = Some(false));
});
})
}
@@ -153,9 +153,7 @@ impl VimTestContext {
pub fn enable_helix(&mut self) {
self.cx.update(|_, cx| {
SettingsStore::update_global(cx, |store, cx| {
store.update_user_settings::<vim_mode_setting::HelixModeSetting>(cx, |s| {
s.helix_mode = Some(true)
});
store.update_user_settings(cx, |s| s.helix_mode = Some(true));
});
})
}
+57 -82
View File
@@ -19,7 +19,6 @@ mod state;
mod surrounds;
mod visual;
use anyhow::Result;
use collections::HashMap;
use editor::{
Anchor, Bias, Editor, EditorEvent, EditorSettings, HideMouseCursorOrigin, SelectionEffects,
@@ -38,15 +37,15 @@ use normal::search::SearchSubmit;
use object::Object;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use settings::{
Settings, SettingsKey, SettingsSources, SettingsStore, SettingsUi, update_settings_file,
pub use settings::{
ModeContent, Settings, SettingsStore, UseSystemClipboard, update_settings_file,
};
use state::{Mode, Operator, RecordedSelection, SearchState, VimGlobals};
use std::{mem, ops::Range, sync::Arc};
use surrounds::SurroundsType;
use theme::ThemeSettings;
use ui::{IntoElement, SharedString, px};
use util::MergeFrom;
use vim_mode_setting::HelixModeSetting;
use vim_mode_setting::VimModeSetting;
use workspace::{self, Pane, Workspace};
@@ -266,7 +265,7 @@ pub fn init(cx: &mut App) {
workspace.register_action(|workspace, _: &ToggleVimMode, _, cx| {
let fs = workspace.app_state().fs.clone();
let currently_enabled = Vim::enabled(cx);
update_settings_file::<VimModeSetting>(fs, cx, move |setting, _| {
update_settings_file(fs, cx, move |setting, _| {
setting.vim_mode = Some(!currently_enabled)
})
});
@@ -1793,21 +1792,19 @@ impl Vim {
}
}
/// Controls when to use system clipboard.
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum UseSystemClipboard {
/// Don't use system clipboard.
Never,
/// Use system clipboard.
Always,
/// Use system clipboard for yank operations.
OnYank,
struct VimSettings {
pub default_mode: Mode,
pub toggle_relative_line_numbers: bool,
pub use_system_clipboard: settings::UseSystemClipboard,
pub use_smartcase_find: bool,
pub custom_digraphs: HashMap<String, Arc<str>>,
pub highlight_on_yank_duration: u64,
pub cursor_shape: CursorShapeSettings,
}
/// The settings for cursor shape.
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
struct CursorShapeSettings {
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct CursorShapeSettings {
/// Cursor shape for the normal mode.
///
/// Default: block
@@ -1826,85 +1823,63 @@ struct CursorShapeSettings {
pub insert: Option<CursorShape>,
}
#[derive(Deserialize)]
struct VimSettings {
pub default_mode: Mode,
pub toggle_relative_line_numbers: bool,
pub use_system_clipboard: UseSystemClipboard,
pub use_smartcase_find: bool,
pub custom_digraphs: HashMap<String, Arc<str>>,
pub highlight_on_yank_duration: u64,
pub cursor_shape: CursorShapeSettings,
impl From<settings::CursorShapeSettings> for CursorShapeSettings {
fn from(settings: settings::CursorShapeSettings) -> Self {
Self {
normal: settings.normal.map(Into::into),
replace: settings.replace.map(Into::into),
visual: settings.visual.map(Into::into),
insert: settings.insert.map(Into::into),
}
}
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, SettingsUi, SettingsKey)]
#[settings_key(key = "vim")]
struct VimSettingsContent {
pub default_mode: Option<ModeContent>,
pub toggle_relative_line_numbers: Option<bool>,
pub use_system_clipboard: Option<UseSystemClipboard>,
pub use_smartcase_find: Option<bool>,
pub custom_digraphs: Option<HashMap<String, Arc<str>>>,
pub highlight_on_yank_duration: Option<u64>,
pub cursor_shape: Option<CursorShapeSettings>,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ModeContent {
#[default]
Normal,
Insert,
Replace,
Visual,
VisualLine,
VisualBlock,
HelixNormal,
}
impl From<ModeContent> for Mode {
impl From<settings::ModeContent> for Mode {
fn from(mode: ModeContent) -> Self {
match mode {
ModeContent::Normal => Self::Normal,
ModeContent::Insert => Self::Insert,
ModeContent::Replace => Self::Replace,
ModeContent::Visual => Self::Visual,
ModeContent::VisualLine => Self::VisualLine,
ModeContent::VisualBlock => Self::VisualBlock,
ModeContent::HelixNormal => Self::HelixNormal,
}
}
}
impl Settings for VimSettings {
type FileContent = VimSettingsContent;
fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
let settings: VimSettingsContent = sources.json_merge()?;
Ok(Self {
default_mode: settings
.default_mode
.ok_or_else(Self::missing_default)?
.into(),
toggle_relative_line_numbers: settings
.toggle_relative_line_numbers
.ok_or_else(Self::missing_default)?,
use_system_clipboard: settings
.use_system_clipboard
.ok_or_else(Self::missing_default)?,
use_smartcase_find: settings
.use_smartcase_find
.ok_or_else(Self::missing_default)?,
custom_digraphs: settings.custom_digraphs.ok_or_else(Self::missing_default)?,
highlight_on_yank_duration: settings
.highlight_on_yank_duration
.ok_or_else(Self::missing_default)?,
cursor_shape: settings.cursor_shape.ok_or_else(Self::missing_default)?,
})
fn from_defaults(content: &settings::SettingsContent, _cx: &mut App) -> Self {
let vim = content.vim.clone().unwrap();
Self {
default_mode: vim.default_mode.unwrap().into(),
toggle_relative_line_numbers: vim.toggle_relative_line_numbers.unwrap(),
use_system_clipboard: vim.use_system_clipboard.unwrap(),
use_smartcase_find: vim.use_smartcase_find.unwrap(),
custom_digraphs: vim.custom_digraphs.unwrap(),
highlight_on_yank_duration: vim.highlight_on_yank_duration.unwrap(),
cursor_shape: vim.cursor_shape.unwrap().into(),
}
}
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {
fn refine(&mut self, content: &settings::SettingsContent, _cx: &mut App) {
let Some(vim) = content.vim.as_ref() else {
return;
};
self.default_mode
.merge_from(&vim.default_mode.map(Into::into));
self.toggle_relative_line_numbers
.merge_from(&vim.toggle_relative_line_numbers);
self.use_system_clipboard
.merge_from(&vim.use_system_clipboard);
self.use_smartcase_find.merge_from(&vim.use_smartcase_find);
self.custom_digraphs.merge_from(&vim.custom_digraphs);
self.highlight_on_yank_duration
.merge_from(&vim.highlight_on_yank_duration);
self.cursor_shape
.merge_from(&vim.cursor_shape.map(Into::into));
}
fn import_from_vscode(
_vscode: &settings::VsCodeSettings,
_current: &mut settings::SettingsContent,
) {
// TODO: translate vim extension settings
}
}