Move some fake readline commands to a separate type

This commit is contained in:
Johannes Altmanninger 2024-12-29 19:31:15 +01:00
parent 48ae19b4b1
commit ca9c5f4cec
3 changed files with 59 additions and 70 deletions

View file

@ -4,7 +4,8 @@ use crate::env::{Environment, CURSES_INITIALIZED};
use crate::event; use crate::event;
use crate::flog::FLOG; use crate::flog::FLOG;
use crate::input_common::{ use crate::input_common::{
CharEvent, CharInputStyle, InputData, InputEventQueuer, ReadlineCmd, R_END_INPUT_FUNCTIONS, CharEvent, CharInputStyle, ImplicitEvent, InputData, InputEventQueuer, ReadlineCmd,
R_END_INPUT_FUNCTIONS,
}; };
use crate::key::{self, canonicalize_raw_escapes, ctrl, Key, Modifiers}; use crate::key::{self, canonicalize_raw_escapes, ctrl, Key, Modifiers};
use crate::proc::job_reap; use crate::proc::job_reap;
@ -120,10 +121,6 @@ const fn make_md(name: &'static wstr, code: ReadlineCmd) -> InputFunctionMetadat
/// Keep this list sorted alphabetically! /// Keep this list sorted alphabetically!
#[rustfmt::skip] #[rustfmt::skip]
const INPUT_FUNCTION_METADATA: &[InputFunctionMetadata] = &[ const INPUT_FUNCTION_METADATA: &[InputFunctionMetadata] = &[
// NULL makes it unusable - this is specially inserted when we detect mouse input
make_md(L!(""), ReadlineCmd::DisableMouseTracking),
make_md(L!(""), ReadlineCmd::FocusIn),
make_md(L!(""), ReadlineCmd::FocusOut),
make_md(L!("accept-autosuggestion"), ReadlineCmd::AcceptAutosuggestion), make_md(L!("accept-autosuggestion"), ReadlineCmd::AcceptAutosuggestion),
make_md(L!("and"), ReadlineCmd::FuncAnd), make_md(L!("and"), ReadlineCmd::FuncAnd),
make_md(L!("backward-bigword"), ReadlineCmd::BackwardBigword), make_md(L!("backward-bigword"), ReadlineCmd::BackwardBigword),
@ -621,9 +618,10 @@ impl<'q, Queuer: InputEventQueuer + ?Sized> EventQueuePeeker<'q, Queuer> {
/// Test if any of our peeked events are readline or check_exit. /// Test if any of our peeked events are readline or check_exit.
fn char_sequence_interrupted(&self) -> bool { fn char_sequence_interrupted(&self) -> bool {
self.peeked self.peeked.iter().any(|evt| {
.iter() evt.is_readline_or_command()
.any(|evt| evt.is_readline_or_command() || evt.is_check_exit()) || matches!(evt, CharEvent::Implicit(ImplicitEvent::CheckExit))
})
} }
/// Reset our index back to 0. /// Reset our index back to 0.
@ -774,15 +772,6 @@ impl<'a> Reader<'a> {
CharEvent::Command(_) => { CharEvent::Command(_) => {
return evt; return evt;
} }
CharEvent::Eof => {
// If we have EOF, we need to immediately quit.
// There's no need to go through the input functions.
return evt;
}
CharEvent::CheckExit => {
// Allow the reader to check for exit conditions.
return evt;
}
CharEvent::Key(ref kevt) => { CharEvent::Key(ref kevt) => {
FLOG!( FLOG!(
reader, reader,
@ -797,6 +786,9 @@ impl<'a> Reader<'a> {
self.push_front(evt); self.push_front(evt);
self.mapping_execute_matching_or_generic(); self.mapping_execute_matching_or_generic();
} }
CharEvent::Implicit(_) => {
return evt;
}
} }
} }
} }

View file

@ -130,10 +130,6 @@ pub enum ReadlineCmd {
BeginUndoGroup, BeginUndoGroup,
EndUndoGroup, EndUndoGroup,
RepeatJump, RepeatJump,
DisableMouseTracking,
FocusIn,
FocusOut,
// ncurses uses the obvious name
ClearScreenAndRepaint, ClearScreenAndRepaint,
// NOTE: This one has to be last. // NOTE: This one has to be last.
ReverseRepeatJump, ReverseRepeatJump,
@ -180,6 +176,21 @@ pub struct KeyEvent {
pub seq: WString, pub seq: WString,
} }
#[derive(Debug, Clone)]
pub enum ImplicitEvent {
/// end-of-file was reached.
Eof,
/// An event was handled internally, or an interrupt was received. Check to see if the reader
/// loop should exit.
CheckExit,
/// Our terminal window gained focus.
FocusIn,
/// Our terminal window lost focus.
FocusOut,
/// Request to disable mouse tracking.
DisableMouseTracking,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum CharEvent { pub enum CharEvent {
/// A character was entered. /// A character was entered.
@ -191,12 +202,8 @@ pub enum CharEvent {
/// A shell command. /// A shell command.
Command(WString), Command(WString),
/// end-of-file was reached. /// Any event that has no user-visible representation.
Eof, Implicit(ImplicitEvent),
/// An event was handled internally, or an interrupt was received. Check to see if the reader
/// loop should exit.
CheckExit,
} }
impl CharEvent { impl CharEvent {
@ -204,14 +211,6 @@ impl CharEvent {
matches!(self, CharEvent::Key(_)) matches!(self, CharEvent::Key(_))
} }
pub fn is_eof(&self) -> bool {
matches!(self, CharEvent::Eof)
}
pub fn is_check_exit(&self) -> bool {
matches!(self, CharEvent::CheckExit)
}
pub fn is_readline(&self) -> bool { pub fn is_readline(&self) -> bool {
matches!(self, CharEvent::Readline(_)) matches!(self, CharEvent::Readline(_))
} }
@ -273,7 +272,7 @@ impl CharEvent {
} }
pub fn from_check_exit() -> CharEvent { pub fn from_check_exit() -> CharEvent {
CharEvent::CheckExit CharEvent::Implicit(ImplicitEvent::CheckExit)
} }
} }
@ -631,7 +630,7 @@ pub trait InputEventQueuer {
let rr = readb(self.get_in_fd(), blocking); let rr = readb(self.get_in_fd(), blocking);
match rr { match rr {
ReadbResult::Eof => { ReadbResult::Eof => {
return Some(CharEvent::Eof); return Some(CharEvent::Implicit(ImplicitEvent::Eof));
} }
ReadbResult::Interrupted => { ReadbResult::Interrupted => {
@ -1028,11 +1027,11 @@ pub trait InputEventQueuer {
} }
b'Z' => shift(key::Tab), b'Z' => shift(key::Tab),
b'I' => { b'I' => {
self.push_front(CharEvent::from_readline(ReadlineCmd::FocusIn)); self.push_front(CharEvent::Implicit(ImplicitEvent::FocusIn));
return Some(Key::from_raw(key::Invalid)); return Some(Key::from_raw(key::Invalid));
} }
b'O' => { b'O' => {
self.push_front(CharEvent::from_readline(ReadlineCmd::FocusOut)); self.push_front(CharEvent::Implicit(ImplicitEvent::FocusOut));
return Some(Key::from_raw(key::Invalid)); return Some(Key::from_raw(key::Invalid));
} }
_ => return None, _ => return None,
@ -1051,7 +1050,7 @@ pub trait InputEventQueuer {
// We shouldn't directly manipulate stdout from here, so we ask the reader to do it. // We shouldn't directly manipulate stdout from here, so we ask the reader to do it.
// writembs(outputter_t::stdoutput(), "\x1B[?1000l"); // writembs(outputter_t::stdoutput(), "\x1B[?1000l");
self.push_front(CharEvent::from_readline(ReadlineCmd::DisableMouseTracking)); self.push_front(CharEvent::Implicit(ImplicitEvent::DisableMouseTracking));
} }
fn parse_ss3(&mut self, buffer: &mut Vec<u8>) -> Option<Key> { fn parse_ss3(&mut self, buffer: &mut Vec<u8>) -> Option<Key> {
@ -1227,7 +1226,9 @@ pub trait InputEventQueuer {
// Find the first sequence of non-char events. // Find the first sequence of non-char events.
// EOF is considered a char: we don't want to pull EOF in front of real chars. // EOF is considered a char: we don't want to pull EOF in front of real chars.
let queue = &mut self.get_input_data_mut().queue; let queue = &mut self.get_input_data_mut().queue;
let is_char = |evt: &CharEvent| evt.is_char() || evt.is_eof(); let is_char = |evt: &CharEvent| {
evt.is_char() || matches!(evt, CharEvent::Implicit(ImplicitEvent::Eof))
};
// Find the index of the first non-char event. // Find the index of the first non-char event.
// If there's none, we're done. // If there's none, we're done.
let Some(first): Option<usize> = queue.iter().position(|e| !is_char(e)) else { let Some(first): Option<usize> = queue.iter().position(|e| !is_char(e)) else {

View file

@ -77,6 +77,7 @@ use crate::history::{
}; };
use crate::input::init_input; use crate::input::init_input;
use crate::input_common::terminal_protocols_disable_ifn; use crate::input_common::terminal_protocols_disable_ifn;
use crate::input_common::ImplicitEvent;
use crate::input_common::IN_MIDNIGHT_COMMANDER_PRE_CSI_U; use crate::input_common::IN_MIDNIGHT_COMMANDER_PRE_CSI_U;
use crate::input_common::{ use crate::input_common::{
terminal_protocol_hacks, terminal_protocols_enable_ifn, CharEvent, CharInputStyle, InputData, terminal_protocol_hacks, terminal_protocols_enable_ifn, CharEvent, CharInputStyle, InputData,
@ -2161,22 +2162,16 @@ impl<'a> Reader<'a> {
let Some(event_needing_handling) = event_needing_handling else { let Some(event_needing_handling) = event_needing_handling else {
return ControlFlow::Continue(()); return ControlFlow::Continue(());
}; };
if event_needing_handling.is_check_exit() {
return ControlFlow::Continue(());
} else if event_needing_handling.is_eof() {
reader_sighup();
return ControlFlow::Continue(());
}
if !matches!(
self.rls().last_cmd,
Some(ReadlineCmd::Yank | ReadlineCmd::YankPop)
) {
self.rls_mut().yank_len = 0;
}
match event_needing_handling { match event_needing_handling {
CharEvent::Readline(readline_cmd_evt) => { CharEvent::Readline(readline_cmd_evt) => {
if !matches!(
self.rls().last_cmd,
Some(ReadlineCmd::Yank | ReadlineCmd::YankPop)
) {
self.rls_mut().yank_len = 0;
}
let readline_cmd = readline_cmd_evt.cmd; let readline_cmd = readline_cmd_evt.cmd;
if readline_cmd == ReadlineCmd::Cancel && self.is_navigating_pager_contents() { if readline_cmd == ReadlineCmd::Cancel && self.is_navigating_pager_contents() {
self.clear_transient_edit(); self.clear_transient_edit();
@ -2230,9 +2225,23 @@ impl<'a> Reader<'a> {
} }
self.rls_mut().last_cmd = None; self.rls_mut().last_cmd = None;
} }
CharEvent::Eof | CharEvent::CheckExit => { CharEvent::Implicit(implicit_event) => match implicit_event {
panic!("Should have a char, readline or command") ImplicitEvent::Eof => {
} reader_sighup();
}
ImplicitEvent::CheckExit => (),
ImplicitEvent::FocusIn => {
event::fire_generic(self.parser, L!("fish_focus_in").to_owned(), vec![]);
}
ImplicitEvent::FocusOut => {
event::fire_generic(self.parser, L!("fish_focus_out").to_owned(), vec![]);
}
ImplicitEvent::DisableMouseTracking => {
Outputter::stdoutput()
.borrow_mut()
.write_wstr(L!("\x1B[?1000l"));
}
},
} }
ControlFlow::Continue(()) ControlFlow::Continue(())
} }
@ -3437,17 +3446,6 @@ impl<'a> Reader<'a> {
let (_elt, el) = self.active_edit_line_mut(); let (_elt, el) = self.active_edit_line_mut();
el.end_edit_group(); el.end_edit_group();
} }
rl::DisableMouseTracking => {
Outputter::stdoutput()
.borrow_mut()
.write_wstr(L!("\x1B[?1000l"));
}
rl::FocusIn => {
event::fire_generic(self.parser, L!("fish_focus_in").to_owned(), vec![]);
}
rl::FocusOut => {
event::fire_generic(self.parser, L!("fish_focus_out").to_owned(), vec![]);
}
rl::ClearScreenAndRepaint => { rl::ClearScreenAndRepaint => {
self.parser.libdata_mut().is_repaint = true; self.parser.libdata_mut().is_repaint = true;
let clear = screen_clear(); let clear = screen_clear();
@ -5129,8 +5127,6 @@ fn command_ends_history_search(c: ReadlineCmd) -> bool {
| rl::EndOfHistory | rl::EndOfHistory
| rl::Repaint | rl::Repaint
| rl::ForceRepaint | rl::ForceRepaint
| rl::FocusIn
| rl::FocusOut
) )
} }