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

Replace use of unstable features #38

Merged
merged 4 commits into from
Jun 3, 2016
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
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
language: rust
rust:
- nightly
- 1.9.0
- beta
- nightly
script:
- cargo build --verbose
- cargo test --verbose
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ license = "MIT"
libc = "0.2.7"
nix = "0.5.0"
unicode-width = "0.1.3"
encode_unicode = "0.1.3"
clippy = {version = "~0.0.58", optional = true}

[dev-dependencies]
Expand Down
106 changes: 106 additions & 0 deletions src/char_iter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
//! An iterator over the `char`s of a reader.
//!
//! A copy of the unstable code from the stdlib's std::io::Read::chars.

use std::error;
use std::fmt;
use std::io;
use std::io::Read;
use std::str;

pub fn chars<R: Read>(read: R) -> Chars<R> where R: Sized {
Chars { inner: read }
}

// 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
];

/// Given a first byte, determine how many bytes are in this UTF-8 character
#[inline]
fn utf8_char_width(b: u8) -> usize {
return UTF8_CHAR_WIDTH[b as usize] as usize;
}

pub struct Chars<R> {
inner: R,
}

#[derive(Debug)]
pub enum CharsError {
NotUtf8,
Other(io::Error),
}

impl<R: Read> Iterator for Chars<R> {
type Item = Result<char, CharsError>;

fn next(&mut self) -> Option<Result<char, CharsError>> {
let mut buf = [0];
let first_byte = match self.inner.read(&mut buf) {
Ok(0) => return None,
Ok(..) => buf[0],
Err(e) => return Some(Err(CharsError::Other(e))),
};
let width = utf8_char_width(first_byte);
if width == 1 { return Some(Ok(first_byte as char)) }
if width == 0 { return Some(Err(CharsError::NotUtf8)) }
let mut buf = [first_byte, 0, 0, 0];
{
let mut start = 1;
while start < width {
match self.inner.read(&mut buf[start..width]) {
Ok(0) => return Some(Err(CharsError::NotUtf8)),
Ok(n) => start += n,
Err(e) => return Some(Err(CharsError::Other(e))),
}
}
}
Some(match str::from_utf8(&buf[..width]).ok() {
Some(s) => Ok(s.chars().next().unwrap()),
None => Err(CharsError::NotUtf8),
})
}
}

impl error::Error for CharsError {
fn description(&self) -> &str {
match *self {
CharsError::NotUtf8 => "invalid utf8 encoding",
CharsError::Other(ref e) => error::Error::description(e),
}
}
fn cause(&self) -> Option<&error::Error> {
match *self {
CharsError::NotUtf8 => None,
CharsError::Other(ref e) => e.cause(),
}
}
}

impl fmt::Display for CharsError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
CharsError::NotUtf8 => {
"byte stream did not contain valid utf8".fmt(f)
}
CharsError::Other(ref e) => e.fmt(f),
}
}
}
8 changes: 5 additions & 3 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use std::error;
use std::fmt;
use nix;

use char_iter;

/// The error type for Rustyline errors that can arise from
/// I/O related errors or Errno when using the nix-rust library
#[derive(Debug)]
Expand All @@ -13,7 +15,7 @@ pub enum ReadlineError {
/// Error from syscall
Errno(nix::Error),
/// Chars Error
Char(io::CharsError),
Char(char_iter::CharsError),
/// EOF (Ctrl-d)
Eof,
/// Ctrl-C
Expand Down Expand Up @@ -56,8 +58,8 @@ impl From<nix::Error> for ReadlineError {
}
}

