-
Notifications
You must be signed in to change notification settings - Fork 157
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: migrate and extend history search #60
Conversation
The list length is hardcoded to 8. |
Having this preview list is awesome! From a maintenance perspective I am somewhat reserved towards pulling I/O into the History implementation. This makes dealing with different keybindings already tricky. If we could move the preview list as a separate modal widget running in the engine we could also use it for other purposes like completions or path jumplists. |
Currently the example binary starts in
|
Putting the logic back into the engine is fine. |
What is the polling behavior I am seing when using reedline? // src/engine.rs +866
loop {
if poll(Duration::from_secs(1))? {
match read()? {
Event::Key(KeyEvent { code, modifiers }) => {
match (modifiers, code, self.edit_mode) { When doing nothing reedline always prints at the end? |
This was added to update the time displayed in the prompt. |
When printing stuff |
If the cursor is positioned in the last line, this leads to scrolling of the screen because of some erroneous reprinting-logic? |
My primary concern when I factored the history into the The history itself will need some work to deal with the problem of having possibly multiple sessions, thus separation of data representation and output wouldn't hurt if we change the data structure again.
Currently
Having a seperate history search struct/trait object is not generally flawed and would definitely allow for customization. |
That's a good call how we could improve the repaints! Yes as soon as the cursor reaches the bottom additional chaos ensues. Especially when resizing the current solution is unsatisfying. |
I will start thinking how I can make the list-logic a reusable component. |
* This PR addresses this Issue nushell#55 * BasicSearch was removed * Additional features are an interactively displayed list, that is scrollable with CTRL-n/CTRL-r or CTRL-p * Maybe in the future make the displayed list optional? * The interactive_history_search has its own loop, handling input events, to make more complicated behavior easier maintainable and removing history_search_state from the main loop in `read_line_helper`
|
With these changes, the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is certainly a complex PR, kudos for your efforts. I feel like the interactions between the input handling, the business logic of handling the search with suggestions and the size aware output are stronger than they need to be.
With the changes @jonathandturner and @sherubthakur are discussing in #61 and #62 on the horizon, how can we get this merged without introducing too many sharp edges for the the refactor?
Can we break this up into:
- necessary state kept in the appropriate struct(s)
- that gets updated upon receiving EditCommands or a resize requirement with simple methods
- a special paint function that is active when searching and provides simply the visualization with the list.
prompt_origin: &mut (u16, u16), | ||
prompt_offset: (u16, u16), | ||
terminal_size: &mut (u16, u16), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we need to keep track of those in a number of places, why not make them members of the Reedline
engine? This would keep the API cleaner.
Additionally the EditCommands shouldn't modify the terminal size as only the resize event in the main event loop should need to set that and then maybe trigger components to provide a shrunk/expanded version of their content and then handle the relayout in the appropriate repaint.
match read()? { | ||
Event::Key(KeyEvent { code, modifiers }) => match (modifiers, code) { | ||
(KeyModifiers::NONE | KeyModifiers::SHIFT, KeyCode::Char(c)) => { | ||
search_string.push(c); | ||
#[rustfmt::skip] | ||
let rows = self.paint_interactive_search( &search_string, search_index, &mut history_index, &mut prompt_offset_rows, )?; | ||
(rows < 8 && search_index >= rows) | ||
.then(|| search_index = rows.saturating_sub(1)); | ||
} | ||
(KeyModifiers::NONE, KeyCode::Backspace) => { | ||
search_string.pop(); | ||
#[rustfmt::skip] | ||
let rows = self.paint_interactive_search( &search_string, search_index, &mut history_index, &mut prompt_offset_rows, )?; | ||
(rows < 8 && search_index >= rows) | ||
.then(|| search_index = rows.saturating_sub(1)); | ||
} | ||
(KeyModifiers::CONTROL, KeyCode::Char('n') | KeyCode::Char('r')) => { | ||
search_index += 1; | ||
#[rustfmt::skip] | ||
let rows = self.paint_interactive_search( &search_string, search_index, &mut history_index, &mut prompt_offset_rows, )?; | ||
(rows < 8 && search_index >= rows).then(|| search_index -= 1); | ||
} | ||
(KeyModifiers::CONTROL, KeyCode::Char('p')) => { | ||
search_index = search_index.saturating_sub(1); | ||
#[rustfmt::skip] | ||
self.paint_interactive_search( &search_string, search_index, &mut history_index, &mut prompt_offset_rows, )?; | ||
} | ||
(_, KeyCode::Enter) => { | ||
if let Some(idx) = history_index { | ||
self.line_buffer | ||
.set_buffer(self.history.get_nth_newest(idx).unwrap().clone()); | ||
self.line_buffer.move_to_end(); | ||
} | ||
// adjust the prompt_offset.1 from the main loop if needed | ||
*prompt_origin_row = prompt_origin_row.saturating_sub(prompt_offset_rows); | ||
return Ok(()); | ||
} | ||
(_, KeyCode::Esc) => { | ||
// adjust the prompt_offset.1 from the main loop if needed | ||
*prompt_origin_row = prompt_origin_row.saturating_sub(prompt_offset_rows); | ||
return Ok(()); | ||
} | ||
_ => {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we break this apart into the handlers of the appropriate EditCommand
s?
In this setup the arrow keys or abort with Ctrl+c
are not yet added but would be trivially mapped with EditCommand to the respective keybindings.
let mut search_results = items | ||
.enumerate() | ||
.skip(list_index.saturating_sub(7)) | ||
.filter(|(_, entry)| entry.as_ref().starts_with(&*search_string)) | ||
.enumerate() | ||
.take(8) | ||
.peekable(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't expect that the actual search takes place here. There rest of the function seems to be concerned with creating the string for the list visualization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I will call it run_search_and_build_list, because the filtering needs to be done repeatedly (on changes to the search_string) and the implementation depends on the different indices that are created through enumerate.
If I factor out even more functionality, only the pushing of the different entries to the list would be left.
let mut prompt_offset_rows = 0; | ||
let mut history_index = None; | ||
|
||
#[rustfmt::skip] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As soon as you have iterated on your signature, I don't think there is a reason to deviate from standard formatting.
I just looked at #62. |
Sure no problem! |
Thanks for the quick replies. |
I will integrate it after #62. |
#62 is mostly to discuss ideas, I would not recommend waiting on that PR. I would like to revisit that PR in the future, One of the things that I wanted to do was merging history and history search, and obviously will like it even more if someone else does it :P. So please go forward with this PR :) |
CTRL-n
/CTRL-r
orCTRL-p
reedline_history.mp4
I wrote this PR against an earlier version of reedline. Now, pressing
CTRL-r
doesn't bring up the history_search anymore?