Skip to content

Commit e3b7604

Browse files
committed
helix: add basic mode switching
1 parent 5c2f105 commit e3b7604

3 files changed

Lines changed: 82 additions & 32 deletions

File tree

examples/helix.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ fn main() -> io::Result<()> {
1111
println!("Helix edit mode demo:\nAbort with Ctrl-C");
1212

1313
let prompt = DefaultPrompt::default();
14-
let mut line_editor = Reedline::create().with_edit_mode(Box::new(Helix));
14+
let mut line_editor = Reedline::create().with_edit_mode(Box::new(Helix::default()));
1515

1616
loop {
1717
let sig = line_editor.read_line(&prompt)?;

src/edit_mode/helix.rs

Lines changed: 79 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,114 @@
11
use crate::{
2-
enums::{EventStatus, ReedlineEvent, ReedlineRawEvent},
2+
edit_mode::EditMode,
3+
enums::{ReedlineEvent, ReedlineRawEvent},
34
PromptEditMode, PromptViMode,
45
};
56
use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
67

7-
use super::EditMode;
8+
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
9+
enum HelixMode {
10+
#[default]
11+
Insert,
12+
Normal,
13+
}
814

915
/// A minimal custom edit mode example for Helix-style integrations.
1016
#[derive(Default)]
11-
pub struct Helix;
17+
pub struct Helix {
18+
mode: HelixMode,
19+
}
20+
21+
impl Helix {
22+
#[cfg(test)]
23+
pub(crate) fn insert() -> Self {
24+
Self {
25+
mode: HelixMode::Insert,
26+
}
27+
}
28+
29+
#[cfg(test)]
30+
pub(crate) fn normal() -> Self {
31+
Self {
32+
mode: HelixMode::Normal,
33+
}
34+
}
35+
}
1236

1337
impl EditMode for Helix {
1438
fn parse_event(&mut self, event: ReedlineRawEvent) -> ReedlineEvent {
15-
match Event::from(event) {
39+
match event.into() {
1640
Event::Key(KeyEvent {
17-
code: KeyCode::Char('c'),
18-
modifiers: KeyModifiers::CONTROL,
19-
..
20-
}) => ReedlineEvent::CtrlC,
41+
code, modifiers, ..
42+
}) => match (self.mode, modifiers, code) {
43+
(_, KeyModifiers::CONTROL, KeyCode::Char('c')) => ReedlineEvent::CtrlC,
44+
(HelixMode::Insert, _, KeyCode::Esc) => {
45+
self.mode = HelixMode::Normal;
46+
ReedlineEvent::Repaint
47+
}
48+
(HelixMode::Normal, _, KeyCode::Char('i')) => {
49+
self.mode = HelixMode::Insert;
50+
ReedlineEvent::Repaint
51+
}
52+
_ => ReedlineEvent::None,
53+
},
2154
_ => ReedlineEvent::None,
2255
}
2356
}
2457

2558
fn edit_mode(&self) -> PromptEditMode {
26-
PromptEditMode::Vi(PromptViMode::Normal)
27-
}
28-
29-
fn handle_mode_specific_event(&mut self, _event: ReedlineEvent) -> EventStatus {
30-
EventStatus::Inapplicable
59+
match self.mode {
60+
HelixMode::Insert => PromptEditMode::Vi(PromptViMode::Insert),
61+
HelixMode::Normal => PromptEditMode::Vi(PromptViMode::Normal),
62+
}
3163
}
3264
}
3365

3466
#[cfg(test)]
3567
mod tests {
3668
use super::*;
37-
use crate::PromptViMode;
69+
use crossterm::event::{KeyEventKind, KeyEventState};
3870

39-
#[test]
40-
fn helix_edit_mode_defaults_to_normal_mode() {
41-
let helix_mode = Helix;
71+
fn key_press(code: KeyCode, modifiers: KeyModifiers) -> ReedlineRawEvent {
72+
Event::Key(KeyEvent {
73+
code,
74+
modifiers,
75+
kind: KeyEventKind::Press,
76+
state: KeyEventState::NONE,
77+
})
78+
.try_into()
79+
.unwrap()
80+
}
4281

43-
let edit_mode = helix_mode.edit_mode();
82+
#[test]
83+
fn helix_editor_defaults_to_insert_mode() {
84+
let helix_editor = Helix::default();
4485

45-
assert!(matches!(
46-
edit_mode,
47-
PromptEditMode::Vi(PromptViMode::Normal)
48-
));
86+
assert_eq!(helix_editor.mode, HelixMode::Insert);
4987
}
5088

5189
#[test]
52-
fn helix_edit_mode_parses_ctrl_c_event() {
53-
let mut helix_mode = Helix;
54-
let ctrl_c_raw_event = ReedlineRawEvent::try_from(Event::Key(KeyEvent::new(
55-
KeyCode::Char('c'),
56-
KeyModifiers::CONTROL,
57-
)));
90+
fn normal_mode_parses_ctrl_c_event() {
91+
let mut helix_mode = Helix::normal();
5892

5993
assert_eq!(
60-
helix_mode.parse_event(ctrl_c_raw_event.unwrap()),
94+
helix_mode.parse_event(key_press(KeyCode::Char('c'), KeyModifiers::CONTROL)),
6195
ReedlineEvent::CtrlC
6296
);
6397
}
98+
99+
#[test]
100+
fn pressing_esc_in_insert_mode_switches_to_normal() {
101+
let mut helix_mode = Helix::insert();
102+
helix_mode.parse_event(key_press(KeyCode::Esc, KeyModifiers::NONE));
103+
104+
assert_eq!(helix_mode.mode, HelixMode::Normal);
105+
}
106+
107+
#[test]
108+
fn pressing_i_in_normal_mode_switches_to_insert() {
109+
let mut helix_mode = Helix::normal();
110+
helix_mode.parse_event(key_press(KeyCode::Char('i'), KeyModifiers::NONE));
111+
112+
assert_eq!(helix_mode.mode, HelixMode::Insert);
113+
}
64114
}

src/engine.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2320,11 +2320,11 @@ mod tests {
23202320
fn with_edit_mode_builder_accepts_custom_helix_mode() {
23212321
use crate::PromptViMode;
23222322

2323-
let reedline = Reedline::create().with_edit_mode(Box::new(crate::Helix));
2323+
let reedline = Reedline::create().with_edit_mode(Box::new(crate::Helix::insert()));
23242324

23252325
assert!(matches!(
23262326
reedline.prompt_edit_mode(),
2327-
PromptEditMode::Vi(PromptViMode::Normal)
2327+
PromptEditMode::Vi(PromptViMode::Insert)
23282328
));
23292329
}
23302330

0 commit comments

Comments
 (0)