Skip to content

Commit

Permalink
Merge pull request #761 from gwenn/typeahead
Browse files Browse the repository at this point in the history
Fix typeahead
  • Loading branch information
gwenn committed Feb 17, 2024
2 parents 57037fd + d3524ae commit 485eef8
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 9 deletions.
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

0 comments on commit 485eef8

Please sign in to comment.