Merge pull request #150 from gwenn/misc
Misc
diff --git a/Cargo.toml b/Cargo.toml
index 30a2fa1..a8ed288 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "rustyline"
-version = "2.0.1"
+version = "2.1.0"
authors = ["Katsu Kawakami <kkawa1570@gmail.com>"]
description = "Rustyline, a readline implementation based on Antirez's Linenoise"
documentation = "http://docs.rs/rustyline"
diff --git a/README.md b/README.md
index 5468a87..ea66ccc 100644
--- a/README.md
+++ b/README.md
@@ -61,7 +61,7 @@
```toml
[dependencies]
-rustyline = "2.0.1"
+rustyline = "2.1.0"
```
## Features
diff --git a/TODO.md b/TODO.md
index d4cd263..75b2667 100644
--- a/TODO.md
+++ b/TODO.md
@@ -9,7 +9,7 @@
Color
- [X] ANSI Colors & Windows 10+
- [ ] ANSI Colors & Windows <10 (https://docs.rs/console/0.6.1/console/fn.strip_ansi_codes.html ? https://github.com/mattn/go-colorable/blob/master/colorable_windows.go)
-- [ ] Syntax highlighting
+- [ ] Syntax highlighting (https://github.com/trishume/syntect/)
- [ ] clicolors spec (https://docs.rs/console/0.6.1/console/fn.colors_enabled.html)
Completion
@@ -76,6 +76,8 @@
Unix
- [ ] Terminfo (https://github.com/Stebalien/term)
- [ ] [ncurses](https://crates.io/crates/ncurses) alternative backend ?
+- [ ] [bracketed paste mode](https://cirw.in/blog/bracketed-paste)
+- [ ] async stdin (https://github.com/Rufflewind/tokio-file-unix)
Windows
- [ ] is_atty is not working with cygwin/msys (https://github.com/softprops/atty works but then how to make `enable_raw_mode` works ?)
diff --git a/src/edit.rs b/src/edit.rs
index f9fcca8..7d706f5 100644
--- a/src/edit.rs
+++ b/src/edit.rs
@@ -32,6 +32,7 @@
pub changes: Rc<RefCell<Changeset>>, // changes to line, for undo/redo
pub hinter: Option<&'out Hinter>,
pub highlighter: Option<&'out Highlighter>,
+ no_hint: bool, // `false` if an hint has been displayed
}
impl<'out, 'prompt> State<'out, 'prompt> {
@@ -57,6 +58,7 @@
changes: Rc::new(RefCell::new(Changeset::new())),
hinter,
highlighter,
+ no_hint: true,
}
}
@@ -130,10 +132,12 @@
Ok(())
}
- fn hint(&self) -> Option<String> {
+ fn hint(&mut self) -> Option<String> {
if let Some(hinter) = self.hinter {
+ self.no_hint = false;
hinter.hint(self.line.as_str(), self.line.pos())
} else {
+ self.no_hint = true;
None
}
}
@@ -186,10 +190,11 @@
if let Some(push) = self.line.insert(ch, n) {
if push {
let prompt_size = self.prompt_size;
+ let no_previous_hint = self.no_hint;
let hint = self.hint();
if n == 1
&& self.cursor.col + ch.width().unwrap_or(0) < self.out.get_columns()
- && hint.is_none() // TODO refresh only current line
+ && (hint.is_none() && no_previous_hint) // TODO refresh only current line
&& !self.highlighter.map_or(true, |h| h.highlight_char(ch.encode_utf8(&mut self.byte_buffer)))
{
// Avoid a full update of the line in the trivial case.
@@ -322,13 +327,12 @@
}
pub fn edit_insert_text(&mut self, text: &str) -> Result<()> {
- if !text.is_empty() {
- let cursor = self.line.pos();
- self.line.insert_str(cursor, text);
- self.refresh_line()
- } else {
- Ok(())
+ if text.is_empty() {
+ return Ok(());
}
+ let cursor = self.line.pos();
+ self.line.insert_str(cursor, text);
+ self.refresh_line()
}
pub fn edit_delete(&mut self, n: RepeatCount) -> Result<()> {
@@ -506,6 +510,7 @@
changes: Rc::new(RefCell::new(Changeset::new())),
hinter: None,
highlighter: None,
+ no_hint: true,
}
}
diff --git a/src/error.rs b/src/error.rs
index f7c1abd..c49595b 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -10,6 +10,7 @@
/// The error type for Rustyline errors that can arise from
/// I/O related errors or Errno when using the nix-rust library
+/// #[non_exhaustive]
#[derive(Debug)]
pub enum ReadlineError {
/// I/O Error
diff --git a/src/keymap.rs b/src/keymap.rs
index 877a12d..9841f78 100644
--- a/src/keymap.rs
+++ b/src/keymap.rs
@@ -5,13 +5,14 @@
use super::Result;
use config::Config;
use config::EditMode;
-use consts::KeyPress;
+use keys::KeyPress;
use tty::RawReader;
/// The number of times one command should be repeated.
pub type RepeatCount = usize;
/// Commands
+/// #[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
pub enum Cmd {
/// abort
@@ -479,20 +480,17 @@
loop {
try!(wrt.refresh_prompt_and_line(&format!("(arg: {}) ", self.num_args)));
let key = try!(rdr.next_key(false));
- match key {
- KeyPress::Char(digit @ '0'...'9') => {
- if self.num_args.abs() < 1000 {
- // shouldn't ever need more than 4 digits
- self.num_args = self
- .num_args
- .saturating_mul(10)
- .saturating_add(digit.to_digit(10).unwrap() as i16);
- }
+ if let KeyPress::Char(digit @ '0'...'9') = key {
+ if self.num_args.abs() < 1000 {
+ // shouldn't ever need more than 4 digits
+ self.num_args = self
+ .num_args
+ .saturating_mul(10)
+ .saturating_add(digit.to_digit(10).unwrap() as i16);
}
- _ => {
- try!(wrt.refresh_line());
- return Ok(key);
- }
+ } else {
+ try!(wrt.refresh_line());
+ return Ok(key);
};
}
}
diff --git a/src/consts.rs b/src/keys.rs
similarity index 94%
rename from src/consts.rs
rename to src/keys.rs
index 5841016..c355e5a 100644
--- a/src/consts.rs
+++ b/src/keys.rs
@@ -1,9 +1,11 @@
//! Key constants
+/// #[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum KeyPress {
UnknownEscSeq,
- Backspace,
+ Backspace, // Ctrl('H')
+ BackTab,
Char(char),
ControlDown,
ControlLeft,
@@ -14,7 +16,7 @@
Down,
End,
Enter, // Ctrl('M')
- Esc,
+ Esc, // Ctrl('[')
F(u8),
Home,
Insert,
@@ -32,7 +34,7 @@
Up,
}
-#[allow(match_same_arms)]
+//#[allow(clippy::match_same_arms)]
pub fn char_to_key_press(c: char) -> KeyPress {
if !c.is_control() {
return KeyPress::Char(c);
diff --git a/src/kill_ring.rs b/src/kill_ring.rs
index b5d8778..03a202f 100644
--- a/src/kill_ring.rs
+++ b/src/kill_ring.rs
@@ -41,34 +41,31 @@
/// Add `text` to the kill-ring.
pub fn kill(&mut self, text: &str, dir: Mode) {
- match self.last_action {
- Action::Kill => {
- if self.slots.capacity() == 0 {
- // disabled
- return;
- }
- match dir {
- Mode::Append => self.slots[self.index].push_str(text),
- Mode::Prepend => self.slots[self.index].insert_str(0, text),
- };
+ if let Action::Kill = self.last_action {
+ if self.slots.capacity() == 0 {
+ // disabled
+ return;
}
- _ => {
- self.last_action = Action::Kill;
- if self.slots.capacity() == 0 {
- // disabled
- return;
- }
- if self.index == self.slots.capacity() - 1 {
- // full
- self.index = 0;
- } else if !self.slots.is_empty() {
- self.index += 1;
- }
- if self.index == self.slots.len() {
- self.slots.push(String::from(text))
- } else {
- self.slots[self.index] = String::from(text);
- }
+ match dir {
+ Mode::Append => self.slots[self.index].push_str(text),
+ Mode::Prepend => self.slots[self.index].insert_str(0, text),
+ };
+ } else {
+ self.last_action = Action::Kill;
+ if self.slots.capacity() == 0 {
+ // disabled
+ return;
+ }
+ if self.index == self.slots.capacity() - 1 {
+ // full
+ self.index = 0;
+ } else if !self.slots.is_empty() {
+ self.index += 1;
+ }
+ if self.index == self.slots.len() {
+ self.slots.push(String::from(text))
+ } else {
+ self.slots[self.index] = String::from(text);
}
}
}
diff --git a/src/lib.rs b/src/lib.rs
index f6f68ea..6546ec1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -16,6 +16,8 @@
//! }
//! ```
#![allow(unknown_lints)]
+// #![feature(non_exhaustive)]
+// #![feature(tool_lints)]
extern crate dirs;
extern crate libc;
@@ -33,13 +35,13 @@
pub mod completion;
pub mod config;
-mod consts;
mod edit;
pub mod error;
pub mod highlight;
pub mod hint;
pub mod history;
mod keymap;
+mod keys;
mod kill_ring;
pub mod line_buffer;
mod undo;
@@ -58,13 +60,13 @@
use completion::{longest_common_prefix, Candidate, Completer};
pub use config::{ColorMode, CompletionType, Config, EditMode, HistoryDuplicates};
-pub use consts::KeyPress;
use edit::State;
use highlight::Highlighter;
use hint::Hinter;
use history::{Direction, History};
pub use keymap::{Anchor, At, CharSearch, Cmd, Movement, RepeatCount, Word};
use keymap::{InputState, Refresher};
+pub use keys::KeyPress;
use kill_ring::{KillRing, Mode};
use line_buffer::WordAction;
@@ -675,7 +677,7 @@
custom_bindings: Arc<RwLock<HashMap<KeyPress, Cmd>>>,
}
-#[allow(new_without_default)]
+//#[allow(clippy::new_without_default)]
impl<H: Helper> Editor<H> {
/// Create an editor with the default configuration
pub fn new() -> Editor<H> {
diff --git a/src/line_buffer.rs b/src/line_buffer.rs
index e17fd62..ae3fe70 100644
--- a/src/line_buffer.rs
+++ b/src/line_buffer.rs
@@ -364,25 +364,19 @@
sow = 0;
let mut gj = gis.next();
'inner: loop {
- match gj {
- Some((j, y)) => {
- let gi = gis.next();
- match gi {
- Some((_, x)) => {
- if is_start_of_word(word_def, x, y) {
- sow = j;
- break 'inner;
- }
- gj = gi;
- }
- None => {
- break 'outer;
- }
+ if let Some((j, y)) = gj {
+ let gi = gis.next();
+ if let Some((_, x)) = gi {
+ if is_start_of_word(word_def, x, y) {
+ sow = j;
+ break 'inner;
}
- }
- None => {
+ gj = gi;
+ } else {
break 'outer;
}
+ } else {
+ break 'outer;
}
}
}
@@ -428,32 +422,26 @@
wp = 0;
gi = gis.next();
'inner: loop {
- match gi {
- Some((i, x)) => {
- let gj = gis.next();
- match gj {
- Some((j, y)) => {
- if at == At::Start && is_start_of_word(word_def, x, y) {
- wp = j;
- break 'inner;
- } else if at != At::Start && is_end_of_word(word_def, x, y) {
- if word_def == Word::Emacs || at == At::AfterEnd {
- wp = j;
- } else {
- wp = i;
- }
- break 'inner;
- }
- gi = gj;
+ if let Some((i, x)) = gi {
+ let gj = gis.next();
+ if let Some((j, y)) = gj {
+ if at == At::Start && is_start_of_word(word_def, x, y) {
+ wp = j;
+ break 'inner;
+ } else if at != At::Start && is_end_of_word(word_def, x, y) {
+ if word_def == Word::Emacs || at == At::AfterEnd {
+ wp = j;
+ } else {
+ wp = i;
}
- None => {
- break 'outer;
- }
+ break 'inner;
}
- }
- None => {
+ gi = gj;
+ } else {
break 'outer;
}
+ } else {
+ break 'outer;
}
}
}
diff --git a/src/test/common.rs b/src/test/common.rs
index 7fe8b17..29bde74 100644
--- a/src/test/common.rs
+++ b/src/test/common.rs
@@ -1,8 +1,8 @@
///! Basic commands tests.
use super::{assert_cursor, assert_line, assert_line_with_initial, init_editor};
use config::EditMode;
-use consts::KeyPress;
use error::ReadlineError;
+use keys::KeyPress;
#[test]
fn home_key() {
diff --git a/src/test/emacs.rs b/src/test/emacs.rs
index 67a1b10..a4c738e 100644
--- a/src/test/emacs.rs
+++ b/src/test/emacs.rs
@@ -1,7 +1,7 @@
//! Emacs specific key bindings
use super::{assert_cursor, assert_history};
use config::EditMode;
-use consts::KeyPress;
+use keys::KeyPress;
#[test]
fn ctrl_a() {
diff --git a/src/test/history.rs b/src/test/history.rs
index faa7a3f..dc3f8f0 100644
--- a/src/test/history.rs
+++ b/src/test/history.rs
@@ -1,7 +1,7 @@
//! History related commands tests
use super::assert_history;
use config::EditMode;
-use consts::KeyPress;
+use keys::KeyPress;
#[test]
fn down_key() {
diff --git a/src/test/mod.rs b/src/test/mod.rs
index 1ce9881..8642b03 100644
--- a/src/test/mod.rs
+++ b/src/test/mod.rs
@@ -4,9 +4,9 @@
use super::{Editor, Result};
use completion::Completer;
use config::{Config, EditMode};
-use consts::KeyPress;
use edit::init_state;
use keymap::{Cmd, InputState};
+use keys::KeyPress;
use tty::Sink;
mod common;
diff --git a/src/test/vi_cmd.rs b/src/test/vi_cmd.rs
index 1c1e4e9..d8ec793 100644
--- a/src/test/vi_cmd.rs
+++ b/src/test/vi_cmd.rs
@@ -1,7 +1,7 @@
//! Vi command mode specific key bindings
use super::{assert_cursor, assert_history};
use config::EditMode;
-use consts::KeyPress;
+use keys::KeyPress;
#[test]
fn dollar() {
diff --git a/src/test/vi_insert.rs b/src/test/vi_insert.rs
index cf86680..fa3c881 100644
--- a/src/test/vi_insert.rs
+++ b/src/test/vi_insert.rs
@@ -1,7 +1,7 @@
//! Vi insert mode specific key bindings
use super::assert_cursor;
use config::EditMode;
-use consts::KeyPress;
+use keys::KeyPress;
#[test]
fn insert_mode_by_default() {
diff --git a/src/tty/mod.rs b/src/tty/mod.rs
index d6767fc..e36ff80 100644
--- a/src/tty/mod.rs
+++ b/src/tty/mod.rs
@@ -4,8 +4,8 @@
use unicode_width::UnicodeWidthStr;
use config::{ColorMode, Config};
-use consts::KeyPress;
use highlight::Highlighter;
+use keys::KeyPress;
use line_buffer::LineBuffer;
use Result;
diff --git a/src/tty/test.rs b/src/tty/test.rs
index 75844be..b1a47d9 100644
--- a/src/tty/test.rs
+++ b/src/tty/test.rs
@@ -5,9 +5,9 @@
use super::{truncate, Position, RawMode, RawReader, Renderer, Term};
use config::{ColorMode, Config};
-use consts::KeyPress;
use error::ReadlineError;
use highlight::Highlighter;
+use keys::KeyPress;
use line_buffer::LineBuffer;
use Result;
diff --git a/src/tty/unix.rs b/src/tty/unix.rs
index 5a8b20f..ed7980f 100644
--- a/src/tty/unix.rs
+++ b/src/tty/unix.rs
@@ -15,9 +15,9 @@
use super::{truncate, width, Position, RawMode, RawReader, Renderer, Term};
use config::{ColorMode, Config};
-use consts::{self, KeyPress};
use error;
use highlight::Highlighter;
+use keys::{self, KeyPress};
use line_buffer::LineBuffer;
use Result;
@@ -27,7 +27,7 @@
/// Unsupported Terminals that don't support RAW mode
static UNSUPPORTED_TERM: [&'static str; 3] = ["dumb", "cons25", "emacs"];
-#[allow(identity_conversion)]
+//#[allow(clippy::identity_conversion)]
fn get_win_size() -> (usize, usize) {
use std::mem::zeroed;
@@ -163,6 +163,20 @@
self.extended_escape(seq2)
}
}
+ } else if seq2 == '[' {
+ let seq3 = try!(self.next_char());
+ // Linux console
+ Ok(match seq3 {
+ 'A' => KeyPress::F(1),
+ 'B' => KeyPress::F(2),
+ 'C' => KeyPress::F(3),
+ 'D' => KeyPress::F(4),
+ 'E' => KeyPress::F(5),
+ _ => {
+ debug!(target: "rustyline", "unsupported esc sequence: ESC [ [ {:?}", seq3);
+ KeyPress::UnknownEscSeq
+ }
+ })
} else {
// ANSI
Ok(match seq2 {
@@ -172,6 +186,7 @@
'D' => KeyPress::Left, // kcub1
'F' => KeyPress::End,
'H' => KeyPress::Home, // khome
+ 'Z' => KeyPress::BackTab,
_ => {
debug!(target: "rustyline", "unsupported esc sequence: ESC [ {:?}", seq2);
KeyPress::UnknownEscSeq
@@ -251,13 +266,13 @@
('2', 'D') => KeyPress::ShiftLeft,
_ => {
debug!(target: "rustyline",
- "unsupported esc sequence: ESC [ {} ; {} {}", seq2, seq4, seq5);
+ "unsupported esc sequence: ESC [ 1 ; {} {:?}", seq4, seq5);
KeyPress::UnknownEscSeq
}
})
} else {
debug!(target: "rustyline",
- "unsupported esc sequence: ESC [ {} ; {} {}", seq2, seq4, seq5);
+ "unsupported esc sequence: ESC [ {} ; {} {:?}", seq2, seq4, seq5);
Ok(KeyPress::UnknownEscSeq)
}
} else {
@@ -296,8 +311,8 @@
'S' => KeyPress::F(4), // kf4
'a' => KeyPress::ControlUp,
'b' => KeyPress::ControlDown,
- 'c' => KeyPress::ControlRight,
- 'd' => KeyPress::ControlLeft,
+ 'c' => KeyPress::ControlRight, // rxvt
+ 'd' => KeyPress::ControlLeft, // rxvt
_ => {
debug!(target: "rustyline", "unsupported esc sequence: ESC O {:?}", seq2);
KeyPress::UnknownEscSeq
@@ -310,7 +325,7 @@
fn next_key(&mut self, single_esc_abort: bool) -> Result<KeyPress> {
let c = try!(self.next_char());
- let mut key = consts::char_to_key_press(c);
+ let mut key = keys::char_to_key_press(c);
if key == KeyPress::Esc {
let timeout_ms = if single_esc_abort && self.timeout_ms == -1 {
0
@@ -559,7 +574,7 @@
}
static SIGWINCH_ONCE: sync::Once = sync::ONCE_INIT;
-static SIGWINCH: atomic::AtomicBool = atomic::ATOMIC_BOOL_INIT;
+static SIGWINCH: atomic::AtomicBool = atomic::AtomicBool::new(false);
fn install_sigwinch_handler() {
SIGWINCH_ONCE.call_once(|| unsafe {
@@ -645,8 +660,9 @@
| InputFlags::ISTRIP
| InputFlags::IXON);
// we don't want raw output, it turns newlines into straight linefeeds
- // raw.c_oflag = raw.c_oflag & !(OutputFlags::OPOST); // disable all output
- // processing
+ // 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
diff --git a/src/tty/windows.rs b/src/tty/windows.rs
index 103ec44..65b699f 100644
--- a/src/tty/windows.rs
+++ b/src/tty/windows.rs
@@ -10,9 +10,9 @@
use super::{truncate, Position, RawMode, RawReader, Renderer, Term};
use config::{ColorMode, Config};
-use consts::{self, KeyPress};
use error;
use highlight::Highlighter;
+use keys::{self, KeyPress};
use line_buffer::LineBuffer;
use Result;
@@ -229,7 +229,13 @@
if meta {
return Ok(KeyPress::Meta(c));
} else {
- return Ok(consts::char_to_key_press(c));
+ let mut key = keys::char_to_key_press(c);
+ if key == KeyPress::Tab && shift {
+ key = KeyPress::BackTab;
+ } else if key == KeyPress::Char(' ') && ctrl {
+ key = KeyPress::Ctrl(' ');
+ }
+ return Ok(key);
}
}
}