Merge pull request #1331 from zed-industries/discoverable-settings

Make settings more discoverable
This commit is contained in:
Max Brunsfeld 2022-07-12 14:38:16 -07:00 committed by GitHub
commit dd554c19df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 348 additions and 244 deletions

View 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
}
}
}

View 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.

View file

@ -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()],
});

View file

@ -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);
});

View file

@ -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()
},

View file

@ -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()
},

View file

@ -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(

View file

@ -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(

View file

@ -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()
}

View file

@ -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)]

View file

@ -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());

View file

@ -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),

View file

@ -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()
},

View file

@ -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);