Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix typeahead #761

Merged
merged 2 commits into from
Feb 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand Down
1 change: 1 addition & 0 deletions src/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ mod test {

#[test]
#[ignore]
#[cfg(target_arch = "x86_64")]
fn size_of_event() {
use core::mem::size_of;
assert_eq!(size_of::<Event>(), 32);
Expand Down
9 changes: 7 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -586,6 +586,7 @@ impl<'h> Context<'h> {
#[must_use]
pub struct Editor<H: Helper, I: History> {
term: Terminal,
buffer: Option<Buffer>,
history: I,
helper: Option<H>,
kill_ring: KillRing,
Expand Down Expand Up @@ -621,6 +622,7 @@ impl<H: Helper, I: History> Editor<H, I> {
)?;
Ok(Self {
term,
buffer: None,
history,
helper: None,
kill_ring: KillRing::new(60),
Expand Down Expand Up @@ -704,7 +706,9 @@ impl<H: Helper, I: History> Editor<H, I> {
);
}

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 {
Expand Down Expand Up @@ -794,6 +798,7 @@ impl<H: Helper, I: History> Editor<H, I> {
if cfg!(windows) {
let _ = original_mode; // silent warning
}
self.buffer = rdr.unbuffer();
Ok(s.line.into_string())
}

Expand Down
13 changes: 11 additions & 2 deletions src/tty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Event>; // TODO replace calls to `next_key` by `wait_for_input` where relevant
/// Blocking read of key pressed.
Expand All @@ -34,6 +35,8 @@ pub trait RawReader {
fn read_pasted_text(&mut self) -> Result<String>;
/// Check if `key` is bound to a peculiar command
fn find_binding(&self, key: &KeyEvent) -> Option<Cmd>;
/// Backup type ahead
fn unbuffer(self) -> Option<Buffer>;
}

/// Display prompt, line and cursor in terminal output
Expand Down Expand Up @@ -215,8 +218,9 @@ pub trait ExternalPrinter {

/// Terminal contract
pub trait Term {
type Buffer;
type KeyMap;
type Reader: RawReader; // rl_instream
type Reader: RawReader<Buffer = Self::Buffer>; // rl_instream
type Writer: Renderer<Reader = Self::Reader>; // rl_outstream
type Mode: RawMode;
type ExternalPrinter: ExternalPrinter;
Expand All @@ -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<Self::Buffer>,
config: &Config,
key_map: Self::KeyMap,
) -> Self::Reader;
/// Create a writer
fn create_writer(&self) -> Self::Writer;
fn writeln(&self) -> Result<()>;
Expand Down
16 changes: 15 additions & 1 deletion src/tty/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ();

Expand All @@ -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<Event> {
self.next_key(single_esc_abort).map(Event::KeyPress)
}
Expand All @@ -45,9 +48,15 @@ impl<'a> RawReader for Iter<'a, KeyEvent> {
fn find_binding(&self, _: &KeyEvent) -> Option<Cmd> {
None
}

fn unbuffer(self) -> Option<Buffer> {
None
}
}

impl RawReader for IntoIter<KeyEvent> {
type Buffer = Buffer;

fn wait_for_input(&mut self, single_esc_abort: bool) -> Result<Event> {
self.next_key(single_esc_abort).map(Event::KeyPress)
}
Expand Down Expand Up @@ -76,6 +85,10 @@ impl RawReader for IntoIter<KeyEvent> {
fn find_binding(&self, _: &KeyEvent) -> Option<Cmd> {
None
}

fn unbuffer(self) -> Option<Buffer> {
None
}
}

#[derive(Default)]
Expand Down Expand Up @@ -160,6 +173,7 @@ pub struct DummyTerminal {
}

impl Term for DummyTerminal {
type Buffer = Buffer;
type CursorGuard = ();
type ExternalPrinter = DummyExternalPrinter;
type KeyMap = KeyMap;
Expand Down Expand Up @@ -208,7 +222,7 @@ impl Term for DummyTerminal {
Ok(((), ()))
}

fn create_reader(&self, _: &Config, _: KeyMap) -> Self::Reader {
fn create_reader(&self, _: Option<Buffer>, _: &Config, _: KeyMap) -> Self::Reader {
self.keys.clone().into_iter()
}

Expand Down
47 changes: 44 additions & 3 deletions src/tty/unix.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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<KeyEvent, Cmd>;
#[cfg(not(test))]
pub type KeyMap = PosixKeyMap;
Expand Down Expand Up @@ -228,12 +239,22 @@ impl PosixRawReader {
fn new(
fd: RawFd,
sigwinch_pipe: Option<RawFd>,
buffer: Option<PosixBuffer>,
config: &Config,
key_map: PosixKeyMap,
pipe_reader: Option<PipeReader>,
) -> 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,
Expand Down Expand Up @@ -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<Event> {
match self.pipe_reader {
Expand Down Expand Up @@ -840,6 +863,17 @@ impl RawReader for PosixRawReader {
}
cmd
}

#[cfg(any(not(feature = "buffer-redux"), test))]
fn unbuffer(self) -> Option<PosixBuffer> {
None
}

#[cfg(all(feature = "buffer-redux", not(test)))]
fn unbuffer(self) -> Option<PosixBuffer> {
let (_, buffer) = self.tty_in.into_inner_with_buffer();
Some(buffer)
}
}

impl Receiver for Utf8 {
Expand Down Expand Up @@ -1253,6 +1287,7 @@ impl PosixTerminal {
}

impl Term for PosixTerminal {
type Buffer = PosixBuffer;
type CursorGuard = PosixCursorGuard;
type ExternalPrinter = ExternalPrinter;
type KeyMap = PosixKeyMap;
Expand Down Expand Up @@ -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<PosixBuffer>,
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(),
Expand Down
18 changes: 17 additions & 1 deletion src/tty/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ fn get_console_mode(handle: HANDLE) -> Result<console::CONSOLE_MODE> {
Ok(original_mode)
}

type ConsoleBuffer = ();
#[cfg(not(test))]
pub type Buffer = ConsoleBuffer;

type ConsoleKeyMap = ();
#[cfg(not(test))]
pub type KeyMap = ConsoleKeyMap;
Expand Down Expand Up @@ -141,6 +145,8 @@ impl ConsoleRawReader {
}

impl RawReader for ConsoleRawReader {
type Buffer = ConsoleBuffer;

fn wait_for_input(&mut self, single_esc_abort: bool) -> Result<Event> {
match self.pipe_reader {
Some(_) => self.select(),
Expand All @@ -159,6 +165,10 @@ impl RawReader for ConsoleRawReader {
fn find_binding(&self, _: &KeyEvent) -> Option<Cmd> {
None
}

fn unbuffer(self) -> Option<ConsoleBuffer> {
None
}
}

fn read_input(handle: HANDLE, max_count: u32) -> Result<KeyEvent> {
Expand Down Expand Up @@ -640,6 +650,7 @@ impl Console {
}

impl Term for Console {
type Buffer = ConsoleBuffer;
type CursorGuard = ConsoleCursorGuard;
type ExternalPrinter = ExternalPrinter;
type KeyMap = ConsoleKeyMap;
Expand Down Expand Up @@ -801,7 +812,12 @@ impl Term for Console {
))
}

fn create_reader(&self, _: &Config, _: ConsoleKeyMap) -> ConsoleRawReader {
fn create_reader(
&self,
_: Option<ConsoleBuffer>,
_: &Config,
_: ConsoleKeyMap,
) -> ConsoleRawReader {
ConsoleRawReader::create(self.conin, self.pipe_reader.clone())
}

Expand Down
Loading