Skip to content

Commit

Permalink
Merge branch 'master' into paste_refresh
Browse files Browse the repository at this point in the history
  • Loading branch information
gwenn authored Sep 3, 2023
2 parents ab116d9 + 2b9e85d commit a0e589b
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 39 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ regex = { version = "1.5.5", optional = true }
rustyline-derive = { version = "0.9.0", optional = true, path = "rustyline-derive" }

[target.'cfg(unix)'.dependencies]
nix = { version = "0.26", default-features = false, features = ["fs", "ioctl", "poll", "signal", "term"] }
nix = { version = "0.27", 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 }
Expand Down
4 changes: 2 additions & 2 deletions examples/example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ impl Highlighter for MyHelper {
self.highlighter.highlight(line, pos)
}

fn highlight_char(&self, line: &str, pos: usize) -> bool {
self.highlighter.highlight_char(line, pos)
fn highlight_char(&self, line: &str, pos: usize, forced: bool) -> bool {
self.highlighter.highlight_char(line, pos, forced)
}
}

Expand Down
2 changes: 1 addition & 1 deletion examples/read_password.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ impl Highlighter for MaskingHighlighter {
}
}

fn highlight_char(&self, _line: &str, _pos: usize) -> bool {
fn highlight_char(&self, line: &str, pos: usize, forced: bool) -> bool {
self.masking
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ pub fn execute<H: Helper>(

match cmd {
Cmd::EndOfFile | Cmd::AcceptLine | Cmd::AcceptOrInsertLine { .. } | Cmd::Newline => {
if s.has_hint() || !s.is_default_prompt() {
if s.has_hint() || !s.is_default_prompt() || s.highlight_char {
// Force a refresh without hints to leave the previous
// line as the user typed it after a newline.
s.forced_refresh = true;
s.refresh_line_with_msg(None)?;
s.forced_refresh = false;
}
}
_ => {}
Expand Down
8 changes: 6 additions & 2 deletions src/edit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ pub struct State<'out, 'prompt, H: Helper> {
pub helper: Option<&'out H>,
pub ctx: Context<'out>, // Give access to history for `hinter`
pub hint: Option<Box<dyn Hint>>, // last hint displayed
highlight_char: bool, // `true` if a char has been highlighted
pub highlight_char: bool, // `true` if a char has been highlighted
pub forced_refresh: bool, // `true` if line is redraw without hint or highlight_char
refresh_rate_limit: RefreshRateLimit,
}

Expand Down Expand Up @@ -114,6 +115,7 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> {
ctx,
hint: None,
highlight_char: false,
forced_refresh: false,
refresh_rate_limit: RefreshRateLimit::new(config.refresh_rate_limit()),
}
}
Expand Down Expand Up @@ -263,7 +265,8 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> {

fn highlight_char(&mut self) -> bool {
if let Some(highlighter) = self.highlighter() {
let highlight_char = highlighter.highlight_char(&self.line, self.line.pos());
let highlight_char =
highlighter.highlight_char(&self.line, self.line.pos(), self.forced_refresh);
if highlight_char {
self.highlight_char = true;
true
Expand Down Expand Up @@ -824,6 +827,7 @@ pub fn init_state<'out, H: Helper>(
ctx: Context::new(history),
hint: Some(Box::new("hint".to_owned())),
highlight_char: false,
forced_refresh: false,
refresh_rate_limit: RefreshRateLimit::new(Duration::from_millis(0)),
}
}
Expand Down
15 changes: 10 additions & 5 deletions src/highlight.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,12 @@ 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).
///
/// Used to optimize refresh when a character is inserted or the cursor is
/// moved.
fn highlight_char(&self, line: &str, pos: usize) -> bool {
let _ = (line, pos);
fn highlight_char(&self, line: &str, pos: usize, forced: bool) -> bool {
let _ = (line, pos, forced);
false
}
}
Expand Down Expand Up @@ -85,8 +86,8 @@ impl<'r, H: ?Sized + Highlighter> Highlighter for &'r H {
(**self).highlight_candidate(candidate, completion)
}

fn highlight_char(&self, line: &str, pos: usize) -> bool {
(**self).highlight_char(line, pos)
fn highlight_char(&self, line: &str, pos: usize, forced: bool) -> bool {
(**self).highlight_char(line, pos, forced)
}
}

Expand Down Expand Up @@ -124,7 +125,11 @@ impl Highlighter for MatchingBracketHighlighter {
Borrowed(line)
}

fn highlight_char(&self, line: &str, pos: usize) -> bool {
fn highlight_char(&self, line: &str, pos: usize, forced: bool) -> bool {
if forced {
self.bracket.set(None);
return false;
}
// will highlight matching brace/bracket/parenthesis if it exists
self.bracket.set(check_bracket(line, pos));
self.bracket.get().is_some()
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,9 @@ impl<H: Helper, I: History> Editor<H, I> {

// Move to end, in case cursor was in the middle of the line, so that
// next thing application prints goes after the input
s.forced_refresh = true;
s.edit_move_buffer_end()?;
s.forced_refresh = false;

if cfg!(windows) {
let _ = original_mode; // silent warning
Expand Down
50 changes: 23 additions & 27 deletions src/tty/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::collections::HashMap;
use std::convert::TryFrom;
use std::fs::{File, OpenOptions};
use std::io::{self, BufReader, ErrorKind, Read, Write};
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, IntoRawFd, RawFd};
use std::os::unix::net::UnixStream;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{self, SyncSender};
Expand All @@ -16,7 +16,7 @@ use nix::errno::Errno;
use nix::poll::{self, PollFlags};
use nix::sys::select::{self, FdSet};
use nix::unistd::{close, isatty, read, write};
use termios::{tcgetattr, tcsetattr, Termios};
use termios::{tcsetattr, Termios};
use unicode_segmentation::UnicodeSegmentation;
use utf8parse::{Parser, Receiver};

Expand Down Expand Up @@ -108,8 +108,7 @@ pub type Mode = PosixMode;
impl RawMode for PosixMode {
/// Disable RAW mode for the terminal.
fn disable_raw_mode(&self) -> Result<()> {
let mut termios = self.termios;
tcgetattr(self.tty_in, &mut termios)?;
tcsetattr(self.tty_in, termios::TCSADRAIN, &self.termios)?;
// disable bracketed paste
if let Some(out) = self.tty_out {
write_all(out, BRACKETED_PASTE_OFF)?;
Expand Down Expand Up @@ -184,12 +183,12 @@ pub struct PosixRawReader {
key_map: PosixKeyMap,
// external print reader
pipe_reader: Option<PipeReader>,
fds: FdSet,
}

impl AsRawFd for PosixRawReader {
fn as_raw_fd(&self) -> RawFd {
self.tty_in.get_ref().fd
impl AsFd for PosixRawReader {
fn as_fd(&self) -> BorrowedFd<'_> {
let fd = self.tty_in.get_ref().fd;
unsafe { BorrowedFd::borrow_raw(fd) }
}
}

Expand Down Expand Up @@ -238,7 +237,6 @@ impl PosixRawReader {
parser: Parser::new(),
key_map,
pipe_reader,
fds: FdSet::new(),
}
}

Expand Down Expand Up @@ -687,7 +685,7 @@ impl PosixRawReader {
if n > 0 {
return Ok(n as i32);
}
let mut fds = [poll::PollFd::new(self.as_raw_fd(), PollFlags::POLLIN)];
let mut fds = [poll::PollFd::new(self, PollFlags::POLLIN)];
let r = poll::poll(&mut fds, timeout_ms);
match r {
Ok(n) => Ok(n),
Expand All @@ -703,29 +701,27 @@ impl PosixRawReader {
}

fn select(&mut self, single_esc_abort: bool) -> Result<Event> {
let tty_in = self.as_raw_fd();
let sigwinch_pipe = self.tty_in.get_ref().sigwinch_pipe;
let tty_in = self.as_fd();
let sigwinch_pipe = self
.tty_in
.get_ref()
.sigwinch_pipe
.map(|fd| unsafe { BorrowedFd::borrow_raw(fd) });
let pipe_reader = self
.pipe_reader
.as_ref()
.map(|pr| pr.lock().unwrap().0.as_raw_fd());
.map(|pr| pr.lock().unwrap().0.as_raw_fd())
.map(|fd| unsafe { BorrowedFd::borrow_raw(fd) });
loop {
let mut readfds = self.fds;
readfds.clear();
if let Some(sigwinch_pipe) = sigwinch_pipe {
let mut readfds = FdSet::new();
if let Some(ref sigwinch_pipe) = sigwinch_pipe {
readfds.insert(sigwinch_pipe);
}
readfds.insert(tty_in);
if let Some(pipe_reader) = pipe_reader {
readfds.insert(&tty_in);
if let Some(ref pipe_reader) = pipe_reader {
readfds.insert(pipe_reader);
}
if let Err(err) = select::select(
readfds.highest().map(|h| h + 1),
Some(&mut readfds),
None,
None,
None,
) {
if let Err(err) = select::select(None, Some(&mut readfds), None, None, None) {
if err == Errno::EINTR && self.tty_in.get_ref().sigwinch()? {
return Err(ReadlineError::WindowResized);
} else if err != Errno::EINTR {
Expand All @@ -734,10 +730,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 {
Expand Down

0 comments on commit a0e589b

Please sign in to comment.