1use std::fmt::{Display, Formatter};
2
3use crate::{
4 self as settings,
5 settings_content::{self, BaseKeymapContent, SettingsContent},
6};
7use gpui::App;
8use schemars::JsonSchema;
9use serde::{Deserialize, Serialize};
10use settings::{Settings, VsCodeSettings};
11use settings_ui_macros::{SettingsKey, SettingsUi};
12
13/// Base key bindings scheme. Base keymaps can be overridden with user keymaps.
14///
15/// Default: VSCode
16#[derive(
17 Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Default, SettingsUi,
18)]
19pub enum BaseKeymap {
20 #[default]
21 VSCode,
22 JetBrains,
23 SublimeText,
24 Atom,
25 TextMate,
26 Emacs,
27 Cursor,
28 None,
29}
30
31impl From<BaseKeymapContent> for BaseKeymap {
32 fn from(value: BaseKeymapContent) -> Self {
33 match value {
34 BaseKeymapContent::VSCode => Self::VSCode,
35 BaseKeymapContent::JetBrains => Self::JetBrains,
36 BaseKeymapContent::SublimeText => Self::SublimeText,
37 BaseKeymapContent::Atom => Self::Atom,
38 BaseKeymapContent::TextMate => Self::TextMate,
39 BaseKeymapContent::Emacs => Self::Emacs,
40 BaseKeymapContent::Cursor => Self::Cursor,
41 BaseKeymapContent::None => Self::None,
42 }
43 }
44}
45impl Into<BaseKeymapContent> for BaseKeymap {
46 fn into(self) -> BaseKeymapContent {
47 match self {
48 BaseKeymap::VSCode => BaseKeymapContent::VSCode,
49 BaseKeymap::JetBrains => BaseKeymapContent::JetBrains,
50 BaseKeymap::SublimeText => BaseKeymapContent::SublimeText,
51 BaseKeymap::Atom => BaseKeymapContent::Atom,
52 BaseKeymap::TextMate => BaseKeymapContent::TextMate,
53 BaseKeymap::Emacs => BaseKeymapContent::Emacs,
54 BaseKeymap::Cursor => BaseKeymapContent::Cursor,
55 BaseKeymap::None => BaseKeymapContent::None,
56 }
57 }
58}
59
60impl Display for BaseKeymap {
61 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
62 match self {
63 BaseKeymap::VSCode => write!(f, "VSCode"),
64 BaseKeymap::JetBrains => write!(f, "JetBrains"),
65 BaseKeymap::SublimeText => write!(f, "Sublime Text"),
66 BaseKeymap::Atom => write!(f, "Atom"),
67 BaseKeymap::TextMate => write!(f, "TextMate"),
68 BaseKeymap::Emacs => write!(f, "Emacs (beta)"),
69 BaseKeymap::Cursor => write!(f, "Cursor (beta)"),
70 BaseKeymap::None => write!(f, "None"),
71 }
72 }
73}
74
75impl BaseKeymap {
76 #[cfg(target_os = "macos")]
77 pub const OPTIONS: [(&'static str, Self); 7] = [
78 ("VSCode (Default)", Self::VSCode),
79 ("Atom", Self::Atom),
80 ("JetBrains", Self::JetBrains),
81 ("Sublime Text", Self::SublimeText),
82 ("Emacs (beta)", Self::Emacs),
83 ("TextMate", Self::TextMate),
84 ("Cursor", Self::Cursor),
85 ];
86
87 #[cfg(not(target_os = "macos"))]
88 pub const OPTIONS: [(&'static str, Self); 6] = [
89 ("VSCode (Default)", Self::VSCode),
90 ("Atom", Self::Atom),
91 ("JetBrains", Self::JetBrains),
92 ("Sublime Text", Self::SublimeText),
93 ("Emacs (beta)", Self::Emacs),
94 ("Cursor", Self::Cursor),
95 ];
96
97 pub fn asset_path(&self) -> Option<&'static str> {
98 #[cfg(target_os = "macos")]
99 match self {
100 BaseKeymap::JetBrains => Some("keymaps/macos/jetbrains.json"),
101 BaseKeymap::SublimeText => Some("keymaps/macos/sublime_text.json"),
102 BaseKeymap::Atom => Some("keymaps/macos/atom.json"),
103 BaseKeymap::TextMate => Some("keymaps/macos/textmate.json"),
104 BaseKeymap::Emacs => Some("keymaps/macos/emacs.json"),
105 BaseKeymap::Cursor => Some("keymaps/macos/cursor.json"),
106 BaseKeymap::VSCode => None,
107 BaseKeymap::None => None,
108 }
109
110 #[cfg(not(target_os = "macos"))]
111 match self {
112 BaseKeymap::JetBrains => Some("keymaps/linux/jetbrains.json"),
113 BaseKeymap::SublimeText => Some("keymaps/linux/sublime_text.json"),
114 BaseKeymap::Atom => Some("keymaps/linux/atom.json"),
115 BaseKeymap::Emacs => Some("keymaps/linux/emacs.json"),
116 BaseKeymap::Cursor => Some("keymaps/linux/cursor.json"),
117 BaseKeymap::TextMate => None,
118 BaseKeymap::VSCode => None,
119 BaseKeymap::None => None,
120 }
121 }
122
123 pub fn names() -> impl Iterator<Item = &'static str> {
124 Self::OPTIONS.iter().map(|(name, _)| *name)
125 }
126
127 pub fn from_names(option: &str) -> BaseKeymap {
128 Self::OPTIONS
129 .iter()
130 .copied()
131 .find_map(|(name, value)| (name == option).then_some(value))
132 .unwrap_or_default()
133 }
134}
135
136#[derive(
137 Copy,
138 Clone,
139 Debug,
140 Serialize,
141 Deserialize,
142 JsonSchema,
143 PartialEq,
144 Eq,
145 Default,
146 SettingsUi,
147 SettingsKey,
148)]
149// extracted so that it can be an option, and still work with derive(SettingsUi)
150#[settings_key(None)]
151pub struct BaseKeymapSetting {
152 pub base_keymap: Option<BaseKeymap>,
153}
154
155impl Settings for BaseKeymap {
156 fn from_defaults(s: &crate::settings_content::SettingsContent, _cx: &mut App) -> Self {
157 s.base_keymap.unwrap().into()
158 }
159
160 fn refine(&mut self, s: &settings_content::SettingsContent, _cx: &mut App) {
161 if let Some(base_keymap) = s.base_keymap {
162 *self = base_keymap.into();
163 };
164 }
165
166 fn import_from_vscode(_vscode: &VsCodeSettings, current: &mut SettingsContent) {
167 current.base_keymap = Some(BaseKeymapContent::VSCode);
168 }
169}