2016-06-30 03:56:12 +00:00
|
|
|
// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
//
|
|
|
|
//! Exports the `Term` type which is a high-level API for the Grid
|
2016-06-08 17:39:49 +00:00
|
|
|
use std::ops::Range;
|
2016-07-04 00:00:00 +00:00
|
|
|
use std::fmt;
|
2016-05-31 03:44:37 +00:00
|
|
|
|
2016-06-09 15:30:55 +00:00
|
|
|
use ansi::{self, Attr};
|
2016-07-04 00:00:00 +00:00
|
|
|
use grid::{Grid, ClearRegion};
|
2016-05-31 03:44:37 +00:00
|
|
|
use tty;
|
|
|
|
use ::Rgb;
|
|
|
|
|
2016-06-29 17:21:02 +00:00
|
|
|
/// coerce val to be between min and max
|
|
|
|
fn limit<T: PartialOrd>(val: T, min: T, max: T) -> T {
|
|
|
|
if val < min {
|
|
|
|
min
|
|
|
|
} else if val > max {
|
|
|
|
max
|
|
|
|
} else {
|
|
|
|
val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-04 00:00:00 +00:00
|
|
|
pub mod cell {
|
|
|
|
use super::{DEFAULT_FG, DEFAULT_BG};
|
|
|
|
use ::Rgb;
|
|
|
|
|
|
|
|
bitflags! {
|
|
|
|
pub flags Flags: u32 {
|
|
|
|
const INVERSE = 0b00000001,
|
|
|
|
const BOLD = 0b00000010,
|
|
|
|
const ITALIC = 0b00000100,
|
|
|
|
const UNDERLINE = 0b00001000,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct Cell {
|
|
|
|
pub c: char,
|
|
|
|
pub fg: Rgb,
|
|
|
|
pub bg: Rgb,
|
|
|
|
pub flags: Flags,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Cell {
|
|
|
|
pub fn new(c: char) -> Cell {
|
|
|
|
Cell {
|
|
|
|
c: c.into(),
|
|
|
|
bg: Default::default(),
|
|
|
|
fg: Default::default(),
|
|
|
|
flags: Flags::empty(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn reset(&mut self) {
|
|
|
|
self.c = ' ';
|
|
|
|
self.flags = Flags::empty();
|
|
|
|
|
|
|
|
self.bg = DEFAULT_BG;
|
|
|
|
self.fg = DEFAULT_FG;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub use self::cell::Cell;
|
|
|
|
|
2016-05-31 03:44:37 +00:00
|
|
|
/// 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
|
|
|
|
];
|
|
|
|
|
2016-06-08 04:17:48 +00:00
|
|
|
pub mod mode {
|
|
|
|
bitflags! {
|
2016-06-23 16:42:00 +00:00
|
|
|
pub flags TermMode: u8 {
|
|
|
|
const SHOW_CURSOR = 0b00000001,
|
|
|
|
const APP_CURSOR = 0b00000010,
|
|
|
|
const ANY = 0b11111111,
|
|
|
|
const NONE = 0b00000000,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for TermMode {
|
|
|
|
fn default() -> TermMode {
|
|
|
|
SHOW_CURSOR
|
2016-06-08 04:17:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub use self::mode::TermMode;
|
|
|
|
|
2016-05-31 03:44:37 +00:00
|
|
|
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;
|
|
|
|
|
2016-07-04 00:00:00 +00:00
|
|
|
use grid::index::{Cursor, Column, Line};
|
2016-05-31 03:44:37 +00:00
|
|
|
|
|
|
|
pub struct Term {
|
|
|
|
/// The grid
|
2016-07-04 00:00:00 +00:00
|
|
|
grid: Grid<Cell>,
|
2016-05-31 03:44:37 +00:00
|
|
|
|
|
|
|
/// Alternate grid
|
2016-07-04 00:00:00 +00:00
|
|
|
alt_grid: Grid<Cell>,
|
2016-05-31 03:44:37 +00:00
|
|
|
|
|
|
|
/// Alt is active
|
|
|
|
alt: bool,
|
|
|
|
|
|
|
|
/// Reference to the underlying tty
|
2016-06-28 16:18:54 +00:00
|
|
|
tty: tty::Tty,
|
2016-05-31 03:44:37 +00:00
|
|
|
|
|
|
|
/// The cursor
|
|
|
|
cursor: Cursor,
|
|
|
|
|
|
|
|
/// Alt cursor
|
|
|
|
alt_cursor: Cursor,
|
|
|
|
|
|
|
|
/// Active foreground color
|
|
|
|
fg: Rgb,
|
|
|
|
|
|
|
|
/// Active background color
|
|
|
|
bg: Rgb,
|
|
|
|
|
|
|
|
/// Tabstops
|
2016-06-06 23:54:15 +00:00
|
|
|
tabs: Vec<bool>,
|
|
|
|
|
|
|
|
/// Cell attributes
|
2016-07-04 00:00:00 +00:00
|
|
|
attr: cell::Flags,
|
2016-06-08 04:15:53 +00:00
|
|
|
|
2016-06-08 04:17:48 +00:00
|
|
|
/// Mode flags
|
|
|
|
mode: TermMode,
|
2016-06-08 17:39:49 +00:00
|
|
|
|
|
|
|
/// Scroll region
|
2016-07-04 00:00:00 +00:00
|
|
|
scroll_region: Range<Line>,
|
2016-06-28 16:18:54 +00:00
|
|
|
|
|
|
|
/// Size
|
|
|
|
size_info: SizeInfo,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Terminal size info
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct SizeInfo {
|
|
|
|
/// Terminal window width
|
|
|
|
pub width: f32,
|
|
|
|
|
|
|
|
/// Terminal window height
|
|
|
|
pub height: f32,
|
|
|
|
|
|
|
|
/// Width of individual cell
|
|
|
|
pub cell_width: f32,
|
|
|
|
|
|
|
|
/// Height of individual cell
|
|
|
|
pub cell_height: f32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SizeInfo {
|
|
|
|
#[inline]
|
2016-07-04 00:00:00 +00:00
|
|
|
pub fn lines(&self) -> Line {
|
|
|
|
Line((self.height / self.cell_height) as usize)
|
2016-06-28 16:18:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2016-07-04 00:00:00 +00:00
|
|
|
pub fn cols(&self) -> Column {
|
|
|
|
Column((self.width / self.cell_width) as usize)
|
2016-06-28 16:18:54 +00:00
|
|
|
}
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Term {
|
2016-06-28 16:18:54 +00:00
|
|
|
pub fn new(width: f32, height: f32, cell_width: f32, cell_height: f32) -> Term {
|
|
|
|
let size = SizeInfo {
|
|
|
|
width: width as f32,
|
|
|
|
height: height as f32,
|
|
|
|
cell_width: cell_width as f32,
|
|
|
|
cell_height: cell_height as f32,
|
|
|
|
};
|
|
|
|
|
|
|
|
let num_cols = size.cols();
|
2016-07-04 00:00:00 +00:00
|
|
|
let num_lines = size.lines();
|
2016-06-28 16:18:54 +00:00
|
|
|
|
2016-07-04 00:00:00 +00:00
|
|
|
println!("num_cols, num_lines = {}, {}", num_cols, num_lines);
|
2016-06-28 16:18:54 +00:00
|
|
|
|
2016-07-04 00:00:00 +00:00
|
|
|
let grid = Grid::new(num_lines, num_cols, &Cell::new(' '));
|
2016-06-28 16:18:54 +00:00
|
|
|
|
2016-07-04 00:00:00 +00:00
|
|
|
let tty = tty::new(*num_lines as u8, *num_cols as u8);
|
|
|
|
tty.resize(*num_lines as usize, *num_cols as usize, size.width as usize, size.height as usize);
|
2016-05-31 03:44:37 +00:00
|
|
|
|
2016-07-04 00:00:00 +00:00
|
|
|
let mut tabs = (Column(0)..grid.num_cols()).map(|i| (*i as usize) % TAB_SPACES == 0)
|
|
|
|
.collect::<Vec<bool>>();
|
2016-05-31 03:44:37 +00:00
|
|
|
tabs[0] = false;
|
|
|
|
|
|
|
|
let alt = grid.clone();
|
2016-07-04 00:00:00 +00:00
|
|
|
let scroll_region = Line(0)..grid.num_lines();
|
2016-05-31 03:44:37 +00:00
|
|
|
|
|
|
|
Term {
|
|
|
|
grid: grid,
|
|
|
|
alt_grid: alt,
|
|
|
|
alt: false,
|
|
|
|
cursor: Cursor::default(),
|
|
|
|
alt_cursor: Cursor::default(),
|
|
|
|
fg: DEFAULT_FG,
|
|
|
|
bg: DEFAULT_BG,
|
2016-06-28 16:18:54 +00:00
|
|
|
tty: tty,
|
2016-05-31 03:44:37 +00:00
|
|
|
tabs: tabs,
|
2016-07-04 00:00:00 +00:00
|
|
|
attr: cell::Flags::empty(),
|
2016-06-23 16:42:00 +00:00
|
|
|
mode: Default::default(),
|
2016-06-08 17:39:49 +00:00
|
|
|
scroll_region: scroll_region,
|
2016-06-28 16:18:54 +00:00
|
|
|
size_info: size
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-29 17:21:02 +00:00
|
|
|
/// Resize terminal to new dimensions
|
|
|
|
pub fn resize(&mut self, width: f32, height: f32) {
|
|
|
|
let size = SizeInfo {
|
|
|
|
width: width,
|
|
|
|
height: height,
|
|
|
|
cell_width: self.size_info.cell_width,
|
|
|
|
cell_height: self.size_info.cell_height,
|
|
|
|
};
|
|
|
|
|
|
|
|
let old_cols = self.size_info.cols();
|
2016-07-04 00:00:00 +00:00
|
|
|
let old_lines = self.size_info.lines();
|
2016-06-29 17:21:02 +00:00
|
|
|
let num_cols = size.cols();
|
2016-07-04 00:00:00 +00:00
|
|
|
let num_lines = size.lines();
|
2016-06-29 17:21:02 +00:00
|
|
|
|
|
|
|
self.size_info = size;
|
|
|
|
|
2016-07-04 00:00:00 +00:00
|
|
|
if old_cols == num_cols && old_lines == num_lines {
|
2016-06-29 17:21:02 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Scroll up to keep cursor and as much context as possible in grid. This only runs when the
|
2016-07-04 00:00:00 +00:00
|
|
|
// lines decreases.
|
|
|
|
self.scroll_region = Line(0)..self.grid.num_lines();
|
|
|
|
|
|
|
|
// Scroll up to keep cursor in terminal
|
|
|
|
if self.cursor.line >= num_lines {
|
|
|
|
let lines = self.cursor.line - num_lines + 1;
|
|
|
|
self.scroll(lines, ScrollDirection::Down);
|
|
|
|
self.cursor.line -= lines;
|
2016-06-29 17:21:02 +00:00
|
|
|
}
|
|
|
|
|
2016-07-04 00:00:00 +00:00
|
|
|
println!("num_cols, num_lines = {}, {}", num_cols, num_lines);
|
2016-06-29 17:21:02 +00:00
|
|
|
|
|
|
|
// Resize grids to new size
|
2016-07-04 00:00:00 +00:00
|
|
|
self.grid.resize(num_lines, num_cols, &Cell::new(' '));
|
|
|
|
self.alt_grid.resize(num_lines, num_cols, &Cell::new(' '));
|
2016-06-29 17:21:02 +00:00
|
|
|
|
|
|
|
// Ensure cursor is in-bounds
|
2016-07-04 00:00:00 +00:00
|
|
|
self.cursor.line = limit(self.cursor.line, Line(0), num_lines);
|
|
|
|
self.cursor.col = limit(self.cursor.col, Column(0), num_cols);
|
2016-06-29 17:21:02 +00:00
|
|
|
|
|
|
|
// Recreate tabs list
|
2016-07-04 00:00:00 +00:00
|
|
|
self.tabs = (Column(0)..self.grid.num_cols()).map(|i| (*i as usize) % TAB_SPACES == 0)
|
|
|
|
.collect::<Vec<bool>>();
|
2016-06-29 17:21:02 +00:00
|
|
|
|
|
|
|
// Make sure bottom of terminal is clear
|
2016-07-04 00:00:00 +00:00
|
|
|
self.grid.clear_region((self.cursor.line).., |c| c.reset());
|
|
|
|
self.alt_grid.clear_region((self.cursor.line).., |c| c.reset());
|
2016-06-29 17:21:02 +00:00
|
|
|
|
|
|
|
// Reset scrolling region to new size
|
2016-07-04 00:00:00 +00:00
|
|
|
self.scroll_region = Line(0)..self.grid.num_lines();
|
2016-06-29 17:21:02 +00:00
|
|
|
|
|
|
|
// Inform tty of new dimensions
|
2016-07-04 00:00:00 +00:00
|
|
|
self.tty.resize(*num_lines as _,
|
|
|
|
*num_cols as _,
|
2016-06-29 17:21:02 +00:00
|
|
|
self.size_info.width as usize,
|
|
|
|
self.size_info.height as usize);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-06-28 16:18:54 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn tty(&self) -> &tty::Tty {
|
|
|
|
&self.tty
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn size_info(&self) -> &SizeInfo {
|
|
|
|
&self.size_info
|
|
|
|
}
|
|
|
|
|
2016-07-04 00:00:00 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn grid(&self) -> &Grid<Cell> {
|
2016-05-31 03:44:37 +00:00
|
|
|
&self.grid
|
|
|
|
}
|
|
|
|
|
2016-06-08 04:17:48 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn mode(&self) -> &TermMode {
|
|
|
|
&self.mode
|
|
|
|
}
|
|
|
|
|
2016-05-31 03:44:37 +00:00
|
|
|
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 {
|
2016-07-04 00:00:00 +00:00
|
|
|
self.grid.clear(|c| c.reset());
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2016-07-04 00:00:00 +00:00
|
|
|
pub fn cursor(&self) -> &Cursor {
|
|
|
|
&self.cursor
|
2016-06-03 03:27:07 +00:00
|
|
|
}
|
|
|
|
|
2016-05-31 03:44:37 +00:00
|
|
|
/// Set character in current cursor position
|
|
|
|
fn set_char(&mut self, c: char) {
|
2016-07-04 00:00:00 +00:00
|
|
|
if self.cursor.col == self.grid.num_cols() {
|
2016-06-08 04:17:48 +00:00
|
|
|
println!("wrapping");
|
2016-07-04 00:00:00 +00:00
|
|
|
self.cursor.line += 1;
|
|
|
|
self.cursor.col = Column(0);
|
2016-06-06 22:13:45 +00:00
|
|
|
}
|
|
|
|
|
2016-07-04 00:00:00 +00:00
|
|
|
if self.cursor.line == self.grid.num_lines() {
|
2016-06-07 00:46:26 +00:00
|
|
|
panic!("cursor fell off grid");
|
|
|
|
}
|
|
|
|
|
2016-07-04 00:00:00 +00:00
|
|
|
let cell = &mut self.grid[&self.cursor];
|
2016-05-31 03:44:37 +00:00
|
|
|
cell.c = c;
|
|
|
|
cell.fg = self.fg;
|
|
|
|
cell.bg = self.bg;
|
2016-06-06 23:54:15 +00:00
|
|
|
cell.flags = self.attr;
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
|
2016-06-08 17:39:49 +00:00
|
|
|
/// Convenience function for scrolling
|
2016-07-04 00:00:00 +00:00
|
|
|
fn scroll(&mut self, lines: Line, direction: ScrollDirection) {
|
|
|
|
println!("[TERM] scrolling {} {} lines", direction, lines);
|
|
|
|
match direction {
|
|
|
|
ScrollDirection::Down => {
|
|
|
|
// Scrolled down, so need to clear from bottom
|
|
|
|
self.grid.scroll(self.scroll_region.clone(), *lines as isize);
|
|
|
|
let start = self.scroll_region.end - lines;
|
|
|
|
self.grid.clear_region(start..self.scroll_region.end, |c| c.reset());
|
|
|
|
},
|
|
|
|
ScrollDirection::Up => {
|
|
|
|
// Scrolled up, clear from top
|
|
|
|
self.grid.scroll(self.scroll_region.clone(), -(*lines as isize));
|
|
|
|
let end = self.scroll_region.start + lines;
|
|
|
|
self.grid.clear_region(self.scroll_region.start..end, |c| c.reset());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Which direction to scroll
|
|
|
|
#[derive(Debug)]
|
|
|
|
enum ScrollDirection {
|
|
|
|
/// Scroll up
|
|
|
|
///
|
|
|
|
/// Lines move down
|
|
|
|
Up,
|
|
|
|
|
|
|
|
/// Scroll down
|
|
|
|
///
|
|
|
|
/// Lines move up
|
|
|
|
Down,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for ScrollDirection {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match *self {
|
|
|
|
ScrollDirection::Up => write!(f, "up"),
|
|
|
|
ScrollDirection::Down => write!(f, "down"),
|
2016-06-08 17:39:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ansi::TermInfo for Term {
|
|
|
|
#[inline]
|
|
|
|
fn rows(&self) -> usize {
|
2016-07-04 00:00:00 +00:00
|
|
|
*self.grid.num_lines() as usize
|
2016-06-08 17:39:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn cols(&self) -> usize {
|
2016-07-04 00:00:00 +00:00
|
|
|
*self.grid.num_cols() as usize
|
2016-06-08 17:39:49 +00:00
|
|
|
}
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ansi::Handler for Term {
|
|
|
|
/// A character to be displayed
|
|
|
|
#[inline]
|
|
|
|
fn input(&mut self, c: char) {
|
|
|
|
self.set_char(c);
|
2016-07-04 00:00:00 +00:00
|
|
|
self.cursor.col += 1;
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
|
2016-07-04 00:00:00 +00:00
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn goto(&mut self, x: i64, y: i64) {
|
|
|
|
println!("goto: x={}, y={}", x, y);
|
2016-07-04 00:12:16 +00:00
|
|
|
self.cursor.line = Line(y as usize);
|
|
|
|
self.cursor.col = Column(x as usize);
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
2016-07-04 00:00:00 +00:00
|
|
|
|
2016-07-04 00:07:23 +00:00
|
|
|
#[inline]
|
2016-07-04 00:00:00 +00:00
|
|
|
fn goto_row(&mut self, row: i64) {
|
|
|
|
println!("goto_row: {}", row);
|
|
|
|
self.cursor.line = Line(row as usize);
|
2016-06-06 22:13:45 +00:00
|
|
|
}
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-07-04 00:00:00 +00:00
|
|
|
fn goto_col(&mut self, col: i64) {
|
|
|
|
println!("goto_col: {}", col);
|
|
|
|
self.cursor.col = Column(col as usize);
|
2016-06-06 22:13:45 +00:00
|
|
|
}
|
|
|
|
|
2016-07-04 00:07:23 +00:00
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn insert_blank(&mut self, num: i64) { println!("insert_blank: {}", num); }
|
|
|
|
|
2016-07-04 00:07:23 +00:00
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn move_up(&mut self, rows: i64) {
|
|
|
|
println!("move_up: {}", rows);
|
2016-07-04 00:00:00 +00:00
|
|
|
self.cursor.line -= Line(rows as usize);
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
|
2016-07-04 00:07:23 +00:00
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn move_down(&mut self, rows: i64) {
|
|
|
|
println!("move_down: {}", rows);
|
2016-07-04 00:00:00 +00:00
|
|
|
self.cursor.line += Line(rows as usize);
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
|
2016-07-04 00:07:23 +00:00
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn move_forward(&mut self, cols: i64) {
|
|
|
|
println!("move_forward: {}", cols);
|
2016-07-04 00:00:00 +00:00
|
|
|
self.cursor.col += Column(cols as usize);
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
|
2016-07-04 00:07:23 +00:00
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn move_backward(&mut self, spaces: i64) {
|
|
|
|
println!("move_backward: {}", spaces);
|
2016-07-04 00:00:00 +00:00
|
|
|
self.cursor.col -= Column(spaces as usize);
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
|
2016-07-04 00:07:23 +00:00
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn identify_terminal(&mut self) { println!("identify_terminal"); }
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn move_down_and_cr(&mut self, rows: i64) { println!("move_down_and_cr: {}", rows); }
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn move_up_and_cr(&mut self, rows: i64) { println!("move_up_and_cr: {}", rows); }
|
2016-07-04 00:00:00 +00:00
|
|
|
|
2016-07-04 00:07:23 +00:00
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn put_tab(&mut self, mut count: i64) {
|
|
|
|
println!("put_tab: {}", count);
|
|
|
|
|
2016-07-04 00:00:00 +00:00
|
|
|
let mut col = self.cursor.col;
|
|
|
|
while col < self.grid.num_cols() && count != 0 {
|
2016-05-31 03:44:37 +00:00
|
|
|
count -= 1;
|
|
|
|
loop {
|
2016-07-04 00:00:00 +00:00
|
|
|
if col == self.grid.num_cols() || self.tabs[*col as usize] {
|
2016-05-31 03:44:37 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-07-04 00:00:00 +00:00
|
|
|
col += 1;
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-04 00:00:00 +00:00
|
|
|
self.cursor.col = col;
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Backspace `count` characters
|
|
|
|
#[inline]
|
2016-06-09 15:37:59 +00:00
|
|
|
fn backspace(&mut self) {
|
2016-06-08 04:15:53 +00:00
|
|
|
println!("backspace");
|
2016-07-04 00:00:00 +00:00
|
|
|
self.cursor.col -= 1;
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Carriage return
|
|
|
|
#[inline]
|
|
|
|
fn carriage_return(&mut self) {
|
2016-06-08 04:15:53 +00:00
|
|
|
println!("carriage_return");
|
2016-07-04 00:00:00 +00:00
|
|
|
self.cursor.col = Column(0);
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Linefeed
|
|
|
|
#[inline]
|
|
|
|
fn linefeed(&mut self) {
|
|
|
|
println!("linefeed");
|
2016-07-04 00:00:00 +00:00
|
|
|
if self.cursor.line + 1 >= self.scroll_region.end {
|
|
|
|
self.scroll(Line(1), ScrollDirection::Down);
|
2016-05-31 03:44:37 +00:00
|
|
|
self.clear_line(ansi::LineClearMode::Right);
|
|
|
|
} else {
|
2016-07-04 00:00:00 +00:00
|
|
|
self.cursor.line += 1;
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set current position as a tabstop
|
2016-07-04 00:07:23 +00:00
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn bell(&mut self) { println!("bell"); }
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn substitute(&mut self) { println!("substitute"); }
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn newline(&mut self) { println!("newline"); }
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn set_horizontal_tabstop(&mut self) { println!("set_horizontal_tabstop"); }
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-06-08 17:39:49 +00:00
|
|
|
fn scroll_up(&mut self, rows: i64) {
|
|
|
|
println!("scroll_up: {}", rows);
|
2016-07-04 00:00:00 +00:00
|
|
|
self.scroll(Line(rows as usize), ScrollDirection::Up);
|
2016-06-08 17:39:49 +00:00
|
|
|
}
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-06-08 17:39:49 +00:00
|
|
|
fn scroll_down(&mut self, rows: i64) {
|
|
|
|
println!("scroll_down: {}", rows);
|
2016-07-04 00:00:00 +00:00
|
|
|
self.scroll(Line(rows as usize), ScrollDirection::Down);
|
2016-06-08 17:39:49 +00:00
|
|
|
}
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-06-08 17:39:49 +00:00
|
|
|
fn insert_blank_lines(&mut self, count: i64) {
|
|
|
|
println!("insert_blank_lines: {}", count);
|
2016-07-04 00:00:00 +00:00
|
|
|
if self.scroll_region.contains(self.cursor.line) {
|
|
|
|
self.scroll(Line(count as usize), ScrollDirection::Down);
|
2016-06-08 17:39:49 +00:00
|
|
|
}
|
|
|
|
}
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-06-08 17:39:49 +00:00
|
|
|
fn delete_lines(&mut self, count: i64) {
|
2016-07-04 00:00:00 +00:00
|
|
|
if self.scroll_region.contains(self.cursor.line) {
|
|
|
|
self.scroll(Line(count as usize), ScrollDirection::Up);
|
2016-06-08 17:39:49 +00:00
|
|
|
}
|
|
|
|
}
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-07-02 04:13:09 +00:00
|
|
|
fn erase_chars(&mut self, count: i64) {
|
|
|
|
println!("erase_chars: {}", count);
|
2016-07-04 00:00:00 +00:00
|
|
|
let col_index = self.cursor.col;
|
2016-07-02 04:13:09 +00:00
|
|
|
let count = count as usize;
|
|
|
|
|
2016-07-04 00:00:00 +00:00
|
|
|
let row = &mut self.grid[self.cursor.line];
|
|
|
|
for c in &mut row[self.cursor.col..(col_index + count)] {
|
2016-07-02 04:13:09 +00:00
|
|
|
c.reset();
|
|
|
|
}
|
|
|
|
}
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn delete_chars(&mut self, count: i64) { println!("delete_chars: {}", count); }
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn move_backward_tabs(&mut self, count: i64) { println!("move_backward_tabs: {}", count); }
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn move_forward_tabs(&mut self, count: i64) { println!("move_forward_tabs: {}", count); }
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn save_cursor_position(&mut self) { println!("save_cursor_position"); }
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn restore_cursor_position(&mut self) { println!("restore_cursor_position"); }
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn clear_line(&mut self, mode: ansi::LineClearMode) {
|
|
|
|
println!("clear_line: {:?}", mode);
|
|
|
|
match mode {
|
|
|
|
ansi::LineClearMode::Right => {
|
2016-07-04 00:00:00 +00:00
|
|
|
let row = &mut self.grid[self.cursor.line];
|
|
|
|
for cell in &mut row[self.cursor.col..] {
|
2016-06-08 17:39:49 +00:00
|
|
|
cell.reset();
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
}
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn clear_screen(&mut self, mode: ansi::ClearMode) {
|
|
|
|
println!("clear_screen: {:?}", mode);
|
|
|
|
match mode {
|
|
|
|
ansi::ClearMode::Below => {
|
2016-07-04 00:00:00 +00:00
|
|
|
let start = self.cursor.line;
|
|
|
|
let end = self.grid.num_lines();
|
|
|
|
|
|
|
|
for row in &mut self.grid[start..end] {
|
2016-07-02 15:25:21 +00:00
|
|
|
for cell in row {
|
|
|
|
cell.reset();
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
ansi::ClearMode::All => {
|
2016-07-04 00:00:00 +00:00
|
|
|
self.grid.clear(|c| c.reset());
|
2016-05-31 03:44:37 +00:00
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
panic!("ansi::ClearMode::Above not implemented");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn clear_tabs(&mut self, mode: ansi::TabulationClearMode) { println!("clear_tabs: {:?}", mode); }
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn reset_state(&mut self) { println!("reset_state"); }
|
2016-07-04 00:07:23 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn reverse_index(&mut self) {
|
|
|
|
println!("reverse_index");
|
|
|
|
// if cursor is at the top
|
2016-07-04 00:00:00 +00:00
|
|
|
if self.cursor.col == Column(0) {
|
|
|
|
self.scroll(Line(1), ScrollDirection::Up);
|
2016-05-31 03:44:37 +00:00
|
|
|
} else {
|
2016-07-04 00:00:00 +00:00
|
|
|
self.cursor.col -= 1;
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// set a terminal attribute
|
2016-07-04 00:07:23 +00:00
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
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];
|
|
|
|
},
|
2016-06-06 22:13:45 +00:00
|
|
|
Attr::ForegroundSpec(rgb) => {
|
|
|
|
self.fg = rgb;
|
|
|
|
},
|
|
|
|
Attr::BackgroundSpec(rgb) => {
|
|
|
|
self.bg = rgb;
|
|
|
|
},
|
2016-05-31 03:44:37 +00:00
|
|
|
Attr::Reset => {
|
|
|
|
self.fg = DEFAULT_FG;
|
|
|
|
self.bg = DEFAULT_BG;
|
2016-07-04 00:00:00 +00:00
|
|
|
self.attr = cell::Flags::empty();
|
2016-06-06 23:54:15 +00:00
|
|
|
},
|
2016-07-04 00:00:00 +00:00
|
|
|
Attr::Reverse => self.attr.insert(cell::INVERSE),
|
|
|
|
Attr::CancelReverse => self.attr.remove(cell::INVERSE),
|
|
|
|
Attr::Bold => self.attr.insert(cell::BOLD),
|
|
|
|
Attr::CancelBoldDim => self.attr.remove(cell::BOLD),
|
|
|
|
Attr::Italic => self.attr.insert(cell::ITALIC),
|
|
|
|
Attr::CancelItalic => self.attr.remove(cell::ITALIC),
|
|
|
|
Attr::Underscore => self.attr.insert(cell::UNDERLINE),
|
|
|
|
Attr::CancelUnderline => self.attr.remove(cell::UNDERLINE),
|
2016-05-31 03:44:37 +00:00
|
|
|
_ => {
|
|
|
|
println!("Term got unhandled attr: {:?}", attr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-04 00:07:23 +00:00
|
|
|
#[inline]
|
2016-05-31 03:44:37 +00:00
|
|
|
fn set_mode(&mut self, mode: ansi::Mode) {
|
|
|
|
println!("set_mode: {:?}", mode);
|
|
|
|
match mode {
|
2016-06-08 04:17:48 +00:00
|
|
|
ansi::Mode::SwapScreenAndSetRestoreCursor => self.swap_alt(),
|
2016-06-23 16:42:00 +00:00
|
|
|
ansi::Mode::ShowCursor => self.mode.insert(mode::SHOW_CURSOR),
|
2016-06-23 16:48:31 +00:00
|
|
|
ansi::Mode::CursorKeys => self.mode.insert(mode::APP_CURSOR),
|
2016-06-08 04:17:48 +00:00
|
|
|
_ => {
|
|
|
|
println!(".. ignoring set_mode");
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-04 00:07:23 +00:00
|
|
|
#[inline]
|
2016-06-08 04:17:48 +00:00
|
|
|
fn unset_mode(&mut self,mode: ansi::Mode) {
|
2016-05-31 03:44:37 +00:00
|
|
|
println!("unset_mode: {:?}", mode);
|
|
|
|
match mode {
|
2016-06-08 04:17:48 +00:00
|
|
|
ansi::Mode::SwapScreenAndSetRestoreCursor => self.swap_alt(),
|
2016-06-23 16:42:00 +00:00
|
|
|
ansi::Mode::ShowCursor => self.mode.remove(mode::SHOW_CURSOR),
|
2016-06-23 16:48:31 +00:00
|
|
|
ansi::Mode::CursorKeys => self.mode.remove(mode::APP_CURSOR),
|
2016-06-08 04:17:48 +00:00
|
|
|
_ => {
|
|
|
|
println!(".. ignoring unset_mode");
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-06-08 17:39:49 +00:00
|
|
|
|
2016-07-04 00:07:23 +00:00
|
|
|
#[inline]
|
2016-06-08 17:39:49 +00:00
|
|
|
fn set_scrolling_region(&mut self, top: i64, bot: i64) {
|
|
|
|
println!("set scroll region: {:?} - {:?}", top, bot);
|
|
|
|
// 1 is added to bottom for inclusive range
|
2016-07-04 00:00:00 +00:00
|
|
|
self.scroll_region = Line(top as usize)..Line((bot as usize) + 1);
|
2016-06-08 17:39:49 +00:00
|
|
|
}
|
2016-05-31 03:44:37 +00:00
|
|
|
}
|