impl From<io::CharsError> for ReadlineError {
fn from(err: io::CharsError) -> ReadlineError {
impl From<char_iter::CharsError> for ReadlineError {
fn from(err: char_iter::CharsError) -> ReadlineError {
ReadlineError::Char(err)
}
}
24 changes: 10 additions & 14 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,13 @@
//! Err(_) => println!("No input"),
//! }
//! ```
#![feature(io)]
#![feature(iter_arith)]
#![feature(unicode)]
#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

extern crate libc;
extern crate nix;
extern crate unicode_width;
extern crate encode_unicode;

pub mod completion;
#[allow(non_camel_case_types)]
Expand All @@ -31,9 +29,10 @@ pub mod error;
pub mod history;
mod kill_ring;
pub mod line_buffer;
mod char_iter;

use std::fmt;
use std::io::{self, Read, Write};
use std::io::{self, Write};
use std::mem;
use std::path::Path;
use std::result;
Expand All @@ -42,6 +41,7 @@ use std::sync::atomic;
use nix::errno::Errno;
use nix::sys::signal;
use nix::sys::termios;
use encode_unicode::CharExt;

use completion::Completer;
use consts::{KeyPress, char_to_key_press};
Expand Down Expand Up @@ -327,9 +327,7 @@ fn edit_insert(s: &mut State, ch: char) -> Result<()> {
if push {
if s.cursor.col + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0) < s.cols {
// Avoid a full update of the line in the trivial case.
let bits = ch.encode_utf8();
let bits = bits.as_slice();
write_and_flush(s.out, bits)
write_and_flush(s.out, ch.to_utf8().as_bytes())
} else {
s.refresh_line()
}
Expand Down Expand Up @@ -527,7 +525,7 @@ fn edit_history_next(s: &mut State, history: &History, prev: bool) -> Result<()>
}

/// Completes the line/word
fn complete_line<R: io::Read>(chars: &mut io::Chars<R>,
fn complete_line<R: io::Read>(chars: &mut char_iter::Chars<R>,
s: &mut State,
completer: &Completer)
-> Result<Option<char>> {
Expand Down Expand Up @@ -580,7 +578,7 @@ fn complete_line<R: io::Read>(chars: &mut io::Chars<R>,

/// Incremental search
#[cfg_attr(feature="clippy", allow(if_not_else))]
fn reverse_incremental_search<R: io::Read>(chars: &mut io::Chars<R>,
fn reverse_incremental_search<R: io::Read>(chars: &mut char_iter::Chars<R>,
s: &mut State,
history: &History)
-> Result<Option<KeyPress>> {
Expand Down Expand Up @@ -657,7 +655,7 @@ fn reverse_incremental_search<R: io::Read>(chars: &mut io::Chars<R>,
Ok(Some(key))
}

fn escape_sequence<R: io::Read>(chars: &mut io::Chars<R>) -> Result<KeyPress> {
fn escape_sequence<R: io::Read>(chars: &mut char_iter::Chars<R>) -> Result<KeyPress> {
// Read the next two bytes representing the escape sequence.
let seq1 = try!(chars.next().unwrap());
if seq1 == '[' {
Expand Down Expand Up @@ -735,7 +733,7 @@ fn readline_edit(prompt: &str,
kill_ring.reset();
let mut s = State::new(&mut stdout, prompt, MAX_LINE, get_columns(), history.len());
let stdin = io::stdin();
let mut chars = stdin.lock().chars();
let mut chars = char_iter::chars(stdin.lock());
loop {
let c = chars.next().unwrap();
if c.is_err() && SIGWINCH.compare_and_swap(true, false, atomic::Ordering::SeqCst) {
Expand Down Expand Up @@ -1164,12 +1162,10 @@ mod test {

#[test]
fn complete_line() {
use std::io::Read;

let mut out = ::std::io::sink();
let mut s = init_state(&mut out, "rus", 3, 80);
let input = b"\n";
let mut chars = input.chars();
let mut chars = ::char_iter::chars(&input[..]);
let completer = SimpleCompleter;
let ch = super::complete_line(&mut chars, &mut s, &completer).unwrap();
assert_eq!(Some('\n'), ch);
Expand Down
10 changes: 5 additions & 5 deletions src/line_buffer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Line buffer with current cursor position
use std::ops::Deref;
use std::ops::{Add, Deref};

/// Maximum buffer size for the line read
pub static MAX_LINE: usize = 4096;
Expand Down Expand Up @@ -259,15 +259,15 @@ impl LineBuffer {
.rev()
.take_while(|ch| test(*ch))
.map(char::len_utf8)
.sum();
.fold(0, Add::add);
if pos > 0 {
// eat any non-spaces on the left
pos -= self.buf[..pos]
.chars()
.rev()
.take_while(|ch| !test(*ch))
.map(char::len_utf8)
.sum();
.fold(0, Add::add);
}
Some(pos)
}
Expand Down Expand Up @@ -305,15 +305,15 @@ impl LineBuffer {
.chars()
.take_while(|ch| !ch.is_alphanumeric())
.map(char::len_utf8)
.sum();
.fold(0, Add::add);
let start = pos;
if pos < self.buf.len() {
// eat any non-spaces
pos += self.buf[pos..]
.chars()
.take_while(|ch| ch.is_alphanumeric())
.map(char::len_utf8)
.sum();
.fold(0, Add::add);
}
Some((start, pos))
} else {
Expand Down