use std::io::{self, Write};
use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr;
use config::{ColorMode, Config, OutputStreamType};
use highlight::Highlighter;
use keys::KeyPress;
use line_buffer::LineBuffer;
use Result;
pub trait RawMode: Sized {
fn disable_raw_mode(&self) -> Result<()>;
}
pub trait RawReader {
fn next_key(&mut self, single_esc_abort: bool) -> Result<KeyPress>;
#[cfg(unix)]
fn next_char(&mut self) -> Result<char>;
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct Position {
pub col: usize,
pub row: usize,
}
pub trait Renderer {
fn move_cursor(&mut self, old: Position, new: Position) -> Result<()>;
fn refresh_line(
&mut self,
prompt: &str,
prompt_size: Position,
line: &LineBuffer,
hint: Option<String>,
current_row: usize,
old_rows: usize,
highlighter: Option<&dyn Highlighter>,
) -> Result<(Position, Position)>;
fn calculate_position(&self, s: &str, orig: Position) -> Position;
fn write_and_flush(&mut self, buf: &[u8]) -> Result<()>;
fn beep(&mut self) -> Result<()> {
try!(io::stderr().write_all(b"\x07"));
try!(io::stderr().flush());
Ok(())
}
fn clear_screen(&mut self) -> Result<()>;
fn sigwinch(&self) -> bool;
fn update_size(&mut self);
fn get_columns(&self) -> usize;
fn get_rows(&self) -> usize;
}
impl<'a, R: Renderer + ?Sized> Renderer for &'a mut R {
fn move_cursor(&mut self, old: Position, new: Position) -> Result<()> {
(**self).move_cursor(old, new)
}
fn refresh_line(
&mut self,
prompt: &str,
prompt_size: Position,
line: &LineBuffer,
hint: Option<String>,
current_row: usize,
old_rows: usize,
highlighter: Option<&dyn Highlighter>,
) -> Result<(Position, Position)> {
(**self).refresh_line(
prompt,
prompt_size,
line,
hint,
current_row,
old_rows,
highlighter,
)
}
fn calculate_position(&self, s: &str, orig: Position) -> Position {
(**self).calculate_position(s, orig)
}
fn write_and_flush(&mut self, buf: &[u8]) -> Result<()> {
(**self).write_and_flush(buf)
}
fn beep(&mut self) -> Result<()> {
(**self).beep()
}
fn clear_screen(&mut self) -> Result<()> {
(**self).clear_screen()
}
fn sigwinch(&self) -> bool {
(**self).sigwinch()
}
fn update_size(&mut self) {
(**self).update_size()
}
fn get_columns(&self) -> usize {
(**self).get_columns()
}
fn get_rows(&self) -> usize {
(**self).get_rows()
}
}
pub trait Term {
type Reader: RawReader; type Writer: Renderer; type Mode: RawMode;
fn new(color_mode: ColorMode, stream: OutputStreamType) -> Self;
fn is_unsupported(&self) -> bool;
fn is_stdin_tty(&self) -> bool;
fn colors_enabled(&self) -> bool;
fn enable_raw_mode(&mut self) -> Result<Self::Mode>;
fn create_reader(&self, config: &Config) -> Result<Self::Reader>;
fn create_writer(&self) -> Self::Writer;
}
fn truncate(text: &str, col: usize, max_col: usize) -> &str {
let mut col = col;
let mut esc_seq = 0;
let mut end = text.len();
for (i, s) in text.grapheme_indices(true) {
col += width(s, &mut esc_seq);
if col > max_col {
end = i;
break;
}
}
&text[..end]
}
fn width(s: &str, esc_seq: &mut u8) -> usize {
if *esc_seq == 1 {
if s == "[" {
*esc_seq = 2;
} else {
*esc_seq = 0;
}
0
} else if *esc_seq == 2 {
if s == ";" || (s.as_bytes()[0] >= b'0' && s.as_bytes()[0] <= b'9') {
} else {
*esc_seq = 0;
}
0
} else if s == "\x1b" {
*esc_seq = 1;
0
} else if s == "\n" {
0
} else {
s.width()
}
}
#[cfg(all(windows, not(test)))]
mod windows;
#[cfg(all(windows, not(test)))]
pub use self::windows::*;
#[cfg(all(unix, not(any(test, target_os = "fuchsia"))))]
mod unix;
#[cfg(all(unix, not(any(test, target_os = "fuchsia"))))]
pub use self::unix::*;
#[cfg(target_os = "fuchsia")]
mod fuchsia;
#[cfg(target_os = "fuchsia")]
pub use self::fuchsia::*;
#[cfg(test)]
mod test;
#[cfg(test)]
pub use self::test::*;