aboutsummaryrefslogtreecommitdiff
path: root/src/term.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/term.rs')
-rw-r--r--src/term.rs350
1 files changed, 350 insertions, 0 deletions
diff --git a/src/term.rs b/src/term.rs
new file mode 100644
index 00000000..28d7c220
--- /dev/null
+++ b/src/term.rs
@@ -0,0 +1,350 @@
+/// Exports the `Term` type which is a high-level API for the Grid
+use std::sync::Arc;
+
+use ansi::{self, Attr, DebugHandler};
+use grid::Grid;
+use tty;
+use ::Rgb;
+
+/// tomorrow night bright
+///
+/// because contrast
+pub static COLORS: &'static [Rgb] = &[
+ Rgb {r: 0x00, g: 0x00, b: 0x00}, // Black
+ Rgb {r: 0xd5, g: 0x4e, b: 0x53}, // Red
+ Rgb {r: 0xb9, g: 0xca, b: 0x4a}, // Green
+ Rgb {r: 0xe6, g: 0xc5, b: 0x47}, // Yellow
+ Rgb {r: 0x7a, g: 0xa6, b: 0xda}, // Blue
+ Rgb {r: 0xc3, g: 0x97, b: 0xd8}, // Magenta
+ Rgb {r: 0x70, g: 0xc0, b: 0xba}, // Cyan
+ Rgb {r: 0x42, g: 0x42, b: 0x42}, // White
+ Rgb {r: 0x66, g: 0x66, b: 0x66}, // Bright black
+ Rgb {r: 0xff, g: 0x33, b: 0x34}, // Bright red
+ Rgb {r: 0x9e, g: 0xc4, b: 0x00}, // Bright green
+ Rgb {r: 0xe7, g: 0xc5, b: 0x47}, // Bright yellow
+ Rgb {r: 0x7a, g: 0xa6, b: 0xda}, // Bright blue
+ Rgb {r: 0xb7, g: 0x7e, b: 0xe0}, // Bright magenta
+ Rgb {r: 0x54, g: 0xce, b: 0xd6}, // Bright cyan
+ Rgb {r: 0x2a, g: 0x2a, b: 0x2a}, // Bright white
+];
+
+pub const CURSOR_SHAPE: char = '█';
+
+pub const DEFAULT_FG: Rgb = Rgb { r: 0xea, g: 0xea, b: 0xea};
+pub const DEFAULT_BG: Rgb = Rgb { r: 0, g: 0, b: 0};
+pub const TAB_SPACES: usize = 8;
+
+/// State for cursor
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub struct Cursor {
+ pub x: u16,
+ pub y: u16,
+}
+
+impl Default for Cursor {
+ fn default() -> Cursor {
+ Cursor { x: 0, y: 0 }
+ }
+}
+
+impl Cursor {
+ pub fn goto(&mut self, x: u16, y: u16) {
+ self.x = x;
+ self.y = y;
+ }
+
+ pub fn advance(&mut self, rows: i64, cols: i64) {
+ self.x = (self.x as i64 + cols) as u16;
+ self.y = (self.y as i64 + rows) as u16;
+ }
+}
+
+struct Mover<'a> {
+ cursor: &'a mut Cursor,
+}
+
+pub struct Term {
+ /// The grid
+ grid: Grid,
+
+ /// Alternate grid
+ alt_grid: Grid,
+
+ /// Alt is active
+ alt: bool,
+
+ /// Reference to the underlying tty
+ tty: tty::Tty,
+
+ /// The cursor
+ cursor: Cursor,
+
+ /// Alt cursor
+ alt_cursor: Cursor,
+
+ /// Active foreground color
+ fg: Rgb,
+
+ /// Active background color
+ bg: Rgb,
+
+ /// Tabstops
+ tabs: Vec<bool>
+}
+
+impl Term {
+ pub fn new(tty: tty::Tty, grid: Grid) -> Term {
+
+ let mut tabs = (0..grid.cols()).map(|i| i % TAB_SPACES == 0)
+ .collect::<Vec<bool>>();
+ tabs[0] = false;
+
+ let alt = grid.clone();
+
+ Term {
+ grid: grid,
+ alt_grid: alt,
+ alt: false,
+ cursor: Cursor::default(),
+ alt_cursor: Cursor::default(),
+ fg: DEFAULT_FG,
+ bg: DEFAULT_BG,
+ tty: tty,
+ tabs: tabs,
+ }
+ }
+
+ pub fn grid(&self) -> &Grid {
+ &self.grid
+ }
+
+ pub fn swap_alt(&mut self) {
+ self.alt = !self.alt;
+ ::std::mem::swap(&mut self.grid, &mut self.alt_grid);
+ ::std::mem::swap(&mut self.cursor, &mut self.alt_cursor);
+
+ if self.alt {
+ self.grid.clear();
+ }
+ }
+
+ pub fn resize(&mut self) {
+ unimplemented!();
+ }
+
+ #[inline]
+ pub fn cursor_x(&self) -> u16 {
+ self.cursor.x
+ }
+
+ #[inline]
+ pub fn cursor_y(&self) -> u16 {
+ self.cursor.y
+ }
+
+ /// Set character in current cursor position
+ fn set_char(&mut self, c: char) {
+ let cell = &mut self.grid[self.cursor];
+ cell.c = c;
+ cell.fg = self.fg;
+ cell.bg = self.bg;
+ }
+
+ /// Advance to next line
+ fn newline_c(&mut self, count: u16) {
+ // TODO handle scroll
+ self.cursor.x = 0;
+ self.cursor.y += 1;
+ }
+}
+
+impl ansi::Handler for Term {
+ /// A character to be displayed
+ #[inline]
+ fn input(&mut self, c: char) {
+ self.set_char(c);
+ self.cursor.x += 1;
+ }
+
+ fn goto(&mut self, x: i64, y: i64) {
+ println!("goto: x={}, y={}", x, y);
+ self.cursor.goto(x as u16, y as u16);
+ }
+ fn goto_row(&mut self, y: i64) { println!("goto_row: {}", y); }
+ fn goto_col(&mut self, x: i64) { println!("goto_col: {}", x); }
+ fn insert_blank(&mut self, num: i64) { println!("insert_blank: {}", num); }
+
+ fn move_up(&mut self, rows: i64) {
+ println!("move_up: {}", rows);
+ self.cursor.advance(-rows, 0);
+ }
+
+ fn move_down(&mut self, rows: i64) {
+ println!("move_down: {}", rows);
+ self.cursor.advance(rows, 0);
+ }
+
+ fn move_forward(&mut self, cols: i64) {
+ println!("move_forward: {}", cols);
+ self.cursor.advance(0, cols);
+ }
+
+ fn move_backward(&mut self, spaces: i64) {
+ println!("move_backward: {}", spaces);
+ self.cursor.advance(0, -spaces);
+ }
+
+ fn identify_terminal(&mut self) { println!("identify_terminal"); }
+ fn move_down_and_cr(&mut self, rows: i64) { println!("move_down_and_cr: {}", rows); }
+ fn move_up_and_cr(&mut self, rows: i64) { println!("move_up_and_cr: {}", rows); }
+ fn put_tab(&mut self, mut count: i64) {
+ println!("put_tab: {}", count);
+
+ let mut x = self.cursor_x();
+ while x < self.grid.cols() as u16 && count != 0 {
+ count -= 1;
+ loop {
+ if x == self.grid.cols() as u16 || self.tabs[x as usize] {
+ break;
+ }
+ x += 1;
+ }
+ }
+
+ self.cursor.x = x;
+ }
+
+ /// Backspace `count` characters
+ #[inline]
+ fn backspace(&mut self, count: i64) {
+ self.cursor.x -= 1;
+ self.set_char(' ');
+ }
+
+ /// Carriage return
+ #[inline]
+ fn carriage_return(&mut self) {
+ self.cursor.x = 0;
+ }
+
+ /// Linefeed
+ #[inline]
+ fn linefeed(&mut self) {
+ println!("linefeed");
+ // TODO handle scroll? not clear what parts of this the pty handle
+ if self.cursor_y() + 1 == self.grid.rows() as u16 {
+ self.grid.feed();
+ self.clear_line(ansi::LineClearMode::Right);
+ } else {
+ self.cursor.y += 1;
+ }
+ }
+
+ /// Set current position as a tabstop
+ fn bell(&mut self) { println!("bell"); }
+ fn substitute(&mut self) { println!("substitute"); }
+ fn newline(&mut self) { println!("newline"); }
+ fn set_horizontal_tabstop(&mut self) { println!("set_horizontal_tabstop"); }
+ fn scroll_up(&mut self, rows: i64) { println!("scroll_up: {}", rows); }
+ fn scroll_down(&mut self, rows: i64) { println!("scroll_down: {}", rows); }
+ fn insert_blank_lines(&mut self, count: i64) { println!("insert_blank_lines: {}", count); }
+ fn delete_lines(&mut self, count: i64) { println!("delete_lines: {}", count); }
+ fn erase_chars(&mut self, count: i64) { println!("erase_chars: {}", count); }
+ fn delete_chars(&mut self, count: i64) { println!("delete_chars: {}", count); }
+ fn move_backward_tabs(&mut self, count: i64) { println!("move_backward_tabs: {}", count); }
+ fn move_forward_tabs(&mut self, count: i64) { println!("move_forward_tabs: {}", count); }
+ fn save_cursor_position(&mut self) { println!("save_cursor_position"); }
+ fn restore_cursor_position(&mut self) { println!("restore_cursor_position"); }
+ fn clear_line(&mut self, mode: ansi::LineClearMode) {
+ println!("clear_line: {:?}", mode);
+ match mode {
+ ansi::LineClearMode::Right => {
+ let cols = self.grid.cols();
+ let row = &mut self.grid[self.cursor.y as usize];
+ let start = self.cursor.x as usize;
+ for col in start..cols {
+ row[col].c = ' ';
+ }
+ },
+ _ => (),
+ }
+ }
+ fn clear_screen(&mut self, mode: ansi::ClearMode) {
+ println!("clear_screen: {:?}", mode);
+ match mode {
+ ansi::ClearMode::Below => {
+ let start = self.cursor_y() as usize;
+ let end = self.grid.rows();
+ for i in start..end {
+ let row = &mut self.grid[i];
+ for cell in row.iter_mut() {
+ cell.c = ' ';
+ }
+ }
+ },
+ ansi::ClearMode::All => {
+ self.grid.clear();
+ },
+ _ => {
+ panic!("ansi::ClearMode::Above not implemented");
+ }
+ }
+ }
+ fn clear_tabs(&mut self, mode: ansi::TabulationClearMode) { println!("clear_tabs: {:?}", mode); }
+ fn reset_state(&mut self) { println!("reset_state"); }
+ fn reverse_index(&mut self) {
+ println!("reverse_index");
+ // if cursor is at the top
+ if self.cursor.y == 0 {
+ self.grid.unfeed();
+ } else {
+ // can't wait for nonlexical lifetimes.. omg borrowck
+ let x = self.cursor.x;
+ let y = self.cursor.y;
+ self.cursor.goto(x, y - 1);
+ }
+ }
+
+ /// set a terminal attribute
+ fn terminal_attribute(&mut self, attr: Attr) {
+ match attr {
+ Attr::DefaultForeground => {
+ self.fg = DEFAULT_FG;
+ },
+ Attr::DefaultBackground => {
+ self.bg = DEFAULT_BG;
+ },
+ Attr::Foreground(named_color) => {
+ self.fg = COLORS[named_color as usize];
+ },
+ Attr::Background(named_color) => {
+ self.bg = COLORS[named_color as usize];
+ },
+ Attr::Reset => {
+ self.fg = DEFAULT_FG;
+ self.bg = DEFAULT_BG;
+ }
+ _ => {
+ println!("Term got unhandled attr: {:?}", attr);
+ }
+ }
+ }
+
+ fn set_mode(&mut self, mode: ansi::Mode) {
+ println!("set_mode: {:?}", mode);
+ match mode {
+ ansi::Mode::SwapScreenAndSetRestoreCursor => {
+ self.swap_alt();
+ }
+ }
+ }
+
+ fn unset_mode(&mut self, mode: ansi::Mode) {
+ println!("unset_mode: {:?}", mode);
+ match mode {
+ ansi::Mode::SwapScreenAndSetRestoreCursor => {
+ self.swap_alt();
+ }
+ }
+ }
+}