mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-18 13:55:23 -05:00
Switch to VTE's built-in ansi feature
Co-authored-by: Christian Duerr <contact@christianduerr.com>
This commit is contained in:
parent
f0379f2da7
commit
cb7ad5b7e6
17 changed files with 211 additions and 2041 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -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",
|
||||
]
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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"] }
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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 {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
0.2126 * r_luminance + 0.7152 * g_luminance + 0.0722 * b_luminance
|
||||
#[inline]
|
||||
pub const fn new(r: u8, g: u8, b: u8) -> Self {
|
||||
Self(VteRgb { r, g, 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();
|
||||
|
||||
let (darker, lighter) = if self_luminance > other_luminance {
|
||||
(other_luminance, self_luminance)
|
||||
} else {
|
||||
(self_luminance, other_luminance)
|
||||
};
|
||||
|
||||
(lighter + 0.05) / (darker + 0.05)
|
||||
#[inline]
|
||||
pub fn as_tuple(self) -> (u8, u8, u8) {
|
||||
(self.0.r, self.0.g, self.0.b)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<VteRgb> for Rgb {
|
||||
fn from(value: VteRgb) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Rgb {
|
||||
type Target = VteRgb;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue