diff --git a/src/command.rs b/src/command.rs index 3216f0e2e..fa9d23f2f 100644 --- a/src/command.rs +++ b/src/command.rs @@ -14,9 +14,9 @@ pub enum Status { Submit, } -pub fn execute( +pub fn execute( cmd: Cmd, - s: &mut State<'_, '_, H>, + s: &mut State<'_, H, P>, input_state: &InputState, kill_ring: &mut KillRing, config: &Config, @@ -221,8 +221,9 @@ pub fn execute( // Move to end, in case cursor was in the middle of the // line, so that next thing application prints goes after // the input + let buf = s.line.as_str().to_owned(); s.move_cursor_to_end()?; - return Err(error::ReadlineError::Interrupted); + return Err(error::ReadlineError::Interrupted(buf)); } _ => { // Ignore the character typed. diff --git a/src/edit.rs b/src/edit.rs index e1dcb9f97..c7bb77878 100644 --- a/src/edit.rs +++ b/src/edit.rs @@ -23,10 +23,9 @@ use crate::KillRing; /// Represent the state during line editing. /// Implement rendering. -pub struct State<'out, 'prompt, H: Helper> { +pub struct State<'out, H: Helper, P> { pub out: &'out mut ::Writer, - prompt: &'prompt str, // Prompt to display (rl_prompt) - prompt_size: Position, // Prompt Unicode/visible width and height + prompt: P, // Prompt to display (rl_prompt) pub line: LineBuffer, // Edited line buffer pub layout: Layout, saved_line_for_history: LineBuffer, // Current edited line before history browsing @@ -44,18 +43,16 @@ enum Info<'m> { Msg(Option<&'m str>), } -impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> { +impl<'out, H: Helper, P: ToString> State<'out, H, P> { pub fn new( out: &'out mut ::Writer, - prompt: &'prompt str, + prompt: P, helper: Option<&'out H>, ctx: Context<'out>, - ) -> State<'out, 'prompt, H> { - let prompt_size = out.calculate_position(prompt, Position::default()); + ) -> Self { State { out, prompt, - prompt_size, line: LineBuffer::with_capacity(MAX_LINE).can_growth(true), layout: Layout::default(), saved_line_for_history: LineBuffer::with_capacity(MAX_LINE).can_growth(true), @@ -93,9 +90,6 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> { if new_cols != old_cols && (self.layout.end.row > 0 || self.layout.end.col >= new_cols) { - self.prompt_size = self - .out - .calculate_position(self.prompt, Position::default()); self.refresh_line()?; } continue; @@ -121,19 +115,20 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> { } pub fn move_cursor(&mut self) -> Result<()> { + let prompt_size = self.out.calculate_position(self.prompt.to_string().as_str(), Position::default()); // calculate the desired position of the cursor let cursor = self .out - .calculate_position(&self.line[..self.line.pos()], self.prompt_size); + .calculate_position(&self.line[..self.line.pos()], prompt_size); if self.layout.cursor == cursor { return Ok(()); } if self.highlight_char() { - let prompt_size = self.prompt_size; - self.refresh(self.prompt, prompt_size, true, Info::NoHint)?; + let prompt_size = prompt_size; + self.refresh(self.prompt.to_string().as_str(), prompt_size, true, Info::NoHint)?; } else { self.out.move_cursor(self.layout.cursor, cursor)?; - self.layout.prompt_size = self.prompt_size; + self.layout.prompt_size = prompt_size; self.layout.cursor = cursor; debug_assert!(self.layout.prompt_size <= self.layout.cursor); debug_assert!(self.layout.cursor <= self.layout.end); @@ -253,25 +248,25 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> { } } -impl<'out, 'prompt, H: Helper> Invoke for State<'out, 'prompt, H> { +impl<'out, P, H: Helper> Invoke for State<'out, H, P> { fn input(&self) -> &str { self.line.as_str() } } -impl<'out, 'prompt, H: Helper> Refresher for State<'out, 'prompt, H> { +impl<'out, P: ToString, H: Helper> Refresher for State<'out, H, P> { fn refresh_line(&mut self) -> Result<()> { - let prompt_size = self.prompt_size; + let prompt_size = self.out.calculate_position(self.prompt.to_string().as_str(), Position::default()); self.hint(); self.highlight_char(); - self.refresh(self.prompt, prompt_size, true, Info::Hint) + self.refresh(self.prompt.to_string().as_str(), prompt_size, true, Info::Hint) } fn refresh_line_with_msg(&mut self, msg: Option<&str>) -> Result<()> { - let prompt_size = self.prompt_size; + let prompt_size = self.out.calculate_position(self.prompt.to_string().as_str(), Position::default()); self.hint = None; self.highlight_char(); - self.refresh(self.prompt, prompt_size, true, Info::Msg(msg)) + self.refresh(self.prompt.to_string().as_str(), prompt_size, true, Info::Msg(msg)) } fn refresh_prompt_and_line(&mut self, prompt: &str) -> Result<()> { @@ -325,11 +320,10 @@ impl<'out, 'prompt, H: Helper> Refresher for State<'out, 'prompt, H> { } } -impl<'out, 'prompt, H: Helper> fmt::Debug for State<'out, 'prompt, H> { +impl<'out, P: ToString, H: Helper> fmt::Debug for State<'out, H, P> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("State") - .field("prompt", &self.prompt) - .field("prompt_size", &self.prompt_size) + .field("prompt", &self.prompt.to_string().as_str()) .field("buf", &self.line) .field("cols", &self.out.get_columns()) .field("layout", &self.layout) @@ -338,7 +332,7 @@ impl<'out, 'prompt, H: Helper> fmt::Debug for State<'out, 'prompt, H> { } } -impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> { +impl<'out, P: ToString, H: Helper> State<'out, H, P> { pub fn clear_screen(&mut self) -> Result<()> { self.out.clear_screen()?; self.layout.cursor = Position::default(); @@ -350,7 +344,7 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> { pub fn edit_insert(&mut self, ch: char, n: RepeatCount) -> Result<()> { if let Some(push) = self.line.insert(ch, n, &mut self.changes) { if push { - let prompt_size = self.prompt_size; + let prompt_size = self.out.calculate_position(self.prompt.to_string().as_str(), Position::default()); let no_previous_hint = self.hint.is_none(); self.hint(); let width = ch.width().unwrap_or(0); @@ -368,7 +362,7 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> { let bits = ch.encode_utf8(&mut self.byte_buffer); self.out.write_and_flush(bits) } else { - self.refresh(self.prompt, prompt_size, true, Info::Hint) + self.refresh(self.prompt.to_string().as_str(), prompt_size, true, Info::Hint) } } else { self.refresh_line() @@ -748,11 +742,10 @@ pub fn init_state<'out, H: Helper>( pos: usize, helper: Option<&'out H>, history: &'out crate::history::DefaultHistory, -) -> State<'out, 'static, H> { +) -> State<'out, H, &'static str> { State { out, prompt: "", - prompt_size: Position::default(), line: LineBuffer::init(line, pos), layout: Layout::default(), saved_line_for_history: LineBuffer::with_capacity(100), diff --git a/src/error.rs b/src/error.rs index 0e2895f61..3b333b862 100644 --- a/src/error.rs +++ b/src/error.rs @@ -17,7 +17,7 @@ pub enum ReadlineError { /// EOF (VEOF / Ctrl-D) Eof, /// Interrupt signal (VINTR / VQUIT / Ctrl-C) - Interrupted, + Interrupted(String), /// Unix Error from syscall #[cfg(unix)] Errno(nix::Error), @@ -36,10 +36,10 @@ pub enum ReadlineError { impl fmt::Display for ReadlineError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { + match self { ReadlineError::Io(ref err) => err.fmt(f), ReadlineError::Eof => write!(f, "EOF"), - ReadlineError::Interrupted => write!(f, "Interrupted"), + ReadlineError::Interrupted(s) => write!(f, "Interrupted({s})"), #[cfg(unix)] ReadlineError::Errno(ref err) => err.fmt(f), ReadlineError::WindowResized => write!(f, "WindowResized"), @@ -58,7 +58,7 @@ impl Error for ReadlineError { match *self { ReadlineError::Io(ref err) => Some(err), ReadlineError::Eof => None, - ReadlineError::Interrupted => None, + ReadlineError::Interrupted(_) => None, #[cfg(unix)] ReadlineError::Errno(ref err) => Some(err), ReadlineError::WindowResized => None, diff --git a/src/lib.rs b/src/lib.rs index 2cb0256c4..e319194a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,9 +74,9 @@ use crate::validate::Validator; pub type Result = result::Result; /// Completes the line/word -fn complete_line( +fn complete_line( rdr: &mut ::Reader, - s: &mut State<'_, '_, H>, + s: &mut State<'_, H, P>, input_state: &mut InputState, config: &Config, ) -> Result> { @@ -263,7 +263,7 @@ fn complete_line( } /// Completes the current hint -fn complete_hint_line(s: &mut State<'_, '_, H>) -> Result<()> { +fn complete_hint_line(s: &mut State<'_, H, P>) -> Result<()> { let hint = match s.hint.as_ref() { Some(hint) => hint, None => return Ok(()), @@ -279,9 +279,9 @@ fn complete_hint_line(s: &mut State<'_, '_, H>) -> Result<()> { s.refresh_line() } -fn page_completions( +fn page_completions( rdr: &mut ::Reader, - s: &mut State<'_, '_, H>, + s: &mut State<'_, H, P>, input_state: &mut InputState, candidates: &[C], ) -> Result> { @@ -360,9 +360,9 @@ fn page_completions( } /// Incremental search -fn reverse_incremental_search( +fn reverse_incremental_search( rdr: &mut ::Reader, - s: &mut State<'_, '_, H>, + s: &mut State<'_, H, P>, input_state: &mut InputState, history: &I, ) -> Result> { @@ -635,7 +635,7 @@ impl Editor { /// terminal. /// Otherwise (e.g., if `stdin` is a pipe or the terminal is not supported), /// it uses file-style interaction. - pub fn readline(&mut self, prompt: &str) -> Result { + pub fn readline(&mut self, prompt: P) -> Result { self.readline_with(prompt, None) } @@ -650,12 +650,12 @@ impl Editor { self.readline_with(prompt, Some(initial)) } - fn readline_with(&mut self, prompt: &str, initial: Option<(&str, &str)>) -> Result { + fn readline_with(&mut self, prompt: P, initial: Option<(&str, &str)>) -> Result { if self.term.is_unsupported() { debug!(target: "rustyline", "unsupported terminal"); // Write prompt and flush it to stdout let mut stdout = io::stdout(); - stdout.write_all(prompt.as_bytes())?; + stdout.write_all(prompt.to_string().as_bytes())?; stdout.flush()?; readline_direct(io::stdin().lock(), io::stderr(), &self.helper) @@ -681,9 +681,9 @@ impl Editor { /// Handles reading and editing the readline buffer. /// It will also handle special inputs in an appropriate fashion /// (e.g., C-c will exit readline) - fn readline_edit( + fn readline_edit( &mut self, - prompt: &str, + prompt: P, initial: Option<(&str, &str)>, original_mode: &tty::Mode, term_key_map: tty::KeyMap, diff --git a/src/test/common.rs b/src/test/common.rs index 0f31dcefa..4dfe18132 100644 --- a/src/test/common.rs +++ b/src/test/common.rs @@ -177,16 +177,16 @@ fn interrupt_key() { for mode in &[EditMode::Emacs, EditMode::Vi] { let mut editor = init_editor(*mode, &[E::ctrl('C')]); let err = editor.readline(">>"); - assert_matches!(err, Err(ReadlineError::Interrupted)); + assert_matches!(err, Err(ReadlineError::Interrupted(_))); let mut editor = init_editor(*mode, &[E::ctrl('C')]); let err = editor.readline_with_initial(">>", ("Hi", "")); - assert_matches!(err, Err(ReadlineError::Interrupted)); + assert_matches!(err, Err(ReadlineError::Interrupted(_))); if *mode == EditMode::Vi { // vi command mode let mut editor = init_editor(*mode, &[E::ESC, E::ctrl('C')]); let err = editor.readline_with_initial(">>", ("Hi", "")); - assert_matches!(err, Err(ReadlineError::Interrupted)); + assert_matches!(err, Err(ReadlineError::Interrupted(_))); } } }