aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnhad Singh <62820092+Andy-Python-Programmer@users.noreply.github.com>2023-05-24 06:35:58 +1000
committerGitHub <noreply@github.com>2023-05-23 20:35:58 +0000
commitcb7ad5b7e6893787c2006cc8cb09fbbc4711c0f7 (patch)
treee8c5315bb620e6d4e1564dfd6825303b498a3d6d
parentf0379f2da751e81ba05bbf65ecb5e59590f39be4 (diff)
downloadalacritty-cb7ad5b7e6893787c2006cc8cb09fbbc4711c0f7.tar.gz
alacritty-cb7ad5b7e6893787c2006cc8cb09fbbc4711c0f7.zip
Switch to VTE's built-in ansi feature
Co-authored-by: Christian Duerr <contact@christianduerr.com>
-rw-r--r--Cargo.lock14
-rw-r--r--alacritty/src/config/bell.rs11
-rw-r--r--alacritty/src/config/color.rs68
-rw-r--r--alacritty/src/config/window.rs18
-rw-r--r--alacritty/src/display/color.rs12
-rw-r--r--alacritty/src/display/content.rs11
-rw-r--r--alacritty/src/display/hint.rs14
-rw-r--r--alacritty/src/display/mod.rs2
-rw-r--r--alacritty/src/renderer/rects.rs2
-rw-r--r--alacritty_terminal/Cargo.toml2
-rw-r--r--alacritty_terminal/src/ansi.rs1871
-rw-r--r--alacritty_terminal/src/config/mod.rs21
-rw-r--r--alacritty_terminal/src/event_loop.rs5
-rw-r--r--alacritty_terminal/src/term/cell.rs13
-rw-r--r--alacritty_terminal/src/term/color.rs104
-rw-r--r--alacritty_terminal/src/term/mod.rs76
-rw-r--r--alacritty_terminal/tests/ref.rs2
17 files changed, 208 insertions, 2038 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 3d8284dd..a7bfeaa8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1487,18 +1487,18 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.57"
+version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4ec6d5fe0b140acb27c9a0444118cf55bfbb4e0b259739429abb4521dd67c16"
+checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
-version = "1.0.27"
+version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500"
+checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
dependencies = [
"proc-macro2",
]
@@ -1945,10 +1945,12 @@ dependencies = [
[[package]]
name = "vte"
-version = "0.10.1"
+version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983"
+checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197"
dependencies = [
+ "log",
+ "serde",
"utf8parse",
"vte_generate_state_changes",
]
diff --git a/alacritty/src/config/bell.rs b/alacritty/src/config/bell.rs
index 2516e2b3..fbf5be2f 100644
--- a/alacritty/src/config/bell.rs
+++ b/alacritty/src/config/bell.rs
@@ -23,7 +23,7 @@ pub struct BellConfig {
impl Default for BellConfig {
fn default() -> Self {
Self {
- color: Rgb { r: 255, g: 255, b: 255 },
+ color: Rgb::new(255, 255, 255),
animation: Default::default(),
command: Default::default(),
duration: Default::default(),
@@ -39,7 +39,7 @@ impl BellConfig {
/// `VisualBellAnimations` are modeled after a subset of CSS transitions and Robert
/// Penner's Easing Functions.
-#[derive(ConfigDeserialize, Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(ConfigDeserialize, Default, Clone, Copy, Debug, PartialEq, Eq)]
pub enum BellAnimation {
// CSS animation.
Ease,
@@ -56,15 +56,10 @@ pub enum BellAnimation {
// Penner animation.
EaseOutQuint,
// Penner animation.
+ #[default]
EaseOutExpo,
// Penner animation.
EaseOutCirc,
// Penner animation.
Linear,
}
-
-impl Default for BellAnimation {
- fn default() -> Self {
- BellAnimation::EaseOutExpo
- }
-}
diff --git a/alacritty/src/config/color.rs b/alacritty/src/config/color.rs
index 5028347c..23c18e50 100644
--- a/alacritty/src/config/color.rs
+++ b/alacritty/src/config/color.rs
@@ -52,8 +52,8 @@ pub struct HintStartColors {
impl Default for HintStartColors {
fn default() -> Self {
Self {
- foreground: CellRgb::Rgb(Rgb { r: 0x1d, g: 0x1f, b: 0x21 }),
- background: CellRgb::Rgb(Rgb { r: 0xe9, g: 0xff, b: 0x5e }),
+ foreground: CellRgb::Rgb(Rgb::new(0x1d, 0x1f, 0x21)),
+ background: CellRgb::Rgb(Rgb::new(0xe9, 0xff, 0x5e)),
}
}
}
@@ -67,8 +67,8 @@ pub struct HintEndColors {
impl Default for HintEndColors {
fn default() -> Self {
Self {
- foreground: CellRgb::Rgb(Rgb { r: 0xe9, g: 0xff, b: 0x5e }),
- background: CellRgb::Rgb(Rgb { r: 0x1d, g: 0x1f, b: 0x21 }),
+ foreground: CellRgb::Rgb(Rgb::new(0xe9, 0xff, 0x5e)),
+ background: CellRgb::Rgb(Rgb::new(0x1d, 0x1f, 0x21)),
}
}
}
@@ -139,8 +139,8 @@ pub struct FocusedMatchColors {
impl Default for FocusedMatchColors {
fn default() -> Self {
Self {
- background: CellRgb::Rgb(Rgb { r: 0x00, g: 0x00, b: 0x00 }),
- foreground: CellRgb::Rgb(Rgb { r: 0xff, g: 0xff, b: 0xff }),
+ background: CellRgb::Rgb(Rgb::new(0x00, 0x00, 0x00)),
+ foreground: CellRgb::Rgb(Rgb::new(0xff, 0xff, 0xff)),
}
}
}
@@ -154,8 +154,8 @@ pub struct MatchColors {
impl Default for MatchColors {
fn default() -> Self {
Self {
- background: CellRgb::Rgb(Rgb { r: 0xff, g: 0xff, b: 0xff }),
- foreground: CellRgb::Rgb(Rgb { r: 0x00, g: 0x00, b: 0x00 }),
+ background: CellRgb::Rgb(Rgb::new(0xff, 0xff, 0xff)),
+ foreground: CellRgb::Rgb(Rgb::new(0x00, 0x00, 0x00)),
}
}
}
@@ -177,8 +177,8 @@ pub struct PrimaryColors {
impl Default for PrimaryColors {
fn default() -> Self {
PrimaryColors {
- background: Rgb { r: 0x1d, g: 0x1f, b: 0x21 },
- foreground: Rgb { r: 0xc5, g: 0xc8, b: 0xc6 },
+ background: Rgb::new(0x1d, 0x1f, 0x21),
+ foreground: Rgb::new(0xc5, 0xc8, 0xc6),
bright_foreground: Default::default(),
dim_foreground: Default::default(),
}
@@ -200,14 +200,14 @@ pub struct NormalColors {
impl Default for NormalColors {
fn default() -> Self {
NormalColors {
- black: Rgb { r: 0x1d, g: 0x1f, b: 0x21 },
- red: Rgb { r: 0xcc, g: 0x66, b: 0x66 },
- green: Rgb { r: 0xb5, g: 0xbd, b: 0x68 },
- yellow: Rgb { r: 0xf0, g: 0xc6, b: 0x74 },
- blue: Rgb { r: 0x81, g: 0xa2, b: 0xbe },
- magenta: Rgb { r: 0xb2, g: 0x94, b: 0xbb },
- cyan: Rgb { r: 0x8a, g: 0xbe, b: 0xb7 },
- white: Rgb { r: 0xc5, g: 0xc8, b: 0xc6 },
+ black: Rgb::new(0x1d, 0x1f, 0x21),
+ red: Rgb::new(0xcc, 0x66, 0x66),
+ green: Rgb::new(0xb5, 0xbd, 0x68),
+ yellow: Rgb::new(0xf0, 0xc6, 0x74),
+ blue: Rgb::new(0x81, 0xa2, 0xbe),
+ magenta: Rgb::new(0xb2, 0x94, 0xbb),
+ cyan: Rgb::new(0x8a, 0xbe, 0xb7),
+ white: Rgb::new(0xc5, 0xc8, 0xc6),
}
}
}
@@ -227,14 +227,14 @@ pub struct BrightColors {
impl Default for BrightColors {
fn default() -> Self {
BrightColors {
- black: Rgb { r: 0x66, g: 0x66, b: 0x66 },
- red: Rgb { r: 0xd5, g: 0x4e, b: 0x53 },
- green: Rgb { r: 0xb9, g: 0xca, b: 0x4a },
- yellow: Rgb { r: 0xe7, g: 0xc5, b: 0x47 },
- blue: Rgb { r: 0x7a, g: 0xa6, b: 0xda },
- magenta: Rgb { r: 0xc3, g: 0x97, b: 0xd8 },
- cyan: Rgb { r: 0x70, g: 0xc0, b: 0xb1 },
- white: Rgb { r: 0xea, g: 0xea, b: 0xea },
+ black: Rgb::new(0x66, 0x66, 0x66),
+ red: Rgb::new(0xd5, 0x4e, 0x53),
+ green: Rgb::new(0xb9, 0xca, 0x4a),
+ yellow: Rgb::new(0xe7, 0xc5, 0x47),
+ blue: Rgb::new(0x7a, 0xa6, 0xda),
+ magenta: Rgb::new(0xc3, 0x97, 0xd8),
+ cyan: Rgb::new(0x70, 0xc0, 0xb1),
+ white: Rgb::new(0xea, 0xea, 0xea),
}
}
}
@@ -254,14 +254,14 @@ pub struct DimColors {
impl Default for DimColors {
fn default() -> Self {
DimColors {
- black: Rgb { r: 0x13, g: 0x14, b: 0x15 },
- red: Rgb { r: 0x86, g: 0x43, b: 0x43 },
- green: Rgb { r: 0x77, g: 0x7c, b: 0x44 },
- yellow: Rgb { r: 0x9e, g: 0x82, b: 0x4c },
- blue: Rgb { r: 0x55, g: 0x6a, b: 0x7d },
- magenta: Rgb { r: 0x75, g: 0x61, b: 0x7b },
- cyan: Rgb { r: 0x5b, g: 0x7d, b: 0x78 },
- white: Rgb { r: 0x82, g: 0x84, b: 0x82 },
+ black: Rgb::new(0x13, 0x14, 0x15),
+ red: Rgb::new(0x86, 0x43, 0x43),
+ green: Rgb::new(0x77, 0x7c, 0x44),
+ yellow: Rgb::new(0x9e, 0x82, 0x4c),
+ blue: Rgb::new(0x55, 0x6a, 0x7d),
+ magenta: Rgb::new(0x75, 0x61, 0x7b),
+ cyan: Rgb::new(0x5b, 0x7d, 0x78),
+ white: Rgb::new(0x82, 0x84, 0x82),
}
}
}
diff --git a/alacritty/src/config/window.rs b/alacritty/src/config/window.rs
index 98bc18b6..db29fd85 100644
--- a/alacritty/src/config/window.rs
+++ b/alacritty/src/config/window.rs
@@ -154,8 +154,9 @@ impl Default for Identity {
}
}
-#[derive(ConfigDeserialize, Debug, Copy, Clone, PartialEq, Eq)]
+#[derive(ConfigDeserialize, Default, Debug, Copy, Clone, PartialEq, Eq)]
pub enum StartupMode {
+ #[default]
Windowed,
Maximized,
Fullscreen,
@@ -163,14 +164,9 @@ pub enum StartupMode {
SimpleFullscreen,
}
-impl Default for StartupMode {
- fn default() -> StartupMode {
- StartupMode::Windowed
- }
-}
-
-#[derive(ConfigDeserialize, Debug, Copy, Clone, PartialEq, Eq)]
+#[derive(ConfigDeserialize, Default, Debug, Copy, Clone, PartialEq, Eq)]
pub enum Decorations {
+ #[default]
Full,
#[cfg(target_os = "macos")]
Transparent,
@@ -179,12 +175,6 @@ pub enum Decorations {
None,
}
-impl Default for Decorations {
- fn default() -> Decorations {
- Decorations::Full
- }
-}
-
/// Window Dimensions.
///
/// Newtype to avoid passing values incorrectly.
diff --git a/alacritty/src/display/color.rs b/alacritty/src/display/color.rs
index 6e0de048..054ca314 100644
--- a/alacritty/src/display/color.rs
+++ b/alacritty/src/display/color.rs
@@ -95,11 +95,11 @@ impl List {
{
self[index] = indexed_color.color;
} else {
- self[index] = Rgb {
- r: if r == 0 { 0 } else { r * 40 + 55 },
- b: if b == 0 { 0 } else { b * 40 + 55 },
- g: if g == 0 { 0 } else { g * 40 + 55 },
- };
+ self[index] = Rgb::new(
+ if r == 0 { 0 } else { r * 40 + 55 },
+ if b == 0 { 0 } else { b * 40 + 55 },
+ if g == 0 { 0 } else { g * 40 + 55 },
+ );
}
index += 1;
}
@@ -126,7 +126,7 @@ impl List {
}
let value = i * 10 + 8;
- self[index] = Rgb { r: value, g: value, b: value };
+ self[index] = Rgb::new(value, value, value);
index += 1;
}
diff --git a/alacritty/src/display/content.rs b/alacritty/src/display/content.rs
index ca49c01a..da211094 100644
--- a/alacritty/src/display/content.rs
+++ b/alacritty/src/display/content.rs
@@ -121,7 +121,7 @@ impl<'a> RenderableContent<'a> {
let insufficient_contrast = (!matches!(cursor_color, CellRgb::Rgb(_))
|| !matches!(text_color, CellRgb::Rgb(_)))
- && cell.fg.contrast(cell.bg) < MIN_CURSOR_CONTRAST;
+ && cell.fg.contrast(*cell.bg) < MIN_CURSOR_CONTRAST;
// Convert from cell colors to RGB.
let mut text_color = text_color.color(cell.fg, cell.bg);
@@ -307,8 +307,11 @@ impl RenderableCell {
let config = &content.config;
match fg {
Color::Spec(rgb) => match flags & Flags::DIM {
- Flags::DIM => rgb * DIM_FACTOR,
- _ => rgb,
+ Flags::DIM => {
+ let rgb: Rgb = rgb.into();
+ rgb * DIM_FACTOR
+ },
+ _ => rgb.into(),
},
Color::Named(ansi) => {
match (config.draw_bold_text_with_bright_colors, flags & Flags::DIM_BOLD) {
@@ -350,7 +353,7 @@ impl RenderableCell {
#[inline]
fn compute_bg_rgb(content: &mut RenderableContent<'_>, bg: Color) -> Rgb {
match bg {
- Color::Spec(rgb) => rgb,
+ Color::Spec(rgb) => rgb.into(),
Color::Named(ansi) => content.color(ansi as usize),
Color::Indexed(idx) => content.color(idx as usize),
}
diff --git a/alacritty/src/display/hint.rs b/alacritty/src/display/hint.rs
index 12047011..c30a88c5 100644
--- a/alacritty/src/display/hint.rs
+++ b/alacritty/src/display/hint.rs
@@ -647,25 +647,25 @@ mod tests {
#[test]
fn collect_unique_hyperlinks() {
let mut term = mock_term("000\r\n111");
- term.goto(Line(0), Column(0));
+ term.goto(0, 0);
let hyperlink_foo = Hyperlink::new(Some("1"), String::from("foo"));
let hyperlink_bar = Hyperlink::new(Some("2"), String::from("bar"));
// Create 2 hyperlinks on the first line.
- term.set_hyperlink(Some(hyperlink_foo.clone()));
+ term.set_hyperlink(Some(hyperlink_foo.clone().into()));
term.input('b');
term.input('a');
- term.set_hyperlink(Some(hyperlink_bar.clone()));
+ term.set_hyperlink(Some(hyperlink_bar.clone().into()));
term.input('r');
- term.set_hyperlink(Some(hyperlink_foo.clone()));
- term.goto(Line(1), Column(0));
+ term.set_hyperlink(Some(hyperlink_foo.clone().into()));
+ term.goto(1, 0);
// Ditto for the second line.
- term.set_hyperlink(Some(hyperlink_foo));
+ term.set_hyperlink(Some(hyperlink_foo.into()));
term.input('b');
term.input('a');
- term.set_hyperlink(Some(hyperlink_bar));
+ term.set_hyperlink(Some(hyperlink_bar.into()));
term.input('r');
term.set_hyperlink(None);
diff --git a/alacritty/src/display/mod.rs b/alacritty/src/display/mod.rs
index 4d9c1540..b575b1a8 100644
--- a/alacritty/src/display/mod.rs
+++ b/alacritty/src/display/mod.rs
@@ -73,7 +73,7 @@ const BACKWARD_SEARCH_LABEL: &str = "Backward Search: ";
const SHORTENER: char = '…';
/// Color which is used to highlight damaged rects when debugging.
-const DAMAGE_RECT_COLOR: Rgb = Rgb { r: 255, g: 0, b: 255 };
+const DAMAGE_RECT_COLOR: Rgb = Rgb::new(255, 0, 255);
#[derive(Debug)]
pub enum Error {
diff --git a/alacritty/src/renderer/rects.rs b/alacritty/src/renderer/rects.rs
index 31818f60..8f6204c2 100644
--- a/alacritty/src/renderer/rects.rs
+++ b/alacritty/src/renderer/rects.rs
@@ -366,7 +366,7 @@ impl RectRenderer {
let y = -rect.y / half_height + 1.0;
let width = rect.width / half_width;
let height = rect.height / half_height;
- let Rgb { r, g, b } = rect.color;
+ let (r, g, b) = rect.color.as_tuple();
let a = (rect.alpha * 255.) as u8;
// Make quad vertices.
diff --git a/alacritty_terminal/Cargo.toml b/alacritty_terminal/Cargo.toml
index 5e4efd0b..99a14e11 100644
--- a/alacritty_terminal/Cargo.toml
+++ b/alacritty_terminal/Cargo.toml
@@ -30,7 +30,7 @@ regex-automata = "0.1.9"
serde = { version = "1", features = ["derive", "rc"] }
serde_yaml = "0.8"
unicode-width = "0.1"
-vte = { version = "0.10.0", default-features = false }
+vte = { version = "0.11.1", default-features = false, features = ["ansi", "serde"] }
[target.'cfg(unix)'.dependencies]
nix = { version = "0.26.2", default-features = false, features = ["term"] }
diff --git a/alacritty_terminal/src/ansi.rs b/alacritty_terminal/src/ansi.rs
index c47007d8..b596cc82 100644
--- a/alacritty_terminal/src/ansi.rs
+++ b/alacritty_terminal/src/ansi.rs
@@ -1,1862 +1,67 @@
//! ANSI Terminal Stream Parsing.
-use std::convert::TryFrom;
-use std::fmt::Write;
-use std::time::{Duration, Instant};
-use std::{iter, str};
+pub use vte::ansi::*;
-use log::{debug, trace};
-use serde::{Deserialize, Serialize};
-use vte::{Params, ParamsIter};
+#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
+pub struct CursorShapeShim(CursorShape);
-use alacritty_config_derive::ConfigDeserialize;
-
-use crate::index::{Column, Line};
-use crate::term::cell::Hyperlink;
-use crate::term::color::Rgb;
-
-/// Maximum time before a synchronized update is aborted.
-const SYNC_UPDATE_TIMEOUT: Duration = Duration::from_millis(150);
-
-/// Maximum number of bytes read in one synchronized update (2MiB).
-const SYNC_BUFFER_SIZE: usize = 0x20_0000;
-
-/// Number of bytes in the synchronized update DCS sequence before the passthrough parameters.
-const SYNC_ESCAPE_START_LEN: usize = 5;
-
-/// Start of the DCS sequence for beginning synchronized updates.
-const SYNC_START_ESCAPE_START: [u8; SYNC_ESCAPE_START_LEN] = [b'\x1b', b'P', b'=', b'1', b's'];
-
-/// Start of the DCS sequence for terminating synchronized updates.
-const SYNC_END_ESCAPE_START: [u8; SYNC_ESCAPE_START_LEN] = [b'\x1b', b'P', b'=', b'2', b's'];
-
-/// Parse colors in XParseColor format.
-fn xparse_color(color: &[u8]) -> Option<Rgb> {
- if !color.is_empty() && color[0] == b'#' {
- parse_legacy_color(&color[1..])
- } else if color.len() >= 4 && &color[..4] == b"rgb:" {
- parse_rgb_color(&color[4..])
- } else {
- None
+impl Default for CursorShapeShim {
+ fn default() -> CursorShapeShim {
+ CursorShapeShim(CursorShape::Block)
}
}
-/// Parse colors in `rgb:r(rrr)/g(ggg)/b(bbb)` format.
-fn parse_rgb_color(color: &[u8]) -> Option<Rgb> {
- let colors = str::from_utf8(color).ok()?.split('/').collect::<Vec<_>>();
-
- if colors.len() != 3 {
- return None;
+impl From<CursorShapeShim> for CursorShape {
+ fn from(value: CursorShapeShim) -> Self {
+ value.0
}
-
- // Scale values instead of filling with `0`s.
- let scale = |input: &str| {
- if input.len() > 4 {
- None
- } else {
- let max = u32::pow(16, input.len() as u32) - 1;
- let value = u32::from_str_radix(input, 16).ok()?;
- Some((255 * value / max) as u8)
- }
- };
-
- Some(Rgb { r: scale(colors[0])?, g: scale(colors[1])?, b: scale(colors[2])? })
}
-/// Parse colors in `#r(rrr)g(ggg)b(bbb)` format.
-fn parse_legacy_color(color: &[u8]) -> Option<Rgb> {
- let item_len = color.len() / 3;
-
- // Truncate/Fill to two byte precision.
- let color_from_slice = |slice: &[u8]| {
- let col = usize::from_str_radix(str::from_utf8(slice).ok()?, 16).ok()? << 4;
- Some((col >> (4 * slice.len().saturating_sub(1))) as u8)
- };
-
- Some(Rgb {
- r: color_from_slice(&color[0..item_len])?,
- g: color_from_slice(&color[item_len..item_len * 2])?,
- b: color_from_slice(&color[item_len * 2..])?,
- })
-}
-
-fn parse_number(input: &[u8]) -> Option<u8> {
- if input.is_empty() {
- return None;
- }
- let mut num: u8 = 0;
- for c in input {
- let c = *c as char;
- if let Some(digit) = c.to_digit(10) {
- num = match num.checked_mul(10).and_then(|v| v.checked_add(digit as u8)) {
- Some(v) => v,
- None => return None,
- }
- } else {
- return None;
- }
- }
- Some(num)
-}
-
-/// Internal state for VTE processor.
-#[derive(Debug, Default)]
-struct ProcessorState {
- /// Last processed character for repetition.
- preceding_char: Option<char>,
-
- /// DCS sequence waiting for termination.
- dcs: Option<Dcs>,
-
- /// State for synchronized terminal updates.
- sync_state: SyncState,
-}
-
-#[derive(Debug)]
-struct SyncState {
- /// Expiration time of the synchronized update.
- timeout: Option<Instant>,
-
- /// Sync DCS waiting for termination sequence.
- pending_dcs: Option<Dcs>,
-
- /// Bytes read during the synchronized update.
- buffer: Vec<u8>,
-}
-
-impl Default for SyncState {
- fn default() -> Self {
- Self { buffer: Vec::with_capacity(SYNC_BUFFER_SIZE), pending_dcs: None, timeout: None }
- }
-}
-
-/// Pending DCS sequence.
-#[derive(Debug)]
-enum Dcs {
- /// Begin of the synchronized update.
- SyncStart,
-
- /// End of the synchronized update.
- SyncEnd,
-}
-
-/// The processor wraps a `vte::Parser` to ultimately call methods on a Handler.
-#[derive(Default)]
-pub struct Processor {
- state: ProcessorState,
- parser: vte::Parser,
-}
-
-impl Processor {
- #[inline]
- pub fn new() -> Self {
- Self::default()
- }
-
- /// Process a new byte from the PTY.
- #[inline]
- pub fn advance<H>(&mut self, handler: &mut H, byte: u8)
- where
- H: Handler,
- {
- if self.state.sync_state.timeout.is_none() {
- let mut performer = Performer::new(&mut self.state, handler);
- self.parser.advance(&mut performer, byte);
- } else {
- self.advance_sync(handler, byte);
- }
- }
-
- /// End a synchronized update.
- pub fn stop_sync<H>(&mut self, handler: &mut H)
- where
- H: Handler,
- {
- // Process all synchronized bytes.
- for i in 0..self.state.sync_state.buffer.len() {
- let byte = self.state.sync_state.buffer[i];
- let mut performer = Performer::new(&mut self.state, handler);
- self.parser.advance(&mut performer, byte);
- }
-
- // Resetting state after processing makes sure we don't interpret buffered sync escapes.
- self.state.sync_state.buffer.clear();
- self.state.sync_state.timeout = None;
- }
+struct CursorShapeVisitor;
- /// Synchronized update expiration time.
- #[inline]
- pub fn sync_timeout(&self) -> Option<&Instant> {
- self.state.sync_state.timeout.as_ref()
- }
+impl<'de> serde::de::Visitor<'de> for CursorShapeVisitor {
+ type Value = CursorShapeShim;
- /// Number of bytes in the synchronization buffer.
- #[inline]
- pub fn sync_bytes_count(&self) -> usize {
- self.state.sync_state.buffer.len()
+ fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ formatter.write_str("one of `Block`, `Underline`, `Beam`")
}
- /// Process a new byte during a synchronized update.
- #[cold]
- fn advance_sync<H>(&mut self, handler: &mut H, byte: u8)
+ fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
- H: Handler,
+ E: serde::de::Error,
{
- self.state.sync_state.buffer.push(byte);
-
- // Handle sync DCS escape sequences.
- match self.state.sync_state.pending_dcs {
- Some(_) => self.advance_sync_dcs_end(handler, byte),
- None => self.advance_sync_dcs_start(),
- }
- }
-
- /// Find the start of sync DCS sequences.
- fn advance_sync_dcs_start(&mut self) {
- // Get the last few bytes for comparison.
- let len = self.state.sync_state.buffer.len();
- let offset = len.saturating_sub(SYNC_ESCAPE_START_LEN);
- let end = &self.state.sync_state.buffer[offset..];
-
- // Check for extension/termination of the synchronized update.
- if end == SYNC_START_ESCAPE_START {
- self.state.sync_state.pending_dcs = Some(Dcs::SyncStart);
- } else if end == SYNC_END_ESCAPE_START || len >= SYNC_BUFFER_SIZE - 1 {
- self.state.sync_state.pending_dcs = Some(Dcs::SyncEnd);
+ match s.to_lowercase().as_str() {
+ "block" => Ok(CursorShapeShim(CursorShape::Block)),
+ "underline" => Ok(CursorShapeShim(CursorShape::Underline)),
+ "beam" => Ok(CursorShapeShim(CursorShape::Beam)),
+ _ => Err(E::custom(format!(
+ "unknown variant `{0}`, expected {1}",
+ s, "one of `Block`, `Underline`, `Beam`"
+ ))),
}
}
+}
- /// Parse the DCS termination sequence for synchronized updates.
- fn advance_sync_dcs_end<H>(&mut self, handler: &mut H, byte: u8)
+impl<'de> serde::Deserialize<'de> for CursorShapeShim {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
- H: Handler,
+ D: serde::Deserializer<'de>,
{
- match byte {
- // Ignore DCS passthrough characters.
- 0x00..=0x17 | 0x19 | 0x1c..=0x7f | 0xa0..=0xff => (),
- // Cancel the DCS sequence.
- 0x18 | 0x1a | 0x80..=0x9f => self.state.sync_state.pending_dcs = None,
- // Dispatch on ESC.
- 0x1b => match self.state.sync_state.pending_dcs.take() {
- Some(Dcs::SyncStart) => {
- self.state.sync_state.timeout = Some(Instant::now() + SYNC_UPDATE_TIMEOUT);
- },
- Some(Dcs::SyncEnd) => self.stop_sync(handler),
- None => (),
- },
- }
+ deserializer.deserialize_str(CursorShapeVisitor)
}
}
-/// Helper type that implements `vte::Perform`.
-///
-/// Processor creates a Performer when running advance and passes the Performer
-/// to `vte::Parser`.
-struct Performer<'a, H: Handler> {
- state: &'a mut ProcessorState,
- handler: &'a mut H,
-}
-
-impl<'a, H: Handler + 'a> Performer<'a, H> {
- /// Create a performer.
- #[inline]
- pub fn new<'b>(state: &'b mut ProcessorState, handler: &'b mut H) -> Performer<'b, H> {
- Performer { state, handler }
- }
-}
-
-/// Type that handles actions from the parser.
-///
-/// XXX Should probably not provide default impls for everything, but it makes
-/// writing specific handler impls for tests far easier.
-pub trait Handler {
- /// OSC to set window title.
- fn set_title(&mut self, _: Option<String>) {}
-
- /// Set the cursor style.
- fn set_cursor_style(&mut self, _: Option<CursorStyle>) {}
-
- /// Set the cursor shape.
- fn set_cursor_shape(&mut self, _shape: CursorShape) {}
-
- /// A character to be displayed.
- fn input(&mut self, _c: char) {}
-
- /// Set cursor to position.
- fn goto(&mut self, _: Line, _: Column) {}
-
- /// Set cursor to specific row.
- fn goto_line(&mut self, _: Line) {}
-
- /// Set cursor to specific column.
- fn goto_col(&mut self, _: Column) {}
-
- /// Insert blank characters in current line starting from cursor.
- fn insert_blank(&mut self, _: usize) {}
-
- /// Move cursor up `rows`.
- fn move_up(&mut self, _: usize) {}
-
- /// Move cursor down `rows`.
- fn move_down(&mut self, _: usize) {}
-
- /// Identify the terminal (should write back to the pty stream).
- fn identify_terminal(&mut self, _intermediate: Option<char>) {}
-
- /// Report device status.
- fn device_status(&mut self, _: usize) {}
-
- /// Move cursor forward `cols`.
- fn move_forward(&mut self, _: Column) {}
-
- /// Move cursor backward `cols`.
- fn move_backward(&mut self, _: Column) {}
-
- /// Move cursor down `rows` and set to column 1.
- fn move_down_and_cr(&mut self, _: usize) {}
-
- /// Move cursor up `rows` and set to column 1.
- fn move_up_and_cr(&mut self, _: usize) {}
-
- /// Put `count` tabs.
- fn put_tab(&mut self, _count: u16) {}
-
- /// Backspace `count` characters.
- fn backspace(&mut self) {}
-
- /// Carriage return.
- fn carriage_return(&mut self) {}
-
- /// Linefeed.
- fn linefeed(&mut self) {}
-
- /// Ring the bell.
- ///
- /// Hopefully this is never implemented.
- fn bell(&mut self) {}
-
- /// Substitute char under cursor.
- fn substitute(&mut self) {}
-
- /// Newline.
- fn newline(&mut self) {}
-
- /// Set current position as a tabstop.
- fn set_horizontal_tabstop(&mut self) {}
-
- /// Scroll up `rows` rows.
- fn scroll_up(&mut self, _: usize) {}
-
- /// Scroll down `rows` rows.
- fn scroll_down(&mut self, _: usize) {}
-
- /// Insert `count` blank lines.
- fn insert_blank_lines(&mut self, _: usize) {}
-
- /// Delete `count` lines.
- fn delete_lines(&mut self, _: usize) {}
-
- /// Erase `count` chars in current line following cursor.
- ///
- /// Erase means resetting to the default state (default colors, no content,
- /// no mode flags).
- fn erase_chars(&mut self, _: Column) {}
-
- /// Delete `count` chars.
- ///
- /// Deleting a character is like the delete key on the keyboard - everything
- /// to the right of the deleted things is shifted left.
- fn delete_chars(&mut self, _: usize) {}
-
- /// Move backward `count` tabs.
- fn move_backward_tabs(&mut self, _count: u16) {}
-
- /// Move forward `count` tabs.
- fn move_forward_tabs(&mut self, _count: u16) {}
-
- /// Save current cursor position.
- fn save_cursor_position(&mut self) {}
-
- /// Restore cursor position.
- fn restore_cursor_position(&mut self) {}
-
- /// Clear current line.
- fn clear_line(&mut self, _mode: LineClearMode) {}
-
- /// Clear screen.
- fn clear_screen(&mut self, _mode: ClearMode) {}
-
- /// Clear tab stops.
- fn clear_tabs(&mut self, _mode: TabulationClearMode) {}
-
- /// Reset terminal state.
- fn reset_state(&mut self) {}
-
- /// Reverse Index.
- ///
- /// Move the active position to the same horizontal position on the
- /// preceding line. If the active position is at the top margin, a scroll
- /// down is performed.
- fn reverse_index(&mut self) {}
-
- /// Set a terminal attribute.
- fn terminal_attribute(&mut self, _attr: Attr) {}
-
- /// Set mode.
- fn set_mode(&mut self, _mode: Mode) {}
-
- /// Unset mode.
- fn unset_mode(&mut self, _: Mode) {}
-
- /// DECSTBM - Set the terminal scrolling region.
- fn set_scrolling_region(&mut self, _top: usize, _bottom: Option<usize>) {}
-
- /// DECKPAM - Set keypad to applications mode (ESCape instead of digits).
- fn set_keypad_application_mode(&mut self) {}
-
- /// DECKPNM - Set keypad to numeric mode (digits instead of ESCape seq).
- fn unset_keypad_application_mode(&mut self) {}
-
- /// Set one of the graphic character sets, G0 to G3, as the active charset.
- ///
- /// 'Invoke' one of G0 to G3 in the GL area. Also referred to as shift in,
- /// shift out and locking shift depending on the set being activated.
- fn set_active_charset(&mut self, _: CharsetIndex) {}
-
- /// Assign a graphic character set to G0, G1, G2 or G3.
- ///
- /// 'Designate' a graphic character set as one of G0 to G3, so that it can
- /// later be 'invoked' by `set_active_charset`.
- fn configure_charset(&mut self, _: CharsetIndex, _: StandardCharset) {}
-
- /// Set an indexed color value.
- fn set_color(&mut self, _: usize, _: Rgb) {}
-
- /// Respond to a color query escape sequence.
- fn dynamic_color_sequence(&mut self, _: String, _: usize, _: &str) {}
-
- /// Reset an indexed color to original value.
- fn reset_color(&mut self, _: usize) {}
-
- /// Store data into clipboard.
- fn clipboard_store(&mut self, _: u8, _: &[u8]) {}
-
- /// Load data from clipboard.
- fn clipboard_load(&mut self, _: u8, _: &str) {}
-
- /// Run the decaln routine.
- fn decaln(&mut self) {}
-
- /// Push a title onto the stack.
- fn push_title(&mut self) {}
-
- /// Pop the last title from the stack.
- fn pop_title(&mut self) {}
-
- /// Report text area size in pixels.
- fn text_area_size_pixels(&mut self) {}
-
- /// Report text area size in characters.
- fn text_area_size_chars(&mut self) {}
-
- /// Set hyperlink.
- fn set_hyperlink(&mut self, _: Option<Hyperlink>) {}
-}
-
-/// Terminal cursor configuration.
-#[derive(ConfigDeserialize, Default, Debug, Eq, PartialEq, Copy, Clone, Hash)]
-pub struct CursorStyle {
- pub shape: CursorShape,
- pub blinking: bool,
-}
-
-/// Terminal cursor shape.
-#[derive(ConfigDeserialize, Debug, Eq, PartialEq, Copy, Clone, Hash)]
-pub enum CursorShape {
- /// Cursor is a block like `▒`.
- Block,
-
- /// Cursor is an underscore like `_`.
- Underline,
-
- /// Cursor is a vertical bar `⎸`.
- Beam,
-
- /// Cursor is a box like `☐`.
- #[config(skip)]
- HollowBlock,
-
- /// Invisible cursor.
- #[config(skip)]
- Hidden,
-}
-
-impl Default for CursorShape {
- fn default() -> CursorShape {
- CursorShape::Block
- }
-}
-
-/// Terminal modes.
-#[derive(Debug, Eq, PartialEq)]
-pub enum Mode {
- /// ?1
- CursorKeys = 1,
- /// Select 80 or 132 columns per page (DECCOLM).
- ///
- /// CSI ? 3 h -> set 132 column font.
- /// CSI ? 3 l -> reset 80 column font.
- ///
- /// Additionally,
- ///
- /// * set margins to default positions
- /// * erases all data in page memory
- /// * resets DECLRMM to unavailable
- /// * clears data from the status line (if set to host-writable)
- ColumnMode = 3,
- /// IRM Insert Mode.
- ///
- /// NB should be part of non-private mode enum.
- ///
- /// * `CSI 4 h` change to insert mode
- /// * `CSI 4 l` reset to replacement mode
- Insert = 4,
- /// ?6
- Origin = 6,
- /// ?7
- LineWrap = 7,
- /// ?12
- BlinkingCursor = 12,
- /// 20
- ///
- /// NB This is actually a private mode. We should consider adding a second
- /// enumeration for public/private modesets.
- LineFeedNewLine = 20,
- /// ?25
- ShowCursor = 25,
- /// ?1000
- ReportMouseClicks = 1000,
- /// ?1002
- ReportCellMouseMotion = 1002,
- /// ?1003
- ReportAllMouseMotion = 1003,
- /// ?1004
- ReportFocusInOut = 1004,
- /// ?1005
- Utf8Mouse = 1005,
- /// ?1006
- SgrMouse = 1006,
- /// ?1007
- AlternateScroll = 1007,
- /// ?1042
- UrgencyHints = 1042,
- /// ?1049
- SwapScreenAndSetRestoreCursor = 1049,
- /// ?2004
- BracketedPaste = 2004,
-}
-
-impl Mode {
- /// Create mode from a primitive.
- pub fn from_primitive(intermediate: Option<&u8>, num: u16) -> Option<Mode> {
- let private = match intermediate {
- Some(b'?') => true,
- None => false,
- _ => return None,
- };
-
- if private {
- Some(match num {
- 1 => Mode::CursorKeys,
- 3 => Mode::ColumnMode,
- 6 => Mode::Origin,
- 7 => Mode::LineWrap,
- 12 => Mode::BlinkingCursor,
- 25 => Mode::ShowCursor,
- 1000 => Mode::ReportMouseClicks,
- 1002 => Mode::ReportCellMouseMotion,
- 1003 => Mode::ReportAllMouseMotion,
- 1004 => Mode::ReportFocusInOut,
- 1005 => Mode::Utf8Mouse,
- 1006 => Mode::SgrMouse,
- 1007 => Mode::AlternateScroll,
- 1042 => Mode::UrgencyHints,
- 1049 => Mode::SwapScreenAndSetRestoreCursor,
- 2004 => Mode::BracketedPaste,
- _ => {
- trace!("[unimplemented] primitive mode: {}", num);
- return None;
- },
- })
- } else {
- Some(match num {
- 4 => Mode::Insert,
- 20 => Mode::LineFeedNewLine,
- _ => return None,
- })
- }
- }
-}
-
-/// Mode for clearing line.
-///
-/// Relative to cursor.
-#[derive(Debug)]
-pub enum LineClearMode {
- /// Clear right of cursor.
- Right,
- /// Clear left of cursor.
- Left,
- /// Clear entire line.
- All,
-}
-
-/// Mode for clearing terminal.
-///
-/// Relative to cursor.
-#[derive(Debug)]
-pub enum ClearMode {
- /// Clear below cursor.
- Below,
- /// Clear above cursor.
- Above,
- /// Clear entire terminal.
- All,
- /// Clear 'saved' lines (scrollback).
- Saved,
-}
-
-/// Mode for clearing tab stops.
-#[derive(Debug)]
-pub enum TabulationClearMode {
- /// Clear stop under cursor.
- Current,
- /// Clear all stops.
- All,
-}
-
-/// Standard colors.
-///
-/// The order here matters since the enum should be castable to a `usize` for
-/// indexing a color list.
-#[derive(Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
-pub enum NamedColor {
- /// Black.
- Black = 0,
- /// Red.
- Red,
- /// Green.
- Green,
- /// Yellow.
- Yellow,
- /// Blue.
- Blue,
- /// Magenta.
- Magenta,
- /// Cyan.
- Cyan,
- /// White.
- White,
- /// Bright black.
- BrightBlack,
- /// Bright red.
- BrightRed,
- /// Bright green.
- BrightGreen,
- /// Bright yellow.
- BrightYellow,
- /// Bright blue.
- BrightBlue,
- /// Bright magenta.
- BrightMagenta,
- /// Bright cyan.
- BrightCyan,
- /// Bright white.
- BrightWhite,
- /// The foreground color.
- Foreground = 256,
- /// The background color.
- Background,
- /// Color for the cursor itself.
- Cursor,
- /// Dim black.
- DimBlack,
- /// Dim red.
- DimRed,
- /// Dim green.
- DimGreen,
- /// Dim yellow.
- DimYellow,
- /// Dim blue.
- DimBlue,
- /// Dim magenta.
- DimMagenta,
- /// Dim cyan.
- DimCyan,
- /// Dim white.
- DimWhite,
- /// The bright foreground color.
- BrightForeground,
- /// Dim foreground.
- DimForeground,
-}
-
-impl NamedColor {
- #[must_use]
- pub fn to_bright(self) -> Self {
- match self {
- NamedColor::Foreground => NamedColor::BrightForeground,
- NamedColor::Black => NamedColor::BrightBlack,
- NamedColor::Red => NamedColor::BrightRed,
- NamedColor::Green => NamedColor::BrightGreen,
- NamedColor::Yellow => NamedColor::BrightYellow,
- NamedColor::Blue => NamedColor::BrightBlue,
- NamedColor::Magenta => NamedColor::BrightMagenta,
- NamedColor::Cyan => NamedColor::BrightCyan,
- NamedColor::White => NamedColor::BrightWhite,
- NamedColor::DimForeground => NamedColor::Foreground,
- NamedColor::DimBlack => NamedColor::Black,
- NamedColor::DimRed => NamedColor::Red,
- NamedColor::DimGreen => NamedColor::Green,
- NamedColor::DimYellow => NamedColor::Yellow,
- NamedColor::DimBlue => NamedColor::Blue,
- NamedColor::DimMagenta => NamedColor::Magenta,
- NamedColor::DimCyan => NamedColor::Cyan,
- NamedColor::DimWhite => NamedColor::White,
- val => val,
- }
- }
-
- #[must_use]
- pub fn to_dim(self) -> Self {
- match self {
- NamedColor::Black => NamedColor::DimBlack,
- NamedColor::Red => NamedColor::DimRed,
- NamedColor::Green => NamedColor::DimGreen,
- NamedColor::Yellow => NamedColor::DimYellow,
- NamedColor::Blue => NamedColor::DimBlue,
- NamedColor::Magenta => NamedColor::DimMagenta,
- NamedColor::Cyan => NamedColor::DimCyan,
- NamedColor::White => NamedColor::DimWhite,
- NamedColor::Foreground => NamedColor::DimForeground,
- NamedColor::BrightBlack => NamedColor::Black,
- NamedColor::BrightRed => NamedColor::Red,
- NamedColor::BrightGreen => NamedColor::Green,
- NamedColor::BrightYellow => NamedColor::Yellow,
- NamedColor::BrightBlue => NamedColor::Blue,
- NamedColor::BrightMagenta => NamedColor::Magenta,
- NamedColor::BrightCyan => NamedColor::Cyan,
- NamedColor::BrightWhite => NamedColor::White,
- NamedColor::BrightForeground => NamedColor::Foreground,
- val => val,
- }
- }
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
-pub enum Color {
- Named(NamedColor),
- Spec(Rgb),
- Indexed(u8),
-}
-
-/// Terminal character attributes.
-#[derive(Debug, Eq, PartialEq)]
-pub enum Attr {
- /// Clear all special abilities.
- Reset,
- /// Bold text.
- Bold,
- /// Dim or secondary color.
- Dim,
- /// Italic text.
- Italic,
- /// Underline text.
- Underline,
- /// Underlined twice.
- DoubleUnderline,
- /// Undercurled text.
- Undercurl,
- /// Dotted underlined text.
- DottedUnderline,
- /// Dashed underlined text.
- DashedUnderline,
- /// Blink cursor slowly.
- BlinkSlow,
- /// Blink cursor fast.
- BlinkFast,
- /// Invert colors.
- Reverse,
- /// Do not display characters.
- Hidden,
- /// Strikeout text.
- Strike,
- /// Cancel bold.
- CancelBold,
- /// Cancel bold and dim.
- CancelBoldDim,
- /// Cancel italic.
- CancelItalic,
- /// Cancel all underlines.
- CancelUnderline,
- /// Cancel blink.
- CancelBlink,
- /// Cancel inversion.
- CancelReverse,
- /// Cancel text hiding.
- CancelHidden,
- /// Cancel strikeout.
- CancelStrike,
- /// Set indexed foreground color.
- Foreground(Color),
- /// Set indexed background color.
- Background(Color),
- /// Underline color.
- UnderlineColor(Option<Color>),
-}
-
-/// Identifiers which can be assigned to a graphic character set.
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub enum CharsetIndex {
- /// Default set, is designated as ASCII at startup.
- G0,
- G1,
- G2,
- G3,
-}
-
-impl Default for CharsetIndex {
- fn default() -> Self {
- CharsetIndex::G0
- }
-}
-
-/// Standard or common character sets which can be designated as G0-G3.
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub enum StandardCharset {
- Ascii,
- SpecialCharacterAndLineDrawing,
-}
-
-impl Default for StandardCharset {
- fn default() -> Self {
- StandardCharset::Ascii
- }
-}
-
-impl StandardCharset {
- /// Switch/Map character to the active charset. Ascii is the common case and
- /// for that we want to do as little as possible.
- #[inline]
- pub fn map(self, c: char) -> char {
- match self {
- StandardCharset::Ascii => c,
- StandardCharset::SpecialCharacterAndLineDrawing => match c {
- '_' => ' ',
- '`' => '◆',
- 'a' => '▒',
- 'b' => '\u{2409}', // Symbol for horizontal tabulation
- 'c' => '\u{240c}', // Symbol for form feed
- 'd' => '\u{240d}', // Symbol for carriage return
- 'e' => '\u{240a}', // Symbol for line feed
- 'f' => '°',
- 'g' => '±',
- 'h' => '\u{2424}', // Symbol for newline
- 'i' => '\u{240b}', // Symbol for vertical tabulation
- 'j' => '┘',
- 'k' => '┐',
- 'l' => '┌',
- 'm' => '└',
- 'n' => '┼',
- 'o' => '⎺',
- 'p' => '⎻',
- 'q' => '─',
- 'r' => '⎼',
- 's' => '⎽',
- 't' => '├',
- 'u' => '┤',
- 'v' => '┴',
- 'w' => '┬',
- 'x' => '│',
- 'y' => '≤',
- 'z' => '≥',
- '{' => 'π',
- '|' => '≠',
- '}' => '£',
- '~' => '·',
- _ => c,
- },
- }
- }
-}
-
-impl<'a, H> vte::Perform for Performer<'a, H>
-where
- H: Handler + 'a,
-{
- #[inline]
- fn print(&mut self, c: char) {
- self.handler.input(c);
- self.state.preceding_char = Some(c);
- }
-
- #[inline]
- fn execute(&mut self, byte: u8) {
- match byte {
- C0::HT => self.handler.put_tab(1),
- C0::BS => self.handler.backspace(),
- C0::CR => self.handler.carriage_return(),
- C0::LF | C0::VT | C0::FF => self.handler.linefeed(),
- C0::BEL => self.handler.bell(),
- C0::SUB => self.handler.substitute(),
- C0::SI => self.handler.set_active_charset(CharsetIndex::G0),
- C0::SO => self.handler.set_active_charset(CharsetIndex::G1),
- _ => debug!("[unhandled] execute byte={:02x}", byte),
- }
- }
-
- #[inline]
- fn hook(&mut self, params: &Params, intermediates: &[u8], ignore: bool, action: char) {
- match (action, intermediates) {
- ('s', [b'=']) => {
- // Start a synchronized update. The end is handled with a separate parser.
- if params.iter().next().map_or(false, |param| param[0] == 1) {
- self.state.dcs = Some(Dcs::SyncStart);
- }
- },
- _ => debug!(
- "[unhandled hook] params={:?}, ints: {:?}, ignore: {:?}, action: {:?}",
- params, intermediates, ignore, action
- ),
- }
- }
-
- #[inline]
- fn put(&mut self, byte: u8) {
- debug!("[unhandled put] byte={:?}", byte);
- }
-
- #[inline]
- fn unhook(&mut self) {
- match self.state.dcs {
- Some(Dcs::SyncStart) => {
- self.state.sync_state.timeout = Some(Instant::now() + SYNC_UPDATE_TIMEOUT);
- },
- Some(Dcs::SyncEnd) => (),
- _ => debug!("[unhandled unhook]"),
- }
- }
-
- #[inline]
- fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) {
- let terminator = if bell_terminated { "\x07" } else { "\x1b\\" };
-
- fn unhandled(params: &[&[u8]]) {
- let mut buf = String::new();
- for items in params {
- buf.push('[');
- for item in *items {
- let _ = write!(buf, "{:?}", *item as char);
- }
- buf.push_str("],");
- }
- debug!("[unhandled osc_dispatch]: [{}] at line {}", &buf, line!());
- }
-
- if params.is_empty() || params[0].is_empty() {
- return;
- }
-
- match params[0] {
- // Set window title.
- b"0" | b"2" => {
- if params.len() >= 2 {
- let title = params[1..]
- .iter()
- .flat_map(|x| str::from_utf8(x))
- .collect::<Vec<&str>>()
- .join(";")
- .trim()
- .to_owned();
- self.handler.set_title(Some(title));
- return;
- }
- unhandled(params);
- },
-
- // Set color index.
- b"4" => {
- if params.len() <= 1 || params.len() % 2 == 0 {
- unhandled(params);
- return;
- }
-
- for chunk in params[1..].chunks(2) {
- let index = match parse_number(chunk[0]) {
- Some(index) => index,
- None => {
- unhandled(params);
- continue;
- },
- };
-
- if let Some(c) = xparse_color(chunk[1]) {
- self.handler.set_color(index as usize, c);
- } else if chunk[1] == b"?" {
- let prefix = format!("4;{index}");
- self.handler.dynamic_color_sequence(prefix, index as usize, terminator);
- } else {
- unhandled(params);
- }
- }
- },
-
- // Hyperlink.
- b"8" if params.len() > 2 => {
- let link_params = params[1];
-
- // NOTE: The escape sequence is of form 'OSC 8 ; params ; URI ST', where
- // URI is URL-encoded. However `;` is a special character and might be
- // passed as is, thus we need to rebuild the URI.
- let mut uri = str::from_utf8(params[2]).unwrap_or_default().to_string();
- for param in params[3..].iter() {
- uri.push(';');
- uri.push_str(str::from_utf8(param).unwrap_or_default());
- }
-
- // The OSC 8 escape sequence must be stopped when getting an empty `uri`.
- if uri.is_empty() {
- self.handler.set_hyperlink(None);
- return;
- }
-
- // Link parameters are in format of `key1=value1:key2=value2`. Currently only key
- // `id` is defined.
- let id = link_params
- .split(|&b| b == b':')
- .find_map(|kv| kv.strip_prefix(b"id="))
- .and_then(|kv| str::from_utf8(kv).ok());
-
- self.handler.set_hyperlink(Some(Hyperlink::new(id, uri)));
- },
-
- // Get/set Foreground, Background, Cursor colors.
- b"10" | b"11" | b"12" => {
- if params.len() >= 2 {
- if let Some(mut dynamic_code) = parse_number(params[0]) {
- for param in &params[1..] {
- // 10 is the first dynamic color, also the foreground.
- let offset = dynamic_code as usize - 10;
- let index = NamedColor::Foreground as usize + offset;
-
- // End of setting dynamic colors.
- if index > NamedColor::Cursor as usize {
- unhandled(params);
- break;
- }
-
- if let Some(color) = xparse_color(param) {
- self.handler.set_color(index, color);
- } else if param == b"?" {
- self.handler.dynamic_color_sequence(
- dynamic_code.to_string(),
- index,
- terminator,
- );
- } else {
- unhandled(params);
- }
- dynamic_code += 1;
- }
- return;
- }
- }
- unhandled(params);
- },
-
- // Set cursor style.
- b"50" => {
- if params.len() >= 2
- && params[1].len() >= 13
- && params[1][0..12] == *b"CursorShape="
- {
- let shape = match params[1][12] as char {
- '0' => CursorShape::Block,
- '1' => CursorShape::Beam,
- '2' => CursorShape::Underline,
- _ => return unhandled(params),
- };
- self.handler.set_cursor_shape(shape);
- return;
- }
- unhandled(params);
- },
-
- // Set clipboard.
- b"52" => {
- if params.len() < 3 {
- return unhandled(params);
- }
-
- let clipboard = params[1].first().unwrap_or(&b'c');
- match params[2] {
- b"?" => self.handler.clipboard_load(*clipboard, terminator),
- base64 => self.handler.clipboard_store(*clipboard, base64),
- }
- },
-
- // Reset color index.
- b"104" => {
- // Reset all color indexes when no parameters are given.
- if params.len() == 1 || params[1].is_empty() {
- for i in 0..256 {
- self.handler.reset_color(i);
- }
- return;
- }
-
- // Reset color indexes given as parameters.
- for param in &params[1..] {
- match parse_number(param) {
- Some(index) => self.handler.reset_color(index as usize),
- None => unhandled(params),
- }
- }
- },
-
- // Reset foreground color.
- b"110" => self.handler.reset_color(NamedColor::Foreground as usize),
-
- // Reset background color.
- b"111" => self.handler.reset_color(NamedColor::Background as usize),
-
- // Reset text cursor color.
- b"112" => self.handler.reset_color(NamedColor::Cursor as usize),
-
- _ => unhandled(params),
- }
- }
-
- #[allow(clippy::cognitive_complexity)]
- #[inline]
- fn csi_dispatch(
+impl alacritty_config::SerdeReplace for CursorShapeShim {
+ fn replace(
&mut self,
- params: &Params,
- intermediates: &[u8],
- has_ignored_intermediates: bool,
- action: char,
- ) {
- macro_rules! unhandled {
- () => {{
- debug!(
- "[Unhandled CSI] action={:?}, params={:?}, intermediates={:?}",
- action, params, intermediates
- );
- }};
- }
-
- if has_ignored_intermediates || intermediates.len() > 1 {
- unhandled!();
- return;
- }
-
- let mut params_iter = params.iter();
- let handler = &mut self.handler;
-
- let mut next_param_or = |default: u16| match params_iter.next() {
- Some(&[param, ..]) if param != 0 => param,
- _ => default,
- };
-
- match (action, intermediates) {
- ('@', []) => handler.insert_blank(next_param_or(1) as usize),
- ('A', []) => handler.move_up(next_param_or(1) as usize),
- ('B', []) | ('e', []) => handler.move_down(next_param_or(1) as usize),
- ('b', []) => {
- if let Some(c) = self.state.preceding_char {
- for _ in 0..next_param_or(1) {
- handler.input(c);
- }
- } else {
- debug!("tried to repeat with no preceding char");
- }
- },
- ('C', []) | ('a', []) => handler.move_forward(Column(next_param_or(1) as usize)),
- ('c', intermediates) if next_param_or(0) == 0 => {
- handler.identify_terminal(intermediates.first().map(|&i| i as char))
- },
- ('D', []) => handler.move_backward(Column(next_param_or(1) as usize)),
- ('d', []) => handler.goto_line(Line(next_param_or(1) as i32 - 1)),
- ('E', []) => handler.move_down_and_cr(next_param_or(1) as usize),
- ('F', []) => handler.move_up_and_cr(next_param_or(1) as usize),
- ('G', []) | ('`', []) => handler.goto_col(Column(next_param_or(1) as usize - 1)),
- ('g', []) => {
- let mode = match next_param_or(0) {
- 0 => TabulationClearMode::Current,
- 3 => TabulationClearMode::All,
- _ => {
- unhandled!();
- return;
- },
- };
-
- handler.clear_tabs(mode);
- },
- ('H', []) | ('f', []) => {
- let y = next_param_or(1) as i32;
- let x = next_param_or(1) as usize;
- handler.goto(Line(y - 1), Column(x - 1));
- },
- ('h', intermediates) => {
- for param in params_iter.map(|param| param[0]) {
- match Mode::from_primitive(intermediates.first(), param) {
- Some(mode) => handler.set_mode(mode),
- None => unhandled!(),
- }
- }
- },
- ('I', []) => handler.move_forward_tabs(next_param_or(1)),
- ('J', []) => {
- let mode = match next_param_or(0) {
- 0 => ClearMode::Below,
- 1 => ClearMode::Above,
- 2 => ClearMode::All,
- 3 => ClearMode::Saved,
- _ => {
- unhandled!();
- return;
- },
- };
-
- handler.clear_screen(mode);
- },
- ('K', []) => {
- let mode = match next_param_or(0) {
- 0 => LineClearMode::Right,
- 1 => LineClearMode::Left,
- 2 => LineClearMode::All,
- _ => {
- unhandled!();
- return;
- },
- };
-
- handler.clear_line(mode);
- },
- ('L', []) => handler.insert_blank_lines(next_param_or(1) as usize),
- ('l', intermediates) => {
- for param in params_iter.map(|param| param[0]) {
- match Mode::from_primitive(intermediates.first(), param) {
- Some(mode) => handler.unset_mode(mode),
- None => unhandled!(),
- }
- }
- },
- ('M', []) => handler.delete_lines(next_param_or(1) as usize),
- ('m', []) => {
- if params.is_empty() {
- handler.terminal_attribute(Attr::Reset);
- } else {
- for attr in attrs_from_sgr_parameters(&mut params_iter) {
- match attr {
- Some(attr) => handler.terminal_attribute(attr),
- None => unhandled!(),
- }
- }
- }
- },
- ('n', []) => handler.device_status(next_param_or(0) as usize),
- ('P', []) => handler.delete_chars(next_param_or(1) as usize),
- ('q', [b' ']) => {
- // DECSCUSR (CSI Ps SP q) -- Set Cursor Style.
- let cursor_style_id = next_param_or(0);
- let shape = match cursor_style_id {
- 0 => None,
- 1 | 2 => Some(CursorShape::Block),
- 3 | 4 => Some(CursorShape::Underline),
- 5 | 6 => Some(CursorShape::Beam),
- _ => {
- unhandled!();
- return;
- },
- };
- let cursor_style =
- shape.map(|shape| CursorStyle { shape, blinking: cursor_style_id % 2 == 1 });
-
- handler.set_cursor_style(cursor_style);
- },
- ('r', []) => {
- let top = next_param_or(1) as usize;
- let bottom =
- params_iter.next().map(|param| param[0] as usize).filter(|&param| param != 0);
-
- handler.set_scrolling_region(top, bottom);
- },
- ('S', []) => handler.scroll_up(next_param_or(1) as usize),
- ('s', []) => handler.save_cursor_position(),
- ('T', []) => handler.scroll_down(next_param_or(1) as usize),
- ('t', []) => match next_param_or(1) as usize {
- 14 => handler.text_area_size_pixels(),
- 18 => handler.text_area_size_chars(),
- 22 => handler.push_title(),
- 23 => handler.pop_title(),
- _ => unhandled!(),
- },
- ('u', []) => handler.restore_cursor_position(),
- ('X', []) => handler.erase_chars(Column(next_param_or(1) as usize)),
- ('Z', []) => handler.move_backward_tabs(next_param_or(1)),
- _ => unhandled!(),
- }
- }
-
- #[inline]
- fn esc_dispatch(&mut self, intermediates: &[u8], _ignore: bool, byte: u8) {
- macro_rules! unhandled {
- () => {{
- debug!(
- "[unhandled] esc_dispatch ints={:?}, byte={:?} ({:02x})",
- intermediates, byte as char, byte
- );
- }};
- }
-
- macro_rules! configure_charset {
- ($charset:path, $intermediates:expr) => {{
- let index: CharsetIndex = match $intermediates {
- [b'('] => CharsetIndex::G0,
- [b')'] => CharsetIndex::G1,
- [b'*'] => CharsetIndex::G2,
- [b'+'] => CharsetIndex::G3,
- _ => {
- unhandled!();
- return;
- },
- };
- self.handler.configure_charset(index, $charset)
- }};
- }
-
- match (byte, intermediates) {
- (b'B', intermediates) => configure_charset!(StandardCharset::Ascii, intermediates),
- (b'D', []) => self.handler.linefeed(),
- (b'E', []) => {
- self.handler.linefeed();
- self.handler.carriage_return();
- },
- (b'H', []) => self.handler.set_horizontal_tabstop(),
- (b'M', []) => self.handler.reverse_index(),
- (b'Z', []) => self.handler.identify_terminal(None),
- (b'c', []) => self.handler.reset_state(),
- (b'0', intermediates) => {
- configure_charset!(StandardCharset::SpecialCharacterAndLineDrawing, intermediates)
- },
- (b'7', []) => self.handler.save_cursor_position(),
- (b'8', [b'#']) => self.handler.decaln(),
- (b'8', []) => self.handler.restore_cursor_position(),
- (b'=', []) => self.handler.set_keypad_application_mode(),
- (b'>', []) => self.handler.unset_keypad_application_mode(),
- // String terminator, do nothing (parser handles as string terminator).
- (b'\\', []) => (),
- _ => unhandled!(),
- }
- }
-}
-
-#[inline]
-fn attrs_from_sgr_parameters(params: &mut ParamsIter<'_>) -> Vec<Option<Attr>> {
- let mut attrs = Vec::with_capacity(params.size_hint().0);
-
- while let Some(param) = params.next() {
- let attr = match param {
- [0] => Some(Attr::Reset),
- [1] => Some(Attr::Bold),
- [2] => Some(Attr::Dim),
- [3] => Some(Attr::Italic),
- [4, 0] => Some(Attr::CancelUnderline),
- [4, 2] => Some(Attr::DoubleUnderline),
- [4, 3] => Some(Attr::Undercurl),
- [4, 4] => Some(Attr::DottedUnderline),
- [4, 5] => Some(Attr::DashedUnderline),
- [4, ..] => Some(Attr::Underline),
- [5] => Some(Attr::BlinkSlow),
- [6] => Some(Attr::BlinkFast),
- [7] => Some(Attr::Reverse),
- [8] => Some(Attr::Hidden),
- [9] => Some(Attr::Strike),
- [21] => Some(Attr::CancelBold),
- [22] => Some(Attr::CancelBoldDim),
- [23] => Some(Attr::CancelItalic),
- [24] => Some(Attr::CancelUnderline),
- [25] => Some(Attr::CancelBlink),
- [27] => Some(Attr::CancelReverse),
- [28] => Some(Attr::CancelHidden),
- [29] => Some(Attr::CancelStrike),
- [30] => Some(Attr::Foreground(Color::Named(NamedColor::Black))),
- [31] => Some(Attr::Foreground(Color::Named(NamedColor::Red))),
- [32] => Some(Attr::Foreground(Color::Named(NamedColor::Green))),
- [33] => Some(Attr::Foreground(Color::Named(NamedColor::Yellow))),
- [34] => Some(Attr::Foreground(Color::Named(NamedColor::Blue))),
- [35] => Some(Attr::Foreground(Color::Named(NamedColor::Magenta))),
- [36] => Some(Attr::Foreground(Color::Named(NamedColor::Cyan))),
- [37] => Some(Attr::Foreground(Color::Named(NamedColor::White))),
- [38] => {
- let mut iter = params.map(|param| param[0]);
- parse_sgr_color(&mut iter).map(Attr::Foreground)
- },
- [38, params @ ..] => handle_colon_rgb(params).map(Attr::Foreground),
- [39] => Some(Attr::Foreground(Color::Named(NamedColor::Foreground))),
- [40] => Some(Attr::Background(Color::Named(NamedColor::Black))),
- [41] => Some(Attr::Background(Color::Named(NamedColor::Red))),
- [42] => Some(Attr::Background(Color::Named(NamedColor::Green))),
- [43] => Some(Attr::Background(Color::Named(NamedColor::Yellow))),
- [44] => Some(Attr::Background(Color::Named(NamedColor::Blue))),
- [45] => Some(Attr::Background(Color::Named(NamedColor::Magenta))),
- [46] => Some(Attr::Background(Color::Named(NamedColor::Cyan))),
- [47] => Some(Attr::Background(Color::Named(NamedColor::White))),
- [48] => {
- let mut iter = params.map(|param| param[0]);
- parse_sgr_color(&mut iter).map(Attr::Background)
- },
- [48, params @ ..] => handle_colon_rgb(params).map(Attr::Background),
- [49] => Some(Attr::Background(Color::Named(NamedColor::Background))),
- [58] => {
- let mut iter = params.map(|param| param[0]);
- parse_sgr_color(&mut iter).map(|color| Attr::UnderlineColor(Some(color)))
- },
- [58, params @ ..] => {
- handle_colon_rgb(params).map(|color| Attr::UnderlineColor(Some(color)))
- },
- [59] => Some(Attr::UnderlineColor(None)),
- [90] => Some(Attr::Foreground(Color::Named(NamedColor::BrightBlack))),
- [91] => Some(Attr::Foreground(Color::Named(NamedColor::BrightRed))),
- [92] => Some(Attr::Foreground(Color::Named(NamedColor::BrightGreen))),
- [93] => Some(Attr::Foreground(Color::Named(NamedColor::BrightYellow))),
- [94] => Some(Attr::Foreground(Color::Named(NamedColor::BrightBlue))),
- [95] => Some(Attr::Foreground(Color::Named(NamedColor::BrightMagenta))),
- [96] => Some(Attr::Foreground(Color::Named(NamedColor::BrightCyan))),
- [97] => Some(Attr::Foreground(Color::Named(NamedColor::BrightWhite))),
- [100] => Some(Attr::Background(Color::Named(NamedColor::BrightBlack))),
- [101] => Some(Attr::Background(Color::Named(NamedColor::BrightRed))),
- [102] => Some(Attr::Background(Color::Named(NamedColor::BrightGreen))),
- [103] => Some(Attr::Background(Color::Named(NamedColor::BrightYellow))),
- [104] => Some(Attr::Background(Color::Named(NamedColor::BrightBlue))),
- [105] => Some(Attr::Background(Color::Named(NamedColor::BrightMagenta))),
- [106] => Some(Attr::Background(Color::Named(NamedColor::BrightCyan))),
- [107] => Some(Attr::Background(Color::Named(NamedColor::BrightWhite))),
- _ => None,
- };
- attrs.push(attr);
- }
-
- attrs
-}
-
-/// Handle colon separated rgb color escape sequence.
-#[inline]
-fn handle_colon_rgb(params: &[u16]) -> Option<Color> {
- let rgb_start = if params.len() > 4 { 2 } else { 1 };
- let rgb_iter = params[rgb_start..].iter().copied();
- let mut iter = iter::once(params[0]).chain(rgb_iter);
-
- parse_sgr_color(&mut iter)
-}
-
-/// Parse a color specifier from list of attributes.
-fn parse_sgr_color(params: &mut dyn Iterator<Item = u16>) -> Option<Color> {
- match params.next() {
- Some(2) => Some(Color::Spec(Rgb {
- r: u8::try_from(params.next()?).ok()?,
- g: u8::try_from(params.next()?).ok()?,
- b: u8::try_from(params.next()?).ok()?,
- })),
- Some(5) => Some(Color::Indexed(u8::try_from(params.next()?).ok()?)),
- _ => None,
- }
-}
-
-/// C0 set of 7-bit control characters (from ANSI X3.4-1977).
-#[allow(non_snake_case)]
-pub mod C0 {
- /// Null filler, terminal should ignore this character.
- pub const NUL: u8 = 0x00;
- /// Start of Header.
- pub const SOH: u8 = 0x01;
- /// Start of Text, implied end of header.
- pub const STX: u8 = 0x02;
- /// End of Text, causes some terminal to respond with ACK or NAK.
- pub const ETX: u8 = 0x03;
- /// End of Transmission.
- pub const EOT: u8 = 0x04;
- /// Enquiry, causes terminal to send ANSWER-BACK ID.
- pub const ENQ: u8 = 0x05;
- /// Acknowledge, usually sent by terminal in response to ETX.
- pub const ACK: u8 = 0x06;
- /// Bell, triggers the bell, buzzer, or beeper on the terminal.
- pub const BEL: u8 = 0x07;
- /// Backspace, can be used to define overstruck characters.
- pub const BS: u8 = 0x08;
- /// Horizontal Tabulation, move to next predetermined position.
- pub const HT: u8 = 0x09;
- /// Linefeed, move to same position on next line (see also NL).
- pub const LF: u8 = 0x0A;
- /// Vertical Tabulation, move to next predetermined line.
- pub const VT: u8 = 0x0B;
- /// Form Feed, move to next form or page.
- pub const FF: u8 = 0x0C;
- /// Carriage Return, move to first character of current line.
- pub const CR: u8 = 0x0D;
- /// Shift Out, switch to G1 (other half of character set).
- pub const SO: u8 = 0x0E;
- /// Shift In, switch to G0 (normal half of character set).
- pub const SI: u8 = 0x0F;
- /// Data Link Escape, interpret next control character specially.
- pub const DLE: u8 = 0x10;
- /// (DC1) Terminal is allowed to resume transmitting.
- pub const XON: u8 = 0x11;
- /// Device Control 2, causes ASR-33 to activate paper-tape reader.
- pub const DC2: u8 = 0x12;
- /// (DC2) Terminal must pause and refrain from transmitting.
- pub const XOFF: u8 = 0x13;
- /// Device Control 4, causes ASR-33 to deactivate paper-tape reader.
- pub const DC4: u8 = 0x14;
- /// Negative Acknowledge, used sometimes with ETX and ACK.
- pub const NAK: u8 = 0x15;
- /// Synchronous Idle, used to maintain timing in Sync communication.
- pub const SYN: u8 = 0x16;
- /// End of Transmission block.
- pub const ETB: u8 = 0x17;
- /// Cancel (makes VT100 abort current escape sequence if any).
- pub const CAN: u8 = 0x18;
- /// End of Medium.
- pub const EM: u8 = 0x19;
- /// Substitute (VT100 uses this to display parity errors).
- pub const SUB: u8 = 0x1A;
- /// Prefix to an escape sequence.
- pub const ESC: u8 = 0x1B;
- /// File Separator.
- pub const FS: u8 = 0x1C;
- /// Group Separator.
- pub const GS: u8 = 0x1D;
- /// Record Separator (sent by VT132 in block-transfer mode).
- pub const RS: u8 = 0x1E;
- /// Unit Separator.
- pub const US: u8 = 0x1F;
- /// Delete, should be ignored by terminal.
- pub const DEL: u8 = 0x7f;
-}
-
-// Tests for parsing escape sequences.
-//
-// Byte sequences used in these tests are recording of pty stdout.
-#[cfg(test)]
-mod tests {
- use super::*;
-
- use crate::term::color::Rgb;
-
- struct MockHandler {
- index: CharsetIndex,
- charset: StandardCharset,
- attr: Option<Attr>,
- identity_reported: bool,
- color: Option<Rgb>,
- reset_colors: Vec<usize>,
- }
-
- impl Handler for MockHandler {
- fn terminal_attribute(&mut self, attr: Attr) {
- self.attr = Some(attr);
- }
-
- fn configure_charset(&mut self, index: CharsetIndex, charset: StandardCharset) {
- self.index = index;
- self.charset = charset;
- }
-
- fn set_active_charset(&mut self, index: CharsetIndex) {
- self.index = index;
- }
-
- fn identify_terminal(&mut self, _intermediate: Option<char>) {
- self.identity_reported = true;
- }
-
- fn reset_state(&mut self) {
- *self = Self::default();
- }
-
- fn set_color(&mut self, _: usize, c: Rgb) {
- self.color = Some(c);
- }
-
- fn reset_color(&mut self, index: usize) {
- self.reset_colors.push(index)
- }
- }
-
- impl Default for MockHandler {
- fn default() -> MockHandler {
- MockHandler {
- index: CharsetIndex::G0,
- charset: StandardCharset::Ascii,
- attr: None,
- identity_reported: false,
- color: None,
- reset_colors: Vec::new(),
- }
- }
- }
-
- #[test]
- fn parse_control_attribute() {
- static BYTES: &[u8] = &[0x1b, b'[', b'1', b'm'];
-
- let mut parser = Processor::new();
- let mut handler = MockHandler::default();
-
- for byte in BYTES {
- parser.advance(&mut handler, *byte);
- }
-
- assert_eq!(handler.attr, Some(Attr::Bold));
- }
-
- #[test]
- fn parse_terminal_identity_csi() {
- let bytes: &[u8] = &[0x1b, b'[', b'1', b'c'];
-
- let mut parser = Processor::new();
- let mut handler = MockHandler::default();
-
- for byte in bytes {
- parser.advance(&mut handler, *byte);
- }
-
- assert!(!handler.identity_reported);
- handler.reset_state();
-
- let bytes: &[u8] = &[0x1b, b'[', b'c'];
-
- for byte in bytes {
- parser.advance(&mut handler, *byte);
- }
-
- assert!(handler.identity_reported);
- handler.reset_state();
-
- let bytes: &[u8] = &[0x1b, b'[', b'0', b'c'];
-
- for byte in bytes {
- parser.advance(&mut handler, *byte);
- }
-
- assert!(handler.identity_reported);
- }
-
- #[test]
- fn parse_terminal_identity_esc() {
- let bytes: &[u8] = &[0x1b, b'Z'];
-
- let mut parser = Processor::new();
- let mut handler = MockHandler::default();
-
- for byte in bytes {
- parser.advance(&mut handler, *byte);
- }
-
- assert!(handler.identity_reported);
- handler.reset_state();
-
- let bytes: &[u8] = &[0x1b, b'#', b'Z'];
-
- let mut parser = Processor::new();
- let mut handler = MockHandler::default();
-
- for byte in bytes {
- parser.advance(&mut handler, *byte);
- }
-
- assert!(!handler.identity_reported);
- handler.reset_state();
- }
-
- #[test]
- fn parse_truecolor_attr() {
- static BYTES: &[u8] = &[
- 0x1b, b'[', b'3', b'8', b';', b'2', b';', b'1', b'2', b'8', b';', b'6', b'6', b';',
- b'2', b'5', b'5', b'm',
- ];
-
- let mut parser = Processor::new();
- let mut handler = MockHandler::default();
-
- for byte in BYTES {
- parser.advance(&mut handler, *byte);
- }
-
- let spec = Rgb { r: 128, g: 66, b: 255 };
-
- assert_eq!(handler.attr, Some(Attr::Foreground(Color::Spec(spec))));
- }
-
- /// No exactly a test; useful for debugging.
- #[test]
- fn parse_zsh_startup() {
- static BYTES: &[u8] = &[
- 0x1b, b'[', b'1', b'm', 0x1b, b'[', b'7', b'm', b'%', 0x1b, b'[', b'2', b'7', b'm',
- 0x1b, b'[', b'1', b'm', 0x1b, b'[', b'0', b'm', b' ', b' ', b' ', b' ', b' ', b' ',
- b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ',
- b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ',
- b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ',
- b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ',
- b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ',
- b' ', b' ', b' ', b'\r', b' ', b'\r', b'\r', 0x1b, b'[', b'0', b'm', 0x1b, b'[', b'2',
- b'7', b'm', 0x1b, b'[', b'2', b'4', b'm', 0x1b, b'[', b'J', b'j', b'w', b'i', b'l',
- b'm', b'@', b'j', b'w', b'i', b'l', b'm', b'-', b'd', b'e', b's', b'k', b' ', 0x1b,
- b'[', b'0', b'1', b';', b'3', b'2', b'm', 0xe2, 0x9e, 0x9c, b' ', 0x1b, b'[', b'0',
- b'1', b';', b'3', b'2', b'm', b' ', 0x1b, b'[', b'3', b'6', b'm', b'~', b'/', b'c',
- b'o', b'd', b'e',
- ];
-
- let mut handler = MockHandler::default();
- let mut parser = Processor::new();
-
- for byte in BYTES {
- parser.advance(&mut handler, *byte);
- }
- }
-
- #[test]
- fn parse_designate_g0_as_line_drawing() {
- static BYTES: &[u8] = &[0x1b, b'(', b'0'];
- let mut parser = Processor::new();
- let mut handler = MockHandler::default();
-
- for byte in BYTES {
- parser.advance(&mut handler, *byte);
- }
-
- assert_eq!(handler.index, CharsetIndex::G0);
- assert_eq!(handler.charset, StandardCharset::SpecialCharacterAndLineDrawing);
- }
-
- #[test]
- fn parse_designate_g1_as_line_drawing_and_invoke() {
- static BYTES: &[u8] = &[0x1b, b')', b'0', 0x0e];
- let mut parser = Processor::new();
- let mut handler = MockHandler::default();
-
- for byte in &BYTES[..3] {
- parser.advance(&mut handler, *byte);
- }
-
- assert_eq!(handler.index, CharsetIndex::G1);
- assert_eq!(handler.charset, StandardCharset::SpecialCharacterAndLineDrawing);
-
- let mut handler = MockHandler::default();
- parser.advance(&mut handler, BYTES[3]);
-
- assert_eq!(handler.index, CharsetIndex::G1);
- }
-
- #[test]
- fn parse_valid_rgb_colors() {
- assert_eq!(xparse_color(b"rgb:f/e/d"), Some(Rgb { r: 0xff, g: 0xee, b: 0xdd }));
- assert_eq!(xparse_color(b"rgb:11/aa/ff"), Some(Rgb { r: 0x11, g: 0xaa, b: 0xff }));
- assert_eq!(xparse_color(b"rgb:f/ed1/cb23"), Some(Rgb { r: 0xff, g: 0xec, b: 0xca }));
- assert_eq!(xparse_color(b"rgb:ffff/0/0"), Some(Rgb { r: 0xff, g: 0x0, b: 0x0 }));
- }
-
- #[test]
- fn parse_valid_legacy_rgb_colors() {
- assert_eq!(xparse_color(b"#1af"), Some(Rgb { r: 0x10, g: 0xa0, b: 0xf0 }));
- assert_eq!(xparse_color(b"#11aaff"), Some(Rgb { r: 0x11, g: 0xaa, b: 0xff }));
- assert_eq!(xparse_color(b"#110aa0ff0"), Some(Rgb { r: 0x11, g: 0xaa, b: 0xff }));
- assert_eq!(xparse_color(b"#1100aa00ff00"), Some(Rgb { r: 0x11, g: 0xaa, b: 0xff }));
- }
-
- #[test]
- fn parse_invalid_rgb_colors() {
- assert_eq!(xparse_color(b"rgb:0//"), None);
- assert_eq!(xparse_color(b"rgb://///"), None);
- }
-
- #[test]
- fn parse_invalid_legacy_rgb_colors() {
- assert_eq!(xparse_color(b"#"), None);
- assert_eq!(xparse_color(b"#f"), None);
- }
-
- #[test]
- fn parse_invalid_number() {
- assert_eq!(parse_number(b"1abc"), None);
- }
-
- #[test]
- fn parse_valid_number() {
- assert_eq!(parse_number(b"123"), Some(123));
- }
-
- #[test]
- fn parse_number_too_large() {
- assert_eq!(parse_number(b"321"), None);
- }
-
- #[test]
- fn parse_osc4_set_color() {
- let bytes: &[u8] = b"\x1b]4;0;#fff\x1b\\";
-
- let mut parser = Processor::new();
- let mut handler = MockHandler::default();
-
- for byte in bytes {
- parser.advance(&mut handler, *byte);
- }
-
- assert_eq!(handler.color, Some(Rgb { r: 0xf0, g: 0xf0, b: 0xf0 }));
- }
-
- #[test]
- fn parse_osc104_reset_color() {
- let bytes: &[u8] = b"\x1b]104;1;\x1b\\";
-
- let mut parser = Processor::new();
- let mut handler = MockHandler::default();
-
- for byte in bytes {
- parser.advance(&mut handler, *byte);
- }
-
- assert_eq!(handler.reset_colors, vec![1]);
- }
-
- #[test]
- fn parse_osc104_reset_all_colors() {
- let bytes: &[u8] = b"\x1b]104;\x1b\\";
-
- let mut parser = Processor::new();
- let mut handler = MockHandler::default();
-
- for byte in bytes {
- parser.advance(&mut handler, *byte);
- }
-
- let expected: Vec<usize> = (0..256).collect();
- assert_eq!(handler.reset_colors, expected);
- }
-
- #[test]
- fn parse_osc104_reset_all_colors_no_semicolon() {
- let bytes: &[u8] = b"\x1b]104\x1b\\";
-
- let mut parser = Processor::new();
- let mut handler = MockHandler::default();
-
- for byte in bytes {
- parser.advance(&mut handler, *byte);
+ key: &str,
+ value: serde_yaml::Value,
+ ) -> Result<(), Box<dyn std::error::Error>> {
+ if !key.is_empty() {
+ return Err(format!("Fields \"{0}\" do not exist", key).into());
}
- let expected: Vec<usize> = (0..256).collect();
- assert_eq!(handler.reset_colors, expected);
+ *self = serde::Deserialize::deserialize(value)?;
+ Ok(())
}
}
diff --git a/alacritty_terminal/src/config/mod.rs b/alacritty_terminal/src/config/mod.rs
index f17c327f..2d921b6e 100644
--- a/alacritty_terminal/src/config/mod.rs
+++ b/alacritty_terminal/src/config/mod.rs
@@ -8,7 +8,7 @@ use alacritty_config_derive::{ConfigDeserialize, SerdeReplace};
mod scrolling;
-use crate::ansi::{CursorShape, CursorStyle};
+use crate::ansi::{CursorShapeShim, CursorStyle};
pub use crate::config::scrolling::{Scrolling, MAX_SCROLLBACK_LINES};
@@ -129,10 +129,10 @@ impl Cursor {
#[derive(SerdeReplace, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
#[serde(untagged)]
pub enum ConfigCursorStyle {
- Shape(CursorShape),
+ Shape(CursorShapeShim),
WithBlinking {
#[serde(default)]
- shape: CursorShape,
+ shape: CursorShapeShim,
#[serde(default)]
blinking: CursorBlinking,
},
@@ -140,7 +140,7 @@ pub enum ConfigCursorStyle {
impl Default for ConfigCursorStyle {
fn default() -> Self {
- Self::Shape(CursorShape::default())
+ Self::Shape(CursorShapeShim::default())
}
}
@@ -157,28 +157,23 @@ impl ConfigCursorStyle {
impl From<ConfigCursorStyle> for CursorStyle {
fn from(config_style: ConfigCursorStyle) -> Self {
match config_style {
- ConfigCursorStyle::Shape(shape) => Self { shape, blinking: false },
+ ConfigCursorStyle::Shape(shape) => Self { shape: shape.into(), blinking: false },
ConfigCursorStyle::WithBlinking { shape, blinking } => {
- Self { shape, blinking: blinking.into() }
+ Self { shape: shape.into(), blinking: blinking.into() }
},
}
}
}
-#[derive(ConfigDeserialize, Debug, Copy, Clone, PartialEq, Eq)]
+#[derive(ConfigDeserialize, Default, Debug, Copy, Clone, PartialEq, Eq)]
pub enum CursorBlinking {
Never,
+ #[default]
Off,
On,
Always,
}
-impl Default for CursorBlinking {
- fn default() -> Self {
- CursorBlinking::Off
- }
-}
-
impl CursorBlinking {
fn blinking_override(&self) -> Option<bool> {
match self {
diff --git a/alacritty_terminal/src/event_loop.rs b/alacritty_terminal/src/event_loop.rs
index 34169801..61dc69bc 100644
--- a/alacritty_terminal/src/event_loop.rs
+++ b/alacritty_terminal/src/event_loop.rs
@@ -333,8 +333,9 @@ where
'event_loop: loop {
// Wakeup the event loop when a synchronized update timeout was reached.
- let sync_timeout = state.parser.sync_timeout();
- let timeout = sync_timeout.map(|st| st.saturating_duration_since(Instant::now()));
+ let handler = state.parser.sync_timeout();
+ let timeout =
+ handler.sync_timeout().map(|st| st.saturating_duration_since(Instant::now()));
if let Err(err) = self.poll.poll(&mut events, timeout) {
match err.kind() {
diff --git a/alacritty_terminal/src/term/cell.rs b/alacritty_terminal/src/term/cell.rs
index 5253ede1..ddf6a745 100644
--- a/alacritty_terminal/src/term/cell.rs
+++ b/alacritty_terminal/src/term/cell.rs
@@ -3,6 +3,7 @@ use std::sync::Arc;
use bitflags::bitflags;
use serde::{Deserialize, Serialize};
+use vte::ansi::Hyperlink as VteHyperlink;
use crate::ansi::{Color, NamedColor};
use crate::grid::{self, GridCell};
@@ -57,6 +58,18 @@ impl Hyperlink {
}
}
+impl From<VteHyperlink> for Hyperlink {
+ fn from(value: VteHyperlink) -> Self {
+ Self::new(value.id, value.uri)
+ }
+}
+
+impl From<Hyperlink> for VteHyperlink {
+ fn from(val: Hyperlink) -> Self {
+ VteHyperlink { id: Some(val.id().to_owned()), uri: val.uri().to_owned() }
+ }
+}
+
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash)]
struct HyperlinkInner {
/// Identifier for the given hyperlink.
diff --git a/alacritty_terminal/src/term/color.rs b/alacritty_terminal/src/term/color.rs
index 8f193b39..b4bdba3a 100644
--- a/alacritty_terminal/src/term/color.rs
+++ b/alacritty_terminal/src/term/color.rs
@@ -1,89 +1,62 @@
use std::fmt::{self, Display, Formatter};
-use std::ops::{Add, Index, IndexMut, Mul};
+use std::ops::{Add, Deref, Index, IndexMut, Mul};
use std::str::FromStr;
-use log::trace;
use serde::de::{Error as _, Visitor};
use serde::{Deserialize, Deserializer, Serialize};
use serde_yaml::Value;
use alacritty_config_derive::SerdeReplace;
+use vte::ansi::Rgb as VteRgb;
+
use crate::ansi::NamedColor;
/// Number of terminal colors.
pub const COUNT: usize = 269;
#[derive(SerdeReplace, Debug, Eq, PartialEq, Copy, Clone, Default, Serialize)]
-pub struct Rgb {
- pub r: u8,
- pub g: u8,
- pub b: u8,
-}
+pub struct Rgb(VteRgb);
impl Rgb {
- /// Implementation of W3C's luminance
- /// [algorithm](https://www.w3.org/TR/WCAG20/#relativeluminancedef)
- fn luminance(self) -> f64 {
- let channel_luminance = |channel| {
- let channel = channel as f64 / 255.;
- if channel <= 0.03928 {
- channel / 12.92
- } else {
- f64::powf((channel + 0.055) / 1.055, 2.4)
- }
- };
-
- let r_luminance = channel_luminance(self.r);
- let g_luminance = channel_luminance(self.g);
- let b_luminance = channel_luminance(self.b);
+ #[inline]
+ pub const fn new(r: u8, g: u8, b: u8) -> Self {
+ Self(VteRgb { r, g, b })
+ }
- 0.2126 * r_luminance + 0.7152 * g_luminance + 0.0722 * b_luminance
+ #[inline]
+ pub fn as_tuple(self) -> (u8, u8, u8) {
+ (self.0.r, self.0.g, self.0.b)
}
+}
- /// Implementation of [W3C's contrast algorithm].
- ///
- /// [W3C's contrast algorithm]: https://www.w3.org/TR/WCAG20/#contrast-ratiodef
- pub fn contrast(self, other: Rgb) -> f64 {
- let self_luminance = self.luminance();
- let other_luminance = other.luminance();
+impl From<VteRgb> for Rgb {
+ fn from(value: VteRgb) -> Self {
+ Self(value)
+ }
+}
- let (darker, lighter) = if self_luminance > other_luminance {
- (other_luminance, self_luminance)
- } else {
- (self_luminance, other_luminance)
- };
+impl Deref for Rgb {
+ type Target = VteRgb;
- (lighter + 0.05) / (darker + 0.05)
+ fn deref(&self) -> &Self::Target {
+ &self.0
}
}
-// A multiply function for Rgb, as the default dim is just *2/3.
impl Mul<f32> for Rgb {
type Output = Rgb;
- fn mul(self, rhs: f32) -> Rgb {
- let result = Rgb {
- r: (f32::from(self.r) * rhs).clamp(0.0, 255.0) as u8,
- g: (f32::from(self.g) * rhs).clamp(0.0, 255.0) as u8,
- b: (f32::from(self.b) * rhs).clamp(0.0, 255.0) as u8,
- };
-
- trace!("Scaling RGB by {} from {:?} to {:?}", rhs, self, result);
-
- result
+ fn mul(self, rhs: f32) -> Self::Output {
+ Rgb(self.0 * rhs)
}
}
impl Add<Rgb> for Rgb {
type Output = Rgb;
- fn add(self, rhs: Rgb) -> Rgb {
- Rgb {
- r: self.r.saturating_add(rhs.r),
- g: self.g.saturating_add(rhs.g),
- b: self.b.saturating_add(rhs.b),
- }
+ fn add(self, rhs: Rgb) -> Self::Output {
+ Rgb(self.0 + rhs.0)
}
}
@@ -130,7 +103,7 @@ impl<'de> Deserialize<'de> for Rgb {
// Attempt to deserialize from struct form.
if let Ok(RgbDerivedDeser { r, g, b }) = RgbDerivedDeser::deserialize(value.clone()) {
- return Ok(Rgb { r, g, b });
+ return Ok(Rgb::new(r, g, b));
}
// Deserialize from hex notation (either 0xff00ff or #ff00ff).
@@ -163,7 +136,7 @@ impl FromStr for Rgb {
let g = (color & 0xff) as u8;
color >>= 8;
let r = color as u8;
- Ok(Rgb { r, g, b })
+ Ok(Rgb::new(r, g, b))
},
Err(_) => Err(()),
}
@@ -283,26 +256,3 @@ impl IndexMut<NamedColor> for Colors {
&mut self.0[index as usize]
}
}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn contrast() {
- let rgb1 = Rgb { r: 0xff, g: 0xff, b: 0xff };
- let rgb2 = Rgb { r: 0x00, g: 0x00, b: 0x00 };
- assert!((rgb1.contrast(rgb2) - 21.).abs() < f64::EPSILON);
-
- let rgb1 = Rgb { r: 0xff, g: 0xff, b: 0xff };
- assert!((rgb1.contrast(rgb1) - 1.).abs() < f64::EPSILON);
-
- let rgb1 = Rgb { r: 0xff, g: 0x00, b: 0xff };
- let rgb2 = Rgb { r: 0x00, g: 0xff, b: 0x00 };
- assert!((rgb1.contrast(rgb2) - 2.285_543_608_124_253_3).abs() < f64::EPSILON);
-
- let rgb1 = Rgb { r: 0x12, g: 0x34, b: 0x56 };
- let rgb2 = Rgb { r: 0xfe, g: 0xdc, b: 0xba };
- assert!((rgb1.contrast(rgb2) - 9.786_558_997_257_74).abs() < f64::EPSILON);
- }
-}
diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs
index bdfd6c9b..7c4abb57 100644
--- a/alacritty_terminal/src/term/mod.rs
+++ b/alacritty_terminal/src/term/mod.rs
@@ -7,6 +7,7 @@ use std::{cmp, mem, ptr, slice, str};
use bitflags::bitflags;
use log::{debug, trace};
use unicode_width::UnicodeWidthChar;
+use vte::ansi::{Hyperlink as VteHyperlink, Rgb as VteRgb};
use crate::ansi::{
self, Attr, CharsetIndex, Color, CursorShape, CursorStyle, Handler, NamedColor, StandardCharset,
@@ -16,8 +17,8 @@ use crate::event::{Event, EventListener};
use crate::grid::{Dimensions, Grid, GridIterator, Scroll};
use crate::index::{self, Boundary, Column, Direction, Line, Point, Side};
use crate::selection::{Selection, SelectionRange, SelectionType};
-use crate::term::cell::{Cell, Flags, Hyperlink, LineLength};
-use crate::term::color::{Colors, Rgb};
+use crate::term::cell::{Cell, Flags, LineLength};
+use crate::term::color::Colors;
use crate::vi_mode::{ViModeCursor, ViMotion};
pub mod cell;
@@ -1069,7 +1070,10 @@ impl<T: EventListener> Handler for Term<T> {
}
#[inline]
- fn goto(&mut self, line: Line, col: Column) {
+ fn goto(&mut self, line: i32, col: usize) {
+ let line = Line(line);
+ let col = Column(col);
+
trace!("Going to: line={}, col={}", line, col);
let (y_offset, max_y) = if self.mode.contains(TermMode::ORIGIN) {
(self.scroll_region.start, self.scroll_region.end - 1)
@@ -1085,15 +1089,15 @@ impl<T: EventListener> Handler for Term<T> {
}
#[inline]
- fn goto_line(&mut self, line: Line) {
+ fn goto_line(&mut self, line: i32) {
trace!("Going to line: {}", line);
- self.goto(line, self.grid.cursor.point.column)
+ self.goto(line, self.grid.cursor.point.column.0)
}
#[inline]
- fn goto_col(&mut self, col: Column) {
+ fn goto_col(&mut self, col: usize) {
trace!("Going to column: {}", col);
- self.goto(self.grid.cursor.point.line, col)
+ self.goto(self.grid.cursor.point.line.0, col)
}
#[inline]
@@ -1127,17 +1131,23 @@ impl<T: EventListener> Handler for Term<T> {
#[inline]
fn move_up(&mut self, lines: usize) {
trace!("Moving up: {}", lines);
- self.goto(self.grid.cursor.point.line - lines, self.grid.cursor.point.column)
+
+ let line = self.grid.cursor.point.line - lines;
+ let column = self.grid.cursor.point.column;
+ self.goto(line.0, column.0)
}
#[inline]
fn move_down(&mut self, lines: usize) {
trace!("Moving down: {}", lines);
- self.goto(self.grid.cursor.point.line + lines, self.grid.cursor.point.column)
+
+ let line = self.grid.cursor.point.line + lines;
+ let column = self.grid.cursor.point.column;
+ self.goto(line.0, column.0)
}
#[inline]
- fn move_forward(&mut self, cols: Column) {
+ fn move_forward(&mut self, cols: usize) {
trace!("Moving forward: {}", cols);
let last_column = cmp::min(self.grid.cursor.point.column + cols, self.last_column());
@@ -1149,9 +1159,9 @@ impl<T: EventListener> Handler for Term<T> {
}
#[inline]
- fn move_backward(&mut self, cols: Column) {
+ fn move_backward(&mut self, cols: usize) {
trace!("Moving backward: {}", cols);
- let column = self.grid.cursor.point.column.saturating_sub(cols.0);
+ let column = self.grid.cursor.point.column.saturating_sub(cols);
let cursor_line = self.grid.cursor.point.line.0 as usize;
self.damage.damage_line(cursor_line, column, self.grid.cursor.point.column.0);
@@ -1198,13 +1208,17 @@ impl<T: EventListener> Handler for Term<T> {
#[inline]
fn move_down_and_cr(&mut self, lines: usize) {
trace!("Moving down and cr: {}", lines);
- self.goto(self.grid.cursor.point.line + lines, Column(0))
+
+ let line = self.grid.cursor.point.line + lines;
+ self.goto(line.0, 0)
}
#[inline]
fn move_up_and_cr(&mut self, lines: usize) {
trace!("Moving up and cr: {}", lines);
- self.goto(self.grid.cursor.point.line - lines, Column(0))
+
+ let line = self.grid.cursor.point.line - lines;
+ self.goto(line.0, 0)
}
/// Insert tab at cursor position.
@@ -1362,7 +1376,7 @@ impl<T: EventListener> Handler for Term<T> {
}
#[inline]
- fn erase_chars(&mut self, count: Column) {
+ fn erase_chars(&mut self, count: usize) {
let cursor = &self.grid.cursor;
trace!("Erasing chars: count={}, col={}", count, cursor.point.column);
@@ -1479,9 +1493,11 @@ impl<T: EventListener> Handler for Term<T> {
/// Set the indexed color value.
#[inline]
- fn set_color(&mut self, index: usize, color: Rgb) {
+ fn set_color(&mut self, index: usize, color: VteRgb) {
trace!("Setting color[{}] = {:?}", index, color);
+ let color = color.into();
+
// Damage terminal if the color changed and it's not the cursor.
if index != NamedColor::Cursor as usize && self.colors[index] != Some(color) {
self.mark_fully_damaged();
@@ -1679,9 +1695,9 @@ impl<T: EventListener> Handler for Term<T> {
}
#[inline]
- fn set_hyperlink(&mut self, hyperlink: Option<Hyperlink>) {
+ fn set_hyperlink(&mut self, hyperlink: Option<VteHyperlink>) {
trace!("Setting hyperlink: {:?}", hyperlink);
- self.grid.cursor.template.set_hyperlink(hyperlink);
+ self.grid.cursor.template.set_hyperlink(hyperlink.map(|e| e.into()));
}
/// Set a terminal attribute.
@@ -1858,7 +1874,7 @@ impl<T: EventListener> Handler for Term<T> {
let screen_lines = Line(self.screen_lines() as i32);
self.scroll_region.start = cmp::min(start, screen_lines);
self.scroll_region.end = cmp::min(end, screen_lines);
- self.goto(Line(0), Column(0));
+ self.goto(0, 0);
}
#[inline]
@@ -2756,7 +2772,7 @@ mod tests {
// Reset terminal for partial damage tests since it's initialized as fully damaged.
term.reset_damage();
- term.goto(Line(1), Column(1));
+ term.goto(1, 1);
// NOTE While we can use `[Term::damage]` to access terminal damage information, in the
// following tests we will be accessing `term.damage.lines` directly to avoid adding extra
@@ -2766,13 +2782,13 @@ mod tests {
assert_eq!(term.damage.lines[1], LineDamageBounds { line: 1, left: 1, right: 1 });
term.damage.reset(num_cols);
- term.move_forward(Column(3));
+ term.move_forward(3);
assert_eq!(term.damage.lines[1], LineDamageBounds { line: 1, left: 1, right: 4 });
term.damage.reset(num_cols);
- term.move_backward(Column(8));
+ term.move_backward(8);
assert_eq!(term.damage.lines[1], LineDamageBounds { line: 1, left: 0, right: 4 });
- term.goto(Line(5), Column(5));
+ term.goto(5, 5);
term.damage.reset(num_cols);
term.backspace();
@@ -2795,7 +2811,7 @@ mod tests {
term.wrapline();
assert_eq!(term.damage.lines[6], LineDamageBounds { line: 6, left: 3, right: 3 });
assert_eq!(term.damage.lines[7], LineDamageBounds { line: 7, left: 0, right: 0 });
- term.move_forward(Column(3));
+ term.move_forward(3);
term.move_up(1);
term.damage.reset(num_cols);
@@ -2808,20 +2824,20 @@ mod tests {
assert_eq!(term.damage.lines[7], LineDamageBounds { line: 7, left: 0, right: 3 });
term.damage.reset(num_cols);
- term.erase_chars(Column(5));
+ term.erase_chars(5);
assert_eq!(term.damage.lines[7], LineDamageBounds { line: 7, left: 0, right: 5 });
term.damage.reset(num_cols);
term.delete_chars(3);
let right = term.columns() - 1;
assert_eq!(term.damage.lines[7], LineDamageBounds { line: 7, left: 0, right });
- term.move_forward(Column(term.columns()));
+ term.move_forward(term.columns());
term.damage.reset(num_cols);
term.move_backward_tabs(1);
assert_eq!(term.damage.lines[7], LineDamageBounds { line: 7, left: 8, right });
term.save_cursor_position();
- term.goto(Line(1), Column(1));
+ term.goto(1, 1);
term.damage.reset(num_cols);
term.restore_cursor_position();
@@ -2896,12 +2912,12 @@ mod tests {
term.reset_damage();
let color_index = 257;
- term.set_color(color_index, Rgb::default());
+ term.set_color(color_index, VteRgb::default());
assert!(term.damage.is_fully_damaged);
term.reset_damage();
// Setting the same color once again shouldn't trigger full damage.
- term.set_color(color_index, Rgb::default());
+ term.set_color(color_index, VteRgb::default());
assert!(!term.damage.is_fully_damaged);
term.reset_color(color_index);
@@ -2909,7 +2925,7 @@ mod tests {
term.reset_damage();
// We shouldn't trigger fully damage when cursor gets update.
- term.set_color(NamedColor::Cursor as usize, Rgb::default());
+ term.set_color(NamedColor::Cursor as usize, VteRgb::default());
assert!(!term.damage.is_fully_damaged);
// However requesting terminal damage should mark terminal as fully damaged in `Insert`
diff --git a/alacritty_terminal/tests/ref.rs b/alacritty_terminal/tests/ref.rs
index 848a0ad1..48704fb8 100644
--- a/alacritty_terminal/tests/ref.rs
+++ b/alacritty_terminal/tests/ref.rs
@@ -109,7 +109,7 @@ fn ref_test(dir: &Path) {
config.scrolling.set_history(ref_config.history_size);
let mut terminal = Term::new(&config, &size, Mock);
- let mut parser = ansi::Processor::new();
+ let mut parser: ansi::Processor = ansi::Processor::new();
for byte in recording {
parser.advance(&mut terminal, byte);