1use reovim_kernel::api::v1::{CursorStyle, Mode, ModeId, ModuleId};
30
31pub const VIM_MODULE: ModuleId = ModuleId::new("vim");
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
42#[repr(u16)]
43pub enum VimMode {
44 Normal = 0,
46 Insert = 1,
48 Visual = 2,
50 VisualLine = 3,
52 VisualBlock = 4,
54 Replace = 5,
56 CommandLine = 6,
58 Window = 8,
60 Delete = 9,
62 Yank = 10,
64 Change = 11,
66 Lowercase = 12,
68 Uppercase = 13,
70 ToggleCase = 14,
72}
73
74impl VimMode {
75 pub const ALL: &'static [Self] = &[
77 Self::Normal,
78 Self::Insert,
79 Self::Visual,
80 Self::VisualLine,
81 Self::VisualBlock,
82 Self::Replace,
83 Self::CommandLine,
84 Self::Window,
85 Self::Delete,
86 Self::Yank,
87 Self::Change,
88 Self::Lowercase,
89 Self::Uppercase,
90 Self::ToggleCase,
91 ];
92
93 pub const NORMAL_ID: ModeId = ModeId::with_discriminant(VIM_MODULE, "normal", 0);
99
100 pub const INSERT_ID: ModeId = ModeId::with_discriminant(VIM_MODULE, "insert", 1);
102
103 pub const VISUAL_ID: ModeId = ModeId::with_discriminant(VIM_MODULE, "visual", 2);
105
106 pub const VISUAL_LINE_ID: ModeId = ModeId::with_discriminant(VIM_MODULE, "visual-line", 3);
108
109 pub const VISUAL_BLOCK_ID: ModeId = ModeId::with_discriminant(VIM_MODULE, "visual-block", 4);
111
112 pub const REPLACE_ID: ModeId = ModeId::with_discriminant(VIM_MODULE, "replace", 5);
114
115 pub const COMMANDLINE_ID: ModeId = ModeId::with_discriminant(VIM_MODULE, "command", 6);
117
118 pub const WINDOW_ID: ModeId = ModeId::with_discriminant(VIM_MODULE, "window", 8);
120
121 pub const DELETE_ID: ModeId = ModeId::with_discriminant(VIM_MODULE, "delete", 9);
123
124 pub const YANK_ID: ModeId = ModeId::with_discriminant(VIM_MODULE, "yank", 10);
126
127 pub const CHANGE_ID: ModeId = ModeId::with_discriminant(VIM_MODULE, "change", 11);
129
130 pub const LOWERCASE_ID: ModeId = ModeId::with_discriminant(VIM_MODULE, "lowercase", 12);
132
133 pub const UPPERCASE_ID: ModeId = ModeId::with_discriminant(VIM_MODULE, "uppercase", 13);
135
136 pub const TOGGLE_CASE_ID: ModeId = ModeId::with_discriminant(VIM_MODULE, "toggle-case", 14);
138}
139
140impl Mode for VimMode {
141 fn module() -> ModuleId {
142 VIM_MODULE
143 }
144
145 fn discriminant(&self) -> u16 {
146 *self as u16
147 }
148
149 fn id(&self) -> ModeId {
150 let name = match self {
153 Self::Normal => "normal",
154 Self::Insert => "insert",
155 Self::Visual => "visual",
156 Self::VisualLine => "visual-line",
157 Self::VisualBlock => "visual-block",
158 Self::Replace => "replace",
159 Self::CommandLine => "command",
160 Self::Window => "window",
161 Self::Delete => "delete",
162 Self::Yank => "yank",
163 Self::Change => "change",
164 Self::Lowercase => "lowercase",
165 Self::Uppercase => "uppercase",
166 Self::ToggleCase => "toggle-case",
167 };
168 ModeId::with_discriminant(VIM_MODULE, name, self.discriminant())
169 }
170
171 fn display_name(&self) -> &'static str {
172 match self {
174 Self::Normal => "NORMAL",
175 Self::Insert => "INSERT",
176 Self::Visual => "VISUAL",
177 Self::VisualLine => "V-LINE",
178 Self::VisualBlock => "V-BLOCK",
179 Self::Replace => "REPLACE",
180 Self::CommandLine => "COMMAND",
181 Self::Window => "WINDOW",
182 Self::Delete => "DELETE",
183 Self::Yank => "YANK",
184 Self::Change => "CHANGE",
185 Self::Lowercase => "LOWERCASE",
186 Self::Uppercase => "UPPERCASE",
187 Self::ToggleCase => "TOGGLE-CASE",
188 }
189 }
190
191 fn cursor_style(&self) -> CursorStyle {
192 match self {
193 Self::Normal | Self::Visual | Self::VisualLine | Self::VisualBlock => {
194 CursorStyle::Block
195 }
196 Self::Insert | Self::CommandLine => CursorStyle::Bar,
197 Self::Replace => CursorStyle::Underline,
198 Self::Window
199 | Self::Delete
200 | Self::Yank
201 | Self::Change
202 | Self::Lowercase
203 | Self::Uppercase
204 | Self::ToggleCase => CursorStyle::Block,
205 }
206 }
207
208 fn accepts_char_input(&self) -> bool {
209 matches!(self, Self::Insert | Self::Replace | Self::CommandLine)
210 }
211
212 fn has_selection(&self) -> bool {
213 matches!(self, Self::Visual | Self::VisualLine | Self::VisualBlock)
214 }
215
216 fn inherits_from(&self) -> Option<Self> {
217 match self {
218 Self::Window
220 | Self::Delete
221 | Self::Yank
222 | Self::Change
223 | Self::Lowercase
224 | Self::Uppercase
225 | Self::ToggleCase
226 | Self::Visual => Some(Self::Normal),
227 Self::VisualLine | Self::VisualBlock => Some(Self::Visual),
228 Self::Replace => Some(Self::Insert),
229 Self::Normal | Self::Insert | Self::CommandLine => None,
230 }
231 }
232
233 fn is_entry(&self) -> bool {
234 matches!(self, Self::Normal)
235 }
236}