Find with callback
This commit is contained in:
parent
b461804354
commit
dcd0c3bec1
102
src/editor.rs
102
src/editor.rs
@ -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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user