summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorb3nj5m1n <47924309+b3nj5m1n@users.noreply.github.com>2022-05-24 22:44:12 +0200
committerGitHub <noreply@github.com>2022-05-24 20:44:12 +0000
commit9ac0c60cc48350dc5f23e821b3416581e9bb6a16 (patch)
tree78d533b8803ddb9511eda2c0fc797b772d200a62
parent119ab9e0079c4b3105598abb8a918bc1e6b86cec (diff)
Implement cursor (#412)
-rw-r--r--src/command/client/search.rs101
1 files changed, 86 insertions, 15 deletions
diff --git a/src/command/client/search.rs b/src/command/client/search.rs
index de6e7961..e1ee55d1 100644
--- a/src/command/client/search.rs
+++ b/src/command/client/search.rs
@@ -110,6 +110,8 @@ impl Cmd {
struct State {
input: String,
+ cursor_index: usize,
+
filter_mode: FilterMode,
results: Vec<History>,
@@ -277,6 +279,31 @@ async fn query_results(
Ok(())
}
+fn get_input_prefix(app: &mut State, i: usize) -> String {
+ return app.input.chars().take(i).collect();
+}
+fn get_input_suffix(app: &mut State, i: usize) -> String {
+ return app.input.chars().skip(i).collect();
+}
+
+fn insert_char_into_input(app: &mut State, i: usize, c: char) {
+ let mut result = String::from("");
+ result.push_str(&get_input_prefix(app, i));
+ result.push_str(&c.to_string());
+ result.push_str(&get_input_suffix(app, i));
+ app.input = result;
+}
+
+fn remove_char_from_input(app: &mut State, i: usize) -> char {
+ let mut result = String::from("");
+ result.push_str(&get_input_prefix(app, i - 1));
+ result.push_str(&get_input_suffix(app, i));
+ let c = app.input.chars().nth(i - 1).unwrap();
+ app.input = result;
+ c
+}
+
+#[allow(clippy::too_many_lines)]
async fn key_handler(
input: Key,
search_mode: SearchMode,
@@ -304,29 +331,56 @@ async fn key_handler(
.map_or(app.input.clone(), |h| h.command.clone()),
);
}
+ Key::Left | Key::Ctrl('h') => {
+ if app.cursor_index != 0 {
+ app.cursor_index -= 1;
+ }
+ }
+ Key::Right | Key::Ctrl('l') => {
+ if app.cursor_index < app.input.width() {
+ app.cursor_index += 1;
+ }
+ }
+ Key::Ctrl('a') => {
+ app.cursor_index = 0;
+ }
+ Key::Ctrl('e') => {
+ app.cursor_index = app.input.chars().count();
+ }
Key::Char(c) => {
- app.input.push(c);
+ insert_char_into_input(app, app.cursor_index, c);
+ app.cursor_index += 1;
query_results(app, search_mode, db).await.unwrap();
}
Key::Backspace => {
- app.input.pop();
- query_results(app, search_mode, db).await.unwrap();
- }
- // \u{7f} is escape sequence for backspace
- Key::Alt('\u{7f}') => {
- let words: Vec<&str> = app.input.split(' ').collect();
- if words.is_empty() {
+ if app.cursor_index == 0 {
return None;
}
- if words.len() == 1 {
- app.input = String::from("");
- } else {
- app.input = words[0..(words.len() - 1)].join(" ");
+ remove_char_from_input(app, app.cursor_index);
+ app.cursor_index -= 1;
+ query_results(app, search_mode, db).await.unwrap();
+ }
+ Key::Ctrl('w') => {
+ let mut stop_on_next_whitespace = false;
+ loop {
+ if app.cursor_index == 0 {
+ break;
+ }
+ if app.input.chars().nth(app.cursor_index - 1) == Some(' ')
+ && stop_on_next_whitespace
+ {
+ break;
+ }
+ if !remove_char_from_input(app, app.cursor_index).is_whitespace() {
+ stop_on_next_whitespace = true;
+ }
+ app.cursor_index -= 1;
}
query_results(app, search_mode, db).await.unwrap();
}
Key::Ctrl('u') => {
app.input = String::from("");
+ app.cursor_index = 0;
query_results(app, search_mode, db).await.unwrap();
}
Key::Ctrl('r') => {
@@ -442,9 +496,16 @@ fn draw<T: Backend>(f: &mut Frame<'_, T>, history_count: i64, app: &mut State) {
);
f.render_widget(input, chunks[2]);
+ let width = UnicodeWidthStr::width(
+ app.input
+ .chars()
+ .take(app.cursor_index)
+ .collect::<String>()
+ .as_str(),
+ );
f.set_cursor(
// Put cursor past the end of the input text
- chunks[2].x + app.input.width() as u16 + 1,
+ chunks[2].x + width as u16 + 1,
// Move one line down, from the border to the input line
chunks[2].y + 1,
);
@@ -514,7 +575,13 @@ fn draw_compact<T: Backend>(f: &mut Frame<'_, T>, history_count: i64, app: &mut
app.render_results(f, chunks[1], Block::default());
f.render_widget(input, chunks[2]);
- let extra_width = app.input.width() + filter_mode.len();
+ let extra_width = UnicodeWidthStr::width(
+ app.input
+ .chars()
+ .take(app.cursor_index)
+ .collect::<String>()
+ .as_str(),
+ ) + filter_mode.len();
f.set_cursor(
// Put cursor past the end of the input text
@@ -544,8 +611,12 @@ async fn select_history(
// Setup event handlers
let events = Events::new();
+ let input = query.join(" ");
+ // Put the cursor at the end of the query by default
+ let cursor_index = input.chars().count();
let mut app = State {
- input: query.join(" "),
+ input,
+ cursor_index,
results: Vec::new(),
results_state: ListState::default(),
context: current_context(),