Implement cursor (#412)
This commit is contained in:
parent
119ab9e007
commit
9ac0c60cc4
1 changed files with 86 additions and 15 deletions
|
@ -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(),
|
||||
|
|
Loading…
Reference in a new issue