mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-03 17:44:30 +00:00
Merge pull request #1331 from zed-industries/discoverable-settings
Make settings more discoverable
This commit is contained in:
commit
dd554c19df
14 changed files with 348 additions and 244 deletions
109
assets/settings/default.json
Normal file
109
assets/settings/default.json
Normal file
|
@ -0,0 +1,109 @@
|
|||
{
|
||||
// The name of the Zed theme to use for the UI
|
||||
"theme": "cave-dark",
|
||||
|
||||
// The name of a font to use for rendering text in the editor
|
||||
"buffer_font_family": "Zed Mono",
|
||||
|
||||
// The default font size for text in the editor
|
||||
"buffer_font_size": 15,
|
||||
|
||||
// Whether to enable vim modes and key bindings
|
||||
"vim_mode": false,
|
||||
|
||||
// Whether to show the informational hover box when moving the mouse
|
||||
// over symbols in the editor.
|
||||
"hover_popover_enabled": true,
|
||||
|
||||
// Whether new projects should start out 'online'. Online projects
|
||||
// appear in the contacts panel under your name, so that your contacts
|
||||
// can see which projects you are working on. Regardless of this
|
||||
// setting, projects keep their last online status when you reopen them.
|
||||
"projects_online_by_default": true,
|
||||
|
||||
// Whether to use language servers to provide code intelligence.
|
||||
"enable_language_server": true,
|
||||
|
||||
// When to automatically save edited buffers. This setting can
|
||||
// take four values.
|
||||
//
|
||||
// 1. Never automatically save:
|
||||
// "autosave": "off",
|
||||
// 2. Save when changing focus away from the Zed window:
|
||||
// "autosave": "on_window_change",
|
||||
// 3. Save when changing focus away from a specific buffer:
|
||||
// "autosave": "on_focus_change",
|
||||
// 4. Save when idle for a certain amount of time:
|
||||
// "autosave": { "after_delay": {"milliseconds": 500} },
|
||||
"autosave": "off",
|
||||
|
||||
// How to auto-format modified buffers when saving them. This
|
||||
// setting can take three values:
|
||||
//
|
||||
// 1. Don't format code
|
||||
// "format_on_save": "off"
|
||||
// 2. Format code using the current language server:
|
||||
// "format_on_save": "language_server"
|
||||
// 3. Format code using an external command:
|
||||
// "format_on_save": {
|
||||
// "external": {
|
||||
// "command": "sed",
|
||||
// "arguments": ["-e", "s/ *$//"]
|
||||
// }
|
||||
// },
|
||||
"format_on_save": "language_server",
|
||||
|
||||
// How to soft-wrap long lines of text. This setting can take
|
||||
// three values:
|
||||
//
|
||||
// 1. Do not soft wrap.
|
||||
// "soft_wrap": "none",
|
||||
// 2. Soft wrap lines that overflow the editor:
|
||||
// "soft_wrap": "editor_width",
|
||||
// 2. Soft wrap lines at the preferred line length
|
||||
// "soft_wrap": "preferred_line_length",
|
||||
"soft_wrap": "none",
|
||||
|
||||
// The column at which to soft-wrap lines, for buffers where soft-wrap
|
||||
// is enabled.
|
||||
"preferred_line_length": 80,
|
||||
|
||||
// Whether to indent lines using tab characters, as opposed to multiple
|
||||
// spaces.
|
||||
"hard_tabs": false,
|
||||
|
||||
// How many columns a tab should occupy.
|
||||
"tab_size": 4,
|
||||
|
||||
// Different settings for specific languages.
|
||||
"languages": {
|
||||
"Plain Text": {
|
||||
"soft_wrap": "preferred_line_length"
|
||||
},
|
||||
"C": {
|
||||
"tab_size": 2
|
||||
},
|
||||
"C++": {
|
||||
"tab_size": 2
|
||||
},
|
||||
"Go": {
|
||||
"tab_size": 4,
|
||||
"hard_tabs": true
|
||||
},
|
||||
"Markdown": {
|
||||
"soft_wrap": "preferred_line_length"
|
||||
},
|
||||
"Rust": {
|
||||
"tab_size": 4
|
||||
},
|
||||
"JavaScript": {
|
||||
"tab_size": 2
|
||||
},
|
||||
"TypeScript": {
|
||||
"tab_size": 2
|
||||
},
|
||||
"TSX": {
|
||||
"tab_size": 2
|
||||
}
|
||||
}
|
||||
}
|
8
assets/settings/header-comments.json
Normal file
8
assets/settings/header-comments.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
// Zed settings
|
||||
//
|
||||
// For information on how to configure Zed, see the Zed
|
||||
// documentation: https://zed.dev/docs/configuring-zed
|
||||
//
|
||||
// To see all of Zed's default settings without changing your
|
||||
// custom settings, run the `open default settings` command
|
||||
// from the command palette or from `Zed` application menu.
|
|
@ -2010,7 +2010,7 @@ async fn test_formatting_buffer(cx_a: &mut TestAppContext, cx_b: &mut TestAppCon
|
|||
// host's configuration is honored as opposed to using the guest's settings.
|
||||
cx_a.update(|cx| {
|
||||
cx.update_global(|settings: &mut Settings, _| {
|
||||
settings.language_settings.format_on_save = Some(FormatOnSave::External {
|
||||
settings.editor_defaults.format_on_save = Some(FormatOnSave::External {
|
||||
command: "awk".to_string(),
|
||||
arguments: vec!["{sub(/two/,\"{buffer_path}\")}1".to_string()],
|
||||
});
|
||||
|
|
|
@ -983,7 +983,7 @@ pub mod tests {
|
|||
language.set_theme(&theme);
|
||||
cx.update(|cx| {
|
||||
let mut settings = Settings::test(cx);
|
||||
settings.language_settings.tab_size = Some(2.try_into().unwrap());
|
||||
settings.editor_defaults.tab_size = Some(2.try_into().unwrap());
|
||||
cx.set_global(settings);
|
||||
});
|
||||
|
||||
|
|
|
@ -6236,7 +6236,7 @@ mod tests {
|
|||
use language::{FakeLspAdapter, LanguageConfig};
|
||||
use lsp::FakeLanguageServer;
|
||||
use project::FakeFs;
|
||||
use settings::LanguageSettings;
|
||||
use settings::EditorSettings;
|
||||
use std::{cell::RefCell, rc::Rc, time::Instant};
|
||||
use text::Point;
|
||||
use unindent::Unindent;
|
||||
|
@ -7613,7 +7613,7 @@ mod tests {
|
|||
let mut cx = EditorTestContext::new(cx).await;
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<Settings, _, _>(|settings, _| {
|
||||
settings.language_settings.hard_tabs = Some(true);
|
||||
settings.editor_overrides.hard_tabs = Some(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -7696,14 +7696,14 @@ mod tests {
|
|||
Settings::test(cx)
|
||||
.with_language_defaults(
|
||||
"TOML",
|
||||
LanguageSettings {
|
||||
EditorSettings {
|
||||
tab_size: Some(2.try_into().unwrap()),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.with_language_defaults(
|
||||
"Rust",
|
||||
LanguageSettings {
|
||||
EditorSettings {
|
||||
tab_size: Some(4.try_into().unwrap()),
|
||||
..Default::default()
|
||||
},
|
||||
|
@ -9380,7 +9380,7 @@ mod tests {
|
|||
cx.update_global::<Settings, _, _>(|settings, _| {
|
||||
settings.language_overrides.insert(
|
||||
"Rust".into(),
|
||||
LanguageSettings {
|
||||
EditorSettings {
|
||||
tab_size: Some(8.try_into().unwrap()),
|
||||
..Default::default()
|
||||
},
|
||||
|
@ -9496,7 +9496,7 @@ mod tests {
|
|||
cx.update_global::<Settings, _, _>(|settings, _| {
|
||||
settings.language_overrides.insert(
|
||||
"Rust".into(),
|
||||
LanguageSettings {
|
||||
EditorSettings {
|
||||
tab_size: Some(8.try_into().unwrap()),
|
||||
..Default::default()
|
||||
},
|
||||
|
|
|
@ -883,7 +883,7 @@ async fn test_toggling_enable_language_server(
|
|||
cx.update_global(|settings: &mut Settings, _| {
|
||||
settings.language_overrides.insert(
|
||||
Arc::from("Rust"),
|
||||
settings::LanguageSettings {
|
||||
settings::EditorSettings {
|
||||
enable_language_server: Some(false),
|
||||
..Default::default()
|
||||
},
|
||||
|
@ -900,14 +900,14 @@ async fn test_toggling_enable_language_server(
|
|||
cx.update_global(|settings: &mut Settings, _| {
|
||||
settings.language_overrides.insert(
|
||||
Arc::from("Rust"),
|
||||
settings::LanguageSettings {
|
||||
settings::EditorSettings {
|
||||
enable_language_server: Some(true),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
settings.language_overrides.insert(
|
||||
Arc::from("JavaScript"),
|
||||
settings::LanguageSettings {
|
||||
settings::EditorSettings {
|
||||
enable_language_server: Some(false),
|
||||
..Default::default()
|
||||
},
|
||||
|
|
|
@ -608,8 +608,11 @@ mod tests {
|
|||
let fonts = cx.font_cache();
|
||||
let mut theme = gpui::fonts::with_font_cache(fonts.clone(), || theme::Theme::default());
|
||||
theme.search.match_background = Color::red();
|
||||
let settings = Settings::new("Courier", &fonts, Arc::new(theme)).unwrap();
|
||||
cx.update(|cx| cx.set_global(settings));
|
||||
cx.update(|cx| {
|
||||
let mut settings = Settings::test(cx);
|
||||
settings.theme = Arc::new(theme);
|
||||
cx.set_global(settings)
|
||||
});
|
||||
|
||||
let buffer = cx.add_model(|cx| {
|
||||
Buffer::new(
|
||||
|
|
|
@ -911,8 +911,11 @@ mod tests {
|
|||
let fonts = cx.font_cache();
|
||||
let mut theme = gpui::fonts::with_font_cache(fonts.clone(), || theme::Theme::default());
|
||||
theme.search.match_background = Color::red();
|
||||
let settings = Settings::new("Courier", &fonts, Arc::new(theme)).unwrap();
|
||||
cx.update(|cx| cx.set_global(settings));
|
||||
cx.update(|cx| {
|
||||
let mut settings = Settings::test(cx);
|
||||
settings.theme = Arc::new(theme);
|
||||
cx.set_global(settings)
|
||||
});
|
||||
|
||||
let fs = FakeFs::new(cx.background());
|
||||
fs.insert_tree(
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
mod keymap_file;
|
||||
|
||||
use anyhow::Result;
|
||||
use gpui::font_cache::{FamilyId, FontCache};
|
||||
use gpui::{
|
||||
font_cache::{FamilyId, FontCache},
|
||||
AssetSource,
|
||||
};
|
||||
use schemars::{
|
||||
gen::{SchemaGenerator, SchemaSettings},
|
||||
schema::{
|
||||
InstanceType, ObjectValidation, Schema, SchemaObject, SingleOrVec, SubschemaValidation,
|
||||
},
|
||||
schema::{InstanceType, ObjectValidation, Schema, SchemaObject, SingleOrVec},
|
||||
JsonSchema,
|
||||
};
|
||||
use serde::{de::DeserializeOwned, Deserialize};
|
||||
use serde_json::Value;
|
||||
use std::{collections::HashMap, num::NonZeroU32, sync::Arc};
|
||||
use std::{collections::HashMap, num::NonZeroU32, str, sync::Arc};
|
||||
use theme::{Theme, ThemeRegistry};
|
||||
use util::ResultExt as _;
|
||||
|
||||
|
@ -26,14 +27,15 @@ pub struct Settings {
|
|||
pub hover_popover_enabled: bool,
|
||||
pub vim_mode: bool,
|
||||
pub autosave: Autosave,
|
||||
pub language_settings: LanguageSettings,
|
||||
pub language_defaults: HashMap<Arc<str>, LanguageSettings>,
|
||||
pub language_overrides: HashMap<Arc<str>, LanguageSettings>,
|
||||
pub editor_defaults: EditorSettings,
|
||||
pub editor_overrides: EditorSettings,
|
||||
pub language_defaults: HashMap<Arc<str>, EditorSettings>,
|
||||
pub language_overrides: HashMap<Arc<str>, EditorSettings>,
|
||||
pub theme: Arc<Theme>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, JsonSchema)]
|
||||
pub struct LanguageSettings {
|
||||
pub struct EditorSettings {
|
||||
pub tab_size: Option<NonZeroU32>,
|
||||
pub hard_tabs: Option<bool>,
|
||||
pub soft_wrap: Option<SoftWrap>,
|
||||
|
@ -83,44 +85,61 @@ pub struct SettingsFileContent {
|
|||
#[serde(default)]
|
||||
pub vim_mode: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub format_on_save: Option<FormatOnSave>,
|
||||
#[serde(default)]
|
||||
pub autosave: Option<Autosave>,
|
||||
#[serde(default)]
|
||||
pub enable_language_server: Option<bool>,
|
||||
#[serde(flatten)]
|
||||
pub editor: LanguageSettings,
|
||||
pub editor: EditorSettings,
|
||||
#[serde(default)]
|
||||
pub language_overrides: HashMap<Arc<str>, LanguageSettings>,
|
||||
#[serde(alias = "language_overrides")]
|
||||
pub languages: HashMap<Arc<str>, EditorSettings>,
|
||||
#[serde(default)]
|
||||
pub theme: Option<String>,
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
pub fn new(
|
||||
buffer_font_family: &str,
|
||||
pub fn defaults(
|
||||
assets: impl AssetSource,
|
||||
font_cache: &FontCache,
|
||||
theme: Arc<Theme>,
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
buffer_font_family: font_cache.load_family(&[buffer_font_family])?,
|
||||
buffer_font_size: 15.,
|
||||
default_buffer_font_size: 15.,
|
||||
hover_popover_enabled: true,
|
||||
vim_mode: false,
|
||||
autosave: Autosave::Off,
|
||||
language_settings: Default::default(),
|
||||
language_defaults: Default::default(),
|
||||
themes: &ThemeRegistry,
|
||||
) -> Self {
|
||||
fn required<T>(value: Option<T>) -> Option<T> {
|
||||
assert!(value.is_some(), "missing default setting value");
|
||||
value
|
||||
}
|
||||
|
||||
let defaults: SettingsFileContent = parse_json_with_comments(
|
||||
str::from_utf8(assets.load("settings/default.json").unwrap().as_ref()).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Self {
|
||||
buffer_font_family: font_cache
|
||||
.load_family(&[defaults.buffer_font_family.as_ref().unwrap()])
|
||||
.unwrap(),
|
||||
buffer_font_size: defaults.buffer_font_size.unwrap(),
|
||||
default_buffer_font_size: defaults.buffer_font_size.unwrap(),
|
||||
hover_popover_enabled: defaults.hover_popover_enabled.unwrap(),
|
||||
projects_online_by_default: defaults.projects_online_by_default.unwrap(),
|
||||
vim_mode: defaults.vim_mode.unwrap(),
|
||||
autosave: defaults.autosave.unwrap(),
|
||||
editor_defaults: EditorSettings {
|
||||
tab_size: required(defaults.editor.tab_size),
|
||||
hard_tabs: required(defaults.editor.hard_tabs),
|
||||
soft_wrap: required(defaults.editor.soft_wrap),
|
||||
preferred_line_length: required(defaults.editor.preferred_line_length),
|
||||
format_on_save: required(defaults.editor.format_on_save),
|
||||
enable_language_server: required(defaults.editor.enable_language_server),
|
||||
},
|
||||
language_defaults: defaults.languages,
|
||||
editor_overrides: Default::default(),
|
||||
language_overrides: Default::default(),
|
||||
projects_online_by_default: true,
|
||||
theme,
|
||||
})
|
||||
theme: themes.get(&defaults.theme.unwrap()).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_language_defaults(
|
||||
mut self,
|
||||
language_name: impl Into<Arc<str>>,
|
||||
overrides: LanguageSettings,
|
||||
overrides: EditorSettings,
|
||||
) -> Self {
|
||||
self.language_defaults
|
||||
.insert(language_name.into(), overrides);
|
||||
|
@ -129,48 +148,37 @@ impl Settings {
|
|||
|
||||
pub fn tab_size(&self, language: Option<&str>) -> NonZeroU32 {
|
||||
self.language_setting(language, |settings| settings.tab_size)
|
||||
.unwrap_or(4.try_into().unwrap())
|
||||
}
|
||||
|
||||
pub fn hard_tabs(&self, language: Option<&str>) -> bool {
|
||||
self.language_setting(language, |settings| settings.hard_tabs)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn soft_wrap(&self, language: Option<&str>) -> SoftWrap {
|
||||
self.language_setting(language, |settings| settings.soft_wrap)
|
||||
.unwrap_or(SoftWrap::None)
|
||||
}
|
||||
|
||||
pub fn preferred_line_length(&self, language: Option<&str>) -> u32 {
|
||||
self.language_setting(language, |settings| settings.preferred_line_length)
|
||||
.unwrap_or(80)
|
||||
}
|
||||
|
||||
pub fn format_on_save(&self, language: Option<&str>) -> FormatOnSave {
|
||||
self.language_setting(language, |settings| settings.format_on_save.clone())
|
||||
.unwrap_or(FormatOnSave::LanguageServer)
|
||||
}
|
||||
|
||||
pub fn enable_language_server(&self, language: Option<&str>) -> bool {
|
||||
self.language_setting(language, |settings| settings.enable_language_server)
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
fn language_setting<F, R>(&self, language: Option<&str>, f: F) -> Option<R>
|
||||
fn language_setting<F, R>(&self, language: Option<&str>, f: F) -> R
|
||||
where
|
||||
F: Fn(&LanguageSettings) -> Option<R>,
|
||||
F: Fn(&EditorSettings) -> Option<R>,
|
||||
{
|
||||
let mut language_override = None;
|
||||
let mut language_default = None;
|
||||
if let Some(language) = language {
|
||||
language_override = self.language_overrides.get(language).and_then(&f);
|
||||
language_default = self.language_defaults.get(language).and_then(&f);
|
||||
}
|
||||
|
||||
language_override
|
||||
.or_else(|| f(&self.language_settings))
|
||||
.or(language_default)
|
||||
None.or_else(|| language.and_then(|l| self.language_overrides.get(l).and_then(&f)))
|
||||
.or_else(|| f(&self.editor_overrides))
|
||||
.or_else(|| language.and_then(|l| self.language_defaults.get(l).and_then(&f)))
|
||||
.or_else(|| f(&self.editor_defaults))
|
||||
.expect("missing default")
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
|
@ -182,7 +190,15 @@ impl Settings {
|
|||
hover_popover_enabled: true,
|
||||
vim_mode: false,
|
||||
autosave: Autosave::Off,
|
||||
language_settings: Default::default(),
|
||||
editor_defaults: EditorSettings {
|
||||
tab_size: Some(4.try_into().unwrap()),
|
||||
hard_tabs: Some(false),
|
||||
soft_wrap: Some(SoftWrap::None),
|
||||
preferred_line_length: Some(80),
|
||||
format_on_save: Some(FormatOnSave::LanguageServer),
|
||||
enable_language_server: Some(true),
|
||||
},
|
||||
editor_overrides: Default::default(),
|
||||
language_defaults: Default::default(),
|
||||
language_overrides: Default::default(),
|
||||
projects_online_by_default: true,
|
||||
|
@ -224,22 +240,23 @@ impl Settings {
|
|||
merge(&mut self.hover_popover_enabled, data.hover_popover_enabled);
|
||||
merge(&mut self.vim_mode, data.vim_mode);
|
||||
merge(&mut self.autosave, data.autosave);
|
||||
|
||||
merge_option(
|
||||
&mut self.language_settings.format_on_save,
|
||||
data.format_on_save.clone(),
|
||||
&mut self.editor_overrides.format_on_save,
|
||||
data.editor.format_on_save.clone(),
|
||||
);
|
||||
merge_option(
|
||||
&mut self.language_settings.enable_language_server,
|
||||
data.enable_language_server,
|
||||
&mut self.editor_overrides.enable_language_server,
|
||||
data.editor.enable_language_server,
|
||||
);
|
||||
merge_option(&mut self.language_settings.soft_wrap, data.editor.soft_wrap);
|
||||
merge_option(&mut self.language_settings.tab_size, data.editor.tab_size);
|
||||
merge_option(&mut self.editor_overrides.soft_wrap, data.editor.soft_wrap);
|
||||
merge_option(&mut self.editor_overrides.tab_size, data.editor.tab_size);
|
||||
merge_option(
|
||||
&mut self.language_settings.preferred_line_length,
|
||||
&mut self.editor_overrides.preferred_line_length,
|
||||
data.editor.preferred_line_length,
|
||||
);
|
||||
|
||||
for (language_name, settings) in data.language_overrides.clone().into_iter() {
|
||||
for (language_name, settings) in data.languages.clone().into_iter() {
|
||||
let target = self
|
||||
.language_overrides
|
||||
.entry(language_name.into())
|
||||
|
@ -270,77 +287,61 @@ pub fn settings_file_json_schema(
|
|||
let generator = SchemaGenerator::new(settings);
|
||||
let mut root_schema = generator.into_root_schema_for::<SettingsFileContent>();
|
||||
|
||||
// Construct theme names reference type
|
||||
let theme_names = theme_names
|
||||
.into_iter()
|
||||
.map(|name| Value::String(name))
|
||||
.collect();
|
||||
let theme_names_schema = Schema::Object(SchemaObject {
|
||||
// Create a schema for a theme name.
|
||||
let theme_name_schema = SchemaObject {
|
||||
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
|
||||
enum_values: Some(theme_names),
|
||||
enum_values: Some(
|
||||
theme_names
|
||||
.into_iter()
|
||||
.map(|name| Value::String(name))
|
||||
.collect(),
|
||||
),
|
||||
..Default::default()
|
||||
});
|
||||
root_schema
|
||||
.definitions
|
||||
.insert("ThemeName".to_owned(), theme_names_schema);
|
||||
};
|
||||
|
||||
// Construct language settings reference type
|
||||
let language_settings_schema_reference = Schema::Object(SchemaObject {
|
||||
reference: Some("#/definitions/LanguageSettings".to_owned()),
|
||||
..Default::default()
|
||||
});
|
||||
let language_settings_properties = language_names
|
||||
.into_iter()
|
||||
.map(|name| {
|
||||
(
|
||||
name,
|
||||
Schema::Object(SchemaObject {
|
||||
subschemas: Some(Box::new(SubschemaValidation {
|
||||
all_of: Some(vec![language_settings_schema_reference.clone()]),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let language_overrides_schema = Schema::Object(SchemaObject {
|
||||
// Create a schema for a 'languages overrides' object, associating editor
|
||||
// settings with specific langauges.
|
||||
assert!(root_schema.definitions.contains_key("EditorSettings"));
|
||||
let languages_object_schema = SchemaObject {
|
||||
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Object))),
|
||||
object: Some(Box::new(ObjectValidation {
|
||||
properties: language_settings_properties,
|
||||
properties: language_names
|
||||
.into_iter()
|
||||
.map(|name| (name, Schema::new_ref("#/definitions/EditorSettings".into())))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
});
|
||||
};
|
||||
|
||||
// Add these new schemas as definitions, and modify properties of the root
|
||||
// schema to reference them.
|
||||
root_schema.definitions.extend([
|
||||
("ThemeName".into(), theme_name_schema.into()),
|
||||
("Languages".into(), languages_object_schema.into()),
|
||||
]);
|
||||
root_schema
|
||||
.definitions
|
||||
.insert("LanguageOverrides".to_owned(), language_overrides_schema);
|
||||
.schema
|
||||
.object
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.properties
|
||||
.extend([
|
||||
(
|
||||
"theme".to_owned(),
|
||||
Schema::new_ref("#/definitions/ThemeName".into()),
|
||||
),
|
||||
(
|
||||
"languages".to_owned(),
|
||||
Schema::new_ref("#/definitions/Languages".into()),
|
||||
),
|
||||
// For backward compatibility
|
||||
(
|
||||
"language_overrides".to_owned(),
|
||||
Schema::new_ref("#/definitions/Languages".into()),
|
||||
),
|
||||
]);
|
||||
|
||||
// Modify theme property to use new theme reference type
|
||||
let settings_file_schema = root_schema.schema.object.as_mut().unwrap();
|
||||
let language_overrides_schema_reference = Schema::Object(SchemaObject {
|
||||
reference: Some("#/definitions/ThemeName".to_owned()),
|
||||
..Default::default()
|
||||
});
|
||||
settings_file_schema.properties.insert(
|
||||
"theme".to_owned(),
|
||||
Schema::Object(SchemaObject {
|
||||
subschemas: Some(Box::new(SubschemaValidation {
|
||||
all_of: Some(vec![language_overrides_schema_reference]),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}),
|
||||
);
|
||||
|
||||
// Modify language_overrides property to use LanguageOverrides reference
|
||||
settings_file_schema.properties.insert(
|
||||
"language_overrides".to_owned(),
|
||||
Schema::Object(SchemaObject {
|
||||
reference: Some("#/definitions/LanguageOverrides".to_owned()),
|
||||
..Default::default()
|
||||
}),
|
||||
);
|
||||
serde_json::to_value(root_schema).unwrap()
|
||||
}
|
||||
|
||||
|
|
|
@ -12,8 +12,6 @@ use std::{collections::HashMap, sync::Arc};
|
|||
|
||||
pub use theme_registry::*;
|
||||
|
||||
pub const DEFAULT_THEME_NAME: &'static str = "cave-dark";
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
pub struct Theme {
|
||||
#[serde(default)]
|
||||
|
|
|
@ -38,7 +38,7 @@ use std::{
|
|||
time::Duration,
|
||||
};
|
||||
use terminal;
|
||||
use theme::{ThemeRegistry, DEFAULT_THEME_NAME};
|
||||
use theme::ThemeRegistry;
|
||||
use util::{ResultExt, TryFutureExt};
|
||||
use workspace::{self, AppState, NewFile, OpenPaths};
|
||||
use zed::{
|
||||
|
@ -72,73 +72,7 @@ fn main() {
|
|||
|
||||
let fs = Arc::new(RealFs);
|
||||
let themes = ThemeRegistry::new(Assets, app.font_cache());
|
||||
let theme = themes.get(DEFAULT_THEME_NAME).unwrap();
|
||||
let default_settings = Settings::new("Zed Mono", &app.font_cache(), theme)
|
||||
.unwrap()
|
||||
.with_language_defaults(
|
||||
languages::PLAIN_TEXT.name(),
|
||||
settings::LanguageSettings {
|
||||
soft_wrap: Some(settings::SoftWrap::PreferredLineLength),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.with_language_defaults(
|
||||
"C",
|
||||
settings::LanguageSettings {
|
||||
tab_size: Some(2.try_into().unwrap()),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.with_language_defaults(
|
||||
"C++",
|
||||
settings::LanguageSettings {
|
||||
tab_size: Some(2.try_into().unwrap()),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.with_language_defaults(
|
||||
"Go",
|
||||
settings::LanguageSettings {
|
||||
tab_size: Some(4.try_into().unwrap()),
|
||||
hard_tabs: Some(true),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.with_language_defaults(
|
||||
"Markdown",
|
||||
settings::LanguageSettings {
|
||||
soft_wrap: Some(settings::SoftWrap::PreferredLineLength),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.with_language_defaults(
|
||||
"Rust",
|
||||
settings::LanguageSettings {
|
||||
tab_size: Some(4.try_into().unwrap()),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.with_language_defaults(
|
||||
"JavaScript",
|
||||
settings::LanguageSettings {
|
||||
tab_size: Some(2.try_into().unwrap()),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.with_language_defaults(
|
||||
"TypeScript",
|
||||
settings::LanguageSettings {
|
||||
tab_size: Some(2.try_into().unwrap()),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.with_language_defaults(
|
||||
"TSX",
|
||||
settings::LanguageSettings {
|
||||
tab_size: Some(2.try_into().unwrap()),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
let default_settings = Settings::defaults(Assets, &app.font_cache(), &themes);
|
||||
|
||||
let config_files = load_config_files(&app, fs.clone());
|
||||
|
||||
|
|
|
@ -26,6 +26,10 @@ pub fn menus() -> Vec<Menu<'static>> {
|
|||
name: "Open Key Bindings",
|
||||
action: Box::new(super::OpenKeymap),
|
||||
},
|
||||
MenuItem::Action {
|
||||
name: "Open Default Settings",
|
||||
action: Box::new(super::OpenDefaultSettings),
|
||||
},
|
||||
MenuItem::Action {
|
||||
name: "Open Default Key Bindings",
|
||||
action: Box::new(super::OpenDefaultKeymap),
|
||||
|
|
|
@ -93,7 +93,7 @@ pub async fn watch_keymap_file(
|
|||
mod tests {
|
||||
use super::*;
|
||||
use project::FakeFs;
|
||||
use settings::{LanguageSettings, SoftWrap};
|
||||
use settings::{EditorSettings, SoftWrap};
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_settings_from_files(cx: &mut gpui::TestAppContext) {
|
||||
|
@ -128,7 +128,7 @@ mod tests {
|
|||
|
||||
let settings = cx.read(Settings::test).with_language_defaults(
|
||||
"JavaScript",
|
||||
LanguageSettings {
|
||||
EditorSettings {
|
||||
tab_size: Some(2.try_into().unwrap()),
|
||||
..Default::default()
|
||||
},
|
||||
|
|
|
@ -18,8 +18,9 @@ use gpui::{
|
|||
geometry::vector::vec2f,
|
||||
impl_actions,
|
||||
platform::{WindowBounds, WindowOptions},
|
||||
AsyncAppContext, ViewContext,
|
||||
AssetSource, AsyncAppContext, ViewContext,
|
||||
};
|
||||
use language::Rope;
|
||||
use lazy_static::lazy_static;
|
||||
pub use lsp;
|
||||
pub use project::{self, fs};
|
||||
|
@ -52,6 +53,7 @@ actions!(
|
|||
DebugElements,
|
||||
OpenSettings,
|
||||
OpenKeymap,
|
||||
OpenDefaultSettings,
|
||||
OpenDefaultKeymap,
|
||||
IncreaseBufferFontSize,
|
||||
DecreaseBufferFontSize,
|
||||
|
@ -99,39 +101,48 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::MutableAppContext) {
|
|||
cx.add_action({
|
||||
let app_state = app_state.clone();
|
||||
move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext<Workspace>| {
|
||||
open_config_file(&SETTINGS_PATH, app_state.clone(), cx);
|
||||
open_config_file(&SETTINGS_PATH, app_state.clone(), cx, || {
|
||||
let header = Assets.load("settings/header-comments.json").unwrap();
|
||||
let json = Assets.load("settings/default.json").unwrap();
|
||||
let header = str::from_utf8(header.as_ref()).unwrap();
|
||||
let json = str::from_utf8(json.as_ref()).unwrap();
|
||||
let mut content = Rope::new();
|
||||
content.push(header);
|
||||
content.push(json);
|
||||
content
|
||||
});
|
||||
}
|
||||
});
|
||||
cx.add_action({
|
||||
let app_state = app_state.clone();
|
||||
move |_: &mut Workspace, _: &OpenKeymap, cx: &mut ViewContext<Workspace>| {
|
||||
open_config_file(&KEYMAP_PATH, app_state.clone(), cx);
|
||||
open_config_file(&KEYMAP_PATH, app_state.clone(), cx, || Default::default());
|
||||
}
|
||||
});
|
||||
cx.add_action({
|
||||
let app_state = app_state.clone();
|
||||
move |workspace: &mut Workspace, _: &OpenDefaultKeymap, cx: &mut ViewContext<Workspace>| {
|
||||
workspace.with_local_workspace(cx, app_state.clone(), |workspace, cx| {
|
||||
let project = workspace.project().clone();
|
||||
let buffer = project.update(cx, |project, cx| {
|
||||
let text = Assets::get("keymaps/default.json").unwrap().data;
|
||||
let text = str::from_utf8(text.as_ref()).unwrap();
|
||||
project
|
||||
.create_buffer(text, project.languages().get_language("JSON"), cx)
|
||||
.expect("creating buffers on a local workspace always succeeds")
|
||||
});
|
||||
let buffer = cx.add_model(|cx| {
|
||||
MultiBuffer::singleton(buffer, cx).with_title("Default Key Bindings".into())
|
||||
});
|
||||
workspace.add_item(
|
||||
Box::new(
|
||||
cx.add_view(|cx| {
|
||||
Editor::for_multibuffer(buffer, Some(project.clone()), cx)
|
||||
}),
|
||||
),
|
||||
cx,
|
||||
);
|
||||
});
|
||||
open_bundled_config_file(
|
||||
workspace,
|
||||
app_state.clone(),
|
||||
"keymaps/default.json",
|
||||
"Default Key Bindings",
|
||||
cx,
|
||||
);
|
||||
}
|
||||
});
|
||||
cx.add_action({
|
||||
let app_state = app_state.clone();
|
||||
move |workspace: &mut Workspace,
|
||||
_: &OpenDefaultSettings,
|
||||
cx: &mut ViewContext<Workspace>| {
|
||||
open_bundled_config_file(
|
||||
workspace,
|
||||
app_state.clone(),
|
||||
"settings/default.json",
|
||||
"Default Settings",
|
||||
cx,
|
||||
);
|
||||
}
|
||||
});
|
||||
cx.add_action(
|
||||
|
@ -366,12 +377,15 @@ fn open_config_file(
|
|||
path: &'static Path,
|
||||
app_state: Arc<AppState>,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
default_content: impl 'static + Send + FnOnce() -> Rope,
|
||||
) {
|
||||
cx.spawn(|workspace, mut cx| async move {
|
||||
let fs = &app_state.fs;
|
||||
if !fs.is_file(path).await {
|
||||
fs.create_dir(&ROOT_PATH).await?;
|
||||
fs.create_file(path, Default::default()).await?;
|
||||
fs.save(path, &default_content(), Default::default())
|
||||
.await?;
|
||||
}
|
||||
|
||||
workspace
|
||||
|
@ -386,6 +400,30 @@ fn open_config_file(
|
|||
.detach_and_log_err(cx)
|
||||
}
|
||||
|
||||
fn open_bundled_config_file(
|
||||
workspace: &mut Workspace,
|
||||
app_state: Arc<AppState>,
|
||||
asset_path: &'static str,
|
||||
title: &str,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) {
|
||||
workspace.with_local_workspace(cx, app_state.clone(), |workspace, cx| {
|
||||
let project = workspace.project().clone();
|
||||
let buffer = project.update(cx, |project, cx| {
|
||||
let text = Assets::get(asset_path).unwrap().data;
|
||||
let text = str::from_utf8(text.as_ref()).unwrap();
|
||||
project
|
||||
.create_buffer(text, project.languages().get_language("JSON"), cx)
|
||||
.expect("creating buffers on a local workspace always succeeds")
|
||||
});
|
||||
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx).with_title(title.into()));
|
||||
workspace.add_item(
|
||||
Box::new(cx.add_view(|cx| Editor::for_multibuffer(buffer, Some(project.clone()), cx))),
|
||||
cx,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -400,7 +438,7 @@ mod tests {
|
|||
collections::HashSet,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use theme::{Theme, ThemeRegistry, DEFAULT_THEME_NAME};
|
||||
use theme::ThemeRegistry;
|
||||
use workspace::{
|
||||
open_paths, pane, Item, ItemHandle, NewFile, Pane, SplitDirection, WorkspaceHandle,
|
||||
};
|
||||
|
@ -1530,23 +1568,29 @@ mod tests {
|
|||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_bundled_themes(cx: &mut MutableAppContext) {
|
||||
fn test_bundled_settings_and_themes(cx: &mut MutableAppContext) {
|
||||
cx.platform()
|
||||
.fonts()
|
||||
.add_fonts(&[
|
||||
Assets
|
||||
.load("fonts/zed-sans/zed-sans-extended.ttf")
|
||||
.unwrap()
|
||||
.to_vec()
|
||||
.into(),
|
||||
Assets
|
||||
.load("fonts/zed-mono/zed-mono-extended.ttf")
|
||||
.unwrap()
|
||||
.to_vec()
|
||||
.into(),
|
||||
])
|
||||
.unwrap();
|
||||
let themes = ThemeRegistry::new(Assets, cx.font_cache().clone());
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref DEFAULT_THEME: parking_lot::Mutex<Option<Arc<Theme>>> = Default::default();
|
||||
static ref FONTS: Vec<Arc<Vec<u8>>> = vec![
|
||||
Assets.load("fonts/zed-sans/zed-sans-extended.ttf").unwrap().to_vec().into(),
|
||||
Assets.load("fonts/zed-mono/zed-mono-extended.ttf").unwrap().to_vec().into(),
|
||||
];
|
||||
}
|
||||
|
||||
cx.platform().fonts().add_fonts(&FONTS).unwrap();
|
||||
let settings = Settings::defaults(Assets, cx.font_cache(), &themes);
|
||||
|
||||
let mut has_default_theme = false;
|
||||
for theme_name in themes.list() {
|
||||
let theme = themes.get(&theme_name).unwrap();
|
||||
if theme.name == DEFAULT_THEME_NAME {
|
||||
if theme.name == settings.theme.name {
|
||||
has_default_theme = true;
|
||||
}
|
||||
assert_eq!(theme.name, theme_name);
|
||||
|
|
Loading…
Reference in a new issue