mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-14 14:03:58 +00:00
Move readline loop state into reader state
To be used by the next commit.
This commit is contained in:
parent
f9bdad3f77
commit
9d7116c12d
1 changed files with 93 additions and 58 deletions
151
src/reader.rs
151
src/reader.rs
|
@ -373,8 +373,6 @@ enum JumpPrecision {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// readline_loop_state_t encapsulates the state used in a readline loop.
|
/// readline_loop_state_t encapsulates the state used in a readline loop.
|
||||||
/// It is always stack allocated transient. This state should not be "publicly visible"; public
|
|
||||||
/// state should be in reader_data_t.
|
|
||||||
struct ReadlineLoopState {
|
struct ReadlineLoopState {
|
||||||
/// The last command that was executed.
|
/// The last command that was executed.
|
||||||
last_cmd: Option<ReadlineCmd>,
|
last_cmd: Option<ReadlineCmd>,
|
||||||
|
@ -550,6 +548,8 @@ pub struct ReaderData {
|
||||||
/// If these differs from the text of the command line, then we must kick off a new request.
|
/// If these differs from the text of the command line, then we must kick off a new request.
|
||||||
in_flight_highlight_request: WString,
|
in_flight_highlight_request: WString,
|
||||||
in_flight_autosuggest_request: WString,
|
in_flight_autosuggest_request: WString,
|
||||||
|
|
||||||
|
rls: Option<ReadlineLoopState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read commands from \c fd until encountering EOF.
|
/// Read commands from \c fd until encountering EOF.
|
||||||
|
@ -1093,6 +1093,7 @@ impl ReaderData {
|
||||||
last_jump_precision: JumpPrecision::To,
|
last_jump_precision: JumpPrecision::To,
|
||||||
in_flight_highlight_request: Default::default(),
|
in_flight_highlight_request: Default::default(),
|
||||||
in_flight_autosuggest_request: Default::default(),
|
in_flight_autosuggest_request: Default::default(),
|
||||||
|
rls: None,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1143,6 +1144,13 @@ impl ReaderData {
|
||||||
&self.parser_ref
|
&self.parser_ref
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rls(&self) -> &ReadlineLoopState {
|
||||||
|
self.rls.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
fn rls_mut(&mut self) -> &mut ReadlineLoopState {
|
||||||
|
self.rls.as_mut().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
// We repaint our prompt if fstat reports the tty as having changed.
|
// We repaint our prompt if fstat reports the tty as having changed.
|
||||||
// But don't react to tty changes that we initiated, because of commands or
|
// But don't react to tty changes that we initiated, because of commands or
|
||||||
// on-variable events (e.g. for fish_bind_mode). See #3481.
|
// on-variable events (e.g. for fish_bind_mode). See #3481.
|
||||||
|
@ -1746,7 +1754,7 @@ impl ReaderData {
|
||||||
/// Read a command to execute, respecting input bindings.
|
/// Read a command to execute, respecting input bindings.
|
||||||
/// \return the command, or none if we were asked to cancel (e.g. SIGHUP).
|
/// \return the command, or none if we were asked to cancel (e.g. SIGHUP).
|
||||||
fn readline(&mut self, nchars: Option<NonZeroUsize>) -> Option<WString> {
|
fn readline(&mut self, nchars: Option<NonZeroUsize>) -> Option<WString> {
|
||||||
let mut rls = ReadlineLoopState::new();
|
self.rls = Some(ReadlineLoopState::new());
|
||||||
|
|
||||||
// Suppress fish_trace during executing key bindings.
|
// Suppress fish_trace during executing key bindings.
|
||||||
// This is simply to reduce noise.
|
// This is simply to reduce noise.
|
||||||
|
@ -1763,7 +1771,7 @@ impl ReaderData {
|
||||||
|
|
||||||
// If nchars_or_0 is positive, then that's the maximum number of chars. Otherwise keep it at
|
// If nchars_or_0 is positive, then that's the maximum number of chars. Otherwise keep it at
|
||||||
// SIZE_MAX.
|
// SIZE_MAX.
|
||||||
rls.nchars = nchars;
|
zelf.rls_mut().nchars = nchars;
|
||||||
|
|
||||||
// The command line before completion.
|
// The command line before completion.
|
||||||
zelf.cycle_command_line.clear();
|
zelf.cycle_command_line.clear();
|
||||||
|
@ -1820,8 +1828,8 @@ impl ReaderData {
|
||||||
// Start out as initially dirty.
|
// Start out as initially dirty.
|
||||||
zelf.force_exec_prompt_and_repaint = true;
|
zelf.force_exec_prompt_and_repaint = true;
|
||||||
|
|
||||||
while !rls.finished && !check_exit_loop_maybe_warning(Some(&mut zelf)) {
|
while !zelf.rls().finished && !check_exit_loop_maybe_warning(Some(&mut zelf)) {
|
||||||
if zelf.handle_char_event(&mut rls, None).is_break() {
|
if zelf.handle_char_event(None).is_break() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1833,7 +1841,7 @@ impl ReaderData {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finish syntax highlighting (but do not wait forever).
|
// Finish syntax highlighting (but do not wait forever).
|
||||||
if rls.finished {
|
if zelf.rls().finished {
|
||||||
zelf.finish_highlighting_before_exec();
|
zelf.finish_highlighting_before_exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1872,7 +1880,12 @@ impl ReaderData {
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.set_color(RgbColor::RESET, RgbColor::RESET);
|
.set_color(RgbColor::RESET, RgbColor::RESET);
|
||||||
}
|
}
|
||||||
rls.finished.then(|| zelf.command_line.text().to_owned())
|
let result = zelf
|
||||||
|
.rls()
|
||||||
|
.finished
|
||||||
|
.then(|| zelf.command_line.text().to_owned());
|
||||||
|
zelf.rls = None;
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_bind_cmd(&mut self, cmd: &wstr) {
|
fn eval_bind_cmd(&mut self, cmd: &wstr) {
|
||||||
|
@ -1907,10 +1920,10 @@ impl ReaderData {
|
||||||
|
|
||||||
/// Read normal characters, inserting them into the command line.
|
/// Read normal characters, inserting them into the command line.
|
||||||
/// \return the next unhandled event.
|
/// \return the next unhandled event.
|
||||||
fn read_normal_chars(&mut self, rls: &mut ReadlineLoopState) -> Option<CharEvent> {
|
fn read_normal_chars(&mut self) -> Option<CharEvent> {
|
||||||
let mut event_needing_handling = None;
|
let mut event_needing_handling = None;
|
||||||
let limit = std::cmp::min(
|
let limit = std::cmp::min(
|
||||||
rls.nchars.map_or(usize::MAX, |nchars| {
|
self.rls().nchars.map_or(usize::MAX, |nchars| {
|
||||||
usize::from(nchars) - self.command_line.len()
|
usize::from(nchars) - self.command_line.len()
|
||||||
}),
|
}),
|
||||||
READAHEAD_MAX,
|
READAHEAD_MAX,
|
||||||
|
@ -1954,7 +1967,7 @@ impl ReaderData {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since we handled a normal character, we don't have a last command.
|
// Since we handled a normal character, we don't have a last command.
|
||||||
rls.last_cmd = None;
|
self.rls_mut().last_cmd = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
event_needing_handling
|
event_needing_handling
|
||||||
|
@ -1974,15 +1987,11 @@ impl ReaderData {
|
||||||
self.force_exec_prompt_and_repaint = false;
|
self.force_exec_prompt_and_repaint = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_char_event(
|
fn handle_char_event(&mut self, injected_event: Option<CharEvent>) -> ControlFlow<()> {
|
||||||
&mut self,
|
|
||||||
rls: &mut ReadlineLoopState,
|
|
||||||
injected_event: Option<CharEvent>,
|
|
||||||
) -> ControlFlow<()> {
|
|
||||||
if self.reset_loop_state {
|
if self.reset_loop_state {
|
||||||
self.reset_loop_state = false;
|
self.reset_loop_state = false;
|
||||||
rls.last_cmd = None;
|
self.rls_mut().last_cmd = None;
|
||||||
rls.complete_did_insert = false;
|
self.rls_mut().complete_did_insert = false;
|
||||||
}
|
}
|
||||||
// Perhaps update the termsize. This is cheap if it has not changed.
|
// Perhaps update the termsize. This is cheap if it has not changed.
|
||||||
self.update_termsize();
|
self.update_termsize();
|
||||||
|
@ -1990,21 +1999,23 @@ impl ReaderData {
|
||||||
// Repaint as needed.
|
// Repaint as needed.
|
||||||
self.color_suggest_repaint_now();
|
self.color_suggest_repaint_now();
|
||||||
|
|
||||||
if rls
|
if self
|
||||||
|
.rls()
|
||||||
.nchars
|
.nchars
|
||||||
.is_some_and(|nchars| usize::from(nchars) <= self.command_line.len())
|
.is_some_and(|nchars| usize::from(nchars) <= self.command_line.len())
|
||||||
{
|
{
|
||||||
// We've already hit the specified character limit.
|
// We've already hit the specified character limit.
|
||||||
rls.finished = true;
|
self.rls_mut().finished = true;
|
||||||
return ControlFlow::Break(());
|
return ControlFlow::Break(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let event_needing_handling = injected_event.or_else(|| loop {
|
let event_needing_handling = injected_event.or_else(|| loop {
|
||||||
let event_needing_handling = self.read_normal_chars(rls);
|
let event_needing_handling = self.read_normal_chars();
|
||||||
if event_needing_handling.is_some() {
|
if event_needing_handling.is_some() {
|
||||||
break event_needing_handling;
|
break event_needing_handling;
|
||||||
}
|
}
|
||||||
if rls
|
if self
|
||||||
|
.rls()
|
||||||
.nchars
|
.nchars
|
||||||
.is_some_and(|nchars| usize::from(nchars) <= self.command_line.len())
|
.is_some_and(|nchars| usize::from(nchars) <= self.command_line.len())
|
||||||
{
|
{
|
||||||
|
@ -2030,8 +2041,11 @@ impl ReaderData {
|
||||||
return ControlFlow::Continue(());
|
return ControlFlow::Continue(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if !matches!(rls.last_cmd, Some(ReadlineCmd::Yank | ReadlineCmd::YankPop)) {
|
if !matches!(
|
||||||
rls.yank_len = 0;
|
self.rls().last_cmd,
|
||||||
|
Some(ReadlineCmd::Yank | ReadlineCmd::YankPop)
|
||||||
|
) {
|
||||||
|
self.rls_mut().yank_len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
match event_needing_handling {
|
match event_needing_handling {
|
||||||
|
@ -2050,7 +2064,7 @@ impl ReaderData {
|
||||||
self.clear_pager();
|
self.clear_pager();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.handle_readline_command(readline_cmd, rls);
|
self.handle_readline_command(readline_cmd);
|
||||||
|
|
||||||
if self.history_search.active() && command_ends_history_search(readline_cmd) {
|
if self.history_search.active() && command_ends_history_search(readline_cmd) {
|
||||||
// "cancel" means to abort the whole thing, other ending commands mean to finish the
|
// "cancel" means to abort the whole thing, other ending commands mean to finish the
|
||||||
|
@ -2063,7 +2077,7 @@ impl ReaderData {
|
||||||
self.command_line_has_transient_edit = false;
|
self.command_line_has_transient_edit = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
rls.last_cmd = Some(readline_cmd);
|
self.rls_mut().last_cmd = Some(readline_cmd);
|
||||||
}
|
}
|
||||||
CharEvent::Command(command) => {
|
CharEvent::Command(command) => {
|
||||||
self.run_input_command_scripts(&command);
|
self.run_input_command_scripts(&command);
|
||||||
|
@ -2087,7 +2101,7 @@ impl ReaderData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rls.last_cmd = None;
|
self.rls_mut().last_cmd = None;
|
||||||
}
|
}
|
||||||
CharEvent::Eof | CharEvent::CheckExit => {
|
CharEvent::Eof | CharEvent::CheckExit => {
|
||||||
panic!("Should have a char, readline or command")
|
panic!("Should have a char, readline or command")
|
||||||
|
@ -2098,7 +2112,7 @@ impl ReaderData {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReaderData {
|
impl ReaderData {
|
||||||
fn handle_readline_command(&mut self, c: ReadlineCmd, rls: &mut ReadlineLoopState) {
|
fn handle_readline_command(&mut self, c: ReadlineCmd) {
|
||||||
type rl = ReadlineCmd;
|
type rl = ReadlineCmd;
|
||||||
match c {
|
match c {
|
||||||
rl::BeginningOfLine => {
|
rl::BeginningOfLine => {
|
||||||
|
@ -2163,8 +2177,11 @@ impl ReaderData {
|
||||||
// but never complete{,_and_search})
|
// but never complete{,_and_search})
|
||||||
//
|
//
|
||||||
// Also paging is already cancelled above.
|
// Also paging is already cancelled above.
|
||||||
if rls.complete_did_insert
|
if self.rls().complete_did_insert
|
||||||
&& matches!(rls.last_cmd, Some(rl::Complete | rl::CompleteAndSearch))
|
&& matches!(
|
||||||
|
self.rls().last_cmd,
|
||||||
|
Some(rl::Complete | rl::CompleteAndSearch)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
let (elt, el) = self.active_edit_line_mut();
|
let (elt, el) = self.active_edit_line_mut();
|
||||||
el.undo();
|
el.undo();
|
||||||
|
@ -2208,9 +2225,9 @@ impl ReaderData {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if self.is_navigating_pager_contents()
|
if self.is_navigating_pager_contents()
|
||||||
|| (!rls.comp.is_empty()
|
|| (!self.rls().comp.is_empty()
|
||||||
&& !rls.complete_did_insert
|
&& !self.rls().complete_did_insert
|
||||||
&& rls.last_cmd == Some(rl::Complete))
|
&& self.rls().last_cmd == Some(rl::Complete))
|
||||||
{
|
{
|
||||||
// The user typed complete more than once in a row. If we are not yet fully
|
// The user typed complete more than once in a row. If we are not yet fully
|
||||||
// disclosed, then become so; otherwise cycle through our available completions.
|
// disclosed, then become so; otherwise cycle through our available completions.
|
||||||
|
@ -2228,7 +2245,7 @@ impl ReaderData {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Either the user hit tab only once, or we had no visible completion list.
|
// Either the user hit tab only once, or we had no visible completion list.
|
||||||
self.compute_and_apply_completions(c, rls);
|
self.compute_and_apply_completions(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rl::PagerToggleSearch => {
|
rl::PagerToggleSearch => {
|
||||||
|
@ -2266,7 +2283,12 @@ impl ReaderData {
|
||||||
|
|
||||||
let range = begin..end;
|
let range = begin..end;
|
||||||
if !range.is_empty() {
|
if !range.is_empty() {
|
||||||
self.kill(elt, range, Kill::Append, rls.last_cmd != Some(rl::KillLine));
|
self.kill(
|
||||||
|
elt,
|
||||||
|
range,
|
||||||
|
Kill::Append,
|
||||||
|
self.rls().last_cmd != Some(rl::KillLine),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rl::BackwardKillLine => {
|
rl::BackwardKillLine => {
|
||||||
|
@ -2297,7 +2319,7 @@ impl ReaderData {
|
||||||
elt,
|
elt,
|
||||||
end - len..end,
|
end - len..end,
|
||||||
Kill::Prepend,
|
Kill::Prepend,
|
||||||
rls.last_cmd != Some(rl::BackwardKillLine),
|
self.rls().last_cmd != Some(rl::BackwardKillLine),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
rl::KillWholeLine | rl::KillInnerLine => {
|
rl::KillWholeLine | rl::KillInnerLine => {
|
||||||
|
@ -2342,20 +2364,25 @@ impl ReaderData {
|
||||||
assert!(end >= begin);
|
assert!(end >= begin);
|
||||||
|
|
||||||
if end > begin {
|
if end > begin {
|
||||||
self.kill(elt, begin..end, Kill::Append, rls.last_cmd != Some(c));
|
self.kill(
|
||||||
|
elt,
|
||||||
|
begin..end,
|
||||||
|
Kill::Append,
|
||||||
|
self.rls().last_cmd != Some(c),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rl::Yank => {
|
rl::Yank => {
|
||||||
let yank_str = kill_yank();
|
let yank_str = kill_yank();
|
||||||
self.insert_string(self.active_edit_line_tag(), &yank_str);
|
self.insert_string(self.active_edit_line_tag(), &yank_str);
|
||||||
rls.yank_len = yank_str.len();
|
self.rls_mut().yank_len = yank_str.len();
|
||||||
if self.cursor_end_mode == CursorEndMode::Inclusive {
|
if self.cursor_end_mode == CursorEndMode::Inclusive {
|
||||||
let (_elt, el) = self.active_edit_line();
|
let (_elt, el) = self.active_edit_line();
|
||||||
self.update_buff_pos(self.active_edit_line_tag(), Some(el.position() - 1));
|
self.update_buff_pos(self.active_edit_line_tag(), Some(el.position() - 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rl::YankPop => {
|
rl::YankPop => {
|
||||||
if rls.yank_len != 0 {
|
if self.rls().yank_len != 0 {
|
||||||
let (elt, el) = self.active_edit_line();
|
let (elt, el) = self.active_edit_line();
|
||||||
let yank_str = kill_yank_rotate();
|
let yank_str = kill_yank_rotate();
|
||||||
let new_yank_len = yank_str.len();
|
let new_yank_len = yank_str.len();
|
||||||
|
@ -2364,11 +2391,11 @@ impl ReaderData {
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
let begin = el.position() + bias - rls.yank_len;
|
let begin = el.position() + bias - self.rls().yank_len;
|
||||||
let end = el.position() + bias;
|
let end = el.position() + bias;
|
||||||
self.replace_substring(elt, begin..end, yank_str);
|
self.replace_substring(elt, begin..end, yank_str);
|
||||||
self.update_buff_pos(elt, None);
|
self.update_buff_pos(elt, None);
|
||||||
rls.yank_len = new_yank_len;
|
self.rls_mut().yank_len = new_yank_len;
|
||||||
self.suppress_autosuggestion = true;
|
self.suppress_autosuggestion = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2397,7 +2424,7 @@ impl ReaderData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rl::Execute => {
|
rl::Execute => {
|
||||||
if !self.handle_execute(rls) {
|
if !self.handle_execute() {
|
||||||
event::fire_generic(
|
event::fire_generic(
|
||||||
self.parser(),
|
self.parser(),
|
||||||
L!("fish_posterror").to_owned(),
|
L!("fish_posterror").to_owned(),
|
||||||
|
@ -2584,7 +2611,7 @@ impl ReaderData {
|
||||||
};
|
};
|
||||||
// Is this the same killring item as the last kill?
|
// Is this the same killring item as the last kill?
|
||||||
let newv = !matches!(
|
let newv = !matches!(
|
||||||
rls.last_cmd,
|
self.rls().last_cmd,
|
||||||
Some(
|
Some(
|
||||||
rl::BackwardKillWord
|
rl::BackwardKillWord
|
||||||
| rl::BackwardKillPathComponent
|
| rl::BackwardKillPathComponent
|
||||||
|
@ -2612,7 +2639,7 @@ impl ReaderData {
|
||||||
MoveWordDir::Right,
|
MoveWordDir::Right,
|
||||||
/*erase=*/ true,
|
/*erase=*/ true,
|
||||||
style,
|
style,
|
||||||
rls.last_cmd != Some(c),
|
self.rls().last_cmd != Some(c),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
rl::BackwardWord | rl::BackwardBigword | rl::PrevdOrBackwardWord => {
|
rl::BackwardWord | rl::BackwardBigword | rl::PrevdOrBackwardWord => {
|
||||||
|
@ -2938,7 +2965,7 @@ impl ReaderData {
|
||||||
self.update_buff_pos(self.active_edit_line_tag(), Some(tmp));
|
self.update_buff_pos(self.active_edit_line_tag(), Some(tmp));
|
||||||
}
|
}
|
||||||
rl::KillSelection => {
|
rl::KillSelection => {
|
||||||
let newv = rls.last_cmd != Some(rl::KillSelection);
|
let newv = self.rls().last_cmd != Some(rl::KillSelection);
|
||||||
if let Some(selection) = self.get_selection() {
|
if let Some(selection) = self.get_selection() {
|
||||||
self.kill(EditableLineTag::Commandline, selection, Kill::Append, newv);
|
self.kill(EditableLineTag::Commandline, selection, Kill::Append, newv);
|
||||||
}
|
}
|
||||||
|
@ -3099,7 +3126,7 @@ impl ReaderData {
|
||||||
// unfinished. It may also set 'finished' and 'cmd' inside the rls.
|
// unfinished. It may also set 'finished' and 'cmd' inside the rls.
|
||||||
// \return true on success, false if we got an error, in which case the caller should fire the
|
// \return true on success, false if we got an error, in which case the caller should fire the
|
||||||
// error event.
|
// error event.
|
||||||
fn handle_execute(&mut self, rls: &mut ReadlineLoopState) -> bool {
|
fn handle_execute(&mut self) -> bool {
|
||||||
// Evaluate. If the current command is unfinished, or if the charater is escaped
|
// Evaluate. If the current command is unfinished, or if the charater is escaped
|
||||||
// using a backslash, insert a newline.
|
// using a backslash, insert a newline.
|
||||||
// If the user hits return while navigating the pager, it only clears the pager.
|
// If the user hits return while navigating the pager, it only clears the pager.
|
||||||
|
@ -3169,7 +3196,7 @@ impl ReaderData {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.add_to_history();
|
self.add_to_history();
|
||||||
rls.finished = true;
|
self.rls_mut().finished = true;
|
||||||
self.update_buff_pos(elt, Some(self.command_line.len()));
|
self.update_buff_pos(elt, Some(self.command_line.len()));
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -5176,7 +5203,7 @@ fn get_best_rank(comp: &[Completion]) -> u32 {
|
||||||
|
|
||||||
impl ReaderData {
|
impl ReaderData {
|
||||||
/// Compute completions and update the pager and/or commandline as needed.
|
/// Compute completions and update the pager and/or commandline as needed.
|
||||||
fn compute_and_apply_completions(&mut self, c: ReadlineCmd, rls: &mut ReadlineLoopState) {
|
fn compute_and_apply_completions(&mut self, c: ReadlineCmd) {
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
c,
|
c,
|
||||||
ReadlineCmd::Complete | ReadlineCmd::CompleteAndSearch
|
ReadlineCmd::Complete | ReadlineCmd::CompleteAndSearch
|
||||||
|
@ -5236,8 +5263,8 @@ impl ReaderData {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ExpandResultCode::ok => {
|
ExpandResultCode::ok => {
|
||||||
rls.comp.clear();
|
self.rls_mut().comp.clear();
|
||||||
rls.complete_did_insert = false;
|
self.rls_mut().complete_did_insert = false;
|
||||||
self.push_edit(
|
self.push_edit(
|
||||||
EditableLineTag::Commandline,
|
EditableLineTag::Commandline,
|
||||||
Edit::new(token_range, wc_expanded),
|
Edit::new(token_range, wc_expanded),
|
||||||
|
@ -5258,31 +5285,38 @@ impl ReaderData {
|
||||||
CompletionRequestOptions::normal(),
|
CompletionRequestOptions::normal(),
|
||||||
&self.parser().context(),
|
&self.parser().context(),
|
||||||
);
|
);
|
||||||
rls.comp = comp;
|
self.rls_mut().comp = comp;
|
||||||
|
|
||||||
|
let el = &self.command_line;
|
||||||
// User-supplied completions may have changed the commandline - prevent buffer
|
// User-supplied completions may have changed the commandline - prevent buffer
|
||||||
// overflow.
|
// overflow.
|
||||||
token_range.start = std::cmp::min(token_range.start, el.text().len());
|
token_range.start = std::cmp::min(token_range.start, el.text().len());
|
||||||
token_range.end = std::cmp::min(token_range.end, el.text().len());
|
token_range.end = std::cmp::min(token_range.end, el.text().len());
|
||||||
|
|
||||||
// Munge our completions.
|
// Munge our completions.
|
||||||
sort_and_prioritize(&mut rls.comp, CompletionRequestOptions::default());
|
sort_and_prioritize(
|
||||||
|
&mut self.rls_mut().comp,
|
||||||
|
CompletionRequestOptions::default(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let el = &self.command_line;
|
||||||
// Record our cycle_command_line.
|
// Record our cycle_command_line.
|
||||||
self.cycle_command_line = el.text().to_owned();
|
self.cycle_command_line = el.text().to_owned();
|
||||||
self.cycle_cursor_pos = token_range.end;
|
self.cycle_cursor_pos = token_range.end;
|
||||||
|
|
||||||
rls.complete_did_insert = self.handle_completions(&rls.comp, token_range);
|
self.rls_mut().complete_did_insert = self.handle_completions(token_range);
|
||||||
|
|
||||||
// Show the search field if requested and if we printed a list of completions.
|
// Show the search field if requested and if we printed a list of completions.
|
||||||
if c == ReadlineCmd::CompleteAndSearch && !rls.complete_did_insert && !self.pager.is_empty()
|
if c == ReadlineCmd::CompleteAndSearch
|
||||||
|
&& !self.rls().complete_did_insert
|
||||||
|
&& !self.pager.is_empty()
|
||||||
{
|
{
|
||||||
self.pager.set_search_field_shown(true);
|
self.pager.set_search_field_shown(true);
|
||||||
self.select_completion_in_direction(SelectionMotion::Next, false);
|
self.select_completion_in_direction(SelectionMotion::Next, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_insert(&mut self, c: &Completion, tok: &wstr, token_range: Range<usize>) {
|
fn try_insert(&mut self, c: Completion, tok: &wstr, token_range: Range<usize>) {
|
||||||
// If this is a replacement completion, check that we know how to replace it, e.g. that
|
// If this is a replacement completion, check that we know how to replace it, e.g. that
|
||||||
// the token doesn't contain evil operators like {}.
|
// the token doesn't contain evil operators like {}.
|
||||||
if !c.flags.contains(CompleteFlags::REPLACES_TOKEN) || reader_can_replace(tok, c.flags) {
|
if !c.flags.contains(CompleteFlags::REPLACES_TOKEN) || reader_can_replace(tok, c.flags) {
|
||||||
|
@ -5305,9 +5339,10 @@ impl ReaderData {
|
||||||
/// \param token_end the position after the token to complete
|
/// \param token_end the position after the token to complete
|
||||||
///
|
///
|
||||||
/// Return true if we inserted text into the command line, false if we did not.
|
/// Return true if we inserted text into the command line, false if we did not.
|
||||||
fn handle_completions(&mut self, comp: &[Completion], token_range: Range<usize>) -> bool {
|
fn handle_completions(&mut self, token_range: Range<usize>) -> bool {
|
||||||
let tok = self.command_line.text()[token_range.clone()].to_owned();
|
let tok = self.command_line.text()[token_range.clone()].to_owned();
|
||||||
|
|
||||||
|
let comp = &self.rls().comp;
|
||||||
// Check trivial cases.
|
// Check trivial cases.
|
||||||
let len = comp.len();
|
let len = comp.len();
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
|
@ -5317,7 +5352,7 @@ impl ReaderData {
|
||||||
} else if len == 1 {
|
} else if len == 1 {
|
||||||
// Exactly one suitable completion found - insert it.
|
// Exactly one suitable completion found - insert it.
|
||||||
let c = &comp[0];
|
let c = &comp[0];
|
||||||
self.try_insert(c, &tok, token_range);
|
self.try_insert(c.clone(), &tok, token_range);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5367,7 +5402,7 @@ impl ReaderData {
|
||||||
// the token is "cma" and the options are "cmake/" and "CMakeLists.txt"
|
// the token is "cma" and the options are "cmake/" and "CMakeLists.txt"
|
||||||
// it would be nice if we could figure
|
// it would be nice if we could figure
|
||||||
// out how to use it more.
|
// out how to use it more.
|
||||||
let c = &surviving_completions[0];
|
let c = std::mem::take(&mut surviving_completions[0]);
|
||||||
|
|
||||||
self.try_insert(c, &tok, token_range);
|
self.try_insert(c, &tok, token_range);
|
||||||
return true;
|
return true;
|
||||||
|
|
Loading…
Reference in a new issue