summaryrefslogtreecommitdiffstats
path: root/alacritty_terminal
diff options
context:
space:
mode:
Diffstat (limited to 'alacritty_terminal')
-rw-r--r--alacritty_terminal/src/config/colors.rs2
-rw-r--r--alacritty_terminal/src/config/mod.rs32
-rw-r--r--alacritty_terminal/src/grid/mod.rs12
-rw-r--r--alacritty_terminal/src/index.rs41
-rw-r--r--alacritty_terminal/src/lib.rs1
-rw-r--r--alacritty_terminal/src/selection.rs106
-rw-r--r--alacritty_terminal/src/term/mod.rs456
-rw-r--r--alacritty_terminal/src/vi_mode.rs799
8 files changed, 1215 insertions, 234 deletions
diff --git a/alacritty_terminal/src/config/colors.rs b/alacritty_terminal/src/config/colors.rs
index 35c03684..5c057619 100644
--- a/alacritty_terminal/src/config/colors.rs
+++ b/alacritty_terminal/src/config/colors.rs
@@ -12,6 +12,8 @@ pub struct Colors {
#[serde(deserialize_with = "failure_default")]
pub cursor: CursorColors,
#[serde(deserialize_with = "failure_default")]
+ pub vi_mode_cursor: CursorColors,
+ #[serde(deserialize_with = "failure_default")]
pub selection: SelectionColors,
#[serde(deserialize_with = "failure_default")]
normal: NormalColors,
diff --git a/alacritty_terminal/src/config/mod.rs b/alacritty_terminal/src/config/mod.rs
index da95391c..df8d37bd 100644
--- a/alacritty_terminal/src/config/mod.rs
+++ b/alacritty_terminal/src/config/mod.rs
@@ -28,7 +28,7 @@ mod scrolling;
mod visual_bell;
mod window;
-use crate::ansi::{Color, CursorStyle, NamedColor};
+use crate::ansi::{CursorStyle, NamedColor};
pub use crate::config::colors::Colors;
pub use crate::config::debug::Debug;
@@ -170,16 +170,28 @@ impl<T> Config<T> {
self.dynamic_title.0
}
- /// Cursor foreground color
+ /// Cursor foreground color.
#[inline]
pub fn cursor_text_color(&self) -> Option<Rgb> {
self.colors.cursor.text
}
- /// Cursor background color
+ /// Cursor background color.
#[inline]
- pub fn cursor_cursor_color(&self) -> Option<Color> {
- self.colors.cursor.cursor.map(|_| Color::Named(NamedColor::Cursor))
+ pub fn cursor_cursor_color(&self) -> Option<NamedColor> {
+ self.colors.cursor.cursor.map(|_| NamedColor::Cursor)
+ }
+
+ /// Vi mode cursor foreground color.
+ #[inline]
+ pub fn vi_mode_cursor_text_color(&self) -> Option<Rgb> {
+ self.colors.vi_mode_cursor.text
+ }
+
+ /// Vi mode cursor background color.
+ #[inline]
+ pub fn vi_mode_cursor_cursor_color(&self) -> Option<Rgb> {
+ self.colors.vi_mode_cursor.cursor
}
#[inline]
@@ -230,20 +242,16 @@ impl Default for EscapeChars {
}
#[serde(default)]
-#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Eq)]
+#[derive(Deserialize, Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct Cursor {
#[serde(deserialize_with = "failure_default")]
pub style: CursorStyle,
+ #[serde(deserialize_with = "option_explicit_none")]
+ pub vi_mode_style: Option<CursorStyle>,
#[serde(deserialize_with = "failure_default")]
unfocused_hollow: DefaultTrueBool,
}
-impl Default for Cursor {
- fn default() -> Self {
- Self { style: Default::default(), unfocused_hollow: Default::default() }
- }
-}
-
impl Cursor {
pub fn unfocused_hollow(self) -> bool {
self.unfocused_hollow.0
diff --git a/alacritty_terminal/src/grid/mod.rs b/alacritty_terminal/src/grid/mod.rs
index 34d989db..37cf0eb6 100644
--- a/alacritty_terminal/src/grid/mod.rs
+++ b/alacritty_terminal/src/grid/mod.rs
@@ -264,11 +264,9 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
let mut new_empty_lines = 0;
let mut reversed: Vec<Row<T>> = Vec::with_capacity(self.raw.len());
for (i, mut row) in self.raw.drain().enumerate().rev() {
- // FIXME: Rust 1.39.0+ allows moving in pattern guard here
// Check if reflowing shoud be performed
- let mut last_row = reversed.last_mut();
- let last_row = match last_row {
- Some(ref mut last_row) if should_reflow(last_row) => last_row,
+ let last_row = match reversed.last_mut() {
+ Some(last_row) if should_reflow(last_row) => last_row,
_ => {
reversed.push(row);
continue;
@@ -356,11 +354,9 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
}
loop {
- // FIXME: Rust 1.39.0+ allows moving in pattern guard here
// Check if reflowing shoud be performed
- let wrapped = row.shrink(cols);
- let mut wrapped = match wrapped {
- Some(_) if reflow => wrapped.unwrap(),
+ let mut wrapped = match row.shrink(cols) {
+ Some(wrapped) if reflow => wrapped,
_ => {
new_raw.push(row);
break;
diff --git a/alacritty_terminal/src/index.rs b/alacritty_terminal/src/index.rs
index 56d32003..1334a74e 100644
--- a/alacritty_terminal/src/index.rs
+++ b/alacritty_terminal/src/index.rs
@@ -30,6 +30,15 @@ pub enum Side {
Right,
}
+impl Side {
+ pub fn opposite(self) -> Self {
+ match self {
+ Side::Right => Side::Left,
+ Side::Left => Side::Right,
+ }
+ }
+}
+
/// Index in the grid using row, column notation
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Serialize, Deserialize, PartialOrd)]
pub struct Point<L = Line> {
@@ -49,7 +58,7 @@ impl<L> Point<L> {
L: Copy + Default + Into<Line> + Add<usize, Output = L> + Sub<usize, Output = L>,
{
let line_changes =
- f32::ceil(rhs.saturating_sub(self.col.0) as f32 / num_cols as f32) as usize;
+ (rhs.saturating_sub(self.col.0) as f32 / num_cols as f32).ceil() as usize;
if self.line.into() > Line(line_changes) {
self.line = self.line - line_changes;
} else {
@@ -63,12 +72,40 @@ impl<L> Point<L> {
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn add(mut self, num_cols: usize, rhs: usize) -> Point<L>
where
- L: Add<usize, Output = L> + Sub<usize, Output = L>,
+ L: Copy + Default + Into<Line> + Add<usize, Output = L> + Sub<usize, Output = L>,
{
self.line = self.line + (rhs + self.col.0) / num_cols;
self.col = Column((self.col.0 + rhs) % num_cols);
self
}
+
+ #[inline]
+ #[must_use = "this returns the result of the operation, without modifying the original"]
+ pub fn sub_absolute(mut self, num_cols: usize, rhs: usize) -> Point<L>
+ where
+ L: Copy + Default + Into<Line> + Add<usize, Output = L> + Sub<usize, Output = L>,
+ {
+ self.line =
+ self.line + (rhs.saturating_sub(self.col.0) as f32 / num_cols as f32).ceil() as usize;
+ self.col = Column((num_cols + self.col.0 - rhs % num_cols) % num_cols);
+ self
+ }
+
+ #[inline]
+ #[must_use = "this returns the result of the operation, without modifying the original"]
+ pub fn add_absolute(mut self, num_cols: usize, rhs: usize) -> Point<L>
+ where
+ L: Copy + Default + Into<Line> + Add<usize, Output = L> + Sub<usize, Output = L>,
+ {
+ let line_changes = (rhs + self.col.0) / num_cols;
+ if self.line.into() > Line(line_changes) {
+ self.line = self.line - line_changes;
+ } else {
+ self.line = Default::default();
+ }
+ self.col = Column((self.col.0 + rhs) % num_cols);
+ self
+ }
}
impl Ord for Point {
diff --git a/alacritty_terminal/src/lib.rs b/alacritty_terminal/src/lib.rs
index 039f2b81..6991ffdc 100644
--- a/alacritty_terminal/src/lib.rs
+++ b/alacritty_terminal/src/lib.rs
@@ -37,6 +37,7 @@ pub mod sync;
pub mod term;
pub mod tty;
pub mod util;
+pub mod vi_mode;
pub use crate::grid::Grid;
pub use crate::term::Term;
diff --git a/alacritty_terminal/src/selection.rs b/alacritty_terminal/src/selection.rs
index f663417f..369846cf 100644
--- a/alacritty_terminal/src/selection.rs
+++ b/alacritty_terminal/src/selection.rs
@@ -27,7 +27,7 @@ use crate::term::{Search, Term};
/// A Point and side within that point.
#[derive(Debug, Copy, Clone, PartialEq)]
-pub struct Anchor {
+struct Anchor {
point: Point<usize>,
side: Side,
}
@@ -67,7 +67,7 @@ impl<L> SelectionRange<L> {
/// Different kinds of selection.
#[derive(Debug, Copy, Clone, PartialEq)]
-enum SelectionType {
+pub enum SelectionType {
Simple,
Block,
Semantic,
@@ -94,48 +94,20 @@ enum SelectionType {
/// [`update`]: enum.Selection.html#method.update
#[derive(Debug, Clone, PartialEq)]
pub struct Selection {
+ pub ty: SelectionType,
region: Range<Anchor>,
- ty: SelectionType,
}
impl Selection {
- pub fn simple(location: Point<usize>, side: Side) -> Selection {
+ pub fn new(ty: SelectionType, location: Point<usize>, side: Side) -> Selection {
Self {
region: Range { start: Anchor::new(location, side), end: Anchor::new(location, side) },
- ty: SelectionType::Simple,
+ ty,
}
}
- pub fn block(location: Point<usize>, side: Side) -> Selection {
- Self {
- region: Range { start: Anchor::new(location, side), end: Anchor::new(location, side) },
- ty: SelectionType::Block,
- }
- }
-
- pub fn semantic(location: Point<usize>) -> Selection {
- Self {
- region: Range {
- start: Anchor::new(location, Side::Left),
- end: Anchor::new(location, Side::Right),
- },
- ty: SelectionType::Semantic,
- }
- }
-
- pub fn lines(location: Point<usize>) -> Selection {
- Self {
- region: Range {
- start: Anchor::new(location, Side::Left),
- end: Anchor::new(location, Side::Right),
- },
- ty: SelectionType::Lines,
- }
- }
-
- pub fn update(&mut self, location: Point<usize>, side: Side) {
- self.region.end.point = location;
- self.region.end.side = side;
+ pub fn update(&mut self, point: Point<usize>, side: Side) {
+ self.region.end = Anchor::new(point, side);
}
pub fn rotate(
@@ -233,6 +205,24 @@ impl Selection {
}
}
+ /// Expand selection sides to include all cells.
+ pub fn include_all(&mut self) {
+ let (start, end) = (self.region.start.point, self.region.end.point);
+ let (start_side, end_side) = match self.ty {
+ SelectionType::Block
+ if start.col > end.col || (start.col == end.col && start.line < end.line) =>
+ {
+ (Side::Right, Side::Left)
+ },
+ SelectionType::Block => (Side::Left, Side::Right),
+ _ if Self::points_need_swap(start, end) => (Side::Right, Side::Left),
+ _ => (Side::Left, Side::Right),
+ };
+
+ self.region.start.side = start_side;
+ self.region.end.side = end_side;
+ }
+
/// Convert selection to grid coordinates.
pub fn to_range<T>(&self, term: &Term<T>) -> Option<SelectionRange> {
let grid = term.grid();
@@ -392,7 +382,8 @@ impl Selection {
/// look like [ B] and [E ].
#[cfg(test)]
mod tests {
- use super::{Selection, SelectionRange};
+ use super::*;
+
use crate::clipboard::Clipboard;
use crate::config::MockConfig;
use crate::event::{Event, EventListener};
@@ -425,7 +416,7 @@ mod tests {
#[test]
fn single_cell_left_to_right() {
let location = Point { line: 0, col: Column(0) };
- let mut selection = Selection::simple(location, Side::Left);
+ let mut selection = Selection::new(SelectionType::Simple, location, Side::Left);
selection.update(location, Side::Right);
assert_eq!(selection.to_range(&term(1, 1)).unwrap(), SelectionRange {
@@ -443,7 +434,7 @@ mod tests {
#[test]
fn single_cell_right_to_left() {
let location = Point { line: 0, col: Column(0) };
- let mut selection = Selection::simple(location, Side::Right);
+ let mut selection = Selection::new(SelectionType::Simple, location, Side::Right);
selection.update(location, Side::Left);
assert_eq!(selection.to_range(&term(1, 1)).unwrap(), SelectionRange {
@@ -460,7 +451,8 @@ mod tests {
/// 3. [ B][E ]
#[test]
fn between_adjacent_cells_left_to_right() {
- let mut selection = Selection::simple(Point::new(0, Column(0)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Simple, Point::new(0, Column(0)), Side::Right);
selection.update(Point::new(0, Column(1)), Side::Left);
assert_eq!(selection.to_range(&term(2, 1)), None);
@@ -473,7 +465,8 @@ mod tests {
/// 3. [ E][B ]
#[test]
fn between_adjacent_cells_right_to_left() {
- let mut selection = Selection::simple(Point::new(0, Column(1)), Side::Left);
+ let mut selection =
+ Selection::new(SelectionType::Simple, Point::new(0, Column(1)), Side::Left);
selection.update(Point::new(0, Column(0)), Side::Right);
assert_eq!(selection.to_range(&term(2, 1)), None);
@@ -489,7 +482,8 @@ mod tests {
/// [XX][XE][ ][ ][ ]
#[test]
fn across_adjacent_lines_upward_final_cell_exclusive() {
- let mut selection = Selection::simple(Point::new(1, Column(1)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Simple, Point::new(1, Column(1)), Side::Right);
selection.update(Point::new(0, Column(1)), Side::Right);
assert_eq!(selection.to_range(&term(5, 2)).unwrap(), SelectionRange {
@@ -511,7 +505,8 @@ mod tests {
/// [XX][XB][ ][ ][ ]
#[test]
fn selection_bigger_then_smaller() {
- let mut selection = Selection::simple(Point::new(0, Column(1)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Simple, Point::new(0, Column(1)), Side::Right);
selection.update(Point::new(1, Column(1)), Side::Right);
selection.update(Point::new(1, Column(0)), Side::Right);
@@ -526,7 +521,8 @@ mod tests {
fn line_selection() {
let num_lines = 10;
let num_cols = 5;
- let mut selection = Selection::lines(Point::new(0, Column(1)));
+ let mut selection =
+ Selection::new(SelectionType::Lines, Point::new(0, Column(1)), Side::Left);
selection.update(Point::new(5, Column(1)), Side::Right);
selection = selection.rotate(num_lines, num_cols, &(Line(0)..Line(num_lines)), 7).unwrap();
@@ -541,7 +537,8 @@ mod tests {
fn semantic_selection() {
let num_lines = 10;
let num_cols = 5;
- let mut selection = Selection::semantic(Point::new(0, Column(3)));
+ let mut selection =
+ Selection::new(SelectionType::Semantic, Point::new(0, Column(3)), Side::Left);
selection.update(Point::new(5, Column(1)), Side::Right);
selection = selection.rotate(num_lines, num_cols, &(Line(0)..Line(num_lines)), 7).unwrap();
@@ -556,7 +553,8 @@ mod tests {
fn simple_selection() {
let num_lines = 10;
let num_cols = 5;
- let mut selection = Selection::simple(Point::new(0, Column(3)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Simple, Point::new(0, Column(3)), Side::Right);
selection.update(Point::new(5, Column(1)), Side::Right);
selection = selection.rotate(num_lines, num_cols, &(Line(0)..Line(num_lines)), 7).unwrap();
@@ -571,7 +569,8 @@ mod tests {
fn block_selection() {
let num_lines = 10;
let num_cols = 5;
- let mut selection = Selection::block(Point::new(0, Column(3)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Block, Point::new(0, Column(3)), Side::Right);
selection.update(Point::new(5, Column(1)), Side::Right);
selection = selection.rotate(num_lines, num_cols, &(Line(0)..Line(num_lines)), 7).unwrap();
@@ -584,7 +583,8 @@ mod tests {
#[test]
fn simple_is_empty() {
- let mut selection = Selection::simple(Point::new(0, Column(0)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Simple, Point::new(0, Column(0)), Side::Right);
assert!(selection.is_empty());
selection.update(Point::new(0, Column(1)), Side::Left);
assert!(selection.is_empty());
@@ -594,7 +594,8 @@ mod tests {
#[test]
fn block_is_empty() {
- let mut selection = Selection::block(Point::new(0, Column(0)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Block, Point::new(0, Column(0)), Side::Right);
assert!(selection.is_empty());
selection.update(Point::new(0, Column(1)), Side::Left);
assert!(selection.is_empty());
@@ -612,7 +613,8 @@ mod tests {
fn rotate_in_region_up() {
let num_lines = 10;
let num_cols = 5;
- let mut selection = Selection::simple(Point::new(2, Column(3)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Simple, Point::new(2, Column(3)), Side::Right);
selection.update(Point::new(5, Column(1)), Side::Right);
selection =
selection.rotate(num_lines, num_cols, &(Line(1)..Line(num_lines - 1)), 4).unwrap();
@@ -628,7 +630,8 @@ mod tests {
fn rotate_in_region_down() {
let num_lines = 10;
let num_cols = 5;
- let mut selection = Selection::simple(Point::new(5, Column(3)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Simple, Point::new(5, Column(3)), Side::Right);
selection.update(Point::new(8, Column(1)), Side::Left);
selection =
selection.rotate(num_lines, num_cols, &(Line(1)..Line(num_lines - 1)), -5).unwrap();
@@ -644,7 +647,8 @@ mod tests {
fn rotate_in_region_up_block() {
let num_lines = 10;
let num_cols = 5;
- let mut selection = Selection::block(Point::new(2, Column(3)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Block, Point::new(2, Column(3)), Side::Right);
selection.update(Point::new(5, Column(1)), Side::Right);
selection =
selection.rotate(num_lines, num_cols, &(Line(1)..Line(num_lines - 1)), 4).unwrap();
diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs
index ac5e56b5..89c3723f 100644
--- a/alacritty_terminal/src/term/mod.rs
+++ b/alacritty_terminal/src/term/mod.rs
@@ -31,10 +31,11 @@ use crate::event::{Event, EventListener};
use crate::grid::{
BidirectionalIterator, DisplayIter, Grid, GridCell, IndexRegion, Indexed, Scroll,
};
-use crate::index::{self, Column, IndexRange, Line, Point};
+use crate::index::{self, Column, IndexRange, Line, Point, Side};
use crate::selection::{Selection, SelectionRange};
use crate::term::cell::{Cell, Flags, LineLength};
use crate::term::color::Rgb;
+use crate::vi_mode::{ViModeCursor, ViMotion};
pub mod cell;
pub mod color;
@@ -180,7 +181,17 @@ impl<T> Search for Term<T> {
}
}
-/// A key for caching cursor glyphs
+/// Cursor storing all information relevant for rendering.
+#[derive(Debug, Eq, PartialEq, Copy, Clone, Deserialize)]
+struct RenderableCursor {
+ text_color: Option<Rgb>,
+ cursor_color: Option<Rgb>,
+ key: CursorKey,
+ point: Point,
+ rendered: bool,
+}
+
+/// A key for caching cursor glyphs.
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash, Deserialize)]
pub struct CursorKey {
pub style: CursorStyle,
@@ -198,10 +209,7 @@ pub struct CursorKey {
pub struct RenderableCellsIter<'a, C> {
inner: DisplayIter<'a, Cell>,
grid: &'a Grid<Cell>,
- cursor: &'a Point,
- cursor_offset: usize,
- cursor_key: Option<CursorKey>,
- cursor_style: CursorStyle,
+ cursor: RenderableCursor,
config: &'a Config<C>,
colors: &'a color::List,
selection: Option<SelectionRange<Line>>,
@@ -216,12 +224,10 @@ impl<'a, C> RenderableCellsIter<'a, C> {
term: &'b Term<T>,
config: &'b Config<C>,
selection: Option<SelectionRange>,
- mut cursor_style: CursorStyle,
) -> RenderableCellsIter<'b, C> {
let grid = &term.grid;
let num_cols = grid.num_cols();
- let cursor_offset = grid.num_lines().0 - term.cursor.point.line.0 - 1;
let inner = grid.display_iter();
let selection_range = selection.and_then(|span| {
@@ -242,29 +248,13 @@ impl<'a, C> RenderableCellsIter<'a, C> {
Some(SelectionRange::new(start, end, span.is_block))
});
- // Load cursor glyph
- let cursor = &term.cursor.point;
- let cursor_visible = term.mode.contains(TermMode::SHOW_CURSOR) && grid.contains(cursor);
- let cursor_key = if cursor_visible {
- let is_wide =
- grid[cursor].flags.contains(Flags::WIDE_CHAR) && (cursor.col + 1) < num_cols;
- Some(CursorKey { style: cursor_style, is_wide })
- } else {
- // Use hidden cursor so text will not get inverted
- cursor_style = CursorStyle::Hidden;
- None
- };
-
RenderableCellsIter {
- cursor,
- cursor_offset,
+ cursor: term.renderable_cursor(config),
grid,
inner,
selection: selection_range,
config,
colors: &term.colors,
- cursor_key,
- cursor_style,
}
}
@@ -275,6 +265,18 @@ impl<'a, C> RenderableCellsIter<'a, C> {
None => return false,
};
+ // Do not invert block cursor at selection boundaries
+ if self.cursor.key.style == CursorStyle::Block
+ && self.cursor.point == point
+ && (selection.start == point
+ || selection.end == point
+ || (selection.is_block
+ && ((selection.start.line == point.line && selection.end.col == point.col)
+ || (selection.end.line == point.line && selection.start.col == point.col))))
+ {
+ return false;
+ }
+
// Point itself is selected
if selection.contains(point.col, point.line) {
return true;
@@ -442,43 +444,46 @@ impl<'a, C> Iterator for RenderableCellsIter<'a, C> {
#[inline]
fn next(&mut self) -> Option<Self::Item> {
loop {
- if self.cursor_offset == self.inner.offset() && self.inner.column() == self.cursor.col {
- let selected = self.is_selected(Point::new(self.cursor.line, self.cursor.col));
+ if self.cursor.point.line == self.inner.line()
+ && self.cursor.point.col == self.inner.column()
+ {
+ let selected = self.is_selected(self.cursor.point);
+
+ // Handle cell below cursor
+ if self.cursor.rendered {
+ let mut cell =
+ RenderableCell::new(self.config, self.colors, self.inner.next()?, selected);
- // Handle cursor
- if let Some(cursor_key) = self.cursor_key.take() {
+ if self.cursor.key.style == CursorStyle::Block {
+ mem::swap(&mut cell.bg, &mut cell.fg);
+
+ if let Some(color) = self.cursor.text_color {
+ cell.fg = color;
+ }
+ }
+
+ return Some(cell);
+ } else {
+ // Handle cursor
+ self.cursor.rendered = true;
+
+ let buffer_point = self.grid.visible_to_buffer(self.cursor.point);
let cell = Indexed {
- inner: self.grid[self.cursor],
- column: self.cursor.col,
- // Using `self.cursor.line` leads to inconsitent cursor position when
- // scrolling. See https://github.com/alacritty/alacritty/issues/2570 for more
- // info.
- line: self.inner.line(),
+ inner: self.grid[buffer_point.line][buffer_point.col],
+ column: self.cursor.point.col,
+ line: self.cursor.point.line,
};
let mut renderable_cell =
RenderableCell::new(self.config, self.colors, cell, selected);
- renderable_cell.inner = RenderableCellContent::Cursor(cursor_key);
+ renderable_cell.inner = RenderableCellContent::Cursor(self.cursor.key);
- if let Some(color) = self.config.cursor_cursor_color() {
- renderable_cell.fg = RenderableCell::compute_bg_rgb(self.colors, color);
+ if let Some(color) = self.cursor.cursor_color {
+ renderable_cell.fg = color;
}
return Some(renderable_cell);
- } else {
- let mut cell =
- RenderableCell::new(self.config, self.colors, self.inner.next()?, selected);
-
- if self.cursor_style == CursorStyle::Block {
- std::mem::swap(&mut cell.bg, &mut cell.fg);
-
- if let Some(color) = self.config.cursor_text_color() {
- cell.fg = color;
- }
- }
-
- return Some(cell);
}
} else {
let cell = self.inner.next()?;
@@ -497,26 +502,27 @@ pub mod mode {
use bitflags::bitflags;
bitflags! {
- pub struct TermMode: u16 {
- const SHOW_CURSOR = 0b0000_0000_0000_0001;
- const APP_CURSOR = 0b0000_0000_0000_0010;
- const APP_KEYPAD = 0b0000_0000_0000_0100;
- const MOUSE_REPORT_CLICK = 0b0000_0000_0000_1000;
- const BRACKETED_PASTE = 0b0000_0000_0001_0000;
- const SGR_MOUSE = 0b0000_0000_0010_0000;
- const MOUSE_MOTION = 0b0000_0000_0100_0000;
- const LINE_WRAP = 0b0000_0000_1000_0000;
- const LINE_FEED_NEW_LINE = 0b0000_0001_0000_0000;
- const ORIGIN = 0b0000_0010_0000_0000;
- const INSERT = 0b0000_0100_0000_0000;
- const FOCUS_IN_OUT = 0b0000_1000_0000_0000;
- const ALT_SCREEN = 0b0001_0000_0000_0000;
- const MOUSE_DRAG = 0b0010_0000_0000_0000;
- const MOUSE_MODE = 0b0010_0000_0100_1000;
- const UTF8_MOUSE = 0b0100_0000_0000_0000;
- const ALTERNATE_SCROLL = 0b1000_0000_0000_0000;
- const ANY = 0b1111_1111_1111_1111;
+ pub struct TermMode: u32 {
const NONE = 0;
+ const SHOW_CURSOR = 0b0000_0000_0000_0000_0001;
+ const APP_CURSOR = 0b0000_0000_0000_0000_0010;
+ const APP_KEYPAD = 0b0000_0000_0000_0000_0100;
+ const MOUSE_REPORT_CLICK = 0b0000_0000_0000_0000_1000;
+ const BRACKETED_PASTE = 0b0000_0000_0000_0001_0000;
+ const SGR_MOUSE = 0b0000_0000_0000_0010_0000;
+ const MOUSE_MOTION = 0b0000_0000_0000_0100_0000;
+ const LINE_WRAP = 0b0000_0000_0000_1000_0000;
+ const LINE_FEED_NEW_LINE = 0b0000_0000_0001_0000_0000;
+ const ORIGIN = 0b0000_0000_0010_0000_0000;
+ const INSERT = 0b0000_0000_0100_0000_0000;
+ const FOCUS_IN_OUT = 0b0000_0000_1000_0000_0000;
+ const ALT_SCREEN = 0b0000_0001_0000_0000_0000;
+ const MOUSE_DRAG = 0b0000_0010_0000_0000_0000;
+ const MOUSE_MODE = 0b0000_0010_0000_0100_1000;
+ const UTF8_MOUSE = 0b0000_0100_0000_0000_0000;
+ const ALTERNATE_SCROLL = 0b0000_1000_0000_0000_0000;
+ const VI = 0b0001_0000_0000_0000_0000;
+ const ANY = std::u32::MAX;
}
}
@@ -730,11 +736,69 @@ impl VisualBell {
}
}
+/// Terminal size info.
+#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq)]
+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,
+
+ /// Horizontal window padding.
+ pub padding_x: f32,
+
+ /// Horizontal window padding.
+ pub padding_y: f32,
+
+ /// DPI factor of the current window.
+ #[serde(default)]
+ pub dpr: f64,
+}
+
+impl SizeInfo {
+ #[inline]
+ pub fn lines(&self) -> Line {
+ Line(((self.height - 2. * self.padding_y) / self.cell_height) as usize)
+ }
+
+ #[inline]
+ pub fn cols(&self) -> Column {
+ Column(((self.width - 2. * self.padding_x) / self.cell_width) as usize)
+ }
+
+ /// Check if coordinates are inside the terminal grid.
+ ///
+ /// The padding is not counted as part of the grid.
+ pub fn contains_point(&self, x: usize, y: usize) -> bool {
+ x < (self.width - self.padding_x) as usize
+ && x >= self.padding_x as usize
+ && y < (self.height - self.padding_y) as usize
+ && y >= self.padding_y as usize
+ }
+
+ pub fn pixels_to_coords(&self, x: usize, y: usize) -> Point {
+ let col = Column(x.saturating_sub(self.padding_x as usize) / (self.cell_width as usize));
+ let line = Line(y.saturating_sub(self.padding_y as usize) / (self.cell_height as usize));
+
+ Point {
+ line: min(line, Line(self.lines().saturating_sub(1))),
+ col: min(col, Column(self.cols().saturating_sub(1))),
+ }
+ }
+}
+
pub struct Term<T> {
- /// Terminal focus
+ /// Terminal focus.
pub is_focused: bool,
- /// The grid
+ /// The grid.
grid: Grid<Cell>,
/// Tracks if the next call to input will need to first handle wrapping.
@@ -744,23 +808,25 @@ pub struct Term<T> {
/// arrays. Without it we would have to sanitize cursor.col every time we used it.
input_needs_wrap: bool,
- /// Alternate grid
+ /// Alternate grid.
alt_grid: Grid<Cell>,
- /// Alt is active
+ /// Alt is active.
alt: bool,
- /// The cursor
+ /// The cursor.
cursor: Cursor,
- /// The graphic character set, out of `charsets`, which ASCII is currently
- /// being mapped to
+ /// Cursor location for vi mode.
+ pub vi_mode_cursor: ViModeCursor,
+
+ /// Index into `charsets`, pointing to what ASCII is currently being mapped to.
active_charset: CharsetIndex,
- /// Tabstops
+ /// Tabstops.
tabs: TabStops,
- /// Mode flags
+ /// Mode flags.
mode: TermMode,
/// Scroll region.
@@ -772,33 +838,36 @@ pub struct Term<T> {
pub visual_bell: VisualBell,
- /// Saved cursor from main grid
+ /// Saved cursor from main grid.
cursor_save: Cursor,
- /// Saved cursor from alt grid
+ /// Saved cursor from alt grid.
cursor_save_alt: Cursor,
semantic_escape_chars: String,
- /// Colors used for rendering
+ /// Colors used for rendering.
colors: color::List,
- /// Is color in `colors` modified or not
+ /// Is color in `colors` modified or not.
color_modified: [bool; color::COUNT],
- /// Original colors from config
+ /// Original colors from config.
original_colors: color::List,
- /// Current style of the cursor
+ /// Current style of the cursor.
cursor_style: Option<CursorStyle>,
- /// Default style for resetting the cursor
+ /// Default style for resetting the cursor.
default_cursor_style: CursorStyle,
+ /// Style of the vi mode cursor.
+ vi_mode_cursor_style: Option<CursorStyle>,
+
/// Clipboard access coupled to the active window
clipboard: Clipboard,
- /// Proxy for sending events to the event loop
+ /// Proxy for sending events to the event loop.
event_proxy: T,
/// Current title of the window.
@@ -815,64 +884,6 @@ pub struct Term<T> {
title_stack: Vec<Option<String>>,
}
-/// Terminal size info
-#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq)]
-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,
-
- /// Horizontal window padding
- pub padding_x: f32,
-
- /// Horizontal window padding
- pub padding_y: f32,
-
- /// DPI factor of the current window
- #[serde(default)]
- pub dpr: f64,
-}
-
-impl SizeInfo {
- #[inline]
- pub fn lines(&self) -> Line {
- Line(((self.height - 2. * self.padding_y) / self.cell_height) as usize)
- }
-
- #[inline]