From 0442bdc22150cffd5320aed5657131afc9db701d Mon Sep 17 00:00:00 2001 From: sujiacong Date: Sun, 10 Sep 2023 14:13:47 +0800 Subject: [PATCH 01/43] add Cmd::Refresh --- src/command.rs | 3 +++ src/keymap.rs | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/command.rs b/src/command.rs index d99c95e53..8f0670bea 100644 --- a/src/command.rs +++ b/src/command.rs @@ -127,6 +127,9 @@ pub fn execute( Cmd::Newline => { s.edit_insert('\n', 1)?; } + Cmd::Refresh => { + s.refresh_line()?; + } Cmd::AcceptLine | Cmd::AcceptOrInsertLine { .. } => { let validation_result = s.validate()?; let valid = validation_result.is_valid(); diff --git a/src/keymap.rs b/src/keymap.rs index adb81fc0c..c21fdb780 100644 --- a/src/keymap.rs +++ b/src/keymap.rs @@ -68,6 +68,8 @@ pub enum Cmd { NextHistory, /// No action Noop, + /// Refresh + Refresh, /// vi-replace Overwrite(char), /// previous-history From 4468126d48f012b21c5d2e09a28d5137c8ee407b Mon Sep 17 00:00:00 2001 From: gwenn Date: Mon, 2 Oct 2023 16:43:05 +0200 Subject: [PATCH 02/43] Fix clippy warnings on Windows --- src/tty/windows.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/tty/windows.rs b/src/tty/windows.rs index 1bd7aa314..296e83df3 100644 --- a/src/tty/windows.rs +++ b/src/tty/windows.rs @@ -6,6 +6,7 @@ use std::io; use std::mem; use std::os::windows::io::IntoRawHandle; use std::ptr; +use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::{sync_channel, Receiver, SyncSender}; use std::sync::Arc; @@ -104,11 +105,11 @@ impl RawMode for ConsoleMode { pub struct ConsoleRawReader { conin: HANDLE, // external print reader - pipe_reader: Option>, + pipe_reader: Option>, } impl ConsoleRawReader { - fn create(conin: HANDLE, pipe_reader: Option>) -> ConsoleRawReader { + fn create(conin: HANDLE, pipe_reader: Option>) -> ConsoleRawReader { ConsoleRawReader { conin, pipe_reader } } @@ -581,7 +582,7 @@ fn write_all(handle: HANDLE, mut data: &[u16]) -> Result<()> { ) })?; if written == 0 { - return Err(Error::new(ErrorKind::WriteZero, "WriteConsoleW"))?; + Err(Error::new(ErrorKind::WriteZero, "WriteConsoleW"))?; } data = &data[(written as usize)..]; } @@ -603,7 +604,7 @@ pub struct Console { bell_style: BellStyle, raw_mode: Arc, // external print reader - pipe_reader: Option>, + pipe_reader: Option>, // external print writer pipe_writer: Option>, } @@ -810,7 +811,7 @@ impl Term for Console { } let (sender, receiver) = sync_channel(1); - let reader = Arc::new(AsyncPipe { + let reader = Rc::new(AsyncPipe { event: Handle(event), receiver, }); From 686c28de6b63316d6bd7521beedf2104c21a0f21 Mon Sep 17 00:00:00 2001 From: sujiacong Date: Thu, 5 Oct 2023 10:57:31 +0800 Subject: [PATCH 03/43] add Cmd::Repaint --- src/command.rs | 2 +- src/keymap.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/command.rs b/src/command.rs index 8f0670bea..f0185e2cb 100644 --- a/src/command.rs +++ b/src/command.rs @@ -127,7 +127,7 @@ pub fn execute( Cmd::Newline => { s.edit_insert('\n', 1)?; } - Cmd::Refresh => { + Cmd::Repaint => { s.refresh_line()?; } Cmd::AcceptLine | Cmd::AcceptOrInsertLine { .. } => { diff --git a/src/keymap.rs b/src/keymap.rs index c21fdb780..b7303df84 100644 --- a/src/keymap.rs +++ b/src/keymap.rs @@ -68,8 +68,8 @@ pub enum Cmd { NextHistory, /// No action Noop, - /// Refresh - Refresh, + /// repaint + Repaint, /// vi-replace Overwrite(char), /// previous-history From 308e89f3f378cd22626b13e7d556ea595fa0ec13 Mon Sep 17 00:00:00 2001 From: gwenn Date: Fri, 6 Oct 2023 20:35:18 +0200 Subject: [PATCH 04/43] Make termios an optional dependency Fix #731 --- Cargo.toml | 2 +- src/tty/unix.rs | 156 ++++++++++++++++++++++++++++++++++++------------ 2 files changed, 118 insertions(+), 40 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a92a2a847..254c3e237 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,7 @@ nix = { version = "0.27", default-features = false, features = ["fs", "ioctl", " utf8parse = "0.2" skim = { version = "0.10", optional = true, default-features = false } signal-hook = { version = "0.3", optional = true, default-features = false } -termios = "0.3.3" +termios = { version = "0.3.3", optional = true } [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["consoleapi", "handleapi", "synchapi", "minwindef", "processenv", "std", "winbase", "wincon", "winuser"] } diff --git a/src/tty/unix.rs b/src/tty/unix.rs index 39bf961cc..00e33dc1e 100644 --- a/src/tty/unix.rs +++ b/src/tty/unix.rs @@ -13,8 +13,11 @@ use log::{debug, warn}; use nix::errno::Errno; use nix::poll::{self, PollFlags}; use nix::sys::select::{self, FdSet}; +#[cfg(not(feature = "termios"))] +use nix::sys::termios::Termios; use nix::unistd::{close, isatty, read, write}; -use termios::{tcsetattr, Termios}; +#[cfg(feature = "termios")] +use termios::Termios; use unicode_segmentation::UnicodeSegmentation; use utf8parse::{Parser, Receiver}; @@ -106,7 +109,7 @@ pub type Mode = PosixMode; impl RawMode for PosixMode { /// Disable RAW mode for the terminal. fn disable_raw_mode(&self) -> Result<()> { - tcsetattr(self.tty_in, termios::TCSADRAIN, &self.termios)?; + termios_::disable_raw_mode(self.tty_in, &self.termios)?; // disable bracketed paste if let Some(out) = self.tty_out { write_all(out, BRACKETED_PASTE_OFF)?; @@ -1199,19 +1202,6 @@ impl SigWinCh { } } -fn map_key( - key_map: &mut HashMap, - raw: &Termios, - index: usize, - name: &str, - cmd: Cmd, -) { - let cc = char::from(raw.c_cc[index]); - let key = KeyEvent::new(cc, M::NONE); - debug!(target: "rustyline", "{}: {:?}", name, key); - key_map.insert(key, cmd); -} - #[cfg(not(test))] pub type Terminal = PosixTerminal; @@ -1332,30 +1322,7 @@ impl Term for PosixTerminal { if !self.is_in_a_tty { return Err(ENOTTY.into()); } - let original_mode = Termios::from_fd(self.tty_in)?; - let mut raw = original_mode; - // disable BREAK interrupt, CR to NL conversion on input, - // input parity check, strip high bit (bit 8), output flow control - raw.c_iflag &= - !(termios::BRKINT | termios::ICRNL | termios::INPCK | termios::ISTRIP | termios::IXON); - // we don't want raw output, it turns newlines into straight line feeds - // disable all output processing - // raw.c_oflag = raw.c_oflag & !(OutputFlags::OPOST); - - // character-size mark (8 bits) - raw.c_cflag |= termios::CS8; - // disable echoing, canonical mode, extended input processing and signals - raw.c_lflag &= !(termios::ECHO | termios::ICANON | termios::IEXTEN | termios::ISIG); - raw.c_cc[termios::VMIN] = 1; // One character-at-a-time input - raw.c_cc[termios::VTIME] = 0; // with blocking read - - let mut key_map: HashMap = HashMap::with_capacity(4); - map_key(&mut key_map, &raw, termios::VEOF, "VEOF", Cmd::EndOfFile); - map_key(&mut key_map, &raw, termios::VINTR, "VINTR", Cmd::Interrupt); - map_key(&mut key_map, &raw, termios::VQUIT, "VQUIT", Cmd::Interrupt); - map_key(&mut key_map, &raw, termios::VSUSP, "VSUSP", Cmd::Suspend); - - tcsetattr(self.tty_in, termios::TCSADRAIN, &raw)?; + let (original_mode, key_map) = termios_::enable_raw_mode(self.tty_in)?; self.raw_mode.store(true, Ordering::SeqCst); // enable bracketed paste @@ -1488,6 +1455,117 @@ pub fn suspend() -> Result<()> { Ok(()) } +#[cfg(not(feature = "termios"))] +mod termios_ { + use super::PosixKeyMap; + use crate::keys::{KeyEvent, Modifiers as M}; + use crate::{Cmd, Result}; + use nix::sys::termios::{self, SetArg, SpecialCharacterIndices as SCI, Termios}; + use std::collections::HashMap; + use std::os::unix::io::{BorrowedFd, RawFd}; + pub fn disable_raw_mode(tty_in: RawFd, termios: &Termios) -> Result<()> { + let fd = unsafe { BorrowedFd::borrow_raw(tty_in) }; + Ok(termios::tcsetattr(fd, SetArg::TCSADRAIN, termios)?) + } + pub fn enable_raw_mode(tty_in: RawFd) -> Result<(Termios, PosixKeyMap)> { + use nix::sys::termios::{ControlFlags, InputFlags, LocalFlags}; + + let fd = unsafe { BorrowedFd::borrow_raw(tty_in) }; + let original_mode = termios::tcgetattr(fd)?; + let mut raw = original_mode.clone(); + // disable BREAK interrupt, CR to NL conversion on input, + // input parity check, strip high bit (bit 8), output flow control + raw.input_flags &= !(InputFlags::BRKINT + | InputFlags::ICRNL + | InputFlags::INPCK + | InputFlags::ISTRIP + | InputFlags::IXON); + // we don't want raw output, it turns newlines into straight line feeds + // disable all output processing + // raw.c_oflag = raw.c_oflag & !(OutputFlags::OPOST); + + // character-size mark (8 bits) + raw.control_flags |= ControlFlags::CS8; + // disable echoing, canonical mode, extended input processing and signals + raw.local_flags &= + !(LocalFlags::ECHO | LocalFlags::ICANON | LocalFlags::IEXTEN | LocalFlags::ISIG); + raw.control_chars[SCI::VMIN as usize] = 1; // One character-at-a-time input + raw.control_chars[SCI::VTIME as usize] = 0; // with blocking read + + let mut key_map: HashMap = HashMap::with_capacity(4); + map_key(&mut key_map, &raw, SCI::VEOF, "VEOF", Cmd::EndOfFile); + map_key(&mut key_map, &raw, SCI::VINTR, "VINTR", Cmd::Interrupt); + map_key(&mut key_map, &raw, SCI::VQUIT, "VQUIT", Cmd::Interrupt); + map_key(&mut key_map, &raw, SCI::VSUSP, "VSUSP", Cmd::Suspend); + + termios::tcsetattr(fd, SetArg::TCSADRAIN, &raw)?; + Ok((original_mode, key_map)) + } + fn map_key( + key_map: &mut HashMap, + raw: &Termios, + index: SCI, + name: &str, + cmd: Cmd, + ) { + let cc = char::from(raw.control_chars[index as usize]); + let key = KeyEvent::new(cc, M::NONE); + log::debug!(target: "rustyline", "{}: {:?}", name, key); + key_map.insert(key, cmd); + } +} +#[cfg(feature = "termios")] +mod termios_ { + use super::PosixKeyMap; + use crate::keys::{KeyEvent, Modifiers as M}; + use crate::{Cmd, Result}; + use std::collections::HashMap; + use std::os::unix::io::RawFd; + use termios::{self, Termios}; + pub fn disable_raw_mode(tty_in: RawFd, termios: &Termios) -> Result<()> { + Ok(termios::tcsetattr(tty_in, termios::TCSADRAIN, termios)?) + } + pub fn enable_raw_mode(tty_in: RawFd) -> Result<(Termios, PosixKeyMap)> { + let original_mode = Termios::from_fd(tty_in)?; + let mut raw = original_mode; + // disable BREAK interrupt, CR to NL conversion on input, + // input parity check, strip high bit (bit 8), output flow control + raw.c_iflag &= + !(termios::BRKINT | termios::ICRNL | termios::INPCK | termios::ISTRIP | termios::IXON); + // we don't want raw output, it turns newlines into straight line feeds + // disable all output processing + // raw.c_oflag = raw.c_oflag & !(OutputFlags::OPOST); + + // character-size mark (8 bits) + raw.c_cflag |= termios::CS8; + // disable echoing, canonical mode, extended input processing and signals + raw.c_lflag &= !(termios::ECHO | termios::ICANON | termios::IEXTEN | termios::ISIG); + raw.c_cc[termios::VMIN] = 1; // One character-at-a-time input + raw.c_cc[termios::VTIME] = 0; // with blocking read + + let mut key_map: HashMap = HashMap::with_capacity(4); + map_key(&mut key_map, &raw, termios::VEOF, "VEOF", Cmd::EndOfFile); + map_key(&mut key_map, &raw, termios::VINTR, "VINTR", Cmd::Interrupt); + map_key(&mut key_map, &raw, termios::VQUIT, "VQUIT", Cmd::Interrupt); + map_key(&mut key_map, &raw, termios::VSUSP, "VSUSP", Cmd::Suspend); + + termios::tcsetattr(tty_in, termios::TCSADRAIN, &raw)?; + Ok((original_mode, key_map)) + } + fn map_key( + key_map: &mut HashMap, + raw: &Termios, + index: usize, + name: &str, + cmd: Cmd, + ) { + let cc = char::from(raw.c_cc[index]); + let key = KeyEvent::new(cc, M::NONE); + log::debug!(target: "rustyline", "{}: {:?}", name, key); + key_map.insert(key, cmd); + } +} + #[cfg(test)] mod test { use super::{Position, PosixRenderer, PosixTerminal, Renderer}; From b66e92f99a20b6014f7fc781ee66a391d7177c75 Mon Sep 17 00:00:00 2001 From: gwenn Date: Sun, 8 Oct 2023 10:05:10 +0200 Subject: [PATCH 05/43] Mapping between linenoise API and rustyline API --- linenoise.md | 34 ++++++++++++++++++++++++++++++++++ src/highlight.rs | 3 ++- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 linenoise.md diff --git a/linenoise.md b/linenoise.md new file mode 100644 index 000000000..7dedb7fef --- /dev/null +++ b/linenoise.md @@ -0,0 +1,34 @@ +Mapping between linenoise API and rustyline API + +| linenoise | rustyline | Remarks | +|--------------------------------|------------------------------|---------------------------| +| linenoiseState | State | | +| *Blocking API* | +| linenoise | Editor::readline | +| linenoiseFree | _ | RAII | +| *Non blocking API* | | +| linenoiseEditStart | _ | +| linenoiseEditFeed | _ | +| linenoiseEditStop | _ | +| linenoiseHide | Renderer::clear_rows | +| linenoiseShow | State::refresh_line | +| *Completion API* | +| linenoiseCompletions | Vec | +| linenoiseCompletionCallback | Completer | +| linenoiseAddCompletion | _ | std Vec::add | +| linenoiseSetCompletionCallback | Editor::set_helper | +| linenoiseHintsCallback | Hinter | +| linenoiseSetHintsCallback | Editor::set_helper | +| linenoiseFreeHintsCallback | _ | RAII | +| linenoiseSetFreeHintsCallback | _ | RAII | +| *History API* | +| linenoiseHistoryAdd | Editor::add_history_entry | +| linenoiseHistorySetMaxLen | Editor::set_max_history_size | +| linenoiseHistorySave | Editor::save_history | +| linenoiseHistoryLoad | Editor::load_history | +| *Other utilities* | +| linenoiseClearScreen | Editor::clear_screen | +| linenoiseSetMultiLine | _ | Always activated | +| linenoisePrintKeyCodes | _ | debug logs | +| linenoiseMaskModeEnable | _ | see read_password example | +| linenoiseMaskModeDisable | _ | diff --git a/src/highlight.rs b/src/highlight.rs index f3a816cc5..d5c0e8967 100644 --- a/src/highlight.rs +++ b/src/highlight.rs @@ -49,7 +49,8 @@ pub trait Highlighter { } /// Tells if `line` needs to be highlighted when a specific char is typed or /// when cursor is moved under a specific char. - /// `forced` flag is `true` mainly when user presses Enter (i.e. transient vs final highlight). + /// `forced` flag is `true` mainly when user presses Enter (i.e. transient + /// vs final highlight). /// /// Used to optimize refresh when a character is inserted or the cursor is /// moved. From f9e15385387881ad36fc89472916a7d25208ce07 Mon Sep 17 00:00:00 2001 From: gwenn <45554+gwenn@users.noreply.github.com> Date: Sat, 21 Oct 2023 09:28:57 +0200 Subject: [PATCH 06/43] Use wrap_at_eol when ENABLE_VIRTUAL_TERMINAL_PROCESSING is set Fix #738 --- src/tty/windows.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tty/windows.rs b/src/tty/windows.rs index 296e83df3..caba851a5 100644 --- a/src/tty/windows.rs +++ b/src/tty/windows.rs @@ -427,6 +427,11 @@ impl Renderer for ConsoleRenderer { col = self.wrap_at_eol(&highlighter.highlight_prompt(prompt, default_prompt), col); // append the input line col = self.wrap_at_eol(&highlighter.highlight(line, line.pos()), col); + } else if self.colors_enabled { + // append the prompt + col = self.wrap_at_eol(prompt, col); + // append the input line + col = self.wrap_at_eol(line, col); } else { // append the prompt self.buffer.push_str(prompt); @@ -437,6 +442,8 @@ impl Renderer for ConsoleRenderer { if let Some(hint) = hint { if let Some(highlighter) = highlighter { self.wrap_at_eol(&highlighter.highlight_hint(hint), col); + } else if self.colors_enabled { + self.wrap_at_eol(hint, col); } else { self.buffer.push_str(hint); } From 0fa1a7b24261a8e95c80cf4945f3c9a170bf6362 Mon Sep 17 00:00:00 2001 From: gwenn Date: Mon, 30 Oct 2023 18:40:32 +0100 Subject: [PATCH 07/43] Ignore binding::test::size_of_event on arch <> x86_64 --- src/binding.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/binding.rs b/src/binding.rs index fe2fa53e4..ed9dff8a4 100644 --- a/src/binding.rs +++ b/src/binding.rs @@ -216,8 +216,6 @@ pub trait ConditionalEventHandler: Send + Sync { #[cfg(test)] mod test { - use core::mem::size_of; - use super::{Event, EventHandler}; use crate::{Cmd, KeyCode, KeyEvent, Modifiers}; use radix_trie::Trie; @@ -251,7 +249,9 @@ mod test { } #[test] + #[cfg(target_arch = "x86_64")] fn size_of_event() { + use core::mem::size_of; assert_eq!(size_of::(), 32); } } From bd1b90d946db314561de5714e03e230602d4fa1b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 08:34:17 +0000 Subject: [PATCH 08/43] Update rusqlite requirement from 0.29.0 to 0.30.0 Updates the requirements on [rusqlite](https://github.com/rusqlite/rusqlite) to permit the latest version. - [Release notes](https://github.com/rusqlite/rusqlite/releases) - [Changelog](https://github.com/rusqlite/rusqlite/blob/master/Changelog.md) - [Commits](https://github.com/rusqlite/rusqlite/compare/v0.29.0...v0.30.0) --- updated-dependencies: - dependency-name: rusqlite dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 254c3e237..0af34b967 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ cfg-if = "1.0" home = { version = "0.5.4", optional = true } # For History fd-lock = { version = "4.0.0", optional = true } -rusqlite = { version = "0.29.0", optional = true, default-features = false, features = ["bundled", "backup"] } +rusqlite = { version = "0.30.0", optional = true, default-features = false, features = ["bundled", "backup"] } libc = "0.2" log = "0.4" unicode-width = "0.1" From 61bcac5ae19ece56922aa69280db70c5e45e5428 Mon Sep 17 00:00:00 2001 From: gwenn Date: Wed, 22 Nov 2023 18:40:03 +0100 Subject: [PATCH 09/43] Bump clipboard-win to version 5.0 --- Cargo.toml | 4 ++-- src/error.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0af34b967..cbe1fdbb1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,9 +49,9 @@ signal-hook = { version = "0.3", optional = true, default-features = false } termios = { version = "0.3.3", optional = true } [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["consoleapi", "handleapi", "synchapi", "minwindef", "processenv", "std", "winbase", "wincon", "winuser"] } +winapi = { version = "0.3", features = ["consoleapi", "handleapi", "synchapi", "minwindef", "processenv", "std", "winbase", "wincon", "winerror", "winuser"] } scopeguard = "1.1" -clipboard-win = "4.5" +clipboard-win = "5.0" [dev-dependencies] doc-comment = "0.3" diff --git a/src/error.rs b/src/error.rs index 0e2895f61..ee7ea1c81 100644 --- a/src/error.rs +++ b/src/error.rs @@ -28,7 +28,7 @@ pub enum ReadlineError { Decode(char::DecodeUtf16Error), /// Something went wrong calling a Windows API #[cfg(windows)] - SystemError(clipboard_win::SystemError), + SystemError(clipboard_win::ErrorCode), /// Error related to SQLite history backend #[cfg(feature = "with-sqlite-history")] SQLiteError(rusqlite::Error), @@ -133,8 +133,8 @@ impl From for ReadlineError { } #[cfg(windows)] -impl From for ReadlineError { - fn from(err: clipboard_win::SystemError) -> Self { +impl From for ReadlineError { + fn from(err: clipboard_win::ErrorCode) -> Self { ReadlineError::SystemError(err) } } From 23bb4ae1e667ab38b83f391b2bc79ebffcd8e49e Mon Sep 17 00:00:00 2001 From: gwenn Date: Sat, 25 Nov 2023 16:58:34 +0100 Subject: [PATCH 10/43] Change cursor visibility --- Cargo.toml | 1 - examples/read_password.rs | 6 +++-- src/lib.rs | 8 +++++++ src/tty/mod.rs | 3 +++ src/tty/test.rs | 5 ++++ src/tty/unix.rs | 26 +++++++++++++++++++++ src/tty/windows.rs | 48 +++++++++++++++++++++++++++------------ 7 files changed, 79 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cbe1fdbb1..3e9492efb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,6 @@ termios = { version = "0.3.3", optional = true } [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["consoleapi", "handleapi", "synchapi", "minwindef", "processenv", "std", "winbase", "wincon", "winerror", "winuser"] } -scopeguard = "1.1" clipboard-win = "5.0" [dev-dependencies] diff --git a/examples/read_password.rs b/examples/read_password.rs index ddcdd79e9..d669d511b 100644 --- a/examples/read_password.rs +++ b/examples/read_password.rs @@ -14,13 +14,13 @@ impl Highlighter for MaskingHighlighter { fn highlight<'l>(&self, line: &'l str, _pos: usize) -> Cow<'l, str> { use unicode_width::UnicodeWidthStr; if self.masking { - Owned("*".repeat(line.width())) + Owned(" ".repeat(line.width())) } else { Borrowed(line) } } - fn highlight_char(&self, line: &str, pos: usize, forced: bool) -> bool { + fn highlight_char(&self, _line: &str, _pos: usize, _forced: bool) -> bool { self.masking } } @@ -37,7 +37,9 @@ fn main() -> Result<()> { rl.helper_mut().expect("No helper").masking = true; rl.set_color_mode(ColorMode::Forced); // force masking rl.set_auto_add_history(false); // make sure password is not added to history + let mut guard = rl.set_cursor_visibility(false)?; let passwd = rl.readline("Password:")?; + guard.take(); println!("Secret: {passwd}"); Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index e15bb3029..b50e807c6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -917,6 +917,14 @@ impl Editor { pub fn create_external_printer(&mut self) -> Result<::ExternalPrinter> { self.term.create_external_printer() } + + /// Change cursor visibility + pub fn set_cursor_visibility( + &mut self, + visible: bool, + ) -> Result::CursorGuard>> { + self.term.set_cursor_visibility(visible) + } } impl config::Configurer for Editor { diff --git a/src/tty/mod.rs b/src/tty/mod.rs index 24f04f751..8bb34c236 100644 --- a/src/tty/mod.rs +++ b/src/tty/mod.rs @@ -220,6 +220,7 @@ pub trait Term { type Writer: Renderer; // rl_outstream type Mode: RawMode; type ExternalPrinter: ExternalPrinter; + type CursorGuard; fn new( color_mode: ColorMode, @@ -246,6 +247,8 @@ pub trait Term { fn writeln(&self) -> Result<()>; /// Create an external printer fn create_external_printer(&mut self) -> Result; + /// Change cursor visibility + fn set_cursor_visibility(&mut self, visible: bool) -> Result>; } // If on Windows platform import Windows TTY module diff --git a/src/tty/test.rs b/src/tty/test.rs index 88e22a6e0..d26af5e0a 100644 --- a/src/tty/test.rs +++ b/src/tty/test.rs @@ -160,6 +160,7 @@ pub struct DummyTerminal { } impl Term for DummyTerminal { + type CursorGuard = (); type ExternalPrinter = DummyExternalPrinter; type KeyMap = KeyMap; type Mode = Mode; @@ -219,6 +220,10 @@ impl Term for DummyTerminal { Ok(DummyExternalPrinter {}) } + fn set_cursor_visibility(&mut self, _: bool) -> Result> { + Ok(None) + } + fn writeln(&self) -> Result<()> { Ok(()) } diff --git a/src/tty/unix.rs b/src/tty/unix.rs index 00e33dc1e..75dace14a 100644 --- a/src/tty/unix.rs +++ b/src/tty/unix.rs @@ -1139,6 +1139,23 @@ fn write_all(fd: RawFd, buf: &str) -> nix::Result<()> { Ok(()) } +pub struct PosixCursorGuard(RawFd); + +impl Drop for PosixCursorGuard { + fn drop(&mut self) { + let _ = set_cursor_visibility(self.0, true); + } +} + +fn set_cursor_visibility(fd: RawFd, visible: bool) -> Result> { + write_all(fd, if visible { "\x1b[?25h" } else { "\x1b[?25l" })?; + Ok(if visible { + None + } else { + Some(PosixCursorGuard(fd)) + }) +} + #[cfg(not(feature = "signal-hook"))] static mut SIGWINCH_PIPE: RawFd = -1; #[cfg(not(feature = "signal-hook"))] @@ -1236,6 +1253,7 @@ impl PosixTerminal { } impl Term for PosixTerminal { + type CursorGuard = PosixCursorGuard; type ExternalPrinter = ExternalPrinter; type KeyMap = PosixKeyMap; type Mode = PosixMode; @@ -1405,6 +1423,14 @@ impl Term for PosixTerminal { tty_out: self.tty_out, }) } + + fn set_cursor_visibility(&mut self, visible: bool) -> Result> { + if self.is_out_a_tty { + set_cursor_visibility(self.tty_out, visible) + } else { + Ok(None) + } + } } #[allow(unused_must_use)] diff --git a/src/tty/windows.rs b/src/tty/windows.rs index caba851a5..8147ee0ce 100644 --- a/src/tty/windows.rs +++ b/src/tty/windows.rs @@ -330,8 +330,8 @@ impl ConsoleRenderer { })?) } - fn set_cursor_visible(&mut self, visible: BOOL) -> Result<()> { - set_cursor_visible(self.conout, visible) + fn set_cursor_visibility(&mut self, visible: bool) -> Result> { + set_cursor_visibility(self.conout, visible) } // You can't have both ENABLE_WRAP_AT_EOL_OUTPUT and @@ -374,16 +374,28 @@ impl ConsoleRenderer { } } -fn set_cursor_visible(handle: HANDLE, visible: BOOL) -> Result<()> { +pub struct ConsoleCursorGuard(HANDLE); + +impl Drop for ConsoleCursorGuard { + fn drop(&mut self) { + let _ = set_cursor_visibility(self.0, true); + } +} + +fn set_cursor_visibility(handle: HANDLE, visible: bool) -> Result> { let mut info = unsafe { mem::zeroed() }; check(unsafe { wincon::GetConsoleCursorInfo(handle, &mut info) })?; - if info.bVisible == visible { - return Ok(()); + let b = if visible { TRUE } else { FALSE }; + if info.bVisible == b { + return Ok(None); } - info.bVisible = visible; - Ok(check(unsafe { - wincon::SetConsoleCursorInfo(handle, &info) - })?) + info.bVisible = b; + check(unsafe { wincon::SetConsoleCursorInfo(handle, &info) })?; + Ok(if visible { + None + } else { + Some(ConsoleCursorGuard(handle)) + }) } impl Renderer for ConsoleRenderer { @@ -449,11 +461,8 @@ impl Renderer for ConsoleRenderer { } } let info = self.get_console_screen_buffer_info()?; - self.set_cursor_visible(FALSE)?; // just to avoid flickering - let handle = self.conout; - scopeguard::defer! { - let _ = set_cursor_visible(handle, TRUE); - } + // just to avoid flickering + let mut guard = self.set_cursor_visibility(false)?; // position at the start of the prompt, clear to end of previous input self.clear_old_rows(&info, old_layout)?; // display prompt, input line and hint @@ -465,7 +474,7 @@ impl Renderer for ConsoleRenderer { coord.X = cursor.col as i16; coord.Y -= (end_pos.row - cursor.row) as i16; self.set_console_cursor_position(coord, info.dwSize)?; - + guard.take(); Ok(()) } @@ -628,6 +637,7 @@ impl Console { } impl Term for Console { + type CursorGuard = ConsoleCursorGuard; type ExternalPrinter = ExternalPrinter; type KeyMap = ConsoleKeyMap; type Mode = ConsoleMode; @@ -831,6 +841,14 @@ impl Term for Console { conout: self.conout, }) } + + fn set_cursor_visibility(&mut self, visible: bool) -> Result> { + if self.conout_isatty { + set_cursor_visibility(self.conout, visible) + } else { + Ok(None) + } + } } impl Drop for Console { From 11cf445aacbc93c2ab113f08e77b7f7be5a43a4b Mon Sep 17 00:00:00 2001 From: gwenn Date: Sat, 2 Dec 2023 09:23:46 +0100 Subject: [PATCH 11/43] Fix some clippy warnings with `cargo test --all --all-targets --all-features` --- examples/custom_key_bindings.rs | 3 +-- src/lib.rs | 2 +- src/tty/mod.rs | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/custom_key_bindings.rs b/examples/custom_key_bindings.rs index 78db874cd..7d6624af7 100644 --- a/examples/custom_key_bindings.rs +++ b/examples/custom_key_bindings.rs @@ -73,8 +73,7 @@ impl ConditionalEventHandler for TabEventHandler { debug_assert_eq!(*evt, Event::from(KeyEvent::from('\t'))); if ctx.line()[..ctx.pos()] .chars() - .rev() - .next() + .next_back() .filter(|c| c.is_whitespace()) .is_some() { diff --git a/src/lib.rs b/src/lib.rs index b50e807c6..a298b125f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -238,7 +238,7 @@ fn complete_line( let selected_items = Skim::run_with(&options, Some(rx_item)) .map(|out| out.selected_items) - .unwrap_or_else(Vec::new); + .unwrap_or_default(); // match the first (and only) returned option with the candidate and update the // line otherwise only refresh line to clear the skim UI changes diff --git a/src/tty/mod.rs b/src/tty/mod.rs index 8bb34c236..e79d2a96b 100644 --- a/src/tty/mod.rs +++ b/src/tty/mod.rs @@ -255,14 +255,14 @@ pub trait Term { // and re-export into mod.rs scope #[cfg(all(windows, not(target_arch = "wasm32")))] mod windows; -#[cfg(all(windows, not(target_arch = "wasm32")))] +#[cfg(all(windows, not(target_arch = "wasm32"), not(test)))] pub use self::windows::*; // If on Unix platform import Unix TTY module // and re-export into mod.rs scope #[cfg(all(unix, not(target_arch = "wasm32")))] mod unix; -#[cfg(all(unix, not(target_arch = "wasm32")))] +#[cfg(all(unix, not(target_arch = "wasm32"), not(test)))] pub use self::unix::*; #[cfg(any(test, target_arch = "wasm32"))] From 5f8bec6dc1ac742e6b1e7c217da82f509fd85d0e Mon Sep 17 00:00:00 2001 From: gwenn Date: Sat, 2 Dec 2023 14:40:43 +0100 Subject: [PATCH 12/43] Support completion candidates that are shorter than the input --- src/lib.rs | 2 +- src/test/mod.rs | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a298b125f..972af0f44 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -151,7 +151,7 @@ fn complete_line( } else if CompletionType::List == config.completion_type() { if let Some(lcp) = longest_common_prefix(&candidates) { // if we can extend the item, extend it - if lcp.len() > s.line.pos() - start { + if lcp.len() > s.line.pos() - start || candidates.len() == 1 { completer.update(&mut s.line, start, lcp, &mut s.changes); s.refresh_line()?; } diff --git a/src/test/mod.rs b/src/test/mod.rs index 8eca186e2..6eb317db0 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -1,7 +1,7 @@ use std::vec::IntoIter; use crate::completion::Completer; -use crate::config::{Config, EditMode}; +use crate::config::{CompletionType, Config, EditMode}; use crate::edit::init_state; use crate::highlight::Highlighter; use crate::hint::Hinter; @@ -35,7 +35,16 @@ impl Completer for SimpleCompleter { _pos: usize, _ctx: &Context<'_>, ) -> Result<(usize, Vec)> { - Ok((0, vec![line.to_owned() + "t"])) + Ok(( + 0, + if line == "rus" { + vec![line.to_owned() + "t"] + } else if line == "\\hbar" { + vec!["ℏ".to_owned()] + } else { + vec![] + }, + )) } } impl Hinter for SimpleCompleter { @@ -61,7 +70,7 @@ fn complete_line() { let mut input_state = InputState::new(&config, &bindings); let keys = vec![E::ENTER]; let mut rdr: IntoIter = keys.into_iter(); - let cmd = super::complete_line(&mut rdr, &mut s, &mut input_state, &Config::default()).unwrap(); + let cmd = super::complete_line(&mut rdr, &mut s, &mut input_state, &config).unwrap(); assert_eq!( Some(Cmd::AcceptOrInsertLine { accept_in_the_middle: true @@ -72,6 +81,25 @@ fn complete_line() { assert_eq!(4, s.line.pos()); } +#[test] +fn complete_symbol() { + let mut out = Sink::default(); + let history = crate::history::DefaultHistory::new(); + let helper = Some(SimpleCompleter); + let mut s = init_state(&mut out, "\\hbar", 5, helper.as_ref(), &history); + let config = Config::builder() + .completion_type(CompletionType::List) + .build(); + let bindings = Bindings::new(); + let mut input_state = InputState::new(&config, &bindings); + let keys = vec![E::ENTER]; + let mut rdr: IntoIter = keys.into_iter(); + let cmd = super::complete_line(&mut rdr, &mut s, &mut input_state, &config).unwrap(); + assert_eq!(None, cmd); + assert_eq!("ℏ", s.line.as_str()); + assert_eq!(3, s.line.pos()); +} + // `keys`: keys to press // `expected_line`: line after enter key fn assert_line(mode: EditMode, keys: &[KeyEvent], expected_line: &str) { From 0bebb37a74e2518820aaf888b53ea9e1a10ca134 Mon Sep 17 00:00:00 2001 From: gwenn Date: Tue, 5 Dec 2023 18:36:28 +0100 Subject: [PATCH 13/43] Fix derive macro with Highlighter attr --- examples/input_multiline.rs | 4 ++++ rustyline-derive/src/lib.rs | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/input_multiline.rs b/examples/input_multiline.rs index 7dd5b6f5b..ead5e8825 100644 --- a/examples/input_multiline.rs +++ b/examples/input_multiline.rs @@ -1,3 +1,4 @@ +use rustyline::highlight::MatchingBracketHighlighter; use rustyline::validate::MatchingBracketValidator; use rustyline::{Cmd, Editor, EventHandler, KeyCode, KeyEvent, Modifiers, Result}; use rustyline::{Completer, Helper, Highlighter, Hinter, Validator}; @@ -6,11 +7,14 @@ use rustyline::{Completer, Helper, Highlighter, Hinter, Validator}; struct InputValidator { #[rustyline(Validator)] brackets: MatchingBracketValidator, + #[rustyline(Highlighter)] + highlighter: MatchingBracketHighlighter, } fn main() -> Result<()> { let h = InputValidator { brackets: MatchingBracketValidator::new(), + highlighter: MatchingBracketHighlighter::new(), }; let mut rl = Editor::new()?; rl.set_helper(Some(h)); diff --git a/rustyline-derive/src/lib.rs b/rustyline-derive/src/lib.rs index 5f57060a8..c25e6165b 100644 --- a/rustyline-derive/src/lib.rs +++ b/rustyline-derive/src/lib.rs @@ -126,8 +126,8 @@ pub fn highlighter_macro_derive(input: TokenStream) -> TokenStream { ::rustyline::highlight::Highlighter::highlight_candidate(&self.#field_name_or_index, candidate, completion) } - fn highlight_char(&self, line: &str, pos: usize) -> bool { - ::rustyline::highlight::Highlighter::highlight_char(&self.#field_name_or_index, line, pos) + fn highlight_char(&self, line: &str, pos: usize, forced: bool) -> bool { + ::rustyline::highlight::Highlighter::highlight_char(&self.#field_name_or_index, line, pos, forced) } } } From 2548151d24e5e9803299ef491f45b28dfd141f42 Mon Sep 17 00:00:00 2001 From: gwenn Date: Tue, 5 Dec 2023 18:56:13 +0100 Subject: [PATCH 14/43] Prepare next release --- Cargo.toml | 4 ++-- README.md | 2 +- rustyline-derive/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3e9492efb..54a91a929 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustyline" -version = "12.0.0" +version = "13.0.0" authors = ["Katsu Kawakami "] edition = "2021" description = "Rustyline, a readline implementation based on Antirez's Linenoise" @@ -39,7 +39,7 @@ memchr = "2.0" radix_trie = { version = "0.2", optional = true } regex = { version = "1.5.5", optional = true } # For derive -rustyline-derive = { version = "0.9.0", optional = true, path = "rustyline-derive" } +rustyline-derive = { version = "0.10.0", optional = true, path = "rustyline-derive" } [target.'cfg(unix)'.dependencies] nix = { version = "0.27", default-features = false, features = ["fs", "ioctl", "poll", "signal", "term"] } diff --git a/README.md b/README.md index 4dd54337f..84add3ae9 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ to your `Cargo.toml`: ```toml [dependencies] -rustyline = "12.0.0" +rustyline = "13.0.0" ``` ## Features diff --git a/rustyline-derive/Cargo.toml b/rustyline-derive/Cargo.toml index c793fdcbf..cc117bfcc 100644 --- a/rustyline-derive/Cargo.toml +++ b/rustyline-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustyline-derive" -version = "0.9.0" +version = "0.10.0" authors = ["gwenn"] edition = "2018" description = "Rustyline macros implementation of #[derive(Completer, Helper, Hinter, Highlighter)]" From 162fb559ede23b7d8fdbd7da7dfba811dd230bc8 Mon Sep 17 00:00:00 2001 From: printfn Date: Fri, 15 Dec 2023 23:10:43 +0000 Subject: [PATCH 15/43] Migrate to windows-sys --- Cargo.toml | 2 +- src/tty/windows.rs | 215 +++++++++++++++++++++++---------------------- 2 files changed, 110 insertions(+), 107 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 54a91a929..4ede8d9a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ signal-hook = { version = "0.3", optional = true, default-features = false } termios = { version = "0.3.3", optional = true } [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["consoleapi", "handleapi", "synchapi", "minwindef", "processenv", "std", "winbase", "wincon", "winerror", "winuser"] } +windows-sys = { version = "0.52.0", features = ["Win32_Foundation", "Win32_System_Console", "Win32_Security", "Win32_System_Threading", "Win32_UI_Input_KeyboardAndMouse"] } clipboard-win = "5.0" [dev-dependencies] diff --git a/src/tty/windows.rs b/src/tty/windows.rs index 8147ee0ce..f1598cbc3 100644 --- a/src/tty/windows.rs +++ b/src/tty/windows.rs @@ -14,13 +14,10 @@ use std::sync::Arc; use log::{debug, warn}; use unicode_segmentation::UnicodeSegmentation; use unicode_width::UnicodeWidthStr; -use winapi::shared::minwindef::{BOOL, DWORD, FALSE, TRUE, WORD}; -use winapi::shared::winerror; -use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE}; -use winapi::um::synchapi::{CreateEventW, ResetEvent, SetEvent}; -use winapi::um::wincon::{self, CONSOLE_SCREEN_BUFFER_INFO, COORD}; -use winapi::um::winnt::{CHAR, HANDLE}; -use winapi::um::{consoleapi, processenv, winbase, winuser}; +use windows_sys::Win32::Foundation::{self as foundation, BOOL, FALSE, HANDLE, TRUE}; +use windows_sys::Win32::System::Console as console; +use windows_sys::Win32::System::Threading as threading; +use windows_sys::Win32::UI::Input::KeyboardAndMouse; use super::{width, Event, RawMode, RawReader, Renderer, Term}; use crate::config::{Behavior, BellStyle, ColorMode, Config}; @@ -30,15 +27,15 @@ use crate::layout::{Layout, Position}; use crate::line_buffer::LineBuffer; use crate::{error, Cmd, Result}; -fn get_std_handle(fd: DWORD) -> Result { - let handle = unsafe { processenv::GetStdHandle(fd) }; +fn get_std_handle(fd: console::STD_HANDLE) -> Result { + let handle = unsafe { console::GetStdHandle(fd) }; check_handle(handle) } fn check_handle(handle: HANDLE) -> Result { - if handle == INVALID_HANDLE_VALUE { + if handle == foundation::INVALID_HANDLE_VALUE { Err(io::Error::last_os_error())?; - } else if handle.is_null() { + } else if handle == 0 { Err(io::Error::new( io::ErrorKind::Other, "no stdio handle available for this process", @@ -57,7 +54,7 @@ fn check(rc: BOOL) -> io::Result<()> { fn get_win_size(handle: HANDLE) -> (usize, usize) { let mut info = unsafe { mem::zeroed() }; - match unsafe { wincon::GetConsoleScreenBufferInfo(handle, &mut info) } { + match unsafe { console::GetConsoleScreenBufferInfo(handle, &mut info) } { FALSE => (80, 24), _ => ( info.dwSize.X as usize, @@ -66,9 +63,9 @@ fn get_win_size(handle: HANDLE) -> (usize, usize) { } } -fn get_console_mode(handle: HANDLE) -> Result { +fn get_console_mode(handle: HANDLE) -> Result { let mut original_mode = 0; - check(unsafe { consoleapi::GetConsoleMode(handle, &mut original_mode) })?; + check(unsafe { console::GetConsoleMode(handle, &mut original_mode) })?; Ok(original_mode) } @@ -82,9 +79,9 @@ pub type Mode = ConsoleMode; #[must_use = "You must restore default mode (disable_raw_mode)"] #[derive(Clone, Debug)] pub struct ConsoleMode { - original_conin_mode: DWORD, + original_conin_mode: console::CONSOLE_MODE, conin: HANDLE, - original_conout_mode: Option, + original_conout_mode: Option, conout: HANDLE, raw_mode: Arc, } @@ -92,9 +89,9 @@ pub struct ConsoleMode { impl RawMode for ConsoleMode { /// Disable RAW mode for the terminal. fn disable_raw_mode(&self) -> Result<()> { - check(unsafe { consoleapi::SetConsoleMode(self.conin, self.original_conin_mode) })?; + check(unsafe { console::SetConsoleMode(self.conin, self.original_conin_mode) })?; if let Some(original_stdstream_mode) = self.original_conout_mode { - check(unsafe { consoleapi::SetConsoleMode(self.conout, original_stdstream_mode) })?; + check(unsafe { console::SetConsoleMode(self.conout, original_stdstream_mode) })?; } self.raw_mode.store(false, Ordering::SeqCst); Ok(()) @@ -114,8 +111,8 @@ impl ConsoleRawReader { } fn select(&mut self) -> Result { - use winapi::um::synchapi::WaitForMultipleObjects; - use winapi::um::winbase::{INFINITE, WAIT_OBJECT_0}; + use foundation::WAIT_OBJECT_0; + use threading::{WaitForMultipleObjects, INFINITE}; let pipe_reader = self.pipe_reader.as_ref().unwrap(); let handles = [self.conin, pipe_reader.event.0]; @@ -124,16 +121,14 @@ impl ConsoleRawReader { let rc = unsafe { WaitForMultipleObjects(n, handles.as_ptr(), FALSE, INFINITE) }; if rc == WAIT_OBJECT_0 { let mut count = 0; - check(unsafe { - consoleapi::GetNumberOfConsoleInputEvents(self.conin, &mut count) - })?; + check(unsafe { console::GetNumberOfConsoleInputEvents(self.conin, &mut count) })?; match read_input(self.conin, count)? { KeyEvent(K::UnknownEscSeq, M::NONE) => continue, // no relevant key => return Ok(Event::KeyPress(key)), }; } else if rc == WAIT_OBJECT_0 + 1 { debug!(target: "rustyline", "ExternalPrinter::receive"); - check(unsafe { ResetEvent(pipe_reader.event.0) })?; + check(unsafe { threading::ResetEvent(pipe_reader.event.0) })?; match pipe_reader.receiver.recv() { Ok(msg) => return Ok(Event::ExternalPrint(msg)), Err(e) => Err(io::Error::new(io::ErrorKind::InvalidInput, e))?, @@ -167,12 +162,12 @@ impl RawReader for ConsoleRawReader { } fn read_input(handle: HANDLE, max_count: u32) -> Result { - use std::char::decode_utf16; - use winapi::um::wincon::{ + use console::{ LEFT_ALT_PRESSED, LEFT_CTRL_PRESSED, RIGHT_ALT_PRESSED, RIGHT_CTRL_PRESSED, SHIFT_PRESSED, }; + use std::char::decode_utf16; - let mut rec: wincon::INPUT_RECORD = unsafe { mem::zeroed() }; + let mut rec: console::INPUT_RECORD = unsafe { mem::zeroed() }; let mut count = 0; let mut total = 0; let mut surrogate = 0; @@ -181,18 +176,18 @@ fn read_input(handle: HANDLE, max_count: u32) -> Result { return Ok(KeyEvent(K::UnknownEscSeq, M::NONE)); } // TODO GetNumberOfConsoleInputEvents - check(unsafe { consoleapi::ReadConsoleInputW(handle, &mut rec, 1, &mut count) })?; + check(unsafe { console::ReadConsoleInputW(handle, &mut rec, 1, &mut count) })?; total += count; - if rec.EventType == wincon::WINDOW_BUFFER_SIZE_EVENT { + if u32::from(rec.EventType) == console::WINDOW_BUFFER_SIZE_EVENT { debug!(target: "rustyline", "SIGWINCH"); return Err(error::ReadlineError::WindowResized); - } else if rec.EventType != wincon::KEY_EVENT { + } else if u32::from(rec.EventType) != console::KEY_EVENT { continue; } - let key_event = unsafe { rec.Event.KeyEvent() }; + let key_event = unsafe { rec.Event.KeyEvent }; // writeln!(io::stderr(), "key_event: {:?}", key_event).unwrap(); - if key_event.bKeyDown == 0 && key_event.wVirtualKeyCode != winuser::VK_MENU as WORD { + if key_event.bKeyDown == 0 && key_event.wVirtualKeyCode != KeyboardAndMouse::VK_MENU { continue; } // key_event.wRepeatCount seems to be always set to 1 (maybe because we only @@ -211,34 +206,34 @@ fn read_input(handle: HANDLE, max_count: u32) -> Result { mods |= M::SHIFT; } - let utf16 = unsafe { *key_event.uChar.UnicodeChar() }; - let key_code = match i32::from(key_event.wVirtualKeyCode) { - winuser::VK_LEFT => K::Left, - winuser::VK_RIGHT => K::Right, - winuser::VK_UP => K::Up, - winuser::VK_DOWN => K::Down, - winuser::VK_DELETE => K::Delete, - winuser::VK_HOME => K::Home, - winuser::VK_END => K::End, - winuser::VK_PRIOR => K::PageUp, - winuser::VK_NEXT => K::PageDown, - winuser::VK_INSERT => K::Insert, - winuser::VK_F1 => K::F(1), - winuser::VK_F2 => K::F(2), - winuser::VK_F3 => K::F(3), - winuser::VK_F4 => K::F(4), - winuser::VK_F5 => K::F(5), - winuser::VK_F6 => K::F(6), - winuser::VK_F7 => K::F(7), - winuser::VK_F8 => K::F(8), - winuser::VK_F9 => K::F(9), - winuser::VK_F10 => K::F(10), - winuser::VK_F11 => K::F(11), - winuser::VK_F12 => K::F(12), - winuser::VK_BACK => K::Backspace, // vs Ctrl-h - winuser::VK_RETURN => K::Enter, // vs Ctrl-m - winuser::VK_ESCAPE => K::Esc, - winuser::VK_TAB => { + let utf16 = unsafe { key_event.uChar.UnicodeChar }; + let key_code = match key_event.wVirtualKeyCode { + KeyboardAndMouse::VK_LEFT => K::Left, + KeyboardAndMouse::VK_RIGHT => K::Right, + KeyboardAndMouse::VK_UP => K::Up, + KeyboardAndMouse::VK_DOWN => K::Down, + KeyboardAndMouse::VK_DELETE => K::Delete, + KeyboardAndMouse::VK_HOME => K::Home, + KeyboardAndMouse::VK_END => K::End, + KeyboardAndMouse::VK_PRIOR => K::PageUp, + KeyboardAndMouse::VK_NEXT => K::PageDown, + KeyboardAndMouse::VK_INSERT => K::Insert, + KeyboardAndMouse::VK_F1 => K::F(1), + KeyboardAndMouse::VK_F2 => K::F(2), + KeyboardAndMouse::VK_F3 => K::F(3), + KeyboardAndMouse::VK_F4 => K::F(4), + KeyboardAndMouse::VK_F5 => K::F(5), + KeyboardAndMouse::VK_F6 => K::F(6), + KeyboardAndMouse::VK_F7 => K::F(7), + KeyboardAndMouse::VK_F8 => K::F(8), + KeyboardAndMouse::VK_F9 => K::F(9), + KeyboardAndMouse::VK_F10 => K::F(10), + KeyboardAndMouse::VK_F11 => K::F(11), + KeyboardAndMouse::VK_F12 => K::F(12), + KeyboardAndMouse::VK_BACK => K::Backspace, // vs Ctrl-h + KeyboardAndMouse::VK_RETURN => K::Enter, // vs Ctrl-m + KeyboardAndMouse::VK_ESCAPE => K::Esc, + KeyboardAndMouse::VK_TAB => { if mods.contains(M::SHIFT) { mods.remove(M::SHIFT); K::BackTab @@ -304,29 +299,33 @@ impl ConsoleRenderer { } } - fn get_console_screen_buffer_info(&self) -> Result { + fn get_console_screen_buffer_info(&self) -> Result { let mut info = unsafe { mem::zeroed() }; - check(unsafe { wincon::GetConsoleScreenBufferInfo(self.conout, &mut info) })?; + check(unsafe { console::GetConsoleScreenBufferInfo(self.conout, &mut info) })?; Ok(info) } - fn set_console_cursor_position(&mut self, mut pos: COORD, size: COORD) -> Result { + fn set_console_cursor_position( + &mut self, + mut pos: console::COORD, + size: console::COORD, + ) -> Result { use std::cmp::{max, min}; // https://docs.microsoft.com/en-us/windows/console/setconsolecursorposition // > The coordinates must be within the boundaries of the console screen buffer. // pos.X = max(0, min(size.X - 1, pos.X)); pos.Y = max(0, min(size.Y - 1, pos.Y)); - check(unsafe { wincon::SetConsoleCursorPosition(self.conout, pos) })?; + check(unsafe { console::SetConsoleCursorPosition(self.conout, pos) })?; Ok(pos) } - fn clear(&mut self, length: DWORD, pos: COORD, attr: WORD) -> Result<()> { + fn clear(&mut self, length: u32, pos: console::COORD, attr: u16) -> Result<()> { let mut _count = 0; check(unsafe { - wincon::FillConsoleOutputCharacterA(self.conout, ' ' as CHAR, length, pos, &mut _count) + console::FillConsoleOutputCharacterA(self.conout, b' ', length, pos, &mut _count) })?; Ok(check(unsafe { - wincon::FillConsoleOutputAttribute(self.conout, attr, length, pos, &mut _count) + console::FillConsoleOutputAttribute(self.conout, attr, length, pos, &mut _count) })?) } @@ -359,7 +358,11 @@ impl ConsoleRenderer { } // position at the start of the prompt, clear to end of previous input - fn clear_old_rows(&mut self, info: &CONSOLE_SCREEN_BUFFER_INFO, layout: &Layout) -> Result<()> { + fn clear_old_rows( + &mut self, + info: &console::CONSOLE_SCREEN_BUFFER_INFO, + layout: &Layout, + ) -> Result<()> { let current_row = layout.cursor.row; let old_rows = layout.end.row; let mut coord = info.dwCursorPosition; @@ -367,7 +370,7 @@ impl ConsoleRenderer { coord.Y -= current_row as i16; let coord = self.set_console_cursor_position(coord, info.dwSize)?; self.clear( - (info.dwSize.X * (old_rows as i16 + 1)) as DWORD, + (info.dwSize.X * (old_rows as i16 + 1)) as u32, coord, info.wAttributes, ) @@ -384,13 +387,13 @@ impl Drop for ConsoleCursorGuard { fn set_cursor_visibility(handle: HANDLE, visible: bool) -> Result> { let mut info = unsafe { mem::zeroed() }; - check(unsafe { wincon::GetConsoleCursorInfo(handle, &mut info) })?; + check(unsafe { console::GetConsoleCursorInfo(handle, &mut info) })?; let b = if visible { TRUE } else { FALSE }; if info.bVisible == b { return Ok(None); } info.bVisible = b; - check(unsafe { wincon::SetConsoleCursorInfo(handle, &info) })?; + check(unsafe { console::SetConsoleCursorInfo(handle, &info) })?; Ok(if visible { None } else { @@ -515,9 +518,9 @@ impl Renderer for ConsoleRenderer { /// Clear the screen. Used to handle ctrl+l fn clear_screen(&mut self) -> Result<()> { let info = self.get_console_screen_buffer_info()?; - let coord = COORD { X: 0, Y: 0 }; - check(unsafe { wincon::SetConsoleCursorPosition(self.conout, coord) })?; - let n = info.dwSize.X as DWORD * info.dwSize.Y as DWORD; + let coord = console::COORD { X: 0, Y: 0 }; + check(unsafe { console::SetConsoleCursorPosition(self.conout, coord) })?; + let n = info.dwSize.X as u32 * info.dwSize.Y as u32; self.clear(n, coord, info.wAttributes) } @@ -559,7 +562,7 @@ impl Renderer for ConsoleRenderer { cursor.Y += 1; let res = self.set_console_cursor_position(cursor, info.dwSize); if let Err(error::ReadlineError::Io(ref e)) = res { - if e.raw_os_error() == Some(winerror::ERROR_INVALID_PARAMETER as i32) { + if e.raw_os_error() == Some(foundation::ERROR_INVALID_PARAMETER as i32) { warn!(target: "rustyline", "invalid cursor position: ({:?}, {:?}) in ({:?}, {:?})", cursor.X, cursor.Y, info.dwSize.X, info.dwSize.Y); write_all(self.conout, &[10; 1])?; return Ok(()); @@ -589,7 +592,7 @@ fn write_all(handle: HANDLE, mut data: &[u16]) -> Result<()> { }; let mut written = 0; check(unsafe { - consoleapi::WriteConsoleW( + console::WriteConsoleW( handle, slice.as_ptr().cast::(), slice.len() as u32, @@ -657,21 +660,21 @@ impl Term for Console { OpenOptions::new().read(true).write(true).open("CONOUT$"), ) { ( - Ok(conin.into_raw_handle()), - Ok(conout.into_raw_handle()), + Ok(conin.into_raw_handle() as HANDLE), + Ok(conout.into_raw_handle() as HANDLE), true, ) } else { ( - get_std_handle(winbase::STD_INPUT_HANDLE), - get_std_handle(winbase::STD_OUTPUT_HANDLE), + get_std_handle(console::STD_INPUT_HANDLE), + get_std_handle(console::STD_OUTPUT_HANDLE), false, ) } } else { ( - get_std_handle(winbase::STD_INPUT_HANDLE), - get_std_handle(winbase::STD_OUTPUT_HANDLE), + get_std_handle(console::STD_INPUT_HANDLE), + get_std_handle(console::STD_OUTPUT_HANDLE), false, ) }; @@ -693,9 +696,9 @@ impl Term for Console { Ok(Console { conin_isatty, - conin: conin.unwrap_or(ptr::null_mut()), + conin: conin.unwrap_or(0), conout_isatty, - conout: conout.unwrap_or(ptr::null_mut()), + conout: conout.unwrap_or(0), close_on_drop, color_mode, ansi_colors_supported: false, @@ -734,44 +737,44 @@ impl Term for Console { let original_conin_mode = get_console_mode(self.conin)?; // Disable these modes let mut raw = original_conin_mode - & !(wincon::ENABLE_LINE_INPUT - | wincon::ENABLE_ECHO_INPUT - | wincon::ENABLE_PROCESSED_INPUT); + & !(console::ENABLE_LINE_INPUT + | console::ENABLE_ECHO_INPUT + | console::ENABLE_PROCESSED_INPUT); // Enable these modes - raw |= wincon::ENABLE_EXTENDED_FLAGS; - raw |= wincon::ENABLE_INSERT_MODE; - raw |= wincon::ENABLE_QUICK_EDIT_MODE; - raw |= wincon::ENABLE_WINDOW_INPUT; - check(unsafe { consoleapi::SetConsoleMode(self.conin, raw) })?; + raw |= console::ENABLE_EXTENDED_FLAGS; + raw |= console::ENABLE_INSERT_MODE; + raw |= console::ENABLE_QUICK_EDIT_MODE; + raw |= console::ENABLE_WINDOW_INPUT; + check(unsafe { console::SetConsoleMode(self.conin, raw) })?; let original_conout_mode = if self.conout_isatty { let original_conout_mode = get_console_mode(self.conout)?; let mut mode = original_conout_mode; - if mode & wincon::ENABLE_WRAP_AT_EOL_OUTPUT == 0 { - mode |= wincon::ENABLE_WRAP_AT_EOL_OUTPUT; + if mode & console::ENABLE_WRAP_AT_EOL_OUTPUT == 0 { + mode |= console::ENABLE_WRAP_AT_EOL_OUTPUT; debug!(target: "rustyline", "activate ENABLE_WRAP_AT_EOL_OUTPUT"); unsafe { - assert_ne!(consoleapi::SetConsoleMode(self.conout, mode), 0); + assert_ne!(console::SetConsoleMode(self.conout, mode), 0); } } // To enable ANSI colors (Windows 10 only): // https://docs.microsoft.com/en-us/windows/console/setconsolemode - self.ansi_colors_supported = mode & wincon::ENABLE_VIRTUAL_TERMINAL_PROCESSING != 0; + self.ansi_colors_supported = mode & console::ENABLE_VIRTUAL_TERMINAL_PROCESSING != 0; if self.ansi_colors_supported { if self.color_mode == ColorMode::Disabled { - mode &= !wincon::ENABLE_VIRTUAL_TERMINAL_PROCESSING; + mode &= !console::ENABLE_VIRTUAL_TERMINAL_PROCESSING; debug!(target: "rustyline", "deactivate ENABLE_VIRTUAL_TERMINAL_PROCESSING"); unsafe { - assert_ne!(consoleapi::SetConsoleMode(self.conout, mode), 0); + assert_ne!(console::SetConsoleMode(self.conout, mode), 0); } } else { debug!(target: "rustyline", "ANSI colors already enabled"); } } else if self.color_mode != ColorMode::Disabled { - mode |= wincon::ENABLE_VIRTUAL_TERMINAL_PROCESSING; + mode |= console::ENABLE_VIRTUAL_TERMINAL_PROCESSING; self.ansi_colors_supported = - unsafe { consoleapi::SetConsoleMode(self.conout, mode) != 0 }; + unsafe { console::SetConsoleMode(self.conout, mode) != 0 }; debug!(target: "rustyline", "ansi_colors_supported: {}", self.ansi_colors_supported); } Some(original_conout_mode) @@ -822,8 +825,8 @@ impl Term for Console { if !self.is_input_tty() || !self.is_output_tty() { Err(io::Error::from(io::ErrorKind::Other))?; // FIXME } - let event = unsafe { CreateEventW(ptr::null_mut(), TRUE, FALSE, ptr::null()) }; - if event.is_null() { + let event = unsafe { threading::CreateEventW(ptr::null_mut(), TRUE, FALSE, ptr::null()) }; + if event == 0 { Err(io::Error::last_os_error())?; } let (sender, receiver) = sync_channel(1); @@ -854,8 +857,8 @@ impl Term for Console { impl Drop for Console { fn drop(&mut self) { if self.close_on_drop { - unsafe { CloseHandle(self.conin) }; - unsafe { CloseHandle(self.conout) }; + unsafe { foundation::CloseHandle(self.conin) }; + unsafe { foundation::CloseHandle(self.conout) }; } } } @@ -890,7 +893,7 @@ impl super::ExternalPrinter for ExternalPrinter { self.sender .send(msg) .map_err(|_| io::Error::from(io::ErrorKind::Other))?; // FIXME - Ok(check(unsafe { SetEvent(self.event) })?) + Ok(check(unsafe { threading::SetEvent(self.event) })?) } } } @@ -903,7 +906,7 @@ unsafe impl Sync for Handle {} impl Drop for Handle { fn drop(&mut self) { - unsafe { CloseHandle(self.0) }; + unsafe { foundation::CloseHandle(self.0) }; } } From a4962f77bc889fe03f5ec50f2ccd00c1e058347e Mon Sep 17 00:00:00 2001 From: Andrei Stan Date: Sun, 7 Jan 2024 12:47:18 +0200 Subject: [PATCH 16/43] Add enable signals config option Signed-off-by: Andrei Stan --- src/config.rs | 31 +++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/tty/mod.rs | 1 + src/tty/test.rs | 1 + src/tty/unix.rs | 19 ++++++++++++++++--- src/tty/windows.rs | 1 + 6 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/config.rs b/src/config.rs index 746145166..5a531d3f3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -35,6 +35,8 @@ pub struct Config { check_cursor_position: bool, /// Bracketed paste on unix platform enable_bracketed_paste: bool, + /// Whether to disable or not the signals in termios + enable_signals: bool, } impl Config { @@ -193,6 +195,18 @@ impl Config { pub fn enable_bracketed_paste(&self) -> bool { self.enable_bracketed_paste } + + /// Enable or disable signals in termios + /// + /// By default, it's disabled. + #[must_use] + pub fn enable_signals(&self) -> bool { + self.enable_signals + } + + pub(crate) fn set_enable_signals(&mut self, enable_signals: bool) { + self.enable_signals = enable_signals; + } } impl Default for Config { @@ -213,6 +227,7 @@ impl Default for Config { indent_size: 2, check_cursor_position: false, enable_bracketed_paste: true, + enable_signals: false, } } } @@ -450,6 +465,15 @@ impl Builder { self } + /// Enable or disable signals in termios + /// + /// By default, it's disabled. + #[must_use] + pub fn enable_signals(mut self, enable_signals: bool) -> Self { + self.p.set_enable_signals(enable_signals); + self + } + /// Builds a `Config` with the settings specified so far. #[must_use] pub fn build(self) -> Config { @@ -567,4 +591,11 @@ pub trait Configurer { fn enable_bracketed_paste(&mut self, enabled: bool) { self.config_mut().enable_bracketed_paste = enabled; } + + /// Enable or disable signals in termios + /// + /// By default, it's disabled. + fn set_enable_signals(&mut self, enable_signals: bool) { + self.config_mut().set_enable_signals(enable_signals); + } } diff --git a/src/lib.rs b/src/lib.rs index 972af0f44..02d42b90d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -618,6 +618,7 @@ impl Editor { config.tab_stop(), config.bell_style(), config.enable_bracketed_paste(), + config.enable_signals(), )?; Ok(Self { term, diff --git a/src/tty/mod.rs b/src/tty/mod.rs index e79d2a96b..2cee68768 100644 --- a/src/tty/mod.rs +++ b/src/tty/mod.rs @@ -228,6 +228,7 @@ pub trait Term { tab_stop: usize, bell_style: BellStyle, enable_bracketed_paste: bool, + enable_signals: bool, ) -> Result where Self: Sized; diff --git a/src/tty/test.rs b/src/tty/test.rs index d26af5e0a..55d830e57 100644 --- a/src/tty/test.rs +++ b/src/tty/test.rs @@ -173,6 +173,7 @@ impl Term for DummyTerminal { _tab_stop: usize, bell_style: BellStyle, _enable_bracketed_paste: bool, + _enable_signals: bool, ) -> Result { Ok(DummyTerminal { keys: Vec::new(), diff --git a/src/tty/unix.rs b/src/tty/unix.rs index 75dace14a..afd0b1cec 100644 --- a/src/tty/unix.rs +++ b/src/tty/unix.rs @@ -1240,6 +1240,7 @@ pub struct PosixTerminal { // external print writer pipe_writer: Option, sigwinch: Option, + enable_signals: bool, } impl PosixTerminal { @@ -1266,6 +1267,7 @@ impl Term for PosixTerminal { tab_stop: usize, bell_style: BellStyle, enable_bracketed_paste: bool, + enable_signals: bool, ) -> Result { let (tty_in, is_in_a_tty, tty_out, is_out_a_tty, close_on_drop) = if behavior == Behavior::PreferTerm { @@ -1314,6 +1316,7 @@ impl Term for PosixTerminal { pipe_reader: None, pipe_writer: None, sigwinch, + enable_signals, }) } @@ -1340,7 +1343,7 @@ impl Term for PosixTerminal { if !self.is_in_a_tty { return Err(ENOTTY.into()); } - let (original_mode, key_map) = termios_::enable_raw_mode(self.tty_in)?; + let (original_mode, key_map) = termios_::enable_raw_mode(self.tty_in, self.enable_signals)?; self.raw_mode.store(true, Ordering::SeqCst); // enable bracketed paste @@ -1493,7 +1496,7 @@ mod termios_ { let fd = unsafe { BorrowedFd::borrow_raw(tty_in) }; Ok(termios::tcsetattr(fd, SetArg::TCSADRAIN, termios)?) } - pub fn enable_raw_mode(tty_in: RawFd) -> Result<(Termios, PosixKeyMap)> { + pub fn enable_raw_mode(tty_in: RawFd, enable_signals: bool) -> Result<(Termios, PosixKeyMap)> { use nix::sys::termios::{ControlFlags, InputFlags, LocalFlags}; let fd = unsafe { BorrowedFd::borrow_raw(tty_in) }; @@ -1515,6 +1518,11 @@ mod termios_ { // disable echoing, canonical mode, extended input processing and signals raw.local_flags &= !(LocalFlags::ECHO | LocalFlags::ICANON | LocalFlags::IEXTEN | LocalFlags::ISIG); + + if enable_signals { + raw.local_flags |= LocalFlags::ISIG; + } + raw.control_chars[SCI::VMIN as usize] = 1; // One character-at-a-time input raw.control_chars[SCI::VTIME as usize] = 0; // with blocking read @@ -1551,7 +1559,7 @@ mod termios_ { pub fn disable_raw_mode(tty_in: RawFd, termios: &Termios) -> Result<()> { Ok(termios::tcsetattr(tty_in, termios::TCSADRAIN, termios)?) } - pub fn enable_raw_mode(tty_in: RawFd) -> Result<(Termios, PosixKeyMap)> { + pub fn enable_raw_mode(tty_in: RawFd, enable_signals: bool) -> Result<(Termios, PosixKeyMap)> { let original_mode = Termios::from_fd(tty_in)?; let mut raw = original_mode; // disable BREAK interrupt, CR to NL conversion on input, @@ -1566,6 +1574,11 @@ mod termios_ { raw.c_cflag |= termios::CS8; // disable echoing, canonical mode, extended input processing and signals raw.c_lflag &= !(termios::ECHO | termios::ICANON | termios::IEXTEN | termios::ISIG); + + if enable_signals { + raw.c_lflag |= termios::ISIG; + } + raw.c_cc[termios::VMIN] = 1; // One character-at-a-time input raw.c_cc[termios::VTIME] = 0; // with blocking read diff --git a/src/tty/windows.rs b/src/tty/windows.rs index f1598cbc3..7ac6ff574 100644 --- a/src/tty/windows.rs +++ b/src/tty/windows.rs @@ -653,6 +653,7 @@ impl Term for Console { _tab_stop: usize, bell_style: BellStyle, _enable_bracketed_paste: bool, + _enable_signals: bool, ) -> Result { let (conin, conout, close_on_drop) = if behavior == Behavior::PreferTerm { if let (Ok(conin), Ok(conout)) = ( From f41a2b9108596f31d969f68dc37ecfd1571bf14b Mon Sep 17 00:00:00 2001 From: gwenn Date: Sat, 20 Jan 2024 10:16:52 +0100 Subject: [PATCH 17/43] Bump env_logger version to 0.11 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4ede8d9a6..4710f185a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,7 +54,7 @@ clipboard-win = "5.0" [dev-dependencies] doc-comment = "0.3" -env_logger = { version = "0.10", default-features = false } +env_logger = { version = "0.11", default-features = false } tempfile = "3.1.0" rand = "0.8" assert_matches = "1.2" From cf2d7cd76deea1002a68a622a585779756293a06 Mon Sep 17 00:00:00 2001 From: gwenn Date: Sun, 21 Jan 2024 11:16:04 +0100 Subject: [PATCH 18/43] First draft to fix typeahead --- Cargo.toml | 1 + src/binding.rs | 1 + src/lib.rs | 9 +++++++-- src/tty/mod.rs | 13 +++++++++++-- src/tty/test.rs | 16 +++++++++++++++- src/tty/unix.rs | 47 +++++++++++++++++++++++++++++++++++++++++++--- src/tty/windows.rs | 18 +++++++++++++++++- 7 files changed, 96 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4710f185a..7ac26453d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ utf8parse = "0.2" skim = { version = "0.10", optional = true, default-features = false } signal-hook = { version = "0.3", optional = true, default-features = false } termios = { version = "0.3.3", optional = true } +buffer-redux = { version = "1.0", optional = true, default-features = false } [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.52.0", features = ["Win32_Foundation", "Win32_System_Console", "Win32_Security", "Win32_System_Threading", "Win32_UI_Input_KeyboardAndMouse"] } diff --git a/src/binding.rs b/src/binding.rs index ed9dff8a4..7c083839d 100644 --- a/src/binding.rs +++ b/src/binding.rs @@ -249,6 +249,7 @@ mod test { } #[test] + #[ignore] #[cfg(target_arch = "x86_64")] fn size_of_event() { use core::mem::size_of; diff --git a/src/lib.rs b/src/lib.rs index 972af0f44..fcea11d5f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,7 +51,7 @@ use log::debug; pub use rustyline_derive::{Completer, Helper, Highlighter, Hinter, Validator}; use unicode_width::UnicodeWidthStr; -use crate::tty::{RawMode, RawReader, Renderer, Term, Terminal}; +use crate::tty::{Buffer, RawMode, RawReader, Renderer, Term, Terminal}; #[cfg(feature = "custom-bindings")] pub use crate::binding::{ConditionalEventHandler, Event, EventContext, EventHandler}; @@ -586,6 +586,7 @@ impl<'h> Context<'h> { #[must_use] pub struct Editor { term: Terminal, + buffer: Option, history: I, helper: Option, kill_ring: KillRing, @@ -621,6 +622,7 @@ impl Editor { )?; Ok(Self { term, + buffer: None, history, helper: None, kill_ring: KillRing::new(60), @@ -704,7 +706,9 @@ impl Editor { ); } - let mut rdr = self.term.create_reader(&self.config, term_key_map); + let mut rdr = self + .term + .create_reader(self.buffer.take(), &self.config, term_key_map); if self.term.is_output_tty() && self.config.check_cursor_position() { if let Err(e) = s.move_cursor_at_leftmost(&mut rdr) { if let ReadlineError::WindowResized = e { @@ -794,6 +798,7 @@ impl Editor { if cfg!(windows) { let _ = original_mode; // silent warning } + self.buffer = rdr.unbuffer(); Ok(s.line.into_string()) } diff --git a/src/tty/mod.rs b/src/tty/mod.rs index e79d2a96b..8ac335d69 100644 --- a/src/tty/mod.rs +++ b/src/tty/mod.rs @@ -23,6 +23,7 @@ pub enum Event { /// Translate bytes read from stdin to keys. pub trait RawReader { + type Buffer; /// Blocking wait for either a key press or an external print fn wait_for_input(&mut self, single_esc_abort: bool) -> Result; // TODO replace calls to `next_key` by `wait_for_input` where relevant /// Blocking read of key pressed. @@ -34,6 +35,8 @@ pub trait RawReader { fn read_pasted_text(&mut self) -> Result; /// Check if `key` is bound to a peculiar command fn find_binding(&self, key: &KeyEvent) -> Option; + /// Backup type ahead + fn unbuffer(self) -> Option; } /// Display prompt, line and cursor in terminal output @@ -215,8 +218,9 @@ pub trait ExternalPrinter { /// Terminal contract pub trait Term { + type Buffer; type KeyMap; - type Reader: RawReader; // rl_instream + type Reader: RawReader; // rl_instream type Writer: Renderer; // rl_outstream type Mode: RawMode; type ExternalPrinter: ExternalPrinter; @@ -241,7 +245,12 @@ pub trait Term { /// Enable RAW mode for the terminal. fn enable_raw_mode(&mut self) -> Result<(Self::Mode, Self::KeyMap)>; /// Create a RAW reader - fn create_reader(&self, config: &Config, key_map: Self::KeyMap) -> Self::Reader; + fn create_reader( + &self, + buffer: Option, + config: &Config, + key_map: Self::KeyMap, + ) -> Self::Reader; /// Create a writer fn create_writer(&self) -> Self::Writer; fn writeln(&self) -> Result<()>; diff --git a/src/tty/test.rs b/src/tty/test.rs index d26af5e0a..755e52366 100644 --- a/src/tty/test.rs +++ b/src/tty/test.rs @@ -12,6 +12,7 @@ use crate::layout::{Layout, Position}; use crate::line_buffer::LineBuffer; use crate::{Cmd, Result}; +pub type Buffer = (); pub type KeyMap = (); pub type Mode = (); @@ -22,6 +23,8 @@ impl RawMode for Mode { } impl<'a> RawReader for Iter<'a, KeyEvent> { + type Buffer = Buffer; + fn wait_for_input(&mut self, single_esc_abort: bool) -> Result { self.next_key(single_esc_abort).map(Event::KeyPress) } @@ -45,9 +48,15 @@ impl<'a> RawReader for Iter<'a, KeyEvent> { fn find_binding(&self, _: &KeyEvent) -> Option { None } + + fn unbuffer(self) -> Option { + None + } } impl RawReader for IntoIter { + type Buffer = Buffer; + fn wait_for_input(&mut self, single_esc_abort: bool) -> Result { self.next_key(single_esc_abort).map(Event::KeyPress) } @@ -76,6 +85,10 @@ impl RawReader for IntoIter { fn find_binding(&self, _: &KeyEvent) -> Option { None } + + fn unbuffer(self) -> Option { + None + } } #[derive(Default)] @@ -160,6 +173,7 @@ pub struct DummyTerminal { } impl Term for DummyTerminal { + type Buffer = Buffer; type CursorGuard = (); type ExternalPrinter = DummyExternalPrinter; type KeyMap = KeyMap; @@ -208,7 +222,7 @@ impl Term for DummyTerminal { Ok(((), ())) } - fn create_reader(&self, _: &Config, _: KeyMap) -> Self::Reader { + fn create_reader(&self, _: Option, _: &Config, _: KeyMap) -> Self::Reader { self.keys.clone().into_iter() } diff --git a/src/tty/unix.rs b/src/tty/unix.rs index 75dace14a..700e46fdf 100644 --- a/src/tty/unix.rs +++ b/src/tty/unix.rs @@ -1,8 +1,12 @@ //! Unix specific definitions +#[cfg(feature = "buffer-redux")] +use buffer_redux::BufReader; use std::cmp; use std::collections::HashMap; use std::fs::{File, OpenOptions}; -use std::io::{self, BufReader, ErrorKind, Read, Write}; +#[cfg(not(feature = "buffer-redux"))] +use std::io::BufReader; +use std::io::{self, ErrorKind, Read, Write}; use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, IntoRawFd, RawFd}; use std::os::unix::net::UnixStream; use std::sync::atomic::{AtomicBool, Ordering}; @@ -91,6 +95,13 @@ fn is_a_tty(fd: RawFd) -> bool { isatty(fd).unwrap_or(false) } +#[cfg(any(not(feature = "buffer-redux"), test))] +pub type PosixBuffer = (); +#[cfg(all(feature = "buffer-redux", not(test)))] +pub type PosixBuffer = buffer_redux::Buffer; +#[cfg(not(test))] +pub type Buffer = PosixBuffer; + pub type PosixKeyMap = HashMap; #[cfg(not(test))] pub type KeyMap = PosixKeyMap; @@ -228,12 +239,22 @@ impl PosixRawReader { fn new( fd: RawFd, sigwinch_pipe: Option, + buffer: Option, config: &Config, key_map: PosixKeyMap, pipe_reader: Option, ) -> Self { + let inner = TtyIn { fd, sigwinch_pipe }; + #[cfg(any(not(feature = "buffer-redux"), test))] + let (tty_in, _) = (BufReader::with_capacity(1024, inner), buffer); + #[cfg(all(feature = "buffer-redux", not(test)))] + let tty_in = if let Some(buffer) = buffer { + BufReader::with_buffer(buffer, inner) + } else { + BufReader::with_capacity(1024, inner) + }; Self { - tty_in: BufReader::with_capacity(1024, TtyIn { fd, sigwinch_pipe }), + tty_in, timeout_ms: config.keyseq_timeout(), parser: Parser::new(), key_map, @@ -750,6 +771,8 @@ impl PosixRawReader { } impl RawReader for PosixRawReader { + type Buffer = PosixBuffer; + #[cfg(not(feature = "signal-hook"))] fn wait_for_input(&mut self, single_esc_abort: bool) -> Result { match self.pipe_reader { @@ -840,6 +863,17 @@ impl RawReader for PosixRawReader { } cmd } + + #[cfg(any(not(feature = "buffer-redux"), test))] + fn unbuffer(self) -> Option { + None + } + + #[cfg(all(feature = "buffer-redux", not(test)))] + fn unbuffer(self) -> Option { + let (_, buffer) = self.tty_in.into_inner_with_buffer(); + Some(buffer) + } } impl Receiver for Utf8 { @@ -1253,6 +1287,7 @@ impl PosixTerminal { } impl Term for PosixTerminal { + type Buffer = PosixBuffer; type CursorGuard = PosixCursorGuard; type ExternalPrinter = ExternalPrinter; type KeyMap = PosixKeyMap; @@ -1371,10 +1406,16 @@ impl Term for PosixTerminal { } /// Create a RAW reader - fn create_reader(&self, config: &Config, key_map: PosixKeyMap) -> PosixRawReader { + fn create_reader( + &self, + buffer: Option, + config: &Config, + key_map: PosixKeyMap, + ) -> PosixRawReader { PosixRawReader::new( self.tty_in, self.sigwinch.as_ref().map(|s| s.pipe), + buffer, config, key_map, self.pipe_reader.clone(), diff --git a/src/tty/windows.rs b/src/tty/windows.rs index f1598cbc3..3ce4169d9 100644 --- a/src/tty/windows.rs +++ b/src/tty/windows.rs @@ -69,6 +69,10 @@ fn get_console_mode(handle: HANDLE) -> Result { Ok(original_mode) } +type ConsoleBuffer = (); +#[cfg(not(test))] +pub type Buffer = ConsoleBuffer; + type ConsoleKeyMap = (); #[cfg(not(test))] pub type KeyMap = ConsoleKeyMap; @@ -141,6 +145,8 @@ impl ConsoleRawReader { } impl RawReader for ConsoleRawReader { + type Buffer = ConsoleBuffer; + fn wait_for_input(&mut self, single_esc_abort: bool) -> Result { match self.pipe_reader { Some(_) => self.select(), @@ -159,6 +165,10 @@ impl RawReader for ConsoleRawReader { fn find_binding(&self, _: &KeyEvent) -> Option { None } + + fn unbuffer(self) -> Option { + None + } } fn read_input(handle: HANDLE, max_count: u32) -> Result { @@ -640,6 +650,7 @@ impl Console { } impl Term for Console { + type Buffer = ConsoleBuffer; type CursorGuard = ConsoleCursorGuard; type ExternalPrinter = ExternalPrinter; type KeyMap = ConsoleKeyMap; @@ -801,7 +812,12 @@ impl Term for Console { )) } - fn create_reader(&self, _: &Config, _: ConsoleKeyMap) -> ConsoleRawReader { + fn create_reader( + &self, + _: Option, + _: &Config, + _: ConsoleKeyMap, + ) -> ConsoleRawReader { ConsoleRawReader::create(self.conin, self.pipe_reader.clone()) } From 4140971e74dbce56eb3df39de5b67435e5b44ba5 Mon Sep 17 00:00:00 2001 From: gwenn Date: Sat, 17 Feb 2024 10:19:12 +0100 Subject: [PATCH 19/43] Bump rusqlite to version 0.31 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4710f185a..2f03621af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ cfg-if = "1.0" home = { version = "0.5.4", optional = true } # For History fd-lock = { version = "4.0.0", optional = true } -rusqlite = { version = "0.30.0", optional = true, default-features = false, features = ["bundled", "backup"] } +rusqlite = { version = "0.31.0", optional = true, default-features = false, features = ["bundled", "backup"] } libc = "0.2" log = "0.4" unicode-width = "0.1" From 60c80e89814092e49151e3018f941b00af06233a Mon Sep 17 00:00:00 2001 From: gwenn Date: Sat, 17 Feb 2024 10:23:36 +0100 Subject: [PATCH 20/43] Ignore unstable test binding::test::size_of_event --- src/binding.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/binding.rs b/src/binding.rs index ed9dff8a4..edb9afb0a 100644 --- a/src/binding.rs +++ b/src/binding.rs @@ -249,7 +249,7 @@ mod test { } #[test] - #[cfg(target_arch = "x86_64")] + #[ignore] fn size_of_event() { use core::mem::size_of; assert_eq!(size_of::(), 32); From a55b343fdb8b8e0e84ed465083f0059b656ee578 Mon Sep 17 00:00:00 2001 From: gwenn Date: Sat, 24 Feb 2024 11:13:12 +0100 Subject: [PATCH 21/43] Fix clippy warnings --- src/history.rs | 2 -- src/layout.rs | 2 +- src/tty/test.rs | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/history.rs b/src/history.rs index d82f1a7b4..d59f4ab17 100644 --- a/src/history.rs +++ b/src/history.rs @@ -11,8 +11,6 @@ use std::collections::VecDeque; use std::fs::{File, OpenOptions}; #[cfg(feature = "with-file-history")] use std::io::SeekFrom; -#[cfg(feature = "with-file-history")] -use std::iter::DoubleEndedIterator; use std::ops::Index; use std::path::Path; #[cfg(feature = "with-file-history")] diff --git a/src/layout.rs b/src/layout.rs index 5679ec14c..5aa8834fa 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -1,4 +1,4 @@ -use std::cmp::{Ord, Ordering, PartialOrd}; +use std::cmp::Ordering; #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] pub struct Position { diff --git a/src/tty/test.rs b/src/tty/test.rs index 5675ded00..a7fa01fc8 100644 --- a/src/tty/test.rs +++ b/src/tty/test.rs @@ -1,5 +1,4 @@ //! Tests specific definitions -use std::iter::IntoIterator; use std::slice::Iter; use std::vec::IntoIter; From bf09447eb22f1d02314bb12507b5d69e1bb68263 Mon Sep 17 00:00:00 2001 From: gwenn Date: Sat, 24 Feb 2024 13:53:15 +0100 Subject: [PATCH 22/43] Upgrade nix to 0.28 --- Cargo.toml | 2 +- src/config.rs | 14 +++++++------- src/tty/unix.rs | 44 ++++++++++++++++++++------------------------ 3 files changed, 28 insertions(+), 32 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 58b99eb2c..581105ccc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ regex = { version = "1.5.5", optional = true } rustyline-derive = { version = "0.10.0", optional = true, path = "rustyline-derive" } [target.'cfg(unix)'.dependencies] -nix = { version = "0.27", default-features = false, features = ["fs", "ioctl", "poll", "signal", "term"] } +nix = { version = "0.28", default-features = false, features = ["fs", "ioctl", "poll", "signal", "term"] } utf8parse = "0.2" skim = { version = "0.10", optional = true, default-features = false } signal-hook = { version = "0.3", optional = true, default-features = false } diff --git a/src/config.rs b/src/config.rs index 5a531d3f3..bb6ec65ae 100644 --- a/src/config.rs +++ b/src/config.rs @@ -15,7 +15,7 @@ pub struct Config { completion_prompt_limit: usize, /// Duration (milliseconds) Rustyline will wait for a character when /// reading an ambiguous key sequence. - keyseq_timeout: i32, + keyseq_timeout: Option, /// Emacs or Vi mode edit_mode: EditMode, /// If true, each nonblank line returned by `readline` will be @@ -108,7 +108,7 @@ impl Config { /// /// By default, no timeout (-1) or 500ms if `EditMode::Vi` is activated. #[must_use] - pub fn keyseq_timeout(&self) -> i32 { + pub fn keyseq_timeout(&self) -> Option { self.keyseq_timeout } @@ -217,7 +217,7 @@ impl Default for Config { history_ignore_space: false, completion_type: CompletionType::Circular, // TODO Validate completion_prompt_limit: 100, - keyseq_timeout: -1, + keyseq_timeout: None, edit_mode: EditMode::Emacs, auto_add_history: false, bell_style: BellStyle::default(), @@ -383,7 +383,7 @@ impl Builder { /// After seeing an ESC key, wait at most `keyseq_timeout_ms` for another /// byte. #[must_use] - pub fn keyseq_timeout(mut self, keyseq_timeout_ms: i32) -> Self { + pub fn keyseq_timeout(mut self, keyseq_timeout_ms: Option) -> Self { self.set_keyseq_timeout(keyseq_timeout_ms); self } @@ -526,7 +526,7 @@ pub trait Configurer { } /// Timeout for ambiguous key sequences in milliseconds. - fn set_keyseq_timeout(&mut self, keyseq_timeout_ms: i32) { + fn set_keyseq_timeout(&mut self, keyseq_timeout_ms: Option) { self.config_mut().keyseq_timeout = keyseq_timeout_ms; } @@ -534,8 +534,8 @@ pub trait Configurer { fn set_edit_mode(&mut self, edit_mode: EditMode) { self.config_mut().edit_mode = edit_mode; match edit_mode { - EditMode::Emacs => self.set_keyseq_timeout(-1), // no timeout - EditMode::Vi => self.set_keyseq_timeout(500), + EditMode::Emacs => self.set_keyseq_timeout(None), // no timeout + EditMode::Vi => self.set_keyseq_timeout(Some(500)), } } diff --git a/src/tty/unix.rs b/src/tty/unix.rs index b4bdd3877..c0c8a0d24 100644 --- a/src/tty/unix.rs +++ b/src/tty/unix.rs @@ -15,7 +15,7 @@ use std::sync::{Arc, Mutex}; use log::{debug, warn}; use nix::errno::Errno; -use nix::poll::{self, PollFlags}; +use nix::poll::{self, PollFlags, PollTimeout}; use nix::sys::select::{self, FdSet}; #[cfg(not(feature = "termios"))] use nix::sys::termios::Termios; @@ -190,7 +190,7 @@ type PipeWriter = (Arc>, SyncSender); /// Console input reader pub struct PosixRawReader { tty_in: BufReader, - timeout_ms: i32, + timeout_ms: PollTimeout, parser: Parser, key_map: PosixKeyMap, // external print reader @@ -255,7 +255,7 @@ impl PosixRawReader { }; Self { tty_in, - timeout_ms: config.keyseq_timeout(), + timeout_ms: config.keyseq_timeout().into(), parser: Parser::new(), key_map, pipe_reader, @@ -298,8 +298,8 @@ impl PosixRawReader { if !allow_recurse { return Ok(E::ESC); } - let timeout = if self.timeout_ms < 0 { - 100 + let timeout = if self.timeout_ms.is_none() { + 100u8.into() } else { self.timeout_ms }; @@ -702,12 +702,12 @@ impl PosixRawReader { }) } - fn poll(&mut self, timeout_ms: i32) -> Result { + fn poll(&mut self, timeout_ms: PollTimeout) -> Result { let n = self.tty_in.buffer().len(); if n > 0 { return Ok(n as i32); } - let mut fds = [poll::PollFd::new(self, PollFlags::POLLIN)]; + let mut fds = [poll::PollFd::new(self.as_fd(), PollFlags::POLLIN)]; let r = poll::poll(&mut fds, timeout_ms); match r { Ok(n) => Ok(n), @@ -736,11 +736,11 @@ impl PosixRawReader { .map(|fd| unsafe { BorrowedFd::borrow_raw(fd) }); loop { let mut readfds = FdSet::new(); - if let Some(ref sigwinch_pipe) = sigwinch_pipe { + if let Some(sigwinch_pipe) = sigwinch_pipe { readfds.insert(sigwinch_pipe); } - readfds.insert(&tty_in); - if let Some(ref pipe_reader) = pipe_reader { + readfds.insert(tty_in); + if let Some(pipe_reader) = pipe_reader { readfds.insert(pipe_reader); } if let Err(err) = select::select(None, Some(&mut readfds), None, None, None) { @@ -752,10 +752,10 @@ impl PosixRawReader { continue; } }; - if sigwinch_pipe.map_or(false, |fd| readfds.contains(&fd)) { + if sigwinch_pipe.map_or(false, |fd| readfds.contains(fd)) { self.tty_in.get_ref().sigwinch()?; return Err(ReadlineError::WindowResized); - } else if readfds.contains(&tty_in) { + } else if readfds.contains(tty_in) { // prefer user input over external print return self.next_key(single_esc_abort).map(Event::KeyPress); } else if let Some(ref pipe_reader) = self.pipe_reader { @@ -794,8 +794,8 @@ impl RawReader for PosixRawReader { if !self.tty_in.buffer().is_empty() { debug!(target: "rustyline", "read buffer {:?}", self.tty_in.buffer()); } - let timeout_ms = if single_esc_abort && self.timeout_ms == -1 { - 0 + let timeout_ms = if single_esc_abort && self.timeout_ms.is_none() { + PollTimeout::ZERO } else { self.timeout_ms }; @@ -1119,14 +1119,14 @@ impl Renderer for PosixRenderer { } fn move_cursor_at_leftmost(&mut self, rdr: &mut PosixRawReader) -> Result<()> { - if rdr.poll(0)? != 0 { + if rdr.poll(PollTimeout::ZERO)? != 0 { debug!(target: "rustyline", "cannot request cursor location"); return Ok(()); } /* Report cursor location */ self.write_and_flush("\x1b[6n")?; /* Read the response: ESC [ rows ; cols R */ - if rdr.poll(100)? == 0 + if rdr.poll(PollTimeout::from(100u8))? == 0 || rdr.next_char()? != '\x1b' || rdr.next_char()? != '[' || read_digits_until(rdr, ';')?.is_none() @@ -1163,7 +1163,7 @@ fn read_digits_until(rdr: &mut PosixRawReader, sep: char) -> Result> fn write_all(fd: RawFd, buf: &str) -> nix::Result<()> { let mut bytes = buf.as_bytes(); while !bytes.is_empty() { - match write(fd, bytes) { + match write(unsafe { BorrowedFd::borrow_raw(fd) }, bytes) { Ok(0) => return Err(Errno::EIO), Ok(n) => bytes = &bytes[n..], Err(Errno::EINTR) => {} @@ -1194,7 +1194,7 @@ fn set_cursor_visibility(fd: RawFd, visible: bool) -> Result Date: Wed, 6 Mar 2024 17:58:14 +0100 Subject: [PATCH 23/43] Prepare next release --- Cargo.toml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 581105ccc..c5cc13be2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustyline" -version = "13.0.0" +version = "14.0.0" authors = ["Katsu Kawakami "] edition = "2021" description = "Rustyline, a readline implementation based on Antirez's Linenoise" diff --git a/README.md b/README.md index 84add3ae9..47d4e1b79 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ to your `Cargo.toml`: ```toml [dependencies] -rustyline = "13.0.0" +rustyline = "14.0.0" ``` ## Features From 81d3766eea47bb8867cc615f87656c51b97c8985 Mon Sep 17 00:00:00 2001 From: gwenn Date: Fri, 15 Mar 2024 19:34:52 +0100 Subject: [PATCH 24/43] Fix clippy warnings --- src/history.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/history.rs b/src/history.rs index d59f4ab17..0dc289db7 100644 --- a/src/history.rs +++ b/src/history.rs @@ -587,7 +587,7 @@ impl FileHistory { )) = self.path_info { if previous_path.as_path() != path { - *previous_path = path.to_owned(); + path.clone_into(previous_path); } *previous_modified = modified; *previous_size = size; From 184b82018d0897a9e1a9c50d9a5bb283a18a300e Mon Sep 17 00:00:00 2001 From: gwenn Date: Sat, 13 Apr 2024 10:21:24 +0200 Subject: [PATCH 25/43] Update github actions --- .github/workflows/rust.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index c4e8503b2..98158be5f 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -29,8 +29,8 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 - - uses: Swatinem/rust-cache@v2.2.0 + - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 - name: Build run: cargo build --workspace --all-targets - name: Run tests From db6c5d7e6a25f423b9217c1c647e7eafc7e539aa Mon Sep 17 00:00:00 2001 From: gwenn Date: Sat, 13 Apr 2024 10:31:36 +0200 Subject: [PATCH 26/43] Fix clippy warnings --- src/line_buffer.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/line_buffer.rs b/src/line_buffer.rs index 329d71e43..3c7b403c6 100644 --- a/src/line_buffer.rs +++ b/src/line_buffer.rs @@ -1119,6 +1119,7 @@ impl LineBuffer { .map_or_else(|| self.buf.len(), |pos| end + pos); let mut index = start; if dedent { + #[allow(clippy::unnecessary_to_owned)] for line in self.buf[start..end].to_string().split('\n') { let max = line.len() - line.trim_start().len(); let deleting = min(max, amount); @@ -1134,6 +1135,7 @@ impl LineBuffer { index += line.len() + 1 - deleting; } } else { + #[allow(clippy::unnecessary_to_owned)] for line in self.buf[start..end].to_string().split('\n') { for off in (0..amount).step_by(INDENT.len()) { self.insert_str(index, &INDENT[..min(amount - off, INDENT.len())], cl); From 6e3762753e22bf38d60ac0e10a22b7c8e978d861 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 09:00:41 +0000 Subject: [PATCH 27/43] Update nix requirement from 0.28 to 0.29 Updates the requirements on [nix](https://github.com/nix-rust/nix) to permit the latest version. - [Changelog](https://github.com/nix-rust/nix/blob/master/CHANGELOG.md) - [Commits](https://github.com/nix-rust/nix/compare/v0.28.0...v0.29.0) --- updated-dependencies: - dependency-name: nix dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c5cc13be2..ac186ceaa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ regex = { version = "1.5.5", optional = true } rustyline-derive = { version = "0.10.0", optional = true, path = "rustyline-derive" } [target.'cfg(unix)'.dependencies] -nix = { version = "0.28", default-features = false, features = ["fs", "ioctl", "poll", "signal", "term"] } +nix = { version = "0.29", default-features = false, features = ["fs", "ioctl", "poll", "signal", "term"] } utf8parse = "0.2" skim = { version = "0.10", optional = true, default-features = false } signal-hook = { version = "0.3", optional = true, default-features = false } From 64fac0752e7b35316b6a14424a24d2633cb645c9 Mon Sep 17 00:00:00 2001 From: gwenn Date: Tue, 28 May 2024 18:56:53 +0200 Subject: [PATCH 28/43] Fix dead_code warnings --- src/keymap.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/keymap.rs b/src/keymap.rs index b7303df84..edaf1ef23 100644 --- a/src/keymap.rs +++ b/src/keymap.rs @@ -389,10 +389,12 @@ pub trait Refresher { /// Returns `true` if there is a hint displayed. fn has_hint(&self) -> bool; /// Returns the hint text that is shown after the current cursor position. + #[cfg_attr(not(feature = "custom-bindings"), allow(dead_code))] fn hint_text(&self) -> Option<&str>; /// currently edited line fn line(&self) -> &str; /// Current cursor position (byte position) + #[cfg_attr(not(feature = "custom-bindings"), allow(dead_code))] fn pos(&self) -> usize; /// Display `msg` above currently edited line. fn external_print(&mut self, msg: String) -> Result<()>; From d045dcc099bf470f149eb9ba3b5c97d2c22f9843 Mon Sep 17 00:00:00 2001 From: gwenn Date: Sat, 20 Jul 2024 07:23:35 +0200 Subject: [PATCH 29/43] Fix clippy warnings --- src/tty/unix.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tty/unix.rs b/src/tty/unix.rs index c0c8a0d24..071e4ba02 100644 --- a/src/tty/unix.rs +++ b/src/tty/unix.rs @@ -1194,7 +1194,7 @@ fn set_cursor_visibility(fd: RawFd, visible: bool) -> Result Date: Mon, 22 Jul 2024 08:58:02 +0000 Subject: [PATCH 30/43] Update rusqlite requirement from 0.31.0 to 0.32.0 Updates the requirements on [rusqlite](https://github.com/rusqlite/rusqlite) to permit the latest version. - [Release notes](https://github.com/rusqlite/rusqlite/releases) - [Changelog](https://github.com/rusqlite/rusqlite/blob/master/Changelog.md) - [Commits](https://github.com/rusqlite/rusqlite/compare/v0.31.0...v0.32.0) --- updated-dependencies: - dependency-name: rusqlite dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ac186ceaa..55ff57328 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ cfg-if = "1.0" home = { version = "0.5.4", optional = true } # For History fd-lock = { version = "4.0.0", optional = true } -rusqlite = { version = "0.31.0", optional = true, default-features = false, features = ["bundled", "backup"] } +rusqlite = { version = "0.32.0", optional = true, default-features = false, features = ["bundled", "backup"] } libc = "0.2" log = "0.4" unicode-width = "0.1" From 18cf882329de2ec568fd0fc5810af59e22332963 Mon Sep 17 00:00:00 2001 From: gwenn Date: Sun, 28 Jul 2024 09:55:09 +0200 Subject: [PATCH 31/43] Fix direct-minimal-versions --- .github/workflows/rust.yml | 4 ++++ Cargo.toml | 12 ++++++------ rustyline-derive/Cargo.toml | 6 +++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 98158be5f..7b8632ee8 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -48,3 +48,7 @@ jobs: run: cargo check --workspace --no-default-features env: RUSTFLAGS: "-D warnings" + - name Test direct-minimal-versions + run: | + cargo update -Z direct-minimal-versions + cargo test --workspace --all-targets diff --git a/Cargo.toml b/Cargo.toml index 55ff57328..c8a3e8e92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,21 +23,21 @@ maintenance = { status = "actively-developed" } members = ["rustyline-derive"] [dependencies] -bitflags = "2.0" +bitflags = "2.6" cfg-if = "1.0" # For file completion home = { version = "0.5.4", optional = true } # For History fd-lock = { version = "4.0.0", optional = true } rusqlite = { version = "0.32.0", optional = true, default-features = false, features = ["bundled", "backup"] } -libc = "0.2" -log = "0.4" -unicode-width = "0.1" +libc = "0.2.155" +log = "0.4.22" +unicode-width = "0.1.13" unicode-segmentation = "1.0" -memchr = "2.0" +memchr = "2.7" # For custom bindings radix_trie = { version = "0.2", optional = true } -regex = { version = "1.5.5", optional = true } +regex = { version = "1.10", optional = true } # For derive rustyline-derive = { version = "0.10.0", optional = true, path = "rustyline-derive" } diff --git a/rustyline-derive/Cargo.toml b/rustyline-derive/Cargo.toml index cc117bfcc..d1596578c 100644 --- a/rustyline-derive/Cargo.toml +++ b/rustyline-derive/Cargo.toml @@ -19,6 +19,6 @@ maintenance = { status = "actively-developed" } proc-macro = true [dependencies] -syn = { version = "2.0", default-features = false, features = ["derive", "parsing", "printing", "proc-macro"] } -quote = { version = "1.0", default-features = false } -proc-macro2 = { version = "1.0", default-features = false } +syn = { version = "2.0.72", default-features = false, features = ["derive", "parsing", "printing", "proc-macro"] } +quote = { version = "1.0.36", default-features = false } +proc-macro2 = { version = "1.0.86", default-features = false } From 149e7b6fcd85ab6cf4fa6aaea5a1c3723f2d508e Mon Sep 17 00:00:00 2001 From: gwenn Date: Sun, 28 Jul 2024 10:21:02 +0200 Subject: [PATCH 32/43] Fix workflow file --- .github/workflows/rust.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 7b8632ee8..169b31f9b 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -48,7 +48,16 @@ jobs: run: cargo check --workspace --no-default-features env: RUSTFLAGS: "-D warnings" - - name Test direct-minimal-versions - run: | + + direct-minimal-versions: + name: Test min versions + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 + - uses: hecrj/setup-rust-action@v2 + with: + rust-version: nightly + - run: | cargo update -Z direct-minimal-versions cargo test --workspace --all-targets From ff2a9e6cad407dfc1239820e01b5f5194785c888 Mon Sep 17 00:00:00 2001 From: gwenn Date: Sat, 3 Aug 2024 09:56:46 +0200 Subject: [PATCH 33/43] Bump windows-sys to 0.59 --- Cargo.toml | 2 +- src/tty/windows.rs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c8a3e8e92..92b4cd953 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ termios = { version = "0.3.3", optional = true } buffer-redux = { version = "1.0", optional = true, default-features = false } [target.'cfg(windows)'.dependencies] -windows-sys = { version = "0.52.0", features = ["Win32_Foundation", "Win32_System_Console", "Win32_Security", "Win32_System_Threading", "Win32_UI_Input_KeyboardAndMouse"] } +windows-sys = { version = "0.59.0", features = ["Win32_Foundation", "Win32_System_Console", "Win32_Security", "Win32_System_Threading", "Win32_UI_Input_KeyboardAndMouse"] } clipboard-win = "5.0" [dev-dependencies] diff --git a/src/tty/windows.rs b/src/tty/windows.rs index fd2a06333..af1f0ccf5 100644 --- a/src/tty/windows.rs +++ b/src/tty/windows.rs @@ -35,7 +35,7 @@ fn get_std_handle(fd: console::STD_HANDLE) -> Result { fn check_handle(handle: HANDLE) -> Result { if handle == foundation::INVALID_HANDLE_VALUE { Err(io::Error::last_os_error())?; - } else if handle == 0 { + } else if handle.is_null() { Err(io::Error::new( io::ErrorKind::Other, "no stdio handle available for this process", @@ -332,7 +332,7 @@ impl ConsoleRenderer { fn clear(&mut self, length: u32, pos: console::COORD, attr: u16) -> Result<()> { let mut _count = 0; check(unsafe { - console::FillConsoleOutputCharacterA(self.conout, b' ', length, pos, &mut _count) + console::FillConsoleOutputCharacterA(self.conout, b' ' as i8, length, pos, &mut _count) })?; Ok(check(unsafe { console::FillConsoleOutputAttribute(self.conout, attr, length, pos, &mut _count) @@ -604,7 +604,7 @@ fn write_all(handle: HANDLE, mut data: &[u16]) -> Result<()> { check(unsafe { console::WriteConsoleW( handle, - slice.as_ptr().cast::(), + slice.as_ptr(), slice.len() as u32, &mut written, ptr::null_mut(), @@ -708,9 +708,9 @@ impl Term for Console { Ok(Console { conin_isatty, - conin: conin.unwrap_or(0), + conin: conin.unwrap_or(ptr::null_mut()), conout_isatty, - conout: conout.unwrap_or(0), + conout: conout.unwrap_or(ptr::null_mut()), close_on_drop, color_mode, ansi_colors_supported: false, @@ -843,7 +843,7 @@ impl Term for Console { Err(io::Error::from(io::ErrorKind::Other))?; // FIXME } let event = unsafe { threading::CreateEventW(ptr::null_mut(), TRUE, FALSE, ptr::null()) }; - if event == 0 { + if event.is_null() { Err(io::Error::last_os_error())?; } let (sender, receiver) = sync_channel(1); From 01b71d6abf27ef2cc97ac25170fdd38e4d50c7f5 Mon Sep 17 00:00:00 2001 From: Adam Nemecek Date: Thu, 8 Aug 2024 11:58:22 -0700 Subject: [PATCH 34/43] use self --- examples/diy_hints.rs | 8 +++---- src/keymap.rs | 50 +++++++++++++++++++++---------------------- src/lib.rs | 2 +- src/validate.rs | 4 ++-- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/examples/diy_hints.rs b/examples/diy_hints.rs index 4bd3438ca..af8fadc80 100644 --- a/examples/diy_hints.rs +++ b/examples/diy_hints.rs @@ -33,16 +33,16 @@ impl Hint for CommandHint { } impl CommandHint { - fn new(text: &str, complete_up_to: &str) -> CommandHint { + fn new(text: &str, complete_up_to: &str) -> Self { assert!(text.starts_with(complete_up_to)); - CommandHint { + Self { display: text.into(), complete_up_to: complete_up_to.len(), } } - fn suffix(&self, strip_chars: usize) -> CommandHint { - CommandHint { + fn suffix(&self, strip_chars: usize) -> Self { + Self { display: self.display[strip_chars..].to_owned(), complete_up_to: self.complete_up_to.saturating_sub(strip_chars), } diff --git a/src/keymap.rs b/src/keymap.rs index edaf1ef23..9939b9c33 100644 --- a/src/keymap.rs +++ b/src/keymap.rs @@ -263,10 +263,10 @@ pub enum CharSearch { impl CharSearch { const fn opposite(self) -> Self { match self { - CharSearch::Forward(c) => CharSearch::Backward(c), - CharSearch::ForwardBefore(c) => CharSearch::BackwardAfter(c), - CharSearch::Backward(c) => CharSearch::Forward(c), - CharSearch::BackwardAfter(c) => CharSearch::ForwardBefore(c), + Self::Forward(c) => Self::Backward(c), + Self::ForwardBefore(c) => Self::BackwardAfter(c), + Self::Backward(c) => Self::Forward(c), + Self::BackwardAfter(c) => Self::ForwardBefore(c), } } } @@ -309,26 +309,26 @@ impl Movement { // Replay this movement with a possible different `RepeatCount`. const fn redo(&self, new: Option) -> Self { match *self { - Movement::WholeLine => Movement::WholeLine, - Movement::BeginningOfLine => Movement::BeginningOfLine, - Movement::ViFirstPrint => Movement::ViFirstPrint, - Movement::EndOfLine => Movement::EndOfLine, - Movement::BackwardWord(previous, word) => { - Movement::BackwardWord(repeat_count(previous, new), word) + Self::WholeLine => Self::WholeLine, + Self::BeginningOfLine => Self::BeginningOfLine, + Self::ViFirstPrint => Self::ViFirstPrint, + Self::EndOfLine => Self::EndOfLine, + Self::BackwardWord(previous, word) => { + Self::BackwardWord(repeat_count(previous, new), word) } - Movement::ForwardWord(previous, at, word) => { - Movement::ForwardWord(repeat_count(previous, new), at, word) + Self::ForwardWord(previous, at, word) => { + Self::ForwardWord(repeat_count(previous, new), at, word) } - Movement::ViCharSearch(previous, char_search) => { - Movement::ViCharSearch(repeat_count(previous, new), char_search) + Self::ViCharSearch(previous, char_search) => { + Self::ViCharSearch(repeat_count(previous, new), char_search) } - Movement::BackwardChar(previous) => Movement::BackwardChar(repeat_count(previous, new)), - Movement::ForwardChar(previous) => Movement::ForwardChar(repeat_count(previous, new)), - Movement::LineUp(previous) => Movement::LineUp(repeat_count(previous, new)), - Movement::LineDown(previous) => Movement::LineDown(repeat_count(previous, new)), - Movement::WholeBuffer => Movement::WholeBuffer, - Movement::BeginningOfBuffer => Movement::BeginningOfBuffer, - Movement::EndOfBuffer => Movement::EndOfBuffer, + Self::BackwardChar(previous) => Self::BackwardChar(repeat_count(previous, new)), + Self::ForwardChar(previous) => Self::ForwardChar(repeat_count(previous, new)), + Self::LineUp(previous) => Self::LineUp(repeat_count(previous, new)), + Self::LineDown(previous) => Self::LineDown(repeat_count(previous, new)), + Self::WholeBuffer => Self::WholeBuffer, + Self::BeginningOfBuffer => Self::BeginningOfBuffer, + Self::EndOfBuffer => Self::EndOfBuffer, } } } @@ -1209,14 +1209,14 @@ enum Event { KeySeq([KeyEvent; 1]), } impl From for Event { - fn from(k: KeyEvent) -> Event { - Event::KeySeq([k]) + fn from(k: KeyEvent) -> Self { + Self::KeySeq([k]) } } pub struct Bindings {} impl Bindings { - pub fn new() -> Bindings { - Bindings {} + pub fn new() -> Self { + Self {} } } } diff --git a/src/lib.rs b/src/lib.rs index 9f0cee529..f05f720d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -563,7 +563,7 @@ impl<'h> Context<'h> { /// Constructor. Visible for testing. #[must_use] pub fn new(history: &'h dyn History) -> Self { - Context { + Self { history, history_index: history.len(), } diff --git a/src/validate.rs b/src/validate.rs index 8ea8acaf8..b73c5dbd8 100644 --- a/src/validate.rs +++ b/src/validate.rs @@ -17,13 +17,13 @@ pub enum ValidationResult { impl ValidationResult { pub(crate) fn is_valid(&self) -> bool { - matches!(self, ValidationResult::Valid(_)) + matches!(self, Self::Valid(_)) } pub(crate) fn has_message(&self) -> bool { matches!( self, - ValidationResult::Valid(Some(_)) | ValidationResult::Invalid(Some(_)) + Self::Valid(Some(_)) | Self::Invalid(Some(_)) ) } } From 081744dec46639aec0aaff34834569b69e06648d Mon Sep 17 00:00:00 2001 From: Adam Nemecek Date: Thu, 8 Aug 2024 12:01:31 -0700 Subject: [PATCH 35/43] refactoring --- src/binding.rs | 12 ++++++------ src/completion.rs | 2 +- src/tty/test.rs | 2 +- src/tty/windows.rs | 6 +++--- src/undo.rs | 26 +++++++++++++------------- src/validate.rs | 5 +---- 6 files changed, 25 insertions(+), 28 deletions(-) diff --git a/src/binding.rs b/src/binding.rs index 7c083839d..902c09773 100644 --- a/src/binding.rs +++ b/src/binding.rs @@ -107,15 +107,15 @@ impl KeyEvent { impl TrieKey for Event { fn encode_bytes(&self) -> Vec { match self { - Event::Any => ANY.to_be_bytes().to_vec(), - Event::KeySeq(keys) => { + Self::Any => ANY.to_be_bytes().to_vec(), + Self::KeySeq(keys) => { let mut dst = Vec::with_capacity(keys.len() * 4); for key in keys { dst.extend_from_slice(&key.encode().to_be_bytes()); } dst } - Event::Mouse() => MOUSE.to_be_bytes().to_vec(), + Self::Mouse() => MOUSE.to_be_bytes().to_vec(), } } } @@ -132,8 +132,8 @@ pub enum EventHandler { } impl From for EventHandler { - fn from(c: Cmd) -> EventHandler { - EventHandler::Simple(c) + fn from(c: Cmd) -> Self { + Self::Simple(c) } } @@ -147,7 +147,7 @@ pub struct EventContext<'r> { impl<'r> EventContext<'r> { pub(crate) fn new(is: &InputState, wrt: &'r dyn Refresher) -> Self { - EventContext { + Self { mode: is.mode, input_mode: is.input_mode, wrt, diff --git a/src/completion.rs b/src/completion.rs index 477dfc475..bea93a2d7 100644 --- a/src/completion.rs +++ b/src/completion.rs @@ -375,7 +375,7 @@ fn filename_complete( dir_path.to_path_buf() }; - let mut entries: Vec = Vec::new(); + let mut entries: Vec = vec![]; // if dir doesn't exist, then don't offer any completions if !dir.exists() { diff --git a/src/tty/test.rs b/src/tty/test.rs index a7fa01fc8..56a37ccfc 100644 --- a/src/tty/test.rs +++ b/src/tty/test.rs @@ -189,7 +189,7 @@ impl Term for DummyTerminal { _enable_signals: bool, ) -> Result { Ok(DummyTerminal { - keys: Vec::new(), + keys: vec![], cursor: 0, color_mode, bell_style, diff --git a/src/tty/windows.rs b/src/tty/windows.rs index af1f0ccf5..8b74e87d5 100644 --- a/src/tty/windows.rs +++ b/src/tty/windows.rs @@ -665,7 +665,7 @@ impl Term for Console { bell_style: BellStyle, _enable_bracketed_paste: bool, _enable_signals: bool, - ) -> Result { + ) -> Result { let (conin, conout, close_on_drop) = if behavior == Behavior::PreferTerm { if let (Ok(conin), Ok(conout)) = ( OpenOptions::new().read(true).write(true).open("CONIN$"), @@ -706,7 +706,7 @@ impl Term for Console { Err(_) => false, }; - Ok(Console { + Ok(Self { conin_isatty, conin: conin.unwrap_or(ptr::null_mut()), conout_isatty, @@ -904,7 +904,7 @@ impl super::ExternalPrinter for ExternalPrinter { fn print(&mut self, msg: String) -> Result<()> { // write directly to stdout/stderr while not in raw mode if !self.raw_mode.load(Ordering::SeqCst) { - let mut utf16 = Vec::new(); + let mut utf16 = vec![]; write_to_console(self.conout, msg.as_str(), &mut utf16) } else { self.sender diff --git a/src/undo.rs b/src/undo.rs index a76776c1c..e9ebbcc86 100644 --- a/src/undo.rs +++ b/src/undo.rs @@ -30,17 +30,17 @@ enum Change { impl Change { fn undo(&self, line: &mut LineBuffer) { match *self { - Change::Begin | Change::End => { + Self::Begin | Self::End => { unreachable!(); } - Change::Insert { idx, ref text } => { + Self::Insert { idx, ref text } => { line.delete_range(idx..idx + text.len(), &mut NoListener); } - Change::Delete { idx, ref text } => { + Self::Delete { idx, ref text } => { line.insert_str(idx, text, &mut NoListener); line.set_pos(idx + text.len()); } - Change::Replace { + Self::Replace { idx, ref old, ref new, @@ -53,16 +53,16 @@ impl Change { #[cfg(test)] fn redo(&self, line: &mut LineBuffer) { match *self { - Change::Begin | Change::End => { + Self::Begin | Change::End => { unreachable!(); } - Change::Insert { idx, ref text } => { + Self::Insert { idx, ref text } => { line.insert_str(idx, text, &mut NoListener); } - Change::Delete { idx, ref text } => { + Self::Delete { idx, ref text } => { line.delete_range(idx..idx + text.len(), &mut NoListener); } - Change::Replace { + Self::Replace { idx, ref old, ref new, @@ -73,7 +73,7 @@ impl Change { } fn insert_seq(&self, indx: usize) -> bool { - if let Change::Insert { idx, ref text } = *self { + if let Self::Insert { idx, ref text } = *self { idx + text.len() == indx } else { false @@ -81,7 +81,7 @@ impl Change { } fn delete_seq(&self, indx: usize, len: usize) -> bool { - if let Change::Delete { idx, .. } = *self { + if let Self::Delete { idx, .. } = *self { // delete or backspace idx == indx || idx == indx + len } else { @@ -90,7 +90,7 @@ impl Change { } fn replace_seq(&self, indx: usize) -> bool { - if let Change::Replace { idx, ref new, .. } = *self { + if let Self::Replace { idx, ref new, .. } = *self { idx + new.len() == indx } else { false @@ -109,8 +109,8 @@ impl Changeset { pub(crate) fn new() -> Self { Self { undo_group_level: 0, - undos: Vec::new(), - redos: Vec::new(), + undos: vec![], + redos: vec![], } } diff --git a/src/validate.rs b/src/validate.rs index b73c5dbd8..e3bf2e247 100644 --- a/src/validate.rs +++ b/src/validate.rs @@ -21,10 +21,7 @@ impl ValidationResult { } pub(crate) fn has_message(&self) -> bool { - matches!( - self, - Self::Valid(Some(_)) | Self::Invalid(Some(_)) - ) + matches!(self, Self::Valid(Some(_)) | Self::Invalid(Some(_))) } } From 301615f3e0c13a45cd863699b0e26e3d6975f415 Mon Sep 17 00:00:00 2001 From: Adam Nemecek Date: Thu, 8 Aug 2024 12:06:57 -0700 Subject: [PATCH 36/43] refactoring --- src/error.rs | 32 +++++++++++----------- src/keymap.rs | 68 +++++++++++++++++++++++----------------------- src/line_buffer.rs | 6 +--- src/undo.rs | 8 ++---- 4 files changed, 53 insertions(+), 61 deletions(-) diff --git a/src/error.rs b/src/error.rs index ee7ea1c81..3007f85c8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -37,18 +37,18 @@ pub enum ReadlineError { impl fmt::Display for ReadlineError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - ReadlineError::Io(ref err) => err.fmt(f), - ReadlineError::Eof => write!(f, "EOF"), - ReadlineError::Interrupted => write!(f, "Interrupted"), + Self::Io(ref err) => err.fmt(f), + Self::Eof => write!(f, "EOF"), + Self::Interrupted => write!(f, "Interrupted"), #[cfg(unix)] - ReadlineError::Errno(ref err) => err.fmt(f), - ReadlineError::WindowResized => write!(f, "WindowResized"), + Self::Errno(ref err) => err.fmt(f), + Self::WindowResized => write!(f, "WindowResized"), #[cfg(windows)] - ReadlineError::Decode(ref err) => err.fmt(f), + Self::Decode(ref err) => err.fmt(f), #[cfg(windows)] - ReadlineError::SystemError(ref err) => err.fmt(f), + Self::SystemError(ref err) => err.fmt(f), #[cfg(feature = "with-sqlite-history")] - ReadlineError::SQLiteError(ref err) => err.fmt(f), + Self::SQLiteError(ref err) => err.fmt(f), } } } @@ -56,18 +56,18 @@ impl fmt::Display for ReadlineError { impl Error for ReadlineError { fn source(&self) -> Option<&(dyn Error + 'static)> { match *self { - ReadlineError::Io(ref err) => Some(err), - ReadlineError::Eof => None, - ReadlineError::Interrupted => None, + Self::Io(ref err) => Some(err), + Self::Eof => None, + Self::Interrupted => None, #[cfg(unix)] - ReadlineError::Errno(ref err) => Some(err), - ReadlineError::WindowResized => None, + Self::Errno(ref err) => Some(err), + Self::WindowResized => None, #[cfg(windows)] - ReadlineError::Decode(ref err) => Some(err), + Self::Decode(ref err) => Some(err), #[cfg(windows)] - ReadlineError::SystemError(_) => None, + Self::SystemError(_) => None, #[cfg(feature = "with-sqlite-history")] - ReadlineError::SQLiteError(ref err) => Some(err), + Self::SQLiteError(ref err) => Some(err), } } } diff --git a/src/keymap.rs b/src/keymap.rs index 9939b9c33..607767c70 100644 --- a/src/keymap.rs +++ b/src/keymap.rs @@ -133,14 +133,14 @@ impl Cmd { pub const fn should_reset_kill_ring(&self) -> bool { #[allow(clippy::match_same_arms)] match *self { - Cmd::Kill(Movement::BackwardChar(_) | Movement::ForwardChar(_)) => true, - Cmd::ClearScreen - | Cmd::Kill(_) - | Cmd::Replace(..) - | Cmd::Noop - | Cmd::Suspend - | Cmd::Yank(..) - | Cmd::YankPop => false, + Self::Kill(Movement::BackwardChar(_) | Movement::ForwardChar(_)) => true, + Self::ClearScreen + | Self::Kill(_) + | Self::Replace(..) + | Self::Noop + | Self::Suspend + | Self::Yank(..) + | Self::YankPop => false, _ => true, } } @@ -148,21 +148,21 @@ impl Cmd { const fn is_repeatable_change(&self) -> bool { matches!( *self, - Cmd::Dedent(..) - | Cmd::Indent(..) - | Cmd::Insert(..) - | Cmd::Kill(_) - | Cmd::ReplaceChar(..) - | Cmd::Replace(..) - | Cmd::SelfInsert(..) - | Cmd::ViYankTo(_) - | Cmd::Yank(..) // Cmd::TransposeChars | TODO Validate + Self::Dedent(..) + | Self::Indent(..) + | Self::Insert(..) + | Self::Kill(_) + | Self::ReplaceChar(..) + | Self::Replace(..) + | Self::SelfInsert(..) + | Self::ViYankTo(_) + | Self::Yank(..) // Cmd::TransposeChars | TODO Validate ) } const fn is_repeatable(&self) -> bool { match *self { - Cmd::Move(_) => true, + Self::Move(_) => true, _ => self.is_repeatable_change(), } } @@ -170,40 +170,40 @@ impl Cmd { // Replay this command with a possible different `RepeatCount`. fn redo(&self, new: Option, wrt: &dyn Refresher) -> Self { match *self { - Cmd::Dedent(ref mvt) => Cmd::Dedent(mvt.redo(new)), - Cmd::Indent(ref mvt) => Cmd::Indent(mvt.redo(new)), - Cmd::Insert(previous, ref text) => { - Cmd::Insert(repeat_count(previous, new), text.clone()) + Self::Dedent(ref mvt) => Self::Dedent(mvt.redo(new)), + Self::Indent(ref mvt) => Self::Indent(mvt.redo(new)), + Self::Insert(previous, ref text) => { + Self::Insert(repeat_count(previous, new), text.clone()) } - Cmd::Kill(ref mvt) => Cmd::Kill(mvt.redo(new)), - Cmd::Move(ref mvt) => Cmd::Move(mvt.redo(new)), - Cmd::ReplaceChar(previous, c) => Cmd::ReplaceChar(repeat_count(previous, new), c), - Cmd::Replace(ref mvt, ref text) => { + Self::Kill(ref mvt) => Self::Kill(mvt.redo(new)), + Self::Move(ref mvt) => Self::Move(mvt.redo(new)), + Self::ReplaceChar(previous, c) => Self::ReplaceChar(repeat_count(previous, new), c), + Self::Replace(ref mvt, ref text) => { if text.is_none() { let last_insert = wrt.last_insert(); if let Movement::ForwardChar(0) = mvt { - Cmd::Replace( + Self::Replace( Movement::ForwardChar(last_insert.as_ref().map_or(0, String::len)), last_insert, ) } else { - Cmd::Replace(mvt.redo(new), last_insert) + Self::Replace(mvt.redo(new), last_insert) } } else { - Cmd::Replace(mvt.redo(new), text.clone()) + Self::Replace(mvt.redo(new), text.clone()) } } - Cmd::SelfInsert(previous, c) => { + Self::SelfInsert(previous, c) => { // consecutive char inserts are repeatable not only the last one... if let Some(text) = wrt.last_insert() { - Cmd::Insert(repeat_count(previous, new), text) + Self::Insert(repeat_count(previous, new), text) } else { - Cmd::SelfInsert(repeat_count(previous, new), c) + Self::SelfInsert(repeat_count(previous, new), c) } } // Cmd::TransposeChars => Cmd::TransposeChars, - Cmd::ViYankTo(ref mvt) => Cmd::ViYankTo(mvt.redo(new)), - Cmd::Yank(previous, anchor) => Cmd::Yank(repeat_count(previous, new), anchor), + Self::ViYankTo(ref mvt) => Self::ViYankTo(mvt.redo(new)), + Self::Yank(previous, anchor) => Self::Yank(repeat_count(previous, new), anchor), _ => unreachable!(), } } diff --git a/src/line_buffer.rs b/src/line_buffer.rs index 3c7b403c6..bc5e2e24e 100644 --- a/src/line_buffer.rs +++ b/src/line_buffer.rs @@ -160,11 +160,7 @@ impl LineBuffer { let max = self.buf.capacity(); if self.must_truncate(buf.len()) { self.insert_str(0, &buf[..max], cl); - if pos > max { - self.pos = max; - } else { - self.pos = pos; - } + self.pos = max.min(pos); } else { self.insert_str(0, buf, cl); self.pos = pos; diff --git a/src/undo.rs b/src/undo.rs index e9ebbcc86..b3eb2ed3b 100644 --- a/src/undo.rs +++ b/src/undo.rs @@ -30,9 +30,7 @@ enum Change { impl Change { fn undo(&self, line: &mut LineBuffer) { match *self { - Self::Begin | Self::End => { - unreachable!(); - } + Self::Begin | Self::End => unreachable!(), Self::Insert { idx, ref text } => { line.delete_range(idx..idx + text.len(), &mut NoListener); } @@ -53,9 +51,7 @@ impl Change { #[cfg(test)] fn redo(&self, line: &mut LineBuffer) { match *self { - Self::Begin | Change::End => { - unreachable!(); - } + Self::Begin | Change::End => unreachable!(), Self::Insert { idx, ref text } => { line.insert_str(idx, text, &mut NoListener); } From b28a8743457025983ddef510af3cacffa2be49e6 Mon Sep 17 00:00:00 2001 From: Adam Nemecek Date: Thu, 8 Aug 2024 12:09:19 -0700 Subject: [PATCH 37/43] refactoring --- src/config.rs | 4 ++-- src/edit.rs | 4 ++-- src/undo.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/config.rs b/src/config.rs index bb6ec65ae..a4c3d12bc 100644 --- a/src/config.rs +++ b/src/config.rs @@ -248,12 +248,12 @@ pub enum BellStyle { impl Default for BellStyle { #[cfg(any(windows, target_arch = "wasm32"))] fn default() -> Self { - BellStyle::None + Self::None } #[cfg(unix)] fn default() -> Self { - BellStyle::Audible + Self::Audible } } diff --git a/src/edit.rs b/src/edit.rs index e6881eb44..c231e4a42 100644 --- a/src/edit.rs +++ b/src/edit.rs @@ -51,9 +51,9 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> { prompt: &'prompt str, helper: Option<&'out H>, ctx: Context<'out>, - ) -> State<'out, 'prompt, H> { + ) -> Self { let prompt_size = out.calculate_position(prompt, Position::default()); - State { + Self { out, prompt, prompt_size, diff --git a/src/undo.rs b/src/undo.rs index b3eb2ed3b..924319f24 100644 --- a/src/undo.rs +++ b/src/undo.rs @@ -51,7 +51,7 @@ impl Change { #[cfg(test)] fn redo(&self, line: &mut LineBuffer) { match *self { - Self::Begin | Change::End => unreachable!(), + Self::Begin | Self::End => unreachable!(), Self::Insert { idx, ref text } => { line.insert_str(idx, text, &mut NoListener); } From 4dce16ee5ac8897b996a466756354de08aa874ea Mon Sep 17 00:00:00 2001 From: gwenn Date: Sat, 10 Aug 2024 10:46:03 +0200 Subject: [PATCH 38/43] clippy::use_self --- src/binding.rs | 8 ++++---- src/error.rs | 18 +++++++++--------- src/hint.rs | 4 ++-- src/line_buffer.rs | 4 ++-- src/sqlite_history.rs | 2 +- src/tty/test.rs | 4 ++-- src/tty/unix.rs | 8 ++++---- src/tty/windows.rs | 8 ++++---- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/binding.rs b/src/binding.rs index 902c09773..464183124 100644 --- a/src/binding.rs +++ b/src/binding.rs @@ -21,7 +21,7 @@ pub enum Event { impl Event { /// See [`KeyEvent::normalize`] pub(crate) fn normalize(mut self) -> Self { - if let Event::KeySeq(ref mut keys) = self { + if let Self::KeySeq(ref mut keys) = self { for key in keys.iter_mut() { *key = KeyEvent::normalize(*key); } @@ -32,7 +32,7 @@ impl Event { /// Return `i`th key event #[must_use] pub fn get(&self, i: usize) -> Option<&KeyEvent> { - if let Event::KeySeq(ref ks) = self { + if let Self::KeySeq(ref ks) = self { ks.get(i) } else { None @@ -41,8 +41,8 @@ impl Event { } impl From for Event { - fn from(k: KeyEvent) -> Event { - Event::KeySeq(vec![k]) + fn from(k: KeyEvent) -> Self { + Self::KeySeq(vec![k]) } } diff --git a/src/error.rs b/src/error.rs index 3007f85c8..718486446 100644 --- a/src/error.rs +++ b/src/error.rs @@ -90,58 +90,58 @@ impl From for ReadlineError { if err.kind() == io::ErrorKind::Interrupted { if let Some(e) = err.get_ref() { if e.downcast_ref::().is_some() { - return ReadlineError::WindowResized; + return Self::WindowResized; } } } - ReadlineError::Io(err) + Self::Io(err) } } impl From for ReadlineError { fn from(kind: io::ErrorKind) -> Self { - ReadlineError::Io(io::Error::from(kind)) + Self::Io(io::Error::from(kind)) } } #[cfg(unix)] impl From for ReadlineError { fn from(err: nix::Error) -> Self { - ReadlineError::Errno(err) + Self::Errno(err) } } #[cfg(windows)] impl From for ReadlineError { fn from(err: char::DecodeUtf16Error) -> Self { - ReadlineError::Io(io::Error::new(io::ErrorKind::InvalidData, err)) + Self::Io(io::Error::new(io::ErrorKind::InvalidData, err)) } } #[cfg(windows)] impl From for ReadlineError { fn from(err: std::string::FromUtf8Error) -> Self { - ReadlineError::Io(io::Error::new(io::ErrorKind::InvalidData, err)) + Self::Io(io::Error::new(io::ErrorKind::InvalidData, err)) } } #[cfg(unix)] impl From for ReadlineError { fn from(err: fmt::Error) -> Self { - ReadlineError::Io(io::Error::new(io::ErrorKind::Other, err)) + Self::Io(io::Error::new(io::ErrorKind::Other, err)) } } #[cfg(windows)] impl From for ReadlineError { fn from(err: clipboard_win::ErrorCode) -> Self { - ReadlineError::SystemError(err) + Self::SystemError(err) } } #[cfg(feature = "with-sqlite-history")] impl From for ReadlineError { fn from(err: rusqlite::Error) -> Self { - ReadlineError::SQLiteError(err) + Self::SQLiteError(err) } } diff --git a/src/hint.rs b/src/hint.rs index 1b4f88ab0..efff9357c 100644 --- a/src/hint.rs +++ b/src/hint.rs @@ -55,8 +55,8 @@ pub struct HistoryHinter {} impl HistoryHinter { /// Create a new `HistoryHinter` - pub fn new() -> HistoryHinter { - HistoryHinter::default() + pub fn new() -> Self { + Self::default() } } diff --git a/src/line_buffer.rs b/src/line_buffer.rs index bc5e2e24e..ac9c68821 100644 --- a/src/line_buffer.rs +++ b/src/line_buffer.rs @@ -1189,8 +1189,8 @@ mod test { } impl Listener { - fn new() -> Listener { - Listener { deleted_str: None } + fn new() -> Self { + Self { deleted_str: None } } fn assert_deleted_str_eq(&self, expected: &str) { diff --git a/src/sqlite_history.rs b/src/sqlite_history.rs index d918ff9a5..867f5b7d5 100644 --- a/src/sqlite_history.rs +++ b/src/sqlite_history.rs @@ -47,7 +47,7 @@ impl SQLiteHistory { fn new(config: Config, path: Option) -> Result { let conn = conn(path.as_ref())?; - let mut sh = SQLiteHistory { + let mut sh = Self { max_len: config.max_history_size(), ignore_space: config.history_ignore_space(), // not strictly consecutive... diff --git a/src/tty/test.rs b/src/tty/test.rs index 56a37ccfc..00ef42152 100644 --- a/src/tty/test.rs +++ b/src/tty/test.rs @@ -187,8 +187,8 @@ impl Term for DummyTerminal { bell_style: BellStyle, _enable_bracketed_paste: bool, _enable_signals: bool, - ) -> Result { - Ok(DummyTerminal { + ) -> Result { + Ok(Self { keys: vec![], cursor: 0, color_mode, diff --git a/src/tty/unix.rs b/src/tty/unix.rs index 071e4ba02..895ad3a72 100644 --- a/src/tty/unix.rs +++ b/src/tty/unix.rs @@ -1207,7 +1207,7 @@ struct SigWinCh { } impl SigWinCh { #[cfg(not(feature = "signal-hook"))] - fn install_sigwinch_handler() -> Result { + fn install_sigwinch_handler() -> Result { use nix::sys::signal; let (pipe, pipe_write) = UnixStream::pair()?; pipe.set_nonblocking(true)?; @@ -1218,18 +1218,18 @@ impl SigWinCh { signal::SigSet::empty(), ); let original = unsafe { signal::sigaction(signal::SIGWINCH, &sigwinch)? }; - Ok(SigWinCh { + Ok(Self { pipe: pipe.into_raw_fd(), original, }) } #[cfg(feature = "signal-hook")] - fn install_sigwinch_handler() -> Result { + fn install_sigwinch_handler() -> Result { let (pipe, pipe_write) = UnixStream::pair()?; pipe.set_nonblocking(true)?; let id = signal_hook::low_level::pipe::register(libc::SIGWINCH, pipe_write)?; - Ok(SigWinCh { + Ok(Self { pipe: pipe.into_raw_fd(), id, }) diff --git a/src/tty/windows.rs b/src/tty/windows.rs index 8b74e87d5..932784ec8 100644 --- a/src/tty/windows.rs +++ b/src/tty/windows.rs @@ -110,8 +110,8 @@ pub struct ConsoleRawReader { } impl ConsoleRawReader { - fn create(conin: HANDLE, pipe_reader: Option>) -> ConsoleRawReader { - ConsoleRawReader { conin, pipe_reader } + fn create(conin: HANDLE, pipe_reader: Option>) -> Self { + Self { conin, pipe_reader } } fn select(&mut self) -> Result { @@ -296,10 +296,10 @@ pub struct ConsoleRenderer { } impl ConsoleRenderer { - fn new(conout: HANDLE, colors_enabled: bool, bell_style: BellStyle) -> ConsoleRenderer { + fn new(conout: HANDLE, colors_enabled: bool, bell_style: BellStyle) -> Self { // Multi line editing is enabled by ENABLE_WRAP_AT_EOL_OUTPUT mode let (cols, _) = get_win_size(conout); - ConsoleRenderer { + Self { conout, cols, buffer: String::with_capacity(1024), From 4b1a527dfd16dd37df1b8aa9d62d8ddc4cb7274c Mon Sep 17 00:00:00 2001 From: gwenn Date: Sat, 10 Aug 2024 11:44:32 +0200 Subject: [PATCH 39/43] clippy::manual_let_else --- src/completion.rs | 8 ++------ src/lib.rs | 5 ++--- src/tty/windows.rs | 4 +--- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/completion.rs b/src/completion.rs index bea93a2d7..9d205bca1 100644 --- a/src/completion.rs +++ b/src/completion.rs @@ -265,9 +265,7 @@ impl Completer for FilenameCompleter { /// Remove escape char #[must_use] pub fn unescape(input: &str, esc_char: Option) -> Cow<'_, str> { - let esc_char = if let Some(c) = esc_char { - c - } else { + let Some(esc_char) = esc_char else { return Borrowed(input); }; if !input.chars().any(|c| c == esc_char) { @@ -310,9 +308,7 @@ pub fn escape( if n == 0 { return input; // no need to escape } - let esc_char = if let Some(c) = esc_char { - c - } else { + let Some(esc_char) = esc_char else { if cfg!(windows) && quote == Quote::None { input.insert(0, '"'); // force double quote return input; diff --git a/src/lib.rs b/src/lib.rs index f05f720d9..10fd4b68a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -264,9 +264,8 @@ fn complete_line( /// Completes the current hint fn complete_hint_line(s: &mut State<'_, '_, H>) -> Result<()> { - let hint = match s.hint.as_ref() { - Some(hint) => hint, - None => return Ok(()), + let Some(hint) = s.hint.as_ref() else { + return Ok(()); }; s.line.move_end(); if let Some(text) = hint.completion() { diff --git a/src/tty/windows.rs b/src/tty/windows.rs index 932784ec8..7574403f0 100644 --- a/src/tty/windows.rs +++ b/src/tty/windows.rs @@ -273,9 +273,7 @@ fn read_input(handle: HANDLE, max_count: u32) -> Result { } else { decode_utf16([surrogate, utf16].iter().copied()).next() }; - let rc = if let Some(rc) = orc { - rc - } else { + let Some(rc) = orc else { return Err(error::ReadlineError::Eof); }; let c = rc?; From 8e7b4110f2bf7c1775418b4b4976152e8c5a569b Mon Sep 17 00:00:00 2001 From: gwenn Date: Sat, 10 Aug 2024 12:09:28 +0200 Subject: [PATCH 40/43] clippy misc --- src/completion.rs | 2 +- src/error.rs | 2 +- src/keymap.rs | 2 +- src/test/mod.rs | 2 +- src/tty/unix.rs | 8 +++----- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/completion.rs b/src/completion.rs index 9d205bca1..f34befb4d 100644 --- a/src/completion.rs +++ b/src/completion.rs @@ -613,7 +613,7 @@ mod tests { assert_eq!(Some(s), lcp); } - let c3 = String::from(""); + let c3 = String::new(); candidates.push(c3); { let lcp = super::longest_common_prefix(&candidates); diff --git a/src/error.rs b/src/error.rs index 718486446..b75101199 100644 --- a/src/error.rs +++ b/src/error.rs @@ -21,7 +21,7 @@ pub enum ReadlineError { /// Unix Error from syscall #[cfg(unix)] Errno(nix::Error), - /// Error generated on WINDOW_BUFFER_SIZE_EVENT / SIGWINCH signal + /// Error generated on `WINDOW_BUFFER_SIZE_EVENT` / `SIGWINCH` signal WindowResized, /// Like Utf8Error on unix #[cfg(windows)] diff --git a/src/keymap.rs b/src/keymap.rs index 607767c70..17c78d421 100644 --- a/src/keymap.rs +++ b/src/keymap.rs @@ -19,7 +19,7 @@ pub enum Cmd { Abort, // Miscellaneous Command /// accept-line /// - /// See also AcceptOrInsertLine + /// See also `AcceptOrInsertLine` AcceptLine, /// beginning-of-history BeginningOfHistory, diff --git a/src/test/mod.rs b/src/test/mod.rs index 6eb317db0..14ff9052b 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -21,7 +21,7 @@ mod vi_insert; fn init_editor(mode: EditMode, keys: &[KeyEvent]) -> DefaultEditor { let config = Config::builder().edit_mode(mode).build(); let mut editor = DefaultEditor::with_config(config).unwrap(); - editor.term.keys.extend(keys.iter().cloned()); + editor.term.keys.extend(keys.iter().copied()); editor } diff --git a/src/tty/unix.rs b/src/tty/unix.rs index 895ad3a72..08d754810 100644 --- a/src/tty/unix.rs +++ b/src/tty/unix.rs @@ -143,7 +143,7 @@ impl Read for TtyIn { let res = unsafe { libc::read( self.fd, - buf.as_mut_ptr() as *mut libc::c_void, + buf.as_mut_ptr().cast::(), buf.len() as libc::size_t, ) }; @@ -1021,9 +1021,7 @@ impl Renderer for PosixRenderer { // we have to generate our own newline on line wrap if end_pos.col == 0 && end_pos.row > 0 - && !hint - .map(|h| h.ends_with('\n')) - .unwrap_or_else(|| line.ends_with('\n')) + && !hint.map_or_else(|| line.ends_with('\n'), |h| h.ends_with('\n')) { self.buffer.push('\n'); } @@ -1440,6 +1438,7 @@ impl Term for PosixTerminal { } fn create_external_printer(&mut self) -> Result { + use nix::unistd::pipe; if let Some(ref writer) = self.pipe_writer { return Ok(ExternalPrinter { writer: writer.clone(), @@ -1450,7 +1449,6 @@ impl Term for PosixTerminal { if self.unsupported || !self.is_input_tty() || !self.is_output_tty() { return Err(nix::Error::ENOTTY.into()); } - use nix::unistd::pipe; let (sender, receiver) = mpsc::sync_channel(1); // TODO validate: bound let (r, w) = pipe()?; let reader = Arc::new(Mutex::new((r.into(), receiver))); From 8bddee02caeedeaf41749e00f89007d140b91aa5 Mon Sep 17 00:00:00 2001 From: Adam Nemecek Date: Mon, 12 Aug 2024 11:08:03 -0700 Subject: [PATCH 41/43] use Self --- src/hint.rs | 4 ++-- src/line_buffer.rs | 4 ++-- src/sqlite_history.rs | 2 +- src/tty/test.rs | 4 ++-- src/tty/windows.rs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/hint.rs b/src/hint.rs index 1b4f88ab0..efff9357c 100644 --- a/src/hint.rs +++ b/src/hint.rs @@ -55,8 +55,8 @@ pub struct HistoryHinter {} impl HistoryHinter { /// Create a new `HistoryHinter` - pub fn new() -> HistoryHinter { - HistoryHinter::default() + pub fn new() -> Self { + Self::default() } } diff --git a/src/line_buffer.rs b/src/line_buffer.rs index bc5e2e24e..ac9c68821 100644 --- a/src/line_buffer.rs +++ b/src/line_buffer.rs @@ -1189,8 +1189,8 @@ mod test { } impl Listener { - fn new() -> Listener { - Listener { deleted_str: None } + fn new() -> Self { + Self { deleted_str: None } } fn assert_deleted_str_eq(&self, expected: &str) { diff --git a/src/sqlite_history.rs b/src/sqlite_history.rs index d918ff9a5..867f5b7d5 100644 --- a/src/sqlite_history.rs +++ b/src/sqlite_history.rs @@ -47,7 +47,7 @@ impl SQLiteHistory { fn new(config: Config, path: Option) -> Result { let conn = conn(path.as_ref())?; - let mut sh = SQLiteHistory { + let mut sh = Self { max_len: config.max_history_size(), ignore_space: config.history_ignore_space(), // not strictly consecutive... diff --git a/src/tty/test.rs b/src/tty/test.rs index 56a37ccfc..00ef42152 100644 --- a/src/tty/test.rs +++ b/src/tty/test.rs @@ -187,8 +187,8 @@ impl Term for DummyTerminal { bell_style: BellStyle, _enable_bracketed_paste: bool, _enable_signals: bool, - ) -> Result { - Ok(DummyTerminal { + ) -> Result { + Ok(Self { keys: vec![], cursor: 0, color_mode, diff --git a/src/tty/windows.rs b/src/tty/windows.rs index 8b74e87d5..da0d0b496 100644 --- a/src/tty/windows.rs +++ b/src/tty/windows.rs @@ -299,7 +299,7 @@ impl ConsoleRenderer { fn new(conout: HANDLE, colors_enabled: bool, bell_style: BellStyle) -> ConsoleRenderer { // Multi line editing is enabled by ENABLE_WRAP_AT_EOL_OUTPUT mode let (cols, _) = get_win_size(conout); - ConsoleRenderer { + Self { conout, cols, buffer: String::with_capacity(1024), From 6da59c41b8e1d2c58d2fb576419e04c1c468637e Mon Sep 17 00:00:00 2001 From: gwenn Date: Sun, 18 Aug 2024 08:04:04 +0200 Subject: [PATCH 42/43] Fix clippy error with --no-default-features --- src/keymap.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keymap.rs b/src/keymap.rs index 17c78d421..784c91016 100644 --- a/src/keymap.rs +++ b/src/keymap.rs @@ -582,6 +582,7 @@ impl<'b> InputState<'b> { } else { let snd_key = match evt { // we may have already read the second key in custom_seq_binding + #[allow(clippy::out_of_bounds_indexing)] Event::KeySeq(ref key_seq) if key_seq.len() > 1 => key_seq[1], _ => rdr.next_key(true)?, }; From 15788df8c452a77b5c53e596426ffa87a936db3c Mon Sep 17 00:00:00 2001 From: gwenn Date: Sat, 31 Aug 2024 10:41:28 +0200 Subject: [PATCH 43/43] Fix clippy warnings --- src/completion.rs | 1 + src/highlight.rs | 2 -- src/validate.rs | 9 +++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/completion.rs b/src/completion.rs index f34befb4d..114d1aa9e 100644 --- a/src/completion.rs +++ b/src/completion.rs @@ -415,6 +415,7 @@ fn normalize(s: &str) -> Cow { /// Given a `line` and a cursor `pos`ition, /// try to find backward the start of a word. +/// /// Return (0, `line[..pos]`) if no break char has been found. /// Return the word and its start position (idx, `line[idx..pos]`) otherwise. #[must_use] diff --git a/src/highlight.rs b/src/highlight.rs index d5c0e8967..a21459e0a 100644 --- a/src/highlight.rs +++ b/src/highlight.rs @@ -5,8 +5,6 @@ use std::borrow::Cow::{self, Borrowed, Owned}; use std::cell::Cell; /// Syntax highlighter with [ANSI color](https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters). -/// Rustyline will try to handle escape sequence for ANSI color on windows -/// when not supported natively (windows <10). /// /// Currently, the highlighted version *must* have the same display width as /// the original input. diff --git a/src/validate.rs b/src/validate.rs index e3bf2e247..12b7f3314 100644 --- a/src/validate.rs +++ b/src/validate.rs @@ -48,10 +48,11 @@ impl<'i> ValidationContext<'i> { } /// This trait provides an extension interface for determining whether -/// the current input buffer is valid. Rustyline uses the method -/// provided by this trait to decide whether hitting the enter key -/// will end the current editing session and return the current line -/// buffer to the caller of `Editor::readline` or variants. +/// the current input buffer is valid. +/// +/// Rustyline uses the method provided by this trait to decide whether hitting +/// the enter key will end the current editing session and return the current +/// line buffer to the caller of `Editor::readline` or variants. pub trait Validator { /// Takes the currently edited `input` and returns a /// `ValidationResult` indicating whether it is valid or not along