Closes #ISSUE Initially, the `SettingsUi` trait was tied to `Settings`, however, given that the `Settings::FileContent` type (which may be the same as the type that implements `Settings`) will be the type that more directly maps to the JSON structure (and therefore have the documentation, correct field names (or `serde` rename attributes), etc) it makes more sense to have the deriving of `SettingsUi` occur on the `FileContent` type rather than the `Settings` type. In order for this to work a relatively important change had to be made to the derive macro, that being that it now "unwraps" options into their inner type, so a field with type `Option<Foo>` where `Foo: SettingsUi` will treat the field as if it were just `Foo`, expecting there to be a default set in `default.json`. This imposes some restrictions on what `Settings::FileContent` can be as seen in 1e19398 where `FileContent` itself can't be optional without manually implementing `SettingsUi`, as well as introducing some risk that if the `FileContent` type has `serde(default)`, the default value will override the default value from `default.json` in the UI even though it may differ (but it should!). A future PR should probably replace the other settings with `FileContent = Option<T>` (all of which currently have `T == bool`) with wrapper structs and have `KEY = None` so the further niceties `derive(SettingsUi)` will provide such as path renaming, custom UI, auto naming and doc comment extraction can be used. Release Notes: - N/A *or* Added/Fixed/Improved ...
136 lines
4.4 KiB
Rust
136 lines
4.4 KiB
Rust
use std::fmt::{Display, Formatter};
|
|
|
|
use crate as settings;
|
|
use schemars::JsonSchema;
|
|
use serde::{Deserialize, Serialize};
|
|
use settings::{Settings, SettingsSources, VsCodeSettings};
|
|
use settings_ui_macros::SettingsUi;
|
|
|
|
/// Base key bindings scheme. Base keymaps can be overridden with user keymaps.
|
|
///
|
|
/// Default: VSCode
|
|
#[derive(
|
|
Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Default, SettingsUi,
|
|
)]
|
|
pub enum BaseKeymap {
|
|
#[default]
|
|
VSCode,
|
|
JetBrains,
|
|
SublimeText,
|
|
Atom,
|
|
TextMate,
|
|
Emacs,
|
|
Cursor,
|
|
None,
|
|
}
|
|
|
|
impl Display for BaseKeymap {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
BaseKeymap::VSCode => write!(f, "VSCode"),
|
|
BaseKeymap::JetBrains => write!(f, "JetBrains"),
|
|
BaseKeymap::SublimeText => write!(f, "Sublime Text"),
|
|
BaseKeymap::Atom => write!(f, "Atom"),
|
|
BaseKeymap::TextMate => write!(f, "TextMate"),
|
|
BaseKeymap::Emacs => write!(f, "Emacs (beta)"),
|
|
BaseKeymap::Cursor => write!(f, "Cursor (beta)"),
|
|
BaseKeymap::None => write!(f, "None"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl BaseKeymap {
|
|
#[cfg(target_os = "macos")]
|
|
pub const OPTIONS: [(&'static str, Self); 7] = [
|
|
("VSCode (Default)", Self::VSCode),
|
|
("Atom", Self::Atom),
|
|
("JetBrains", Self::JetBrains),
|
|
("Sublime Text", Self::SublimeText),
|
|
("Emacs (beta)", Self::Emacs),
|
|
("TextMate", Self::TextMate),
|
|
("Cursor", Self::Cursor),
|
|
];
|
|
|
|
#[cfg(not(target_os = "macos"))]
|
|
pub const OPTIONS: [(&'static str, Self); 6] = [
|
|
("VSCode (Default)", Self::VSCode),
|
|
("Atom", Self::Atom),
|
|
("JetBrains", Self::JetBrains),
|
|
("Sublime Text", Self::SublimeText),
|
|
("Emacs (beta)", Self::Emacs),
|
|
("Cursor", Self::Cursor),
|
|
];
|
|
|
|
pub fn asset_path(&self) -> Option<&'static str> {
|
|
#[cfg(target_os = "macos")]
|
|
match self {
|
|
BaseKeymap::JetBrains => Some("keymaps/macos/jetbrains.json"),
|
|
BaseKeymap::SublimeText => Some("keymaps/macos/sublime_text.json"),
|
|
BaseKeymap::Atom => Some("keymaps/macos/atom.json"),
|
|
BaseKeymap::TextMate => Some("keymaps/macos/textmate.json"),
|
|
BaseKeymap::Emacs => Some("keymaps/macos/emacs.json"),
|
|
BaseKeymap::Cursor => Some("keymaps/macos/cursor.json"),
|
|
BaseKeymap::VSCode => None,
|
|
BaseKeymap::None => None,
|
|
}
|
|
|
|
#[cfg(not(target_os = "macos"))]
|
|
match self {
|
|
BaseKeymap::JetBrains => Some("keymaps/linux/jetbrains.json"),
|
|
BaseKeymap::SublimeText => Some("keymaps/linux/sublime_text.json"),
|
|
BaseKeymap::Atom => Some("keymaps/linux/atom.json"),
|
|
BaseKeymap::Emacs => Some("keymaps/linux/emacs.json"),
|
|
BaseKeymap::Cursor => Some("keymaps/linux/cursor.json"),
|
|
BaseKeymap::TextMate => None,
|
|
BaseKeymap::VSCode => None,
|
|
BaseKeymap::None => None,
|
|
}
|
|
}
|
|
|
|
pub fn names() -> impl Iterator<Item = &'static str> {
|
|
Self::OPTIONS.iter().map(|(name, _)| *name)
|
|
}
|
|
|
|
pub fn from_names(option: &str) -> BaseKeymap {
|
|
Self::OPTIONS
|
|
.iter()
|
|
.copied()
|
|
.find_map(|(name, value)| (name == option).then_some(value))
|
|
.unwrap_or_default()
|
|
}
|
|
}
|
|
|
|
#[derive(
|
|
Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Default, SettingsUi,
|
|
)]
|
|
// extracted so that it can be an option, and still work with derive(SettingsUi)
|
|
pub struct BaseKeymapSetting {
|
|
pub base_keymap: Option<BaseKeymap>,
|
|
}
|
|
|
|
impl Settings for BaseKeymap {
|
|
const KEY: Option<&'static str> = None;
|
|
|
|
type FileContent = BaseKeymapSetting;
|
|
|
|
fn load(
|
|
sources: SettingsSources<Self::FileContent>,
|
|
_: &mut gpui::App,
|
|
) -> anyhow::Result<Self> {
|
|
if let Some(Some(user_value)) = sources.user.map(|setting| setting.base_keymap) {
|
|
return Ok(user_value);
|
|
}
|
|
if let Some(Some(server_value)) = sources.server.map(|setting| setting.base_keymap) {
|
|
return Ok(server_value);
|
|
}
|
|
sources
|
|
.default
|
|
.base_keymap
|
|
.ok_or_else(Self::missing_default)
|
|
}
|
|
|
|
fn import_from_vscode(_vscode: &VsCodeSettings, current: &mut Self::FileContent) {
|
|
current.base_keymap = Some(BaseKeymap::VSCode);
|
|
}
|
|
}
|