aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoe Wilm <joe@jwilm.com>2016-07-03 17:00:00 -0700
committerJoe Wilm <joe@jwilm.com>2016-07-03 17:00:00 -0700
commit7f1c1efe474851a129e4a2e5bc012d9b76ed2ed0 (patch)
tree4fc278de8e08f16ff80d976c60c454a29e452e7f /src
parentbc2793a762b505d2d3c7af65e878f864a36cb19b (diff)
downloadr-alacritty-7f1c1efe474851a129e4a2e5bc012d9b76ed2ed0.tar.gz
r-alacritty-7f1c1efe474851a129e4a2e5bc012d9b76ed2ed0.tar.bz2
r-alacritty-7f1c1efe474851a129e4a2e5bc012d9b76ed2ed0.zip
Grid API is now generic and strongly typed
The Grid no longer knows about a `Cell` and is instead generic. The `Cell` type is coupled to the `term` module already, and it's been moved there to reflect the strong relationship. Grid APIs previously accepted `usize` for many arguments. If the caller intended rows to be columns, but the function accepted them in reverse, there would be no compiler error. Now there is, and this should prevent such bugs from entering the code. The Grid internals grew significantly to accomodate the strongly typed APIs. There is now a `grid::index` module which defines Cursor, Line, and Column. The Grid APIs are all based on these types now. Indexing for Ranges proved to be somewhat awkward. A new range had to be constructed in the implementation. If the optimizer can't figure out what's going on in that case, the ranges may not be a zero-cost abstraction.
Diffstat (limited to 'src')
-rw-r--r--src/grid.rs620
-rw-r--r--src/main.rs2
-rw-r--r--src/renderer/mod.rs27
-rw-r--r--src/term.rs350
4 files changed, 685 insertions, 314 deletions
diff --git a/src/grid.rs b/src/grid.rs
index 042aabb7..37c9dee6 100644
--- a/src/grid.rs
+++ b/src/grid.rs
@@ -11,160 +11,362 @@
// 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.
-//
-//! Functions for computing properties of the terminal grid
-use std::ops::{Index, IndexMut, Deref, DerefMut, Range, RangeTo, RangeFrom, RangeFull};
+//! A generic 2d grid implementation optimized for use in a terminal.
+//!
+//! The current implementation uses a vector of vectors to store cell data.
+//! Reimplementing the store as a single contiguous vector may be desirable in
+//! the future. Rotation and indexing would need to be reconsidered at that
+//! time; rotation currently reorganize Vecs in the lines Vec, and indexing with
+//! ranges is currently supported.
+
+use std::ops::{Deref, DerefMut, Range, RangeTo, RangeFrom, RangeFull, Index, IndexMut};
use std::cmp::Ordering;
use std::slice::{self, Iter, IterMut};
use std::iter::IntoIterator;
+use std::borrow::ToOwned;
use util::Rotate;
-use term::{Cursor, DEFAULT_FG, DEFAULT_BG};
-use ::Rgb;
-
-#[derive(Clone, Debug)]
-pub struct Cell {
- pub c: char,
- pub fg: Rgb,
- pub bg: Rgb,
- pub flags: CellFlags,
-}
+/// Indexing types and implementations for Grid and Line
+pub mod index {
+ use std::fmt;
+ use std::iter::Step;
+ use std::num::{One, Zero};
+ use std::ops::{self, Deref, Add};
-bitflags! {
- pub flags CellFlags: u32 {
- const INVERSE = 0b00000001,
- const BOLD = 0b00000010,
- const ITALIC = 0b00000100,
- const UNDERLINE = 0b00001000,
+ /// Index in the grid using row, column notation
+ #[derive(Debug, Clone, Default, Eq, PartialEq)]
+ pub struct Cursor {
+ pub line: Line,
+ pub col: Column,
}
-}
-impl Cell {
- pub fn new(c: char) -> Cell {
- Cell {
- c: c.into(),
- bg: Default::default(),
- fg: Default::default(),
- flags: CellFlags::empty(),
+ /// A line
+ ///
+ /// Newtype to avoid passing values incorrectly
+ #[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Ord, PartialOrd)]
+ pub struct Line(pub usize);
+
+ impl fmt::Display for Line {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Line({})", self.0)
}
}
- pub fn reset(&mut self) {
- self.c = ' ';
- self.flags = CellFlags::empty();
+ /// A column
+ ///
+ /// Newtype to avoid passing values incorrectly
+ #[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Ord, PartialOrd)]
+ pub struct Column(pub usize);
- // FIXME shouldn't know about term
- self.bg = DEFAULT_BG;
- self.fg = DEFAULT_FG;
+ impl fmt::Display for Column {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Column({})", self.0)
+ }
}
-}
-/// Represents the terminal display contents
-#[derive(Clone)]
-pub struct Grid {
- /// Rows in the grid. Each row holds a list of cells corresponding to the columns in that row.
- raw: Vec<Row>,
+ /// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+ /// file at the top-level directory of this distribution and at
+ /// http://rust-lang.org/COPYRIGHT.
+ ///
+ /// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+ /// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+ /// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+ /// option. This file may not be copied, modified, or distributed
+ /// except according to those terms.
+ ///
+ /// implements binary operators "&T op U", "T op &U", "&T op &U"
+ /// based on "T op U" where T and U are expected to be `Copy`able
+ macro_rules! forward_ref_binop {
+ (impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
+ impl<'a> $imp<$u> for &'a $t {
+ type Output = <$t as $imp<$u>>::Output;
+
+ #[inline]
+ fn $method(self, other: $u) -> <$t as $imp<$u>>::Output {
+ $imp::$method(*self, other)
+ }
+ }
- /// Number of columns
- cols: usize,
+ impl<'a> $imp<&'a $u> for $t {
+ type Output = <$t as $imp<$u>>::Output;
- /// Number of rows.
- ///
- /// Invariant: rows is equivalent to cells.len()
- rows: usize,
-}
+ #[inline]
+ fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
+ $imp::$method(self, *other)
+ }
+ }
-impl Grid {
- pub fn new(rows: usize, cols: usize) -> Grid {
- let mut raw = Vec::with_capacity(rows);
- for _ in 0..rows {
- raw.push(Row::new(cols));
- }
+ impl<'a, 'b> $imp<&'a $u> for &'b $t {
+ type Output = <$t as $imp<$u>>::Output;
- Grid {
- raw: raw,
- cols: cols,
- rows: rows,
+ #[inline]
+ fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
+ $imp::$method(*self, *other)
+ }
+ }
}
}
- #[inline]
- pub fn rows(&self) -> Iter<Row> {
- self.raw.iter()
+ /// Macro for deriving deref
+ macro_rules! deref {
+ ($ty:ty, $target:ty) => {
+ impl Deref for $ty {
+ type Target = $target;
+
+ #[inline]
+ fn deref(&self) -> &$target {
+ &self.0
+ }
+ }
+ }
}
- #[inline]
- pub fn rows_mut(&mut self) -> IterMut<Row> {
- self.raw.iter_mut()
+ macro_rules! add {
+ ($ty:ty, $construct:expr) => {
+ impl ops::Add<$ty> for $ty {
+ type Output = $ty;
+
+ #[inline]
+ fn add(self, rhs: $ty) -> $ty {
+ $construct(self.0 + rhs.0)
+ }
+ }
+ }
}
- #[inline]
- pub fn num_rows(&self) -> usize {
- self.raw.len()
+ macro_rules! sub {
+ ($ty:ty, $construct:expr) => {
+ impl ops::Sub<$ty> for $ty {
+ type Output = $ty;
+
+ #[inline]
+ fn sub(self, rhs: $ty) -> $ty {
+ $construct(self.0 - rhs.0)
+ }
+ }
+ }
}
- #[inline]
- pub fn num_cols(&self) -> usize {
- self.raw[0].len()
+ macro_rules! zero_one {
+ ($ty:ty, $construct:expr) => {
+ impl One for $ty {
+ fn one() -> $ty {
+ $construct(1)
+ }
+ }
+
+ impl Zero for $ty {
+ fn zero() -> $ty {
+ $construct(0)
+ }
+ }
+ }
}
- pub fn scroll(&mut self, region: Range<usize>, positions: isize) {
- self.raw[region].rotate(positions)
+ macro_rules! ops {
+ ($ty:ty, $construct:expr) => {
+ add!($ty, $construct);
+ sub!($ty, $construct);
+ zero_one!($ty, $construct);
+ deref!($ty, usize);
+ forward_ref_binop!(impl Add, add for $ty, $ty);
+
+ impl Step for $ty {
+ fn step(&self, by: &$ty) -> Option<$ty> {
+ Some(*self + *by)
+ }
+
+ #[inline]
+ #[allow(trivial_numeric_casts)]
+ fn steps_between(start: &$ty, end: &$ty, by: &$ty) -> Option<usize> {
+ if *by == $construct(0) { return None; }
+ if *start < *end {
+ // Note: We assume $t <= usize here
+ let diff = (*end - *start).0;
+ let by = by.0;
+ if diff % by > 0 {
+ Some(diff / by + 1)
+ } else {
+ Some(diff / by)
+ }
+ } else {
+ Some(0)
+ }
+ }
+ }
+
+ impl ops::AddAssign<$ty> for $ty {
+ #[inline]
+ fn add_assign(&mut self, rhs: $ty) {
+ self.0 += rhs.0
+ }
+ }
+
+ impl ops::SubAssign<$ty> for $ty {
+ #[inline]
+ fn sub_assign(&mut self, rhs: $ty) {
+ self.0 -= rhs.0
+ }
+ }
+
+ impl ops::AddAssign<usize> for $ty {
+ #[inline]
+ fn add_assign(&mut self, rhs: usize) {
+ self.0 += rhs
+ }
+ }
+
+ impl ops::SubAssign<usize> for $ty {
+ #[inline]
+ fn sub_assign(&mut self, rhs: usize) {
+ self.0 -= rhs
+ }
+ }
+
+ impl From<usize> for $ty {
+ #[inline]
+ fn from(val: usize) -> $ty {
+ $construct(val)
+ }
+ }
+
+ impl ops::Add<usize> for $ty {
+ type Output = $ty;
+
+ #[inline]
+ fn add(self, rhs: usize) -> $ty {
+ $construct(self.0 + rhs)
+ }
+ }
+
+ impl ops::Sub<usize> for $ty {
+ type Output = $ty;
+
+ #[inline]
+ fn sub(self, rhs: usize) -> $ty {
+ $construct(self.0 - rhs)
+ }
+ }
+ }
}
- #[inline]
- pub fn clear(&mut self) {
- let region = 0..self.num_rows();
- self.clear_region(region);
+ ops!(Line, Line);
+ ops!(Column, Column);
+}
+
+use self::index::Cursor;
+
+/// Represents the terminal display contents
+#[derive(Clone)]
+pub struct Grid<T> {
+ /// Lines in the grid. Each row holds a list of cells corresponding to the
+ /// columns in that row.
+ raw: Vec<Row<T>>,
+
+ /// Number of columns
+ cols: index::Column,
+
+ /// Number of lines.
+ ///
+ /// Invariant: lines is equivalent to raw.len()
+ lines: index::Line,
+}
+
+impl<T: Clone> Grid<T> {
+ pub fn new(lines: index::Line, cols: index::Column, template: &T) -> Grid<T> {
+ let mut raw = Vec::with_capacity(*lines);
+ for _ in index::Line(0)..lines {
+ raw.push(Row::new(cols, template));
+ }
+
+ Grid {
+ raw: raw,
+ cols: cols,
+ lines: lines,
+ }
}
- pub fn resize(&mut self, rows: usize, cols: usize) {
+ pub fn resize(&mut self, lines: index::Line, cols: index::Column, template: &T) {
// Check that there's actually work to do and return early if not
- if rows == self.rows && cols == self.cols {
+ if lines == self.lines && cols == self.cols {
return;
}
- match self.rows.cmp(&rows) {
- Ordering::Less => self.grow_rows(rows),
- Ordering::Greater => self.shrink_rows(rows),
+ match self.lines.cmp(&lines) {
+ Ordering::Less => self.grow_lines(lines, template),
+ Ordering::Greater => self.shrink_lines(lines),
Ordering::Equal => (),
}
match self.cols.cmp(&cols) {
- Ordering::Less => self.grow_cols(cols),
+ Ordering::Less => self.grow_cols(cols, template),
Ordering::Greater => self.shrink_cols(cols),
Ordering::Equal => (),
}
}
- fn grow_rows(&mut self, rows: usize) {
- for _ in self.num_rows()..rows {
- self.raw.push(Row::new(self.cols));
+ fn grow_lines(&mut self, lines: index::Line, template: &T) {
+ for _ in self.num_lines()..lines {
+ self.raw.push(Row::new(self.cols, template));
}
- self.rows = rows;
+ self.lines = lines;
}
- fn shrink_rows(&mut self, rows: usize) {
- while self.raw.len() != rows {
- self.raw.pop();
+ fn grow_cols(&mut self, cols: index::Column, template: &T) {
+ for row in self.lines_mut() {
+ row.grow(cols, template);
}
- self.rows = rows;
+ self.cols = cols;
+ }
+
+}
+
+impl<T> Grid<T> {
+ #[inline]
+ pub fn lines(&self) -> Iter<Row<T>> {
+ self.raw.iter()
+ }
+
+ #[inline]
+ pub fn lines_mut(&mut self) -> IterMut<Row<T>> {
+ self.raw.iter_mut()
+ }
+
+ #[inline]
+ pub fn num_lines(&self) -> index::Line {
+ index::Line(self.raw.len())
+ }
+
+ #[inline]
+ pub fn num_cols(&self) -> index::Column {
+ index::Column(self.raw[0].len())
+ }
+
+ #[inline]
+ pub fn scroll(&mut self, region: Range<index::Line>, positions: isize) {
+ self[region].rotate(positions)
+ }
+
+ #[inline]
+ pub fn clear<F: Fn(&mut T)>(&mut self, func: F) {
+ let region = index::Line(0)..self.num_lines();
+ self.clear_region(region, func);
}
- fn grow_cols(&mut self, cols: usize) {
- for row in self.rows_mut() {
- row.grow(cols);
+ fn shrink_lines(&mut self, lines: index::Line) {
+ while index::Line(self.raw.len()) != lines {
+ self.raw.pop();
}
- self.cols = cols;
+ self.lines = lines;
}
- fn shrink_cols(&mut self, cols: usize) {
- for row in self.rows_mut() {
+ fn shrink_cols(&mut self, cols: index::Column) {
+ for row in self.lines_mut() {
row.shrink(cols);
}
@@ -172,128 +374,138 @@ impl Grid {
}
}
-impl Index<usize> for Grid {
- type Output = Row;
+impl<T> Index<index::Line> for Grid<T> {
+ type Output = Row<T>;
#[inline]
- fn index<'a>(&'a self, index: usize) -> &'a Row {
- &self.raw[index]
+ fn index<'a>(&'a self, index: index::Line) -> &'a Row<T> {
+ &self.raw[index.0]
}
}
-impl IndexMut<usize> for Grid {
+impl<T> IndexMut<index::Line> for Grid<T> {
#[inline]
- fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut Row {
- &mut self.raw[index]
+ fn index_mut<'a>(&'a mut self, index: index::Line) -> &'a mut Row<T> {
+ &mut self.raw[index.0]
}
}
-impl Index<Cursor> for Grid {
- type Output = Cell;
+impl<'cursor, T> Index<&'cursor Cursor> for Grid<T> {
+ type Output = T;
#[inline]
- fn index<'a>(&'a self, cursor: Cursor) -> &'a Cell {
- &self.raw[cursor.y as usize][cursor.x as usize]
+ fn index<'a, 'b>(&'a self, cursor: &'b Cursor) -> &'a T {
+ &self.raw[cursor.line.0][cursor.col]
}
}
-impl IndexMut<Cursor> for Grid {
+impl<'cursor, T> IndexMut<&'cursor Cursor> for Grid<T> {
#[inline]
- fn index_mut<'a>(&'a mut self, cursor: Cursor) -> &'a mut Cell {
- &mut self.raw[cursor.y as usize][cursor.x as usize]
+ fn index_mut<'a, 'b>(&'a mut self, cursor: &'b Cursor) -> &'a mut T {
+ &mut self.raw[cursor.line.0][cursor.col]
}
}
/// A row in the grid
-#[derive(Debug, Clone)]
-pub struct Row(Vec<Cell>);
+#[derive(Clone)]
+pub struct Row<T>(Vec<T>);
-impl Row {
- pub fn new(columns: usize) -> Row {
- Row(vec![Cell::new(' '); columns])
+impl<T: Clone> Row<T> {
+ pub fn new(columns: index::Column, template: &T) -> Row<T> {
+ Row(vec![template.to_owned(); *columns])
}
- pub fn grow(&mut self, cols: usize) {
- while self.len() != cols {
- self.push(Cell::new(' '));
+ pub fn grow(&mut self, cols: index::Column, template: &T) {
+ while self.len() != *cols {
+ self.push(template.to_owned());
}
}
+}
- pub fn shrink(&mut self, cols: usize) {
- while self.len() != cols {
+impl<T> Row<T> {
+ pub fn shrink(&mut self, cols: index::Column) {
+ while self.len() != *cols {
self.pop();
}
}
- pub fn cells(&self) -> Iter<Cell> {
+ #[inline]
+ pub fn cells(&self) -> Iter<T> {
self.0.iter()
}
- pub fn cells_mut(&mut self) -> IterMut<Cell> {
+ #[inline]
+ pub fn cells_mut(&mut self) -> IterMut<T> {
self.0.iter_mut()
}
}
-impl<'a> IntoIterator for &'a Row {
- type Item = &'a Cell;
- type IntoIter = slice::Iter<'a, Cell>;
+impl<'a, T> IntoIterator for &'a Row<T> {
+ type Item = &'a T;
+ type IntoIter = slice::Iter<'a, T>;
- fn into_iter(self) -> slice::Iter<'a, Cell> {
+ #[inline]
+ fn into_iter(self) -> slice::Iter<'a, T> {
self.iter()
}
}
-impl<'a> IntoIterator for &'a mut Row {
- type Item = &'a mut Cell;
- type IntoIter = slice::IterMut<'a, Cell>;
+impl<'a, T> IntoIterator for &'a mut Row<T> {
+ type Item = &'a mut T;
+ type IntoIter = slice::IterMut<'a, T>;
- fn into_iter(mut self) -> slice::IterMut<'a, Cell> {
+ #[inline]
+ fn into_iter(mut self) -> slice::IterMut<'a, T> {
self.iter_mut()
}
}
-impl Deref for Row {
- type Target = Vec<Cell>;
+impl<T> Deref for Row<T> {
+ type Target = Vec<T>;
+
+ #[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
-impl DerefMut for Row {
+impl<T> DerefMut for Row<T> {
+ #[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
-impl Index<usize> for Row {
- type Output = Cell;
+impl<T> Index<index::Column> for Row<T> {
+ type Output = T;
#[inline]
- fn index<'a>(&'a self, index: usize) -> &'a Cell {
- &self.0[index]
+ fn index<'a>(&'a self, index: index::Column) -> &'a T {
+ &self.0[index.0]
}
}
-impl IndexMut<usize> for Row {
+impl<T> IndexMut<index::Column> for Row<T> {
#[inline]
- fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut Cell {
- &mut self.0[index]
+ fn index_mut<'a>(&'a mut self, index: index::Column) -> &'a mut T {
+ &mut self.0[index.0]
}
}
macro_rules! row_index_range {
($range:ty) => {
- impl Index<$range> for Row {
- type Output = [Cell];
+ impl<T> Index<$range> for Row<T> {
+ type Output = [T];
+
#[inline]
- fn index<'a>(&'a self, index: $range) -> &'a [Cell] {
+ fn index<'a>(&'a self, index: $range) -> &'a [T] {
&self.0[index]
}
}
- impl IndexMut<$range> for Row {
+ impl<T> IndexMut<$range> for Row<T> {
#[inline]
- fn index_mut<'a>(&'a mut self, index: $range) -> &'a mut [Cell] {
+ fn index_mut<'a>(&'a mut self, index: $range) -> &'a mut [T] {
&mut self.0[index]
}
}
@@ -305,17 +517,121 @@ row_index_range!(RangeTo<usize>);
row_index_range!(RangeFrom<usize>);
row_index_range!(RangeFull);
-pub trait ClearRegion<T> {
- fn clear_region(&mut self, region: T);
+// -------------------------------------------------------------------------------------------------
+// Row ranges for Grid
+// -------------------------------------------------------------------------------------------------
+
+impl<T> Index<Range<index::Line>> for Grid<T> {
+ type Output = [Row<T>];
+
+ #[inline]
+ fn index(&self, index: Range<index::Line>) -> &[Row<T>] {
+ &self.raw[(index.start.0)..(index.end.0)]
+ }
+}
+
+impl<T> IndexMut<Range<index::Line>> for Grid<T> {
+ #[inline]
+ fn index_mut(&mut self, index: Range<index::Line>) -> &mut [Row<T>] {
+ &mut self.raw[(index.start.0)..(index.end.0)]
+ }
+}
+
+impl<T> Index<RangeTo<index::Line>> for Grid<T> {
+ type Output = [Row<T>];
+
+ #[inline]
+ fn index(&self, index: RangeTo<index::Line>) -> &[Row<T>] {
+ &self.raw[..(index.end.0)]
+ }
+}
+
+impl<T> IndexMut<RangeTo<index::Line>> for Grid<T> {
+ #[inline]
+ fn index_mut(&mut self, index: RangeTo<index::Line>) -> &mut [Row<T>] {
+ &mut self.raw[..(index.end.0)]
+ }
+}
+
+impl<T> Index<RangeFrom<index::Line>> for Grid<T> {
+ type Output = [Row<T>];
+
+ #[inline]
+ fn index(&self, index: RangeFrom<index::Line>) -> &[Row<T>] {
+ &self.raw[(index.start.0)..]
+ }
+}
+
+impl<T> IndexMut<RangeFrom<index::Line>> for Grid<T> {
+ #[inline]
+ fn index_mut(&mut self, index: RangeFrom<index::Line>) -> &mut [Row<T>] {
+ &mut self.raw[(index.start.0)..]
+ }
+}
+
+// -------------------------------------------------------------------------------------------------
+// Column ranges for Row
+// -------------------------------------------------------------------------------------------------
+
+impl<T> Index<Range<index::Column>> for Row<T> {
+ type Output = [T];
+
+ #[inline]
+ fn index(&self, index: Range<index::Column>) -> &[T] {
+ &self.0[(index.start.0)..(index.end.0)]
+ }
+}
+
+impl<T> IndexMut<Range<index::Column>> for Row<T> {
+ #[inline]
+ fn index_mut(&mut self, index: Range<index::Column>) -> &mut [T] {
+ &mut self.0[(index.start.0)..(index.end.0)]
+ }
+}
+
+impl<T> Index<RangeTo<index::Column>> for Row<T> {
+ type Output = [T];
+
+ #[inline]
+ fn index(&self, index: RangeTo<index::Column>) -> &[T] {
+ &self.0[..(index.end.0)]
+ }
+}
+
+impl<T> IndexMut<RangeTo<index::Column>> for Row<T> {
+ #[inline]
+ fn index_mut(&mut self, index: RangeTo<index::Column>) -> &mut [T] {
+ &mut self.0[..(index.end.0)]
+ }
+}
+
+impl<T> Index<RangeFrom<index::Column>> for Row<T> {
+ type Output = [T];
+
+ #[inline]
+ fn index(&self, index: RangeFrom<index::Column>) -> &[T] {
+ &self.0[(index.start.0)..]
+ }
+}
+
+impl<T> IndexMut<RangeFrom<index::Column>> for Row<T> {
+ #[inline]
+ fn index_mut(&mut self, index: RangeFrom<index::Column>) -> &mut [T] {
+ &mut self.0[(index.start.0)..]
+ }
+}
+
+pub trait ClearRegion<R, T> {
+ fn clear_region<F: Fn(&mut T)>(&mut self, region: R, func: F);
}
macro_rules! clear_region_impl {
($range:ty) => {
- impl ClearRegion<$range> for Grid {
- fn clear_region(&mut self, region: $range) {
- for row in self.raw[region].iter_mut() {
+ impl<T> ClearRegion<$range, T> for Grid<T> {
+ fn clear_region<F: Fn(&mut T)>(&mut self, region: $range, func: F) {
+ for row in self[region].iter_mut() {
for cell in row {
- cell.reset();
+ func(cell);
}
}
}
@@ -323,6 +639,6 @@ macro_rules! clear_region_impl {
}
}
-clear_region_impl!(Range<usize>);
-clear_region_impl!(RangeTo<usize>);
-clear_region_impl!(RangeFrom<usize>);
+clear_region_impl!(Range<index::Line>);
+clear_region_impl!(RangeTo<index::Line>);
+clear_region_impl!(RangeFrom<index::Line>);
diff --git a/src/main.rs b/src/main.rs
index aae02322..e73ec15c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -18,6 +18,8 @@
#![feature(inclusive_range_syntax)]
#![feature(drop_types_in_const)]
#![feature(unicode)]
+#![feature(zero_one)]
+#![feature(step_trait)]
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]
diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs
index 19a69b8b..c967fa05 100644
--- a/src/renderer/mod.rs
+++ b/src/renderer/mod.rs
@@ -27,8 +27,8 @@ use gl;
use notify::{Watcher as WatcherApi, RecommendedWatcher as Watcher, op};
use font::{Rasterizer, RasterizedGlyph, FontDesc};
-use grid::{self, Grid, Cell, CellFlags};
-use term;
+use grid::{self, Grid};
+use term::{self, cell, Cell};
use super::Rgb;
@@ -80,8 +80,8 @@ pub struct Glyph {
/// Naïve glyph cache
///
-/// Currently only keyed by `char`, and thus not possible to hold different representations of the
-/// same code point.
+/// Currently only keyed by `char`, and thus not possible to hold different
+/// representations of the same code point.
pub struct GlyphCache {
/// Cache of buffered glyphs
cache: HashMap<char, Glyph>,
@@ -236,7 +236,7 @@ impl Batch {
bg_b: cell.bg.b as f32,
};
- if cell.flags.contains(grid::INVERSE) {
+ if cell.flags.contains(cell::INVERSE) {
instance.r = cell.bg.r as f32;
instance.g = cell.bg.g as f32;
instance.b = cell.bg.b as f32;
@@ -550,7 +550,7 @@ impl<'a> RenderApi<'a> {
c: c,
fg: *color,
bg: term::DEFAULT_BG,
- flags: grid::INVERSE,
+ flags: cell::INVERSE,
};
self.add_render_item(row, col, &cell, glyph);
}
@@ -576,22 +576,25 @@ impl<'a> RenderApi<'a> {
}
}
- pub fn render_cursor(&mut self, cursor: term::Cursor, glyph_cache: &mut GlyphCache) {
+ pub fn render_cursor(&mut self, cursor: &grid::index::Cursor, glyph_cache: &mut GlyphCache) {
if let Some(glyph) = glyph_cache.get(term::CURSOR_SHAPE, self) {
let cell = Cell {
c: term::CURSOR_SHAPE,
fg: term::DEFAULT_FG,
bg: term::DEFAULT_BG,
- flags: CellFlags::empty(),
+ flags: cell::Flags::empty(),
};
- self.add_render_item(cursor.y as f32, cursor.x as f32, &cell, glyph);
+ let y: usize = *cursor.line;
+ let x: usize = *cursor.col;
+
+ self.add_render_item(y as f32, x as f32, &cell, glyph);
}
}
- pub fn render_grid(&mut self, grid: &Grid, glyph_cache: &mut GlyphCache) {
- for (i, row) in grid.rows().enumerate() {
- for (j, cell) in row.cells().enumerate() {
+ pub fn render_grid(&mut self, grid: &Grid<Cell>, glyph_cache: &mut GlyphCache) {
+ for (i, line) in grid.lines().enumerate() {
+ for (j, cell) in line.cells().enumerate() {
// Skip empty cells
if cell.c == ' ' && cell.bg == term::DEFAULT_BG {
continue;
diff --git a/src/term.rs b/src/term.rs
index 699df8de..9c8cff30 100644
--- a/src/term.rs
+++ b/src/term.rs
@@ -14,9 +14,10 @@
//
//! Exports the `Term` type which is a high-level API for the Grid
use std::ops::Range;
+use std::fmt;
use ansi::{self, Attr};
-use grid::{self, Grid, CellFlags, ClearRegion};
+use grid::{Grid, ClearRegion};
use tty;
use ::Rgb;
@@ -31,6 +32,49 @@ fn limit<T: PartialOrd>(val: T, min: T, max: T) -> T {
}
}
+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;
+
/// tomorrow night bright
///
/// because contrast
@@ -78,37 +122,31 @@ 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,
-}
+use grid::index::{Cursor, Column, Line};
-impl Default for Cursor {
- fn default() -> Cursor {
- Cursor { x: 0, y: 0 }
- }
+trait CursorExt {
+ fn goto(&mut self, Line, Column);
+ fn advance(&mut self, Line, Column);
}
-impl Cursor {
- pub fn goto(&mut self, x: u16, y: u16) {
- self.x = x;
- self.y = y;
+impl CursorExt for Cursor {
+ fn goto(&mut self, line: Line, col: Column) {
+ self.col = col;
+ self.line = line;
}
- 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;
+ fn advance(&mut self, lines: Line, cols: Column) {
+ self.col = self.col + cols;
+ self.line = self.line + lines;
}
}
pub struct Term {
/// The grid
- grid: Grid,
+ grid: Grid<Cell>,
/// Alternate grid
- alt_grid: Grid,
+ alt_grid: Grid<Cell>,
/// Alt is active
alt: bool,
@@ -132,13 +170,13 @@ pub struct Term {
tabs: Vec<bool>,
/// Cell attributes
- attr: grid::CellFlags,
+ attr: cell::Flags,
/// Mode flags
mode: TermMode,
/// Scroll region
- scroll_region: Range<usize>,
+ scroll_region: Range<Line>,
/// Size
size_info: SizeInfo,
@@ -162,13 +200,13 @@ pub struct SizeInfo {
impl SizeInfo {
#[inline]
- pub fn rows(&self) -> usize {
- (self.height / self.cell_height) as usize
+ pub fn lines(&self) -> Line {
+ Line((self.height / self.cell_height) as usize)
}
#[inline]
- pub fn cols(&self) -> usize {
- (self.width / self.cell_width) as usize
+ pub fn cols(&self) -> Column {
+ Column((self.width / self.cell_width) as usize)
}
}
@@ -182,21 +220,21 @@ impl Term {
};
let num_cols = size.cols();
- let num_rows = size.rows();
+ let num_lines = size.lines();
- println!("num_cols, num_rows = {}, {}", num_cols, num_rows);
+ println!("num_cols, num_lines = {}, {}", num_cols, num_lines);
- let grid = Grid::new(num_rows, num_cols);
+ let grid = Grid::new(num_lines, num_cols, &Cell::new(' '));
- let tty = tty::new(num_rows as u8, num_cols as u8);
- tty.resize(num_rows, num_cols, size.width as usize, size.height as usize);
+ 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);
- let mut tabs = (0..grid.num_cols()).map(|i| i % TAB_SPACES == 0)
- .collect::<Vec<bool>>();
+ let mut tabs = (Column(0)..grid.num_cols()).map(|i| (*i as usize) % TAB_SPACES == 0)
+ .collect::<Vec<bool>>();
tabs[0] = false;
let alt = grid.clone();
- let scroll_region = 0..grid.num_rows();
+ let scroll_region = Line(0)..grid.num_lines();
Term {
grid: grid,
@@ -208,7 +246,7 @@ impl Term {
bg: DEFAULT_BG,
tty: tty,
tabs: tabs,
- attr: CellFlags::empty(),
+ attr: cell::Flags::empty(),
mode: Default::default(),
scroll_region: scroll_region,
size_info: size
@@ -225,52 +263,51 @@ impl Term {
};
let old_cols = self.size_info.cols();
- let old_rows = self.size_info.rows();
+ let old_lines = self.size_info.lines();
let num_cols = size.cols();
- let num_rows = size.rows();
+ let num_lines = size.lines();
self.size_info = size;
- if old_cols == num_cols && old_rows == num_rows {
+ if old_cols == num_cols && old_lines == num_lines {
return;
}
// Scroll up to keep cursor and as much context as possible in grid. This only runs when the
- // rows decreases.
- self.scroll_region = 0..self.grid.num_rows();
- // XXX why is +1 required?
- let row_diff = (self.cursor_y() as isize - num_rows as isize) + 1;
- if row_diff > 0 {
- self.scroll(row_diff);
- self.cursor.advance(-row_diff as i64, 0);
+ // 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;
}
- println!("num_cols, num_rows = {}, {}", num_cols, num_rows);
+ println!("num_cols, num_lines = {}, {}", num_cols, num_lines);
// Resize grids to new size
- self.grid.resize(num_rows, num_cols);
- self.alt_grid.resize(num_rows, num_cols);
+ self.grid.resize(num_lines, num_cols, &Cell::new(' '));
+ self.alt_grid.resize(num_lines, num_cols, &Cell::new(' '));
// Ensure cursor is in-bounds
- self.cursor.y = limit(self.cursor.y, 0, num_rows as u16);
- self.cursor.x = limit(self.cursor.x, 0, num_cols as u16);
+ self.cursor.line = limit(self.cursor.line, Line(0), num_lines);
+ self.cursor.col = limit(self.cursor.col, Column(0), num_cols);
// Recreate tabs list
- self.tabs = (0..self.grid.num_cols()).map(|i| i % TAB_SPACES == 0)
- .collect::<Vec<bool>>();
+ self.tabs = (Column(0)..self.grid.num_cols()).map(|i| (*i as usize) % TAB_SPACES == 0)
+ .collect::<Vec<bool>>();
// Make sure bottom of terminal is clear
- if row_diff > 0 {
- self.grid.clear_region((self.cursor.y as usize)..);
- self.alt_grid.clear_region((self.cursor.y as usize)..);
- }
+ self.grid.clear_region((self.cursor.line).., |c| c.reset());
+ self.alt_grid.clear_region((self.cursor.line).., |c| c.reset());
// Reset scrolling region to new size
- self.scroll_region = 0..self.grid.num_rows();
+ self.scroll_region = Line(0)..self.grid.num_lines();
// Inform tty of new dimensions
- self.tty.resize(num_rows,
- num_cols,
+ self.tty.resize(*num_lines as _,
+ *num_cols as _,
self.size_info.width as usize,
self.size_info.height as usize);
@@ -286,7 +323,8 @@ impl Term {
&self.size_info
}
- pub fn grid(&self) -> &Grid {
+ #[inline]
+ pub fn grid(&self) -> &Grid<Cell> {
&self.grid
}
@@ -301,38 +339,28 @@ impl Term {
::std::mem::swap(&mut self.cursor, &mut self.alt_cursor);
if self.alt {
- self.grid.clear();
+ self.grid.clear(|c| c.reset());
}
}
#[inline]
- pub fn cursor_x(&self) -> u16 {
- self.cursor.x
- }
-
- #[inline]
- pub fn cursor_y(&self) -> u16 {
- self.cursor.y
- }
-
- #[inline]
- pub fn cursor(&self) -> Cursor {
- self.cursor
+ pub fn cursor(&self) -> &Cursor {
+ &self.cursor
}
/// Set character in current cursor position
fn set_char(&mut self, c: char) {
- if self.cursor.x == self.grid.num_cols() as u16 {
+ if self.cursor.col == self.grid.num_cols() {
println!("wrapping");
- self.cursor.y += 1;
- self.cursor.x = 0;
+ self.cursor.line += 1;
+ self.cursor.col = Column(0);
}
- if self.cursor.y == self.grid.num_rows() as u16 {
+ if self.cursor.line == self.grid.num_lines() {
panic!("cursor fell off grid");
}
- let cell = &mut self.grid[self.cursor];
+ let cell = &mut self.grid[&self.cursor];
cell.c = c;
cell.fg = self.fg;
cell.bg = self.bg;
@@ -340,17 +368,44 @@ impl Term {
}
/// Convenience function for scrolling
- fn scroll(&mut self, count: isize) {
- println!("[TERM] scrolling {} lines", count);
- self.grid.scroll(self.scroll_region.clone(), count);
- if count > 0 {
- // Scrolled down, so need to clear from bottom
- let start = self.scroll_region.end - (count as usize);
- self.grid.clear_region(start..self.scroll_region.end);
- } else {
- // Scrolled up, clear from top
- let end = self.scroll_region.start + ((-count) as usize);
- self.grid.clear_region(self.scroll_region.start..end);
+ 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"),
}
}
}
@@ -358,12 +413,12 @@ impl Term {
impl ansi::TermInfo for Term {
#[inline]
fn rows(&self) -> usize {
- self.grid.num_rows()
+ *self.grid.num_lines() as usize
}
#[inline]
fn cols(&self) -> usize {
- self.grid.num_cols()
+ *self.grid.num_cols() as usize
}
}
@@ -372,90 +427,90 @@ impl ansi::Handler for Term {
#[inline]
fn input(&mut self, c: char) {
self.set_char(c);
- self.cursor.x += 1;
+ self.cursor.col += 1;
}
+ #[inline]
fn goto(&mut self, x: i64, y: i64) {
println!("goto: x={}, y={}", x, y);
- self.cursor.goto(x as u16, y as u16);
+ self.cursor.goto(Line(y as usize), Column(x as usize));
}
- fn goto_row(&mut self, y: i64) {
- println!("goto_row: {}", y);
- let x = self.cursor_x();
- self.cursor.goto(x, y as u16);
+
+ fn goto_row(&mut self, row: i64) {
+ println!("goto_row: {}", row);
+ self.cursor.line = Line(row as usize);
}
- fn goto_col(&mut self, x: i64) {
- println!("goto_col: {}", x);
- let y = self.cursor_y();
- self.cursor.goto(x as u16, y);
+ fn goto_col(&mut self, col: i64) {
+ println!("goto_col: {}", col);
+ self.cursor.col = Column(col as usize);
}
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);
+ self.cursor.line -= Line(rows as usize);
}
fn move_down(&mut self, rows: i64) {
println!("move_down: {}", rows);
- self.cursor.advance(rows, 0);
+ self.cursor.line += Line(rows as usize);
}
fn move_forward(&mut self, cols: i64) {
println!("move_forward: {}", cols);
- self.cursor.advance(0, cols);
+ self.cursor.col += Column(cols as usize);
}
fn move_backward(&mut self, spaces: i64) {
println!("move_backward: {}", spaces);
- self.cursor.advance(0, -spaces);
+ self.cursor.col -= Column(spaces as usize);
}
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.num_cols() as u16 && count != 0 {
+ let mut col = self.cursor.col;
+ while col < self.grid.num_cols() && count != 0 {
count -= 1;
loop {
- if x == self.grid.num_cols() as u16 || self.tabs[x as usize] {
+ if col == self.grid.num_cols() || self.tabs[*col as usize] {
break;
}
- x += 1;
+ col += 1;
}
}
- self.cursor.x = x;
+ self.cursor.col = col;
}
/// Backspace `count` characters
#[inline]
fn backspace(&mut self) {
println!("backspace");
- self.cursor.x -= 1;
+ self.cursor.col -= 1;
}
/// Carriage return
#[inline]
fn carriage_return(&mut self) {
println!("carriage_return");
- self.cursor.x = 0;
+ self.cursor.col = Column(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.scroll_region.end as u16 {
- self.scroll(1);
+ if self.cursor.line + 1 >= self.scroll_region.end {
+ self.scroll(Line(1), ScrollDirection::Down);
self.clear_line(ansi::LineClearMode::Right);
} else {
- self.cursor.y += 1;
+ self.cursor.line += 1;
}
}
@@ -466,31 +521,30 @@ impl ansi::Handler for Term {
fn set_horizontal_tabstop(&mut self) { println!("set_horizontal_tabstop"); }
fn scroll_up(&mut self, rows: i64) {
println!("scroll_up: {}", rows);
- self.scroll(rows as isize);
+ self.scroll(Line(rows as usize), ScrollDirection::Up);
}
fn scroll_down(&mut self, rows: i64) {
println!("scroll_down: {}", rows);
- self.scroll(-rows as isize);
+ self.scroll(Line(rows as usize), ScrollDirection::Down);
}
fn insert_blank_lines(&mut self, count: i64) {
println!("insert_blank_lines: {}", count);
- if self.scroll_region.contains(self.cursor_y() as usize) {
- self.scroll(-count as isize);
+ if self.scroll_region.contains(self.cursor.line) {
+ self.scroll(Line(count as usize), ScrollDirection::Down);
}
}
fn delete_lines(&mut self, count: i64) {
- if self.scroll_region.contains(self.cursor_y() as usize) {
- self.scroll(count as isize);
+ if self.scroll_region.contains(self.cursor.line) {
+ self.scroll(Line(count as usize), ScrollDirection::Up);
}
}
fn erase_chars(&mut self, count: i64) {
println!("erase_chars: {}", count);
- let row_index = self.cursor.y as usize;
- let col_index = self.cursor.x as usize;
+ let col_index = self.cursor.col;
let count = count as usize;
- let row = &mut self.grid[row_index];
- for c in &mut row[col_index..(count + col_index)] {
+ let row = &mut self.grid[self.cursor.line];
+ for c in &mut row[self.cursor.col..(col_index + count)] {
c.reset();
}
}
@@ -503,9 +557,8 @@ impl ansi::Handler for Term {
println!("clear_line: {:?}", mode);
match mode {
ansi::LineClearMode::Right => {
- let row = &mut self.grid[self.cursor.y as usize];
- let start = self.cursor.x as usize;
- for cell in &mut row[start..] {
+ let row = &mut self.grid[self.cursor.line];
+ for cell in &mut row[self.cursor.col..] {
cell.reset();
}
},
@@ -516,17 +569,17 @@ impl ansi::Handler for Term {
println!("clear_screen: {:?}", mode);
match mode {
ansi::ClearMode::Below => {
- let start = self.cursor_y() as usize;
- let end = self.grid.num_rows();
- for i in start..end {
- let row = &mut self.grid[i];
+ let start = self.cursor.line;
+ let end = self.grid.num_lines();
+
+ for row in &mut self.grid[start..end] {
for cell in row {
cell.reset();
}
}
},
ansi::ClearMode::All => {
- self.grid.clear();
+ self.grid.clear(|c| c.reset());
},
_ => {
panic!("ansi::ClearMode::Above not implemented");
@@ -538,13 +591,10 @@ impl ansi::Handler for Term {
fn reverse_index(&mut self) {
println!("reverse_index");
// if cursor is at the top
- if self.cursor.y == 0 {
- self.scroll(-1);
+ if self.cursor.col == Column(0) {
+ self.scroll(Line(1), ScrollDirection::Up);
} 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);
+ self.cursor.col -= 1;
}
}
@@ -572,16 +622,16 @@ impl ansi::Handler for Term {
Attr::Reset => {
self.fg = DEFAULT_FG;
self.bg = DEFAULT_BG;
- self.attr = CellFlags::empty();
+ self.attr = cell::Flags::empty();
},
- Attr::Reverse => self.attr.insert(grid::INVERSE),
- Attr::CancelReverse => self.attr.remove(grid::INVERSE),
- Attr::Bold => self.attr.insert(grid::BOLD),
- Attr::CancelBoldDim => self.attr.remove(grid::BOLD),
- Attr::Italic => self.attr.insert(grid::ITALIC),
- Attr::CancelItalic => self.attr.remove(grid::ITALIC),
- Attr::Underscore => self.attr.insert(grid::UNDERLINE),
- Attr::CancelUnderline => self.attr.remove(grid::UNDERLINE),
+ 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),
_ => {
println!("Term got unhandled attr: {:?}", attr);
}
@@ -615,6 +665,6 @@ impl ansi::Handler for Term {
fn set_scrolling_region(&mut self, top: i64, bot: i64) {
println!("set scroll region: {:?} - {:?}", top, bot);
// 1 is added to bottom for inclusive range
- self.scroll_region = (top as usize)..((bot as usize) + 1);
+ self.scroll_region = Line(top as usize)..Line((bot as usize) + 1);
}
}