diff --git a/.travis.yml b/.travis.yml index 4075f5cf0ba10e8aa718304e53ef4419a14e8edc..711713eb690688e32b2492e9f4e46eac737274dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,5 @@ sudo: false language: rust -rust: - - nightly script: - cargo build --verbose - cargo test --verbose diff --git a/README.md b/README.md index dae7a212050fa379f958f9e8b634fc6aaaedf19b..33826e3656808bfc65799574d63393cbd86acf73 100644 --- a/README.md +++ b/README.md @@ -17,12 +17,6 @@ Readline implementation in Rust that is based on [Antirez' Linenoise](https://gi * Powershell ISE is not supported, check [issue #56](https://github.com/kkawakam/rustyline/issues/56) * Mintty (Cygwin/Mingw) is not supported -## Build -This project uses Cargo and Rust nightly -```bash -cargo build --release -``` - ## Example ```rust extern crate rustyline; diff --git a/appveyor.yml b/appveyor.yml index 862c484b487650240e0e51835d73f13a8b6c8e7c..4506f3af83c2ae62fb45caec18f0bbc018d9ce5d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,7 +2,7 @@ environment: TARGET: x86_64-pc-windows-msvc install: - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - - rustup-init -yv --default-toolchain nightly --default-host %TARGET% + - rustup-init -yv --default-toolchain stable --default-host %TARGET% - set PATH=%PATH%;%USERPROFILE%\.cargo\bin - rustc -V - cargo -V diff --git a/src/error.rs b/src/error.rs index 85183006914e8e08d1a11e90a3795960161aff7f..d9cfdb85e9d32362a44725b8eda47a9d3af0c6ea 100644 --- a/src/error.rs +++ b/src/error.rs @@ -6,6 +6,7 @@ use std::char; use std::error; use std::fmt; use std::io; +use std::str; /// The error type for Rustyline errors that can arise from /// I/O related errors or Errno when using the nix-rust library @@ -19,7 +20,7 @@ pub enum ReadlineError { Interrupted, /// Chars Error #[cfg(unix)] - Char(io::CharsError), + Char(str::Utf8Error), /// Unix Error from syscall #[cfg(unix)] Errno(nix::Error), @@ -79,8 +80,8 @@ impl From<nix::Error> for ReadlineError { } #[cfg(unix)] -impl From<io::CharsError> for ReadlineError { - fn from(err: io::CharsError) -> ReadlineError { +impl From<str::Utf8Error> for ReadlineError { + fn from(err: str::Utf8Error) -> ReadlineError { ReadlineError::Char(err) } } diff --git a/src/lib.rs b/src/lib.rs index fdff16977f738c7e4fd6861fb1cbe9d3da28d9a6..712036f9985f9aa5db51cab0e44328d23e7748fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,6 @@ //! Err(_) => println!("No input"), //! } //! ``` -#![feature(io)] #![allow(unknown_lints)] extern crate libc; diff --git a/src/tty/unix.rs b/src/tty/unix.rs index da3db4d05361ea1e95b863ea4f3c606987fc5da7..cd7fec625e4270320665553a04ccbfb8f3e61090 100644 --- a/src/tty/unix.rs +++ b/src/tty/unix.rs @@ -1,6 +1,6 @@ //! Unix specific definitions use std; -use std::io::{self, Chars, Read, Stdout, Write}; +use std::io::{self, Read, Stdout, Write}; use std::sync; use std::sync::atomic; @@ -96,16 +96,17 @@ impl Read for StdinRaw { /// Console input reader pub struct PosixRawReader { - chars: Chars<StdinRaw>, + stdin: StdinRaw, timeout_ms: i32, + buf: [u8; 4], } impl PosixRawReader { fn new(config: &Config) -> Result<PosixRawReader> { - let stdin = StdinRaw {}; Ok(PosixRawReader { - chars: stdin.chars(), + stdin: StdinRaw{}, timeout_ms: config.keyseq_timeout(), + buf: [0; 4], }) } @@ -258,6 +259,26 @@ impl PosixRawReader { } } +// https://tools.ietf.org/html/rfc3629 +static UTF8_CHAR_WIDTH: [u8; 256] = [ +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x1F +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x3F +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x5F +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x7F +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x9F +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xBF +0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xDF +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 0xEF +4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, // 0xFF +]; + impl RawReader for PosixRawReader { fn next_key(&mut self, single_esc_abort: bool) -> Result<KeyPress> { let c = try!(self.next_char()); @@ -287,9 +308,22 @@ impl RawReader for PosixRawReader { } fn next_char(&mut self) -> Result<char> { - match self.chars.next() { - Some(c) => Ok(try!(c)), - None => Err(error::ReadlineError::Eof), + let n = try!(self.stdin.read(&mut self.buf[..1])); + if n == 0 { + return Err(error::ReadlineError::Eof); + } + let first = self.buf[0]; + if first >= 128 { + let width = UTF8_CHAR_WIDTH[first as usize] as usize; + if width == 0 { + try!(std::str::from_utf8(&self.buf[..1])); + unreachable!() + } + try!(self.stdin.read_exact(&mut self.buf[1..width])); + let s = try!(std::str::from_utf8(&self.buf[..width])); + Ok(s.chars().next().unwrap()) + } else { + return Ok(first as char); } } }