1use std::borrow::Cow;
2use std::collections::HashMap;
3
4use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
5use lazy_static::lazy_static;
6
7use crate::keymap::KeyMap;
8use crate::operations as ops;
9use crate::selection::Direction;
10use crate::{
11 cmd_count, modes,
12 modes::mode::{DirtyBytes, Mode, ModeTransition},
13 Buffers,
14};
15
16use super::insert::InsertionMode;
17
18#[derive(Debug, PartialEq, Eq, Clone, Copy)]
19pub struct Normal {
20 count_state: cmd_count::State,
21}
22
23#[derive(Debug, PartialEq, Clone, Copy)]
24enum Action {
25 Move(Direction),
26 Extend(Direction),
27 SplitMode,
28 JumpToMode,
29 ExtendToMode,
30 CollapseMode { hex: bool },
31 CommandMode,
32 SwapCaret,
33 CollapseSelection,
34 Delete { register: char },
35 Yank { register: char },
36 Paste { after: bool, register: char },
37 Change { hex: bool, register: char },
38 Insert { hex: bool },
39 Append { hex: bool },
40 Overwrite { hex: bool },
41 RemoveMain,
42 RetainMain,
43 SelectPrev,
44 SelectNext,
45 SelectAll,
46 ReplaceMode { hex: bool },
47 Measure,
48 Undo,
49 Redo,
50}
51
52fn default_maps() -> KeyMap<Action> {
53 KeyMap {
54 maps: keys!(
55 ('h' => Action::Move(Direction::Left)),
56 (key KeyCode::Left => Action::Move(Direction::Left)),
57 ('j' => Action::Move(Direction::Down)),
58 (key KeyCode::Down => Action::Move(Direction::Down)),
59 ('k' => Action::Move(Direction::Up)),
60 (key KeyCode::Up => Action::Move(Direction::Up)),
61 ('l' => Action::Move(Direction::Right)),
62 (key KeyCode::Right => Action::Move(Direction::Right)),
63 ('H' => Action::Extend(Direction::Left)),
64 ('J' => Action::Extend(Direction::Down)),
65 ('K' => Action::Extend(Direction::Up)),
66 ('L' => Action::Extend(Direction::Right)),
67 ('g' => Action::JumpToMode),
68 ('G' => Action::ExtendToMode),
69 (alt 's' => Action::SplitMode),
70 (':' => Action::CommandMode),
71 (';' => Action::CollapseSelection),
72 (alt ';' => Action::SwapCaret),
73 ('%' => Action::SelectAll),
74 (' ' => Action::RetainMain),
75 (alt ' ' => Action::RemoveMain),
76 ('(' => Action::SelectPrev),
77 (')' => Action::SelectNext),
78 ('M' => Action::Measure),
79 ('u' => Action::Undo),
80 ('U' => Action::Redo),
81
82 ('p' => Action::Paste{after: true, register: '"'}),
83 ('P' => Action::Paste{after: false, register: '"'}),
84 ('d' => Action::Delete{register: '"'}),
85 ('y' => Action::Yank{register: '"'}),
86 ('c' => Action::Change{hex: false, register: '"'}),
87 ('C' => Action::Change{hex: true, register: '"'}),
88
89 ('i' => Action::Insert{hex: false}),
90 ('I' => Action::Insert{hex: true}),
91 ('a' => Action::Append{hex: false}),
92 ('A' => Action::Append{hex: true}),
93 ('r' => Action::ReplaceMode{hex: false}),
94 ('R' => Action::ReplaceMode{hex: true}),
95 ('o' => Action::Overwrite{hex: false}),
96 ('O' => Action::Overwrite{hex: true}),
97
98 ('s' => Action::CollapseMode{hex: false}),
99 ('S' => Action::CollapseMode{hex: true})
100 ),
101 }
102}
103
104lazy_static! {
105 static ref DEFAULT_MAPS: KeyMap<Action> = default_maps();
106}
107
108impl Mode for Normal {
109 fn name(&self) -> Cow<'static, str> {
110 format!("NORMAL{}", self.count_state).into()
111 }
112
113 fn transition(
114 &self,
115 event: &Event,
116 buffers: &mut Buffers,
117 bytes_per_line: usize,
118 ) -> Option<ModeTransition> {
119 let buffer = buffers.current_mut();
120 if let cmd_count::Transition::Update(new_state) = self.count_state.transition(event) {
121 Some(ModeTransition::new_mode(Normal {
122 count_state: new_state,
123 }))
124 } else if let Some(action) = DEFAULT_MAPS.event_to_action(event) {
125 Some(match action {
126 Action::JumpToMode => match self.count_state {
127 cmd_count::State::None => {
128 ModeTransition::new_mode(modes::jumpto::JumpTo { extend: false })
129 }
130 cmd_count::State::Some { count: offset, .. } => {
131 ModeTransition::new_mode_and_dirty(
132 Normal::new(),
133 buffer.map_selections(|region| vec![region.jump_to(offset)]),
134 )
135 }
136 },
137 Action::ExtendToMode => match self.count_state {
138 cmd_count::State::None => {
139 ModeTransition::new_mode(modes::jumpto::JumpTo { extend: true })
140 }
141 cmd_count::State::Some { count: offset, .. } => {
142 ModeTransition::new_mode_and_dirty(
143 Normal::new(),
144 buffer.map_selections(|region| vec![region.extend_to(offset)]),
145 )
146 }
147 },
148 Action::SplitMode => ModeTransition::new_mode(modes::split::Split::new()),
149 Action::Insert { hex } => ModeTransition::new_mode_and_dirty(
150 modes::insert::Insert {
151 hex,
152 mode: InsertionMode::Insert,
153 hex_half: None,
154 },
155 buffer.map_selections(|region| vec![region.to_backward()]),
156 ),
157 Action::Append { hex } => ModeTransition::new_mode_and_dirty(
158 modes::insert::Insert {
159 hex,
160 mode: InsertionMode::Append,
161 hex_half: None,
162 },
163 {
164 let max_size = buffer.data.len();
165 buffer.map_selections(|region| {
166 vec![region.to_forward().simple_extend(
167 Direction::Right,
168 bytes_per_line,
169 max_size,
170 1,
171 )]
172 })
173 },
174 ),
175 Action::ReplaceMode { hex } => ModeTransition::new_mode(modes::replace::Replace {
176 hex,
177 hex_half: None,
178 }),
179 Action::Overwrite { hex } => ModeTransition::new_mode(modes::insert::Insert {
180 hex,
181 mode: InsertionMode::Overwrite,
182 hex_half: None,
183 }),
184 Action::Move(direction) => {
185 let max_bytes = buffer.data.len();
186 ModeTransition::new_mode_and_dirty(
187 Normal::new(),
188 buffer.map_selections(|region| {
189 vec![region.simple_move(
190 direction,
191 bytes_per_line,
192 max_bytes,
193 self.count_state.to_count(),
194 )]
195 }),
196 )
197 }
198 Action::Extend(direction) => {
199 let max_bytes = buffer.data.len();
200 ModeTransition::new_mode_and_dirty(
201 Normal::new(),
202 buffer.map_selections(|region| {
203 vec![region.simple_extend(
204 direction,
205 bytes_per_line,
206 max_bytes,
207 self.count_state.to_count(),
208 )]
209 }),
210 )
211 }
212 Action::SwapCaret => ModeTransition::DirtyBytes(
213 buffer.map_selections(|region| vec![region.swap_caret()]),
214 ),
215 Action::CollapseSelection => ModeTransition::DirtyBytes(
216 buffer.map_selections(|region| vec![region.collapse()]),
217 ),
218 Action::Delete { register } => {
219 buffer.yank_selections(register);
220 if !buffer.data.is_empty() {
221 let delta = ops::deletion(&buffer.data, &buffer.selection);
222 ModeTransition::DirtyBytes(buffer.apply_delta(delta))
223 } else {
224 ModeTransition::None
225 }
226 }
227 Action::Change { hex, register } => {
228 buffer.yank_selections(register);
229 if !buffer.data.is_empty() {
230 let delta = ops::deletion(&buffer.data, &buffer.selection);
231 ModeTransition::new_mode_and_dirty(
232 modes::insert::Insert {
233 hex,
234 mode: InsertionMode::Insert,
235 hex_half: None,
236 },
237 buffer.apply_delta(delta),
238 )
239 } else {
240 ModeTransition::new_mode(modes::insert::Insert {
241 hex,
242 mode: InsertionMode::Insert,
243 hex_half: None,
244 })
245 }
246 }
247 Action::Yank { register } => {
248 buffer.yank_selections(register);
249 ModeTransition::None
250 }
251 Action::Paste { register, after } => {
252 let delta = ops::paste(
253 &buffer.data,
254 &buffer.selection,
255 buffer.registers.get(®ister).unwrap_or(&vec![vec![]]),
256 after,
257 self.count_state.to_count(),
258 );
259 ModeTransition::DirtyBytes(buffer.apply_delta(delta))
260 }
261 Action::RemoveMain => match self.count_state {
264 cmd_count::State::Some { count, .. } if count > 0 => {
265 ModeTransition::new_mode_and_dirty(
266 Normal::new(),
267 buffer.remove_selection(count - 1),
268 )
269 }
270 _ => ModeTransition::DirtyBytes(
271 buffer.remove_selection(buffer.selection.main_selection),
272 ),
273 },
274 Action::RetainMain => match self.count_state {
275 cmd_count::State::Some { count, .. } if count > 0 => {
276 ModeTransition::new_mode_and_dirty(
277 Normal::new(),
278 buffer.retain_selection(count - 1),
279 )
280 }
281 _ => ModeTransition::DirtyBytes(
282 buffer.retain_selection(buffer.selection.main_selection),
283 ),
284 },
285
286 Action::SelectNext => ModeTransition::new_mode_and_dirty(
288 Normal::new(),
289 buffer.select_next(self.count_state.to_count()),
290 ),
291 Action::SelectPrev => ModeTransition::new_mode_and_dirty(
292 Normal::new(),
293 buffer.select_prev(self.count_state.to_count()),
294 ),
295 Action::SelectAll => {
296 buffer.selection.select_all(buffer.data.len());
297 ModeTransition::DirtyBytes(DirtyBytes::ChangeInPlace(vec![(0..buffer
298 .data
299 .len())
300 .into()]))
301 }
302 Action::CollapseMode { hex } => ModeTransition::new_mode(
303 modes::search::Search::new(modes::collapse::Collapse(), hex),
304 ),
305 Action::Measure => ModeTransition::new_mode_and_info(
306 Normal::new(),
307 format!(
308 "{} = 0x{:x} bytes",
309 buffer.selection.main().len(),
310 buffer.selection.main().len()
311 ),
312 ),
313 Action::CommandMode => ModeTransition::new_mode(modes::command::Command::new()),
314 Action::Undo => buffer.perform_undo().map_or_else(
315 || {
316 ModeTransition::new_mode_and_info(
317 Normal::new(),
318 "nothing left to undo".to_owned(),
319 )
320 },
321 |dirty| ModeTransition::new_mode_and_dirty(Normal::new(), dirty),
322 ),
323 Action::Redo => buffer.perform_redo().map_or_else(
324 || {
325 ModeTransition::new_mode_and_info(
326 Normal::new(),
327 "nothing left to redo".to_owned(),
328 )
329 },
330 |dirty| ModeTransition::new_mode_and_dirty(Normal::new(), dirty),
331 ),
332 })
333 } else {
334 None
335 }
336 }
337 fn as_any(&self) -> &dyn std::any::Any {
338 self
339 }
340}
341
342impl Normal {
343 pub fn new() -> Normal {
344 Normal {
345 count_state: cmd_count::State::None,
346 }
347 }
348}