mirror of
https://github.com/alacritty/alacritty.git
synced 2025-07-31 22:03:40 -04:00
Add support for Beam, Underline cursors
Notable about this implementation is it takes a different approach for managing cursor cells that previously. The terminal Grid is now borrowed *immutably*. Instead of mutating Cells in the Grid, a list is managed within the RenderableCellsIter. The cell at the cursor location is skipped over, and instead cells are popped off a list of cursor cells. It would be good in the future to share some more code between the different cursor style implementations for populating the cursor cells list. Supercedes #349.
This commit is contained in:
parent
9825adf695
commit
529ac47fc8
6 changed files with 274 additions and 108 deletions
26
Cargo.lock
generated
26
Cargo.lock
generated
|
@ -2,6 +2,7 @@
|
||||||
name = "alacritty"
|
name = "alacritty"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"arraydeque 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cgmath 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cgmath 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -38,6 +39,15 @@ name = "ansi_term"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arraydeque"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"nodrop 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
@ -624,6 +634,14 @@ dependencies = [
|
||||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nodrop"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "1.2.4"
|
version = "1.2.4"
|
||||||
|
@ -740,6 +758,11 @@ dependencies = [
|
||||||
"objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "odds"
|
||||||
|
version = "0.2.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "osmesa-sys"
|
name = "osmesa-sys"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
@ -1223,6 +1246,7 @@ dependencies = [
|
||||||
[metadata]
|
[metadata]
|
||||||
"checksum android_glue 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d8289e9637439939cc92b1995b0972117905be88bc28116c86b64d6e589bcd38"
|
"checksum android_glue 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d8289e9637439939cc92b1995b0972117905be88bc28116c86b64d6e589bcd38"
|
||||||
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
|
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
|
||||||
|
"checksum arraydeque 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "96e774cadb24c2245225280c6799793f9802b918a58a79615e9490607489a717"
|
||||||
"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
|
"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
|
||||||
"checksum bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "32866f4d103c4e438b1db1158aa1b1a80ee078e5d77a59a2f906fd62a577389c"
|
"checksum bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "32866f4d103c4e438b1db1158aa1b1a80ee078e5d77a59a2f906fd62a577389c"
|
||||||
"checksum bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3"
|
"checksum bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3"
|
||||||
|
@ -1287,6 +1311,7 @@ dependencies = [
|
||||||
"checksum net2 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "bc01404e7568680f1259aa5729539f221cb1e6d047a0d9053cab4be8a73b5d67"
|
"checksum net2 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "bc01404e7568680f1259aa5729539f221cb1e6d047a0d9053cab4be8a73b5d67"
|
||||||
"checksum nix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfb3ddedaa14746434a02041940495bf11325c22f6d36125d3bdd56090d50a79"
|
"checksum nix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfb3ddedaa14746434a02041940495bf11325c22f6d36125d3bdd56090d50a79"
|
||||||
"checksum nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0d95c5fa8b641c10ad0b8887454ebaafa3c92b5cd5350f8fc693adafd178e7b"
|
"checksum nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0d95c5fa8b641c10ad0b8887454ebaafa3c92b5cd5350f8fc693adafd178e7b"
|
||||||
|
"checksum nodrop 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "52cd74cd09beba596430cc6e3091b74007169a56246e1262f0ba451ea95117b2"
|
||||||
"checksum nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"
|
"checksum nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"
|
||||||
"checksum notify 2.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4e0e7eec936337952c4228b023007528a33b2fa039d96c2e8f32d764221a9c07"
|
"checksum notify 2.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4e0e7eec936337952c4228b023007528a33b2fa039d96c2e8f32d764221a9c07"
|
||||||
"checksum num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "98b15ba84e910ea7a1973bccd3df7b31ae282bf9d8bd2897779950c9b8303d40"
|
"checksum num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "98b15ba84e910ea7a1973bccd3df7b31ae282bf9d8bd2897779950c9b8303d40"
|
||||||
|
@ -1299,6 +1324,7 @@ dependencies = [
|
||||||
"checksum objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "877f30f37acef6749b1841cceab289707f211aecfc756553cd63976190e6cc2e"
|
"checksum objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "877f30f37acef6749b1841cceab289707f211aecfc756553cd63976190e6cc2e"
|
||||||
"checksum objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
|
"checksum objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
|
||||||
"checksum objc_id 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e4730aa1c64d722db45f7ccc4113a3e2c465d018de6db4d3e7dfe031e8c8a297"
|
"checksum objc_id 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e4730aa1c64d722db45f7ccc4113a3e2c465d018de6db4d3e7dfe031e8c8a297"
|
||||||
|
"checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba"
|
||||||
"checksum osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b"
|
"checksum osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b"
|
||||||
"checksum owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9d52571ddcb42e9c900c901a18d8d67e393df723fcd51dd59c5b1a85d0acb6cc"
|
"checksum owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9d52571ddcb42e9c900c901a18d8d67e393df723fcd51dd59c5b1a85d0acb6cc"
|
||||||
"checksum parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fa12d706797d42551663426a45e2db2e0364bd1dbf6aeada87e89c5f981f43e9"
|
"checksum parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fa12d706797d42551663426a45e2db2e0364bd1dbf6aeada87e89c5f981f43e9"
|
||||||
|
|
|
@ -32,7 +32,7 @@ log = "0.3"
|
||||||
clap = "2.20"
|
clap = "2.20"
|
||||||
fnv = "1.0.5"
|
fnv = "1.0.5"
|
||||||
unicode-width = "0.1.4"
|
unicode-width = "0.1.4"
|
||||||
|
arraydeque = "0.2"
|
||||||
clippy = { version = "0.0.104", optional = true }
|
clippy = { version = "0.0.104", optional = true }
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "linux", target_os = "freebsd", target_os="dragonfly", target_os="openbsd"))'.dependencies]
|
[target.'cfg(any(target_os = "linux", target_os = "freebsd", target_os="dragonfly", target_os="openbsd"))'.dependencies]
|
||||||
|
@ -44,6 +44,7 @@ default = ["err-println"]
|
||||||
live-shader-reload = []
|
live-shader-reload = []
|
||||||
err-println = []
|
err-println = []
|
||||||
nightly = []
|
nightly = []
|
||||||
|
bench = []
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
gl_generator = "0.5"
|
gl_generator = "0.5"
|
||||||
|
|
26
src/ansi.rs
26
src/ansi.rs
|
@ -102,6 +102,9 @@ pub trait Handler {
|
||||||
/// OSC to set window title
|
/// OSC to set window title
|
||||||
fn set_title(&mut self, &str) {}
|
fn set_title(&mut self, &str) {}
|
||||||
|
|
||||||
|
/// Set the cursor style
|
||||||
|
fn set_cursor_style(&mut self, _: CursorStyle) {}
|
||||||
|
|
||||||
/// A character to be displayed
|
/// A character to be displayed
|
||||||
fn input(&mut self, _c: char) {}
|
fn input(&mut self, _c: char) {}
|
||||||
|
|
||||||
|
@ -261,6 +264,19 @@ pub trait Handler {
|
||||||
fn dectest(&mut self) {}
|
fn dectest(&mut self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Describes shape of cursor
|
||||||
|
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
||||||
|
pub enum CursorStyle {
|
||||||
|
/// Cursor is a block like `▒`
|
||||||
|
Block,
|
||||||
|
|
||||||
|
/// Cursor is an underscore like `_`
|
||||||
|
Underline,
|
||||||
|
|
||||||
|
/// Cursor is a vertical bar `⎸`
|
||||||
|
Beam,
|
||||||
|
}
|
||||||
|
|
||||||
/// Terminal modes
|
/// Terminal modes
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub enum Mode {
|
pub enum Mode {
|
||||||
|
@ -895,6 +911,16 @@ impl<'a, H, W> vte::Perform for Performer<'a, H, W>
|
||||||
},
|
},
|
||||||
's' => handler.save_cursor_position(),
|
's' => handler.save_cursor_position(),
|
||||||
'u' => handler.restore_cursor_position(),
|
'u' => handler.restore_cursor_position(),
|
||||||
|
'q' => {
|
||||||
|
let style = match arg_or_default!(idx: 0, default: 0) {
|
||||||
|
0 ... 2 => CursorStyle::Block,
|
||||||
|
3 | 4 => CursorStyle::Underline,
|
||||||
|
5 | 6 => CursorStyle::Beam,
|
||||||
|
_ => unhandled!()
|
||||||
|
};
|
||||||
|
|
||||||
|
handler.set_cursor_style(style);
|
||||||
|
}
|
||||||
_ => unhandled!(),
|
_ => unhandled!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#![cfg_attr(feature = "clippy", deny(if_not_else))]
|
#![cfg_attr(feature = "clippy", deny(if_not_else))]
|
||||||
#![cfg_attr(feature = "clippy", deny(wrong_pub_self_convention))]
|
#![cfg_attr(feature = "clippy", deny(wrong_pub_self_convention))]
|
||||||
#![cfg_attr(feature = "nightly", feature(core_intrinsics))]
|
#![cfg_attr(feature = "nightly", feature(core_intrinsics))]
|
||||||
|
#![cfg_attr(all(test, feature = "bench"), feature(test))]
|
||||||
|
|
||||||
#[macro_use] extern crate bitflags;
|
#[macro_use] extern crate bitflags;
|
||||||
#[macro_use] extern crate clap;
|
#[macro_use] extern crate clap;
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os="dragonfly", target_os="openbsd"))]
|
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os="dragonfly", target_os="openbsd"))]
|
||||||
extern crate x11_dl;
|
extern crate x11_dl;
|
||||||
|
|
||||||
|
extern crate arraydeque;
|
||||||
extern crate cgmath;
|
extern crate cgmath;
|
||||||
extern crate copypasta;
|
extern crate copypasta;
|
||||||
extern crate errno;
|
extern crate errno;
|
||||||
|
|
|
@ -86,6 +86,17 @@ impl Cell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get foreground and background colors adjusted for INVERSE flag
|
||||||
|
///
|
||||||
|
/// First color is the foreground, second color is the background.
|
||||||
|
pub fn colors(&self, force_invert: bool) -> (&Color, &Color) {
|
||||||
|
if self.flags.contains(INVERSE) || force_invert {
|
||||||
|
(&self.bg, &self.fg)
|
||||||
|
} else {
|
||||||
|
(&self.fg, &self.bg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.c == ' ' &&
|
self.c == ' ' &&
|
||||||
|
|
314
src/term/mod.rs
314
src/term/mod.rs
|
@ -13,16 +13,16 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
//! Exports the `Term` type which is a high-level API for the Grid
|
//! Exports the `Term` type which is a high-level API for the Grid
|
||||||
use std::mem;
|
|
||||||
use std::ops::{Range, Index, IndexMut};
|
use std::ops::{Range, Index, IndexMut};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::cmp::{min, max};
|
use std::cmp::{min, max};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
use arraydeque::ArrayDeque;
|
||||||
use unicode_width::UnicodeWidthChar;
|
use unicode_width::UnicodeWidthChar;
|
||||||
|
|
||||||
use ansi::{self, Color, NamedColor, Attr, Handler, CharsetIndex, StandardCharset};
|
use ansi::{self, Color, NamedColor, Attr, Handler, CharsetIndex, StandardCharset, CursorStyle};
|
||||||
use grid::{BidirectionalIterator, Grid, ClearRegion, ToRange, Indexed};
|
use grid::{BidirectionalIterator, Grid, ClearRegion, ToRange, Indexed};
|
||||||
use index::{self, Point, Column, Line, Linear, IndexRange, Contains, RangeInclusive, Side};
|
use index::{self, Point, Column, Line, Linear, IndexRange, Contains, RangeInclusive, Side};
|
||||||
use selection::{Span, Selection};
|
use selection::{Span, Selection};
|
||||||
|
@ -43,15 +43,16 @@ use self::cell::LineLength;
|
||||||
/// This manages the cursor during a render. The cursor location is inverted to
|
/// This manages the cursor during a render. The cursor location is inverted to
|
||||||
/// draw it, and reverted after drawing to maintain state.
|
/// draw it, and reverted after drawing to maintain state.
|
||||||
pub struct RenderableCellsIter<'a> {
|
pub struct RenderableCellsIter<'a> {
|
||||||
grid: &'a mut Grid<Cell>,
|
grid: &'a Grid<Cell>,
|
||||||
cursor: &'a Point,
|
cursor: &'a Point,
|
||||||
|
cursor_index: index::Linear,
|
||||||
mode: TermMode,
|
mode: TermMode,
|
||||||
line: Line,
|
line: Line,
|
||||||
column: Column,
|
column: Column,
|
||||||
config: &'a Config,
|
config: &'a Config,
|
||||||
colors: &'a color::List,
|
colors: &'a color::List,
|
||||||
selection: Option<RangeInclusive<index::Linear>>,
|
selection: Option<RangeInclusive<index::Linear>>,
|
||||||
cursor_original: (Option<Indexed<Cell>>, Option<Indexed<Cell>>),
|
cursor_cells: ArrayDeque<[Indexed<Cell>; 3]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RenderableCellsIter<'a> {
|
impl<'a> RenderableCellsIter<'a> {
|
||||||
|
@ -60,72 +61,156 @@ impl<'a> RenderableCellsIter<'a> {
|
||||||
/// The cursor and terminal mode are required for properly displaying the
|
/// The cursor and terminal mode are required for properly displaying the
|
||||||
/// cursor.
|
/// cursor.
|
||||||
fn new<'b>(
|
fn new<'b>(
|
||||||
grid: &'b mut Grid<Cell>,
|
grid: &'b Grid<Cell>,
|
||||||
cursor: &'b Point,
|
cursor: &'b Point,
|
||||||
colors: &'b color::List,
|
colors: &'b color::List,
|
||||||
mode: TermMode,
|
mode: TermMode,
|
||||||
config: &'b Config,
|
config: &'b Config,
|
||||||
selection: &Selection,
|
selection: &Selection,
|
||||||
|
cursor_style: CursorStyle,
|
||||||
) -> RenderableCellsIter<'b> {
|
) -> RenderableCellsIter<'b> {
|
||||||
let selection = selection.span()
|
let selection = selection.span()
|
||||||
.map(|span| span.to_range(grid.num_cols()));
|
.map(|span| span.to_range(grid.num_cols()));
|
||||||
|
|
||||||
|
let cursor_index = Linear(cursor.line.0 * grid.num_cols().0 + cursor.col.0);
|
||||||
|
|
||||||
RenderableCellsIter {
|
RenderableCellsIter {
|
||||||
grid: grid,
|
grid: grid,
|
||||||
cursor: cursor,
|
cursor: cursor,
|
||||||
|
cursor_index: cursor_index,
|
||||||
mode: mode,
|
mode: mode,
|
||||||
line: Line(0),
|
line: Line(0),
|
||||||
column: Column(0),
|
column: Column(0),
|
||||||
selection: selection,
|
selection: selection,
|
||||||
config: config,
|
config: config,
|
||||||
colors: colors,
|
colors: colors,
|
||||||
cursor_original: (None, None),
|
cursor_cells: ArrayDeque::new(),
|
||||||
}.initialize()
|
}.initialize(cursor_style)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize(mut self) -> Self {
|
fn populate_block_cursor(&mut self) {
|
||||||
if self.cursor_is_visible() {
|
let (text_color, cursor_color) = if self.config.custom_cursor_colors() {
|
||||||
self.cursor_original.0 = Some(Indexed {
|
(
|
||||||
line: self.cursor.line,
|
Color::Named(NamedColor::CursorText),
|
||||||
column: self.cursor.col,
|
Color::Named(NamedColor::Cursor)
|
||||||
inner: self.grid[self.cursor]
|
)
|
||||||
|
} else {
|
||||||
|
// Swap fg, bg
|
||||||
|
let cell = &self.grid[self.cursor];
|
||||||
|
(cell.bg, cell.fg)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut cell_under_cursor = self.grid[self.cursor];
|
||||||
|
cell_under_cursor.fg = text_color;
|
||||||
|
cell_under_cursor.bg = cursor_color;
|
||||||
|
|
||||||
|
self.cursor_cells.push_back(Indexed {
|
||||||
|
line: self.cursor.line,
|
||||||
|
column: self.cursor.col,
|
||||||
|
inner: cell_under_cursor,
|
||||||
|
});
|
||||||
|
|
||||||
|
if self.is_wide_cursor(&cell_under_cursor) {
|
||||||
|
cell_under_cursor.c = ' ';
|
||||||
|
self.cursor_cells.push_back(Indexed {
|
||||||
|
line: self.cursor.line,
|
||||||
|
column: self.cursor.col + 1,
|
||||||
|
inner: cell_under_cursor,
|
||||||
});
|
});
|
||||||
let mut spacer = false;
|
}
|
||||||
let mut location = *self.cursor;
|
}
|
||||||
|
|
||||||
if self.grid[self.cursor].flags.contains(cell::WIDE_CHAR) &&
|
#[inline]
|
||||||
self.cursor.col + 1 < self.grid.num_cols()
|
fn is_wide_cursor(&self, cell: &Cell) -> bool {
|
||||||
{
|
cell.flags.contains(cell::WIDE_CHAR) && (self.cursor.col + 1) < self.grid.num_cols()
|
||||||
spacer = true;
|
}
|
||||||
location.col += 1;
|
|
||||||
self.cursor_original.1 = Some(Indexed {
|
|
||||||
line: location.line,
|
|
||||||
column: location.col,
|
|
||||||
inner: self.grid[&location]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.config.custom_cursor_colors() {
|
fn populate_beam_cursor(&mut self) {
|
||||||
{
|
let mut cursor_cell = self.grid[self.cursor];
|
||||||
let cell = &mut self.grid[self.cursor];
|
self.cursor_cells.push_back(Indexed {
|
||||||
cell.fg = Color::Named(NamedColor::CursorText);
|
line: self.cursor.line,
|
||||||
cell.bg = Color::Named(NamedColor::Cursor);
|
column: self.cursor.col,
|
||||||
}
|
inner: cursor_cell,
|
||||||
if spacer {
|
});
|
||||||
let cell = &mut self.grid[&location];
|
|
||||||
cell.fg = Color::Named(NamedColor::CursorText);
|
let cursor_color = self.text_cursor_color(&cursor_cell);
|
||||||
cell.bg = Color::Named(NamedColor::Cursor);
|
cursor_cell.c = '▎';
|
||||||
}
|
cursor_cell.fg = cursor_color;
|
||||||
} else {
|
self.cursor_cells.push_back(Indexed {
|
||||||
{
|
line: self.cursor.line,
|
||||||
let cell = &mut self.grid[self.cursor];
|
column: self.cursor.col,
|
||||||
mem::swap(&mut cell.fg, &mut cell.bg);
|
inner: cursor_cell,
|
||||||
}
|
});
|
||||||
if spacer {
|
|
||||||
let cell = &mut self.grid[&location];
|
if self.is_wide_cursor(&cursor_cell) {
|
||||||
mem::swap(&mut cell.fg, &mut cell.bg);
|
cursor_cell.c = ' ';
|
||||||
|
self.cursor_cells.push_back(Indexed {
|
||||||
|
line: self.cursor.line,
|
||||||
|
column: self.cursor.col + 1,
|
||||||
|
inner: cursor_cell,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn populate_underline_cursor(&mut self) {
|
||||||
|
let mut cursor_cell = self.grid[self.cursor];
|
||||||
|
self.cursor_cells.push_back(Indexed {
|
||||||
|
line: self.cursor.line,
|
||||||
|
column: self.cursor.col,
|
||||||
|
inner: cursor_cell,
|
||||||
|
});
|
||||||
|
|
||||||
|
let cursor_color = self.text_cursor_color(&cursor_cell);
|
||||||
|
cursor_cell.c = '▁';
|
||||||
|
cursor_cell.fg = cursor_color;
|
||||||
|
self.cursor_cells.push_back(Indexed {
|
||||||
|
line: self.cursor.line,
|
||||||
|
column: self.cursor.col,
|
||||||
|
inner: cursor_cell,
|
||||||
|
});
|
||||||
|
|
||||||
|
if self.is_wide_cursor(&cursor_cell) {
|
||||||
|
self.cursor_cells.push_back(Indexed {
|
||||||
|
line: self.cursor.line,
|
||||||
|
column: self.cursor.col + 1,
|
||||||
|
inner: cursor_cell,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn text_cursor_color(&self, cell: &Cell) -> Color {
|
||||||
|
if self.config.custom_cursor_colors() {
|
||||||
|
Color::Named(NamedColor::Cursor)
|
||||||
|
} else {
|
||||||
|
// Cursor is same color as text
|
||||||
|
cell.fg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Populates list of cursor cells with the original cell
|
||||||
|
fn populate_no_cursor(&mut self) {
|
||||||
|
self.cursor_cells.push_back(Indexed {
|
||||||
|
line: self.cursor.line,
|
||||||
|
column: self.cursor.col,
|
||||||
|
inner: self.grid[self.cursor],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initialize(mut self, cursor_style: CursorStyle) -> Self {
|
||||||
|
if self.cursor_is_visible() {
|
||||||
|
match cursor_style {
|
||||||
|
CursorStyle::Block => {
|
||||||
|
self.populate_block_cursor();
|
||||||
|
},
|
||||||
|
CursorStyle::Beam => {
|
||||||
|
self.populate_beam_cursor();
|
||||||
|
},
|
||||||
|
CursorStyle::Underline => {
|
||||||
|
self.populate_underline_cursor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self.populate_no_cursor();
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -135,22 +220,39 @@ impl<'a> RenderableCellsIter<'a> {
|
||||||
fn cursor_is_visible(&self) -> bool {
|
fn cursor_is_visible(&self) -> bool {
|
||||||
self.mode.contains(mode::SHOW_CURSOR) && self.grid.contains(self.cursor)
|
self.mode.contains(mode::SHOW_CURSOR) && self.grid.contains(self.cursor)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Drop for RenderableCellsIter<'a> {
|
fn compute_fg_rgb(&self, fg: &Color, cell: &Cell) -> Rgb {
|
||||||
/// Resets temporary render state on the grid
|
match *fg {
|
||||||
fn drop(&mut self) {
|
Color::Spec(rgb) => rgb,
|
||||||
if self.cursor_is_visible() {
|
Color::Named(ansi) => {
|
||||||
if let Some(ref original) = self.cursor_original.0 {
|
if self.config.draw_bold_text_with_bright_colors() && cell.bold() {
|
||||||
self.grid[self.cursor] = original.inner;
|
self.colors[ansi.to_bright()]
|
||||||
}
|
} else {
|
||||||
if let Some(ref original) = self.cursor_original.1 {
|
self.colors[ansi]
|
||||||
let mut location = *self.cursor;
|
}
|
||||||
location.col += 1;
|
},
|
||||||
self.grid[&location] = original.inner;
|
Color::Indexed(idx) => {
|
||||||
|
let idx = if self.config.draw_bold_text_with_bright_colors()
|
||||||
|
&& cell.bold()
|
||||||
|
&& idx < 8
|
||||||
|
{
|
||||||
|
idx + 8
|
||||||
|
} else {
|
||||||
|
idx
|
||||||
|
};
|
||||||
|
|
||||||
|
self.colors[idx]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compute_bg_rgb(&self, bg: &Color) -> Rgb {
|
||||||
|
match *bg {
|
||||||
|
Color::Spec(rgb) => rgb,
|
||||||
|
Color::Named(ansi) => self.colors[ansi],
|
||||||
|
Color::Indexed(idx) => self.colors[idx],
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RenderableCell {
|
pub struct RenderableCell {
|
||||||
|
@ -180,56 +282,39 @@ impl<'a> Iterator for RenderableCellsIter<'a> {
|
||||||
|
|
||||||
let index = Linear(line.0 * self.grid.num_cols().0 + column.0);
|
let index = Linear(line.0 * self.grid.num_cols().0 + column.0);
|
||||||
|
|
||||||
// Update state for next iteration
|
let (cell, selected) = if index == self.cursor_index {
|
||||||
self.column += 1;
|
// Cursor cell
|
||||||
|
let cell = self.cursor_cells.pop_front().unwrap();
|
||||||
|
|
||||||
let selected = self.selection.as_ref()
|
// Since there may be multiple cursor cells (for a wide
|
||||||
.map(|range| range.contains_(index))
|
// char), only update iteration position after all cursor
|
||||||
.unwrap_or(false);
|
// cells have been drawn.
|
||||||
|
if self.cursor_cells.is_empty() {
|
||||||
// Skip empty cells
|
self.line = cell.line;
|
||||||
if cell.is_empty() && !selected {
|
self.column = cell.column + 1;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// fg, bg are dependent on INVERSE flag
|
|
||||||
let invert = cell.flags.contains(cell::INVERSE) || selected;
|
|
||||||
let (fg, bg) = if invert {
|
|
||||||
(&cell.bg, &cell.fg)
|
|
||||||
} else {
|
|
||||||
(&cell.fg, &cell.bg)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get Rgb value for foreground
|
|
||||||
let fg = match *fg {
|
|
||||||
Color::Spec(rgb) => rgb,
|
|
||||||
Color::Named(ansi) => {
|
|
||||||
if self.config.draw_bold_text_with_bright_colors() && cell.bold() {
|
|
||||||
self.colors[ansi.to_bright()]
|
|
||||||
} else {
|
|
||||||
self.colors[ansi]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Color::Indexed(idx) => {
|
|
||||||
let idx = if self.config.draw_bold_text_with_bright_colors()
|
|
||||||
&& cell.bold()
|
|
||||||
&& idx < 8
|
|
||||||
{
|
|
||||||
idx + 8
|
|
||||||
} else {
|
|
||||||
idx
|
|
||||||
};
|
|
||||||
|
|
||||||
self.colors[idx]
|
|
||||||
}
|
}
|
||||||
|
(cell.inner, false)
|
||||||
|
} else {
|
||||||
|
// Normal cell
|
||||||
|
self.column += 1;
|
||||||
|
|
||||||
|
let selected = self.selection.as_ref()
|
||||||
|
.map(|range| range.contains_(index))
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
// Skip empty cells
|
||||||
|
if cell.is_empty() && !selected {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
(*cell, selected)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get Rgb value for background
|
// `Color` fg, bg
|
||||||
let bg = match *bg {
|
let (fg, bg) = cell.colors(selected);
|
||||||
Color::Spec(rgb) => rgb,
|
|
||||||
Color::Named(ansi) => self.colors[ansi],
|
// `Rgb` fg, bg
|
||||||
Color::Indexed(idx) => self.colors[idx],
|
let fg = self.compute_fg_rgb(fg, &cell);
|
||||||
};
|
let bg = self.compute_bg_rgb(bg);
|
||||||
|
|
||||||
return Some(RenderableCell {
|
return Some(RenderableCell {
|
||||||
line: line,
|
line: line,
|
||||||
|
@ -247,6 +332,7 @@ impl<'a> Iterator for RenderableCellsIter<'a> {
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod mode {
|
pub mod mode {
|
||||||
|
@ -536,6 +622,8 @@ pub struct Term {
|
||||||
|
|
||||||
/// Colors used for rendering
|
/// Colors used for rendering
|
||||||
colors: color::List,
|
colors: color::List,
|
||||||
|
|
||||||
|
cursor_style: CursorStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Terminal size info
|
/// Terminal size info
|
||||||
|
@ -636,6 +724,7 @@ impl Term {
|
||||||
empty_cell: template,
|
empty_cell: template,
|
||||||
colors: color::List::from(config.colors()),
|
colors: color::List::from(config.colors()),
|
||||||
semantic_escape_chars: config.selection().semantic_escape_chars.clone(),
|
semantic_escape_chars: config.selection().semantic_escape_chars.clone(),
|
||||||
|
cursor_style: CursorStyle::Block,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -855,17 +944,18 @@ impl Term {
|
||||||
/// background color. Cells with an alternate background color are
|
/// background color. Cells with an alternate background color are
|
||||||
/// considered renderable as are cells with any text content.
|
/// considered renderable as are cells with any text content.
|
||||||
pub fn renderable_cells<'b>(
|
pub fn renderable_cells<'b>(
|
||||||
&'b mut self,
|
&'b self,
|
||||||
config: &'b Config,
|
config: &'b Config,
|
||||||
selection: &'b Selection
|
selection: &'b Selection
|
||||||
) -> RenderableCellsIter {
|
) -> RenderableCellsIter {
|
||||||
RenderableCellsIter::new(
|
RenderableCellsIter::new(
|
||||||
&mut self.grid,
|
&self.grid,
|
||||||
&self.cursor.point,
|
&self.cursor.point,
|
||||||
&self.colors,
|
&self.colors,
|
||||||
self.mode,
|
self.mode,
|
||||||
config,
|
config,
|
||||||
selection,
|
selection,
|
||||||
|
self.cursor_style
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1704,6 +1794,12 @@ impl ansi::Handler for Term {
|
||||||
trace!("Activate {:?} character set", index);
|
trace!("Activate {:?} character set", index);
|
||||||
self.active_charset = index;
|
self.active_charset = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_cursor_style(&mut self, style: CursorStyle) {
|
||||||
|
trace!("set_cursor_style {:?}", style);
|
||||||
|
self.cursor_style = style;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -1842,6 +1938,7 @@ mod benches {
|
||||||
|
|
||||||
use grid::Grid;
|
use grid::Grid;
|
||||||
use selection::Selection;
|
use selection::Selection;
|
||||||
|
use config::Config;
|
||||||
|
|
||||||
use super::{SizeInfo, Term};
|
use super::{SizeInfo, Term};
|
||||||
use super::cell::Cell;
|
use super::cell::Cell;
|
||||||
|
@ -1878,11 +1975,14 @@ mod benches {
|
||||||
let mut grid: Grid<Cell> = json::from_str(&serialized_grid).unwrap();
|
let mut grid: Grid<Cell> = json::from_str(&serialized_grid).unwrap();
|
||||||
let size: SizeInfo = json::from_str(&serialized_size).unwrap();
|
let size: SizeInfo = json::from_str(&serialized_size).unwrap();
|
||||||
|
|
||||||
let mut terminal = Term::new(&Default::default(), size);
|
let config = Config::default();
|
||||||
|
let selection = Selection::Empty;
|
||||||
|
|
||||||
|
let mut terminal = Term::new(&config, size);
|
||||||
mem::swap(&mut terminal.grid, &mut grid);
|
mem::swap(&mut terminal.grid, &mut grid);
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let iter = terminal.renderable_cells(&Selection::Empty);
|
let iter = terminal.renderable_cells(&config, &selection);
|
||||||
for cell in iter {
|
for cell in iter {
|
||||||
test::black_box(cell);
|
test::black_box(cell);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue