Add support for Fuchsia
diff --git a/Cargo.toml b/Cargo.toml
index ec6586a..c35c55d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,6 +14,7 @@
travis-ci = { repository = "kkawakam/rustyline" }
appveyor = { repository = "kkawakam/rustyline" }
+
[dependencies]
libc = "0.2.7"
log = "0.3"
@@ -21,9 +22,13 @@
unicode-segmentation = "1.0"
encode_unicode = "0.1.3"
-[target.'cfg(unix)'.dependencies]
+[target.'cfg(all(unix, not(any(target_os = "fuchsia"))))'.dependencies]
nix = "0.8"
+[target.'cfg(target_os = "fuchsia")'.dependencies]
+fuchsia-zircon = "0.3.2"
+fuchsia-device = "0.1.0"
+
[target.'cfg(windows)'.dependencies]
winapi = "0.2"
kernel32-sys = "0.2"
diff --git a/src/error.rs b/src/error.rs
index 009ec65..d778960 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -4,7 +4,7 @@
use std::io;
use std::error;
use std::fmt;
-#[cfg(unix)]
+#[cfg(all(unix, not(any(target_os = "fuchsia"))))]
use nix;
#[cfg(unix)]
@@ -24,7 +24,7 @@
#[cfg(unix)]
Char(char_iter::CharsError),
/// Unix Error from syscall
- #[cfg(unix)]
+ #[cfg(all(unix, not(any(target_os = "fuchsia"))))]
Errno(nix::Error),
#[cfg(windows)]
WindowResize,
@@ -40,7 +40,7 @@
ReadlineError::Interrupted => write!(f, "Interrupted"),
#[cfg(unix)]
ReadlineError::Char(ref err) => err.fmt(f),
- #[cfg(unix)]
+ #[cfg(all(unix, not(any(target_os = "fuchsia"))))]
ReadlineError::Errno(ref err) => write!(f, "Errno: {}", err.errno().desc()),
#[cfg(windows)]
ReadlineError::WindowResize => write!(f, "WindowResize"),
@@ -58,7 +58,7 @@
ReadlineError::Interrupted => "Interrupted",
#[cfg(unix)]
ReadlineError::Char(ref err) => err.description(),
- #[cfg(unix)]
+ #[cfg(all(unix, not(any(target_os = "fuchsia"))))]
ReadlineError::Errno(ref err) => err.errno().desc(),
#[cfg(windows)]
ReadlineError::WindowResize => "WindowResize",
@@ -74,7 +74,7 @@
}
}
-#[cfg(unix)]
+#[cfg(all(unix, not(any(target_os = "fuchsia"))))]
impl From<nix::Error> for ReadlineError {
fn from(err: nix::Error) -> ReadlineError {
ReadlineError::Errno(err)
diff --git a/src/lib.rs b/src/lib.rs
index 24829e0..133b569 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -22,12 +22,16 @@
extern crate log;
extern crate unicode_segmentation;
extern crate unicode_width;
-#[cfg(unix)]
+#[cfg(all(unix, not(any(target_os = "fuchsia"))))]
extern crate nix;
#[cfg(windows)]
extern crate winapi;
#[cfg(windows)]
extern crate kernel32;
+#[cfg(target_os = "fuchsia")]
+extern crate fuchsia_zircon as zx;
+#[cfg(target_os = "fuchsia")]
+extern crate fuchsia_device;
pub mod completion;
mod consts;
@@ -1089,7 +1093,7 @@
Cmd::Interrupt => {
return Err(error::ReadlineError::Interrupted);
}
- #[cfg(unix)]
+ #[cfg(all(unix, not(any(target_os = "fuchsia"))))]
Cmd::Suspend => {
try!(original_mode.disable_raw_mode());
try!(tty::suspend());
diff --git a/src/tty/fuchsia.rs b/src/tty/fuchsia.rs
new file mode 100644
index 0000000..a63723b
--- /dev/null
+++ b/src/tty/fuchsia.rs
@@ -0,0 +1,244 @@
+//! Fuchsia specific definitions
+use std::io::{self, Read, Stdout, Write};
+use std::mem;
+use std::sync::atomic;
+use libc;
+use char_iter;
+
+use config::Config;
+use consts::{self, KeyPress};
+use error;
+use Result;
+use super::{RawMode, RawReader, Term};
+use fuchsia_device::pty;
+
+const STDIN_FILENO: usize = 0;
+const STDOUT_FILENO: usize = 1;
+
+fn get_win_size() -> (usize, usize) {
+ match pty::get_window_size() {
+ Ok(size) => {
+ (size.width as usize, size.height as usize)
+ }
+ _ => (80, 24),
+ }
+}
+
+struct StdinRaw {}
+
+impl Read for StdinRaw {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ loop {
+ let res = unsafe {
+ libc::read(
+ STDIN_FILENO as i32,
+ buf.as_mut_ptr() as *mut libc::c_void,
+ buf.len() as libc::size_t,
+ )
+ };
+ if res == -1 {
+ let error = io::Error::last_os_error();
+ if error.kind() != io::ErrorKind::Interrupted {
+ return Err(error);
+ }
+ } else {
+ return Ok(res as usize);
+ }
+ }
+ }
+}
+
+pub type Mode = ConsoleMode;
+
+#[derive(Clone, Copy, Debug)]
+pub struct ConsoleMode {}
+
+impl RawMode for Mode {
+ /// RAW mode is never on w/ Fuchsia
+ fn disable_raw_mode(&self) -> Result<()> {
+ Ok(())
+ }
+}
+
+pub type Terminal = Console;
+
+#[derive(Clone, Debug)]
+pub struct Console {
+ stdin_isatty: bool,
+}
+
+pub struct FuchsiaRawReader {
+ chars: char_iter::Chars<StdinRaw>,
+}
+
+impl FuchsiaRawReader {
+ pub fn new() -> Result<FuchsiaRawReader> {
+ let stdin = StdinRaw {};
+ Ok(FuchsiaRawReader {
+ chars: char_iter::chars(stdin),
+ })
+ }
+ fn escape_sequence(&mut self) -> Result<KeyPress> {
+ // Read the next two bytes representing the escape sequence.
+ let seq1 = try!(self.next_char());
+ if seq1 == '[' {
+ // ESC [ sequences.
+ let seq2 = try!(self.next_char());
+ if seq2.is_digit(10) {
+ // Extended escape, read additional byte.
+ let seq3 = try!(self.next_char());
+ if seq3 == '~' {
+ Ok(match seq2 {
+ '1' | '7' => KeyPress::Home, // '1': xterm
+ '3' => KeyPress::Delete,
+ '4' | '8' => KeyPress::End, // '4': xterm
+ '5' => KeyPress::PageUp,
+ '6' => KeyPress::PageDown,
+ _ => {
+ debug!(target: "rustyline", "unsupported esc sequence: ESC{:?}{:?}{:?}", seq1, seq2, seq3);
+ KeyPress::UnknownEscSeq
+ }
+ })
+ } else {
+ debug!(target: "rustyline", "unsupported esc sequence: ESC{:?}{:?}{:?}", seq1, seq2, seq3);
+ Ok(KeyPress::UnknownEscSeq)
+ }
+ } else {
+ Ok(match seq2 {
+ 'A' => KeyPress::Up, // ANSI
+ 'B' => KeyPress::Down,
+ 'C' => KeyPress::Right,
+ 'D' => KeyPress::Left,
+ 'F' => KeyPress::End,
+ 'H' => KeyPress::Home,
+ _ => {
+ debug!(target: "rustyline", "unsupported esc sequence: ESC{:?}{:?}", seq1, seq2);
+ KeyPress::UnknownEscSeq
+ }
+ })
+ }
+ } else if seq1 == 'O' {
+ // ESC O sequences.
+ let seq2 = try!(self.next_char());
+ Ok(match seq2 {
+ 'A' => KeyPress::Up,
+ 'B' => KeyPress::Down,
+ 'C' => KeyPress::Right,
+ 'D' => KeyPress::Left,
+ 'F' => KeyPress::End,
+ 'H' => KeyPress::Home,
+ _ => {
+ debug!(target: "rustyline", "unsupported esc sequence: ESC{:?}{:?}", seq1, seq2);
+ KeyPress::UnknownEscSeq
+ }
+ })
+ } else {
+ // TODO ESC-R (r): Undo all changes made to this line.
+ Ok(match seq1 {
+ '\x08' => KeyPress::Meta('\x08'), // Backspace
+ '-' => KeyPress::Meta('-'),
+ '0'...'9' => KeyPress::Meta(seq1),
+ '<' => KeyPress::Meta('<'),
+ '>' => KeyPress::Meta('>'),
+ 'b' | 'B' => KeyPress::Meta('B'),
+ 'c' | 'C' => KeyPress::Meta('C'),
+ 'd' | 'D' => KeyPress::Meta('D'),
+ 'f' | 'F' => KeyPress::Meta('F'),
+ 'l' | 'L' => KeyPress::Meta('L'),
+ 'n' | 'N' => KeyPress::Meta('N'),
+ 'p' | 'P' => KeyPress::Meta('P'),
+ 't' | 'T' => KeyPress::Meta('T'),
+ 'u' | 'U' => KeyPress::Meta('U'),
+ 'y' | 'Y' => KeyPress::Meta('Y'),
+ '\x7f' => KeyPress::Meta('\x7f'), // Delete
+ _ => {
+ debug!(target: "rustyline", "unsupported esc sequence: M-{:?}", seq1);
+ KeyPress::UnknownEscSeq
+ }
+ })
+ }
+ }
+}
+
+// TODO properly set raw mode, process escape keys
+
+impl RawReader for FuchsiaRawReader {
+ fn next_key(&mut self) -> Result<KeyPress> {
+ let c = try!(self.next_char());
+
+ let mut key = consts::char_to_key_press(c);
+ if key == KeyPress::Esc {
+ // TODO
+ debug!(target: "rustyline", "ESC + {:?} currently unsupported", key);
+ }
+
+ Ok(key)
+ }
+
+ fn next_char(&mut self) -> Result<char> {
+ match self.chars.next() {
+ Some(ch) => Ok(ch?),
+ None => Err(error::ReadlineError::Eof),
+ }
+ }
+}
+
+impl Term for Console {
+ type Reader = FuchsiaRawReader;
+ type Writer = Stdout;
+ type Mode = Mode;
+
+ fn new() -> Console {
+ let stdin_isatty = true;
+ Console {
+ stdin_isatty: stdin_isatty,
+ }
+ }
+
+ /// Checking for an unsupported TERM in fuchsia is a no-op
+ fn is_unsupported(&self) -> bool {
+ false
+ }
+
+ fn is_stdin_tty(&self) -> bool {
+ self.stdin_isatty
+ }
+
+ /// Try to get the number of columns in the current terminal,
+ /// or assume 80 if it fails.
+ fn get_columns(&self) -> usize {
+ let (cols, _) = get_win_size();
+ cols
+ }
+
+ /// Try to get the number of rows in the current terminal,
+ /// or assume 24 if it fails.
+ fn get_rows(&self) -> usize {
+ let (_, rows) = get_win_size();
+ rows
+ }
+
+ /// Enable RAW mode for the terminal. No termios support, so this fakes it
+ fn enable_raw_mode(&self) -> Result<Mode> {
+ Ok(Mode {})
+ }
+
+ fn create_reader(&self, _: &Config) -> Result<FuchsiaRawReader> {
+ FuchsiaRawReader::new()
+ }
+
+ fn create_writer(&self) -> Stdout {
+ io::stdout()
+ }
+
+ fn sigwinch(&self) -> bool {
+ false
+ }
+
+ /// Clear the screen. Used to handle ctrl+l
+ fn clear_screen(&mut self, w: &mut Write) -> Result<()> {
+ try!(w.write_all(b"\x1b[H\x1b[2J"));
+ try!(w.flush());
+ Ok(())
+ }
+}
diff --git a/src/tty/mod.rs b/src/tty/mod.rs
index fe3ac99..f7ce051 100644
--- a/src/tty/mod.rs
+++ b/src/tty/mod.rs
@@ -55,11 +55,18 @@
// If on Unix platform import Unix TTY module
// and re-export into mod.rs scope
-#[cfg(all(unix, not(test)))]
+#[cfg(all(unix, not(any(test, target_os = "fuchsia"))))]
mod unix;
-#[cfg(all(unix, not(test)))]
+#[cfg(all(unix, not(any(test, target_os = "fuchsia"))))]
pub use self::unix::*;
+// If on a Fuchsia platform import Fuchsia TTY module
+// and re-export into mod.rs scope
+#[cfg(target_os = "fuchsia")]
+mod fuchsia;
+#[cfg(target_os = "fuchsia")]
+pub use self::fuchsia::*;
+
#[cfg(test)]
mod test;
#[cfg(test)]