Find with callback

This commit is contained in:
Timothy Warren 2019-09-03 16:19:19 -04:00
parent b461804354
commit dcd0c3bec1
2 changed files with 97 additions and 7 deletions

View File

@ -278,8 +278,15 @@ impl Editor {
// Input
// ------------------------------------------------------------------------
fn prompt(&mut self, prompt: &str) -> String {
fn prompt(&mut self, prompt: &str, cb: Option<&mut dyn Fn(&mut Self, &str, EditorKey<char>)>) -> String {
let mut buffer = String::new();
let default_cb = &mut Self::_noop_prompt_cb;
let cb = if cb.is_some() {
cb.unwrap()
} else {
default_cb
};
loop {
self.set_status_message(&format!("{} {}", prompt, buffer));
@ -297,26 +304,32 @@ impl Editor {
},
Escape => {
self.set_status_message("");
cb(self, &String::from(""), char);
return String::from("");
}
Enter => {
if buffer.len() != 0 {
self.set_status_message("");
cb(self, &buffer, char);
return buffer;
}
}
OtherKey(ch) => {
if (!ch.is_ascii_control()) && (ch as u8) < 128 {
buffer.push(ch);
continue;
// continue;
}
}
_ => (),
};
cb(self, &buffer, char);
}
}
}
fn _noop_prompt_cb(&mut self, _: &str, _: EditorKey<char>) {}
fn move_cursor(&mut self, key: &EditorKey<char>) {
let row = self.rows.get(self.cursor_y);
match key {
@ -394,6 +407,10 @@ impl Editor {
Function(_) => (),
OtherKey(c) => {
if c.is_ascii_control() {
if c == ctrl_key('f') {
self.find();
}
if c == ctrl_key('q') {
if self.dirty > 0 && self.quit_times > 0 {
self.set_status_message(&format!("WARNING!!! File has unsaved changes. Press Ctrl-Q {} more times to quit.", self.quit_times));
@ -482,7 +499,7 @@ impl Editor {
fn scroll(&mut self) {
self.render_x = 0;
if self.cursor_y < self.rows.len() {
self.render_x = self.row_cx_to_rx(self.cursor_y);
self.render_x = self.row_cx_to_rx(self.cursor_y, self.cursor_x);
}
// Vertical scrolling
@ -643,20 +660,50 @@ impl Editor {
// Row Operations
// ------------------------------------------------------------------------
fn row_cx_to_rx(&mut self, index: usize) -> usize {
fn row_cx_to_rx(&mut self, index: usize, cx: usize) -> usize {
let mut rx: usize = 0;
let mut i: usize = 0;
let row = &mut self.rows[index];
for char in row.chars.chars() {
if char == '\t' {
rx += (KILO_TAB_STOP - 1) - (rx % KILO_TAB_STOP);
} else {
rx += 1;
}
rx += 1;
if i > cx {
return rx;
}
i += 1;
}
rx
}
fn row_rx_to_cx(&mut self, index: usize, rx: usize) -> usize {
let mut current_rx:usize = 0;
let mut cx: usize = 0;
let row = &mut self.rows[index];
for char in row.chars.chars() {
if char == '\t' {
current_rx += (KILO_TAB_STOP - 1) - (current_rx % KILO_TAB_STOP);
} else {
current_rx += 1;
}
if current_rx > rx {
return cx;
}
cx += 1;
}
cx
}
/// Convert tab characters to spaces for display
fn update_row(&mut self, index: usize) {
let row = &mut self.rows[index];
@ -820,7 +867,7 @@ impl Editor {
fn save(&mut self) -> io::Result<()> {
if self.filename.len() == 0 {
self.filename = self.prompt("Save as (ESC to cancel):");
self.filename = self.prompt("Save as (ESC to cancel):", None);
if self.filename.len() == 0 {
self.set_status_message("Save aborted");
return Ok(())
@ -845,4 +892,47 @@ impl Editor {
Ok(())
}
// ------------------------------------------------------------------------
// Find
// ------------------------------------------------------------------------
fn find_callback(&mut self, query: &str, key: EditorKey<char>) {
if key == Enter || key == Escape {
return;
}
if query.is_empty() {
return;
}
for x in 0..self.rows.len() {
match self.rows[x].render.find(query) {
None => (),
Some(start) => {
self.cursor_y = x;
self.cursor_x = self.row_rx_to_cx(x, start);
self.row_offset = self.rows.len();
break;
}
}
}
}
fn find(&mut self) {
let saved_cx = self.cursor_x;
let saved_cy = self.cursor_y;
let saved_coloff = self.col_offset;
let saved_rowoff = self.row_offset;
let query = self.prompt("Search (ESC to cancel):", Some(&mut Self::find_callback));
if query.is_empty() {
self.cursor_x = saved_cx;
self.cursor_y = saved_cy;
self.col_offset = saved_coloff;
self.row_offset = saved_rowoff;
}
}
}

View File

@ -25,7 +25,7 @@ fn main() -> Result<(), Error> {
editor.open(&args[1])?;
}
editor.set_status_message("HELP: Ctrl-S = save | Ctrl-Q = quit");
editor.set_status_message("HELP: Ctrl-S = save | Ctrl-Q = quit | Ctrl-F = find");
// Main input loop. Editor::process_keypress uses an Option Enum as a sentinel.
// `None` is returned on a quit action, in other cases, `Some(())` is returned,