blob: a63723b1cb5a173263848bfb11d8dfc6f0a9f02d [file] [log] [blame]
//! 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(())
}
}