ViEditor: implement search, capture commands

This commit is contained in:
Jeremy Soller 2023-10-20 13:55:18 -06:00
parent 7526fa9726
commit c1e40363ab
No known key found for this signature in database
GPG key ID: DCFCA852D3906975

View file

@ -7,7 +7,7 @@ use crate::{
SyntaxEditor, SyntaxEditor,
}; };
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum ViMode { pub enum ViMode {
/// Passthrough mode, disables vi features /// Passthrough mode, disables vi features
Passthrough, Passthrough,
@ -16,15 +16,16 @@ pub enum ViMode {
/// Insert mode /// Insert mode
Insert, Insert,
/// Command mode /// Command mode
Command, Command { value: String },
/// Search mode /// Search mode
Search { forwards: bool }, Search { value: String, forwards: bool },
} }
#[derive(Debug)] #[derive(Debug)]
pub struct ViEditor<'a> { pub struct ViEditor<'a> {
editor: SyntaxEditor<'a>, editor: SyntaxEditor<'a>,
mode: ViMode, mode: ViMode,
search_opt: Option<(String, bool)>,
} }
impl<'a> ViEditor<'a> { impl<'a> ViEditor<'a> {
@ -32,6 +33,7 @@ impl<'a> ViEditor<'a> {
Self { Self {
editor, editor,
mode: ViMode::Normal, mode: ViMode::Normal,
search_opt: None,
} }
} }
@ -66,8 +68,66 @@ impl<'a> ViEditor<'a> {
} }
/// Get current vi editing mode /// Get current vi editing mode
pub fn mode(&self) -> ViMode { pub fn mode(&self) -> &ViMode {
self.mode &self.mode
}
fn search(&mut self, inverted: bool) {
let (search, mut forwards) = match &self.search_opt {
Some(some) => some,
None => return,
};
if inverted {
forwards = !forwards;
}
let mut cursor = self.cursor();
let start_line = cursor.line;
if forwards {
while cursor.line < self.buffer().lines.len() {
if let Some(index) = self.buffer().lines[cursor.line]
.text()
.match_indices(search.as_str())
.filter_map(|(i, _)| {
if cursor.line != start_line || i > cursor.index {
Some(i)
} else {
None
}
})
.next()
{
cursor.index = index;
self.set_cursor(cursor);
return;
}
cursor.line += 1;
}
} else {
cursor.line += 1;
while cursor.line > 0 {
cursor.line -= 1;
if let Some(index) = self.buffer().lines[cursor.line]
.text()
.rmatch_indices(search.as_str())
.filter_map(|(i, _)| {
if cursor.line != start_line || i < cursor.index {
Some(i)
} else {
None
}
})
.next()
{
cursor.index = index;
self.set_cursor(cursor);
return;
}
}
}
} }
} }
@ -113,7 +173,7 @@ impl<'a> Edit for ViEditor<'a> {
} }
fn action(&mut self, font_system: &mut FontSystem, action: Action) { fn action(&mut self, font_system: &mut FontSystem, action: Action) {
let old_mode = self.mode; let old_mode = self.mode.clone();
match self.mode { match self.mode {
ViMode::Passthrough => self.editor.action(font_system, action), ViMode::Passthrough => self.editor.action(font_system, action),
@ -203,6 +263,10 @@ impl<'a> Edit for ViEditor<'a> {
//TODO: 'L' => self.editor.action(Action::ScreenLow), //TODO: 'L' => self.editor.action(Action::ScreenLow),
// Middle of screen // Middle of screen
//TODO: 'M' => self.editor.action(Action::ScreenMiddle), //TODO: 'M' => self.editor.action(Action::ScreenMiddle),
// Next search item
'n' => self.search(false),
// Previous search item
'N' => self.search(true),
// Enter visual mode // Enter visual mode
'v' => { 'v' => {
if self.editor.select_opt().is_some() { if self.editor.select_opt().is_some() {
@ -244,15 +308,23 @@ impl<'a> Edit for ViEditor<'a> {
'^' => self.editor.action(font_system, Action::SoftHome), '^' => self.editor.action(font_system, Action::SoftHome),
// Enter command mode // Enter command mode
':' => { ':' => {
self.mode = ViMode::Command; self.mode = ViMode::Command {
value: String::new(),
};
} }
// Enter search mode // Enter search mode
'/' => { '/' => {
self.mode = ViMode::Search { forwards: true }; self.mode = ViMode::Search {
value: String::new(),
forwards: true,
};
} }
// Enter search backwards mode // Enter search backwards mode
'?' => { '?' => {
self.mode = ViMode::Search { forwards: false }; self.mode = ViMode::Search {
value: String::new(),
forwards: false,
};
} }
_ => (), _ => (),
}, },
@ -278,24 +350,47 @@ impl<'a> Edit for ViEditor<'a> {
} }
_ => self.editor.action(font_system, action), _ => self.editor.action(font_system, action),
}, },
ViMode::Command => match action { ViMode::Command { ref mut value } => match action {
Action::Escape => { Action::Escape => {
self.mode = ViMode::Normal; self.mode = ViMode::Normal;
} }
Action::Enter => {}
Action::Insert(c) => match c { Action::Insert(c) => match c {
_ => {} _ => {
value.push(c);
}
}, },
Action::Enter => {
//TODO: run command
self.mode = ViMode::Normal;
}
Action::Backspace => {
if value.pop().is_none() {
self.mode = ViMode::Normal;
}
}
_ => self.editor.action(font_system, action), _ => self.editor.action(font_system, action),
}, },
ViMode::Search { forwards } => match action { ViMode::Search {
ref mut value,
forwards,
} => match action {
Action::Escape => { Action::Escape => {
self.mode = ViMode::Normal; self.mode = ViMode::Normal;
} }
Action::Enter => {} Action::Insert(c) => {
Action::Insert(c) => match c { value.push(c);
_ => {} }
}, Action::Enter => {
//TODO: do not require clone?
self.search_opt = Some((value.clone(), forwards));
self.mode = ViMode::Normal;
self.search(false);
}
Action::Backspace => {
if value.pop().is_none() {
self.mode = ViMode::Normal;
}
}
_ => self.editor.action(font_system, action), _ => self.editor.action(font_system, action),
}, },
} }