use unicode_width::UnicodeWidthStr;
use crate::config::{Behavior, BellStyle, ColorMode, Config};
use crate::highlight::Highlighter;
use crate::keys::KeyEvent;
use crate::layout::{Layout, Position};
use crate::line_buffer::LineBuffer;
use crate::{Cmd, Result};
pub trait RawMode: Sized {
fn disable_raw_mode(&self) -> Result<()>;
}
pub enum Event {
KeyPress(KeyEvent),
ExternalPrint(String),
}
pub trait RawReader {
fn wait_for_input(&mut self, single_esc_abort: bool) -> Result<Event>; fn next_key(&mut self, single_esc_abort: bool) -> Result<KeyEvent>;
#[cfg(unix)]
fn next_char(&mut self) -> Result<char>;
fn read_pasted_text(&mut self) -> Result<String>;
fn find_binding(&self, key: &KeyEvent) -> Option<Cmd>;
}
pub trait Renderer {
type Reader: RawReader;
fn move_cursor(&mut self, old: Position, new: Position) -> Result<()>;
#[allow(clippy::too_many_arguments)]
fn refresh_line(
&mut self,
prompt: &str,
line: &LineBuffer,
hint: Option<&str>,
old_layout: &Layout,
new_layout: &Layout,
highlighter: Option<&dyn Highlighter>,
) -> Result<()>;
fn compute_layout(
&self,
prompt_size: Position,
default_prompt: bool,
line: &LineBuffer,
info: Option<&str>,
) -> Layout {
let pos = line.pos();
let cursor = self.calculate_position(&line[..pos], prompt_size);
let mut end = if pos == line.len() {
cursor
} else {
self.calculate_position(&line[pos..], cursor)
};
if let Some(info) = info {
end = self.calculate_position(info, end);
}
let new_layout = Layout {
prompt_size,
default_prompt,
cursor,
end,
};
debug_assert!(new_layout.prompt_size <= new_layout.cursor);
debug_assert!(new_layout.cursor <= new_layout.end);
new_layout
}
fn calculate_position(&self, s: &str, orig: Position) -> Position;
fn write_and_flush(&mut self, buf: &str) -> Result<()>;
fn beep(&mut self) -> Result<()>;
fn clear_screen(&mut self) -> Result<()>;
fn clear_rows(&mut self, layout: &Layout) -> Result<()>;
fn update_size(&mut self);
fn get_columns(&self) -> usize;
fn get_rows(&self) -> usize;
fn colors_enabled(&self) -> bool;
fn move_cursor_at_leftmost(&mut self, rdr: &mut Self::Reader) -> Result<()>;
}
impl<'a, R: Renderer + ?Sized> Renderer for &'a mut R {
type Reader = R::Reader;
fn move_cursor(&mut self, old: Position, new: Position) -> Result<()> {
(**self).move_cursor(old, new)
}
fn refresh_line(
&mut self,
prompt: &str,
line: &LineBuffer,
hint: Option<&str>,
old_layout: &Layout,
new_layout: &Layout,
highlighter: Option<&dyn Highlighter>,
) -> Result<()> {
(**self).refresh_line(prompt, line, hint, old_layout, new_layout, highlighter)
}
fn calculate_position(&self, s: &str, orig: Position) -> Position {
(**self).calculate_position(s, orig)
}
fn write_and_flush(&mut self, buf: &str) -> Result<()> {
(**self).write_and_flush(buf)
}
fn beep(&mut self) -> Result<()> {
(**self).beep()
}
fn clear_screen(&mut self) -> Result<()> {
(**self).clear_screen()
}
fn clear_rows(&mut self, layout: &Layout) -> Result<()> {
(**self).clear_rows(layout)
}
fn update_size(&mut self) {
(**self).update_size();
}
fn get_columns(&self) -> usize {
(**self).get_columns()
}
fn get_rows(&self) -> usize {
(**self).get_rows()
}
fn colors_enabled(&self) -> bool {
(**self).colors_enabled()
}
fn move_cursor_at_leftmost(&mut self, rdr: &mut R::Reader) -> Result<()> {
(**self).move_cursor_at_leftmost(rdr)
}
}
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()
}
}
pub trait ExternalPrinter {
fn print(&mut self, msg: String) -> Result<()>;
}
pub trait Term {
type KeyMap;
type Reader: RawReader; type Writer: Renderer<Reader = Self::Reader>; type Mode: RawMode;
type ExternalPrinter: ExternalPrinter;
fn new(
color_mode: ColorMode,
behavior: Behavior,
tab_stop: usize,
bell_style: BellStyle,
enable_bracketed_paste: bool,
) -> Result<Self>
where
Self: Sized;
fn is_unsupported(&self) -> bool;
fn is_input_tty(&self) -> bool;
fn is_output_tty(&self) -> bool;
fn enable_raw_mode(&mut self) -> Result<(Self::Mode, Self::KeyMap)>;
fn create_reader(&self, config: &Config, key_map: Self::KeyMap) -> Self::Reader;
fn create_writer(&self) -> Self::Writer;
fn writeln(&self) -> Result<()>;
fn create_external_printer(&mut self) -> Result<Self::ExternalPrinter>;
}
#[cfg(all(windows, not(target_arch = "wasm32")))]
mod windows;
#[cfg(all(windows, not(target_arch = "wasm32")))]
pub use self::windows::*;
#[cfg(all(unix, not(target_arch = "wasm32")))]
mod unix;
#[cfg(all(unix, not(target_arch = "wasm32")))]
pub use self::unix::*;
#[cfg(any(test, target_arch = "wasm32"))]
mod test;
#[cfg(any(test, target_arch = "wasm32"))]
pub use self::test::*;