diff options
Diffstat (limited to 'alacritty/src/display')
-rw-r--r-- | alacritty/src/display/color.rs | 199 | ||||
-rw-r--r-- | alacritty/src/display/content.rs | 13 | ||||
-rw-r--r-- | alacritty/src/display/cursor.rs | 4 | ||||
-rw-r--r-- | alacritty/src/display/hint.rs | 2 | ||||
-rw-r--r-- | alacritty/src/display/mod.rs | 21 |
5 files changed, 213 insertions, 26 deletions
diff --git a/alacritty/src/display/color.rs b/alacritty/src/display/color.rs index f742ee84..669bf502 100644 --- a/alacritty/src/display/color.rs +++ b/alacritty/src/display/color.rs @@ -1,9 +1,14 @@ -use std::ops::{Index, IndexMut}; +use std::fmt::{self, Display, Formatter}; +use std::ops::{Add, Deref, Index, IndexMut, Mul}; +use std::str::FromStr; use log::trace; +use serde::de::{Error as SerdeError, Visitor}; +use serde::{Deserialize, Deserializer}; -use alacritty_terminal::ansi::NamedColor; -use alacritty_terminal::term::color::{Rgb, COUNT}; +use alacritty_config_derive::SerdeReplace; +use alacritty_terminal::term::color::COUNT; +use alacritty_terminal::vte::ansi::{NamedColor, Rgb as VteRgb}; use crate::config::color::Colors; @@ -165,3 +170,191 @@ impl IndexMut<NamedColor> for List { &mut self.0[idx as usize] } } + +#[derive(SerdeReplace, Debug, Eq, PartialEq, Copy, Clone, Default)] +pub struct Rgb(pub VteRgb); + +impl Rgb { + #[inline] + pub const fn new(r: u8, g: u8, b: u8) -> Self { + Self(VteRgb { r, g, b }) + } + + #[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 + } +} + +impl Mul<f32> for Rgb { + type Output = Rgb; + + fn mul(self, rhs: f32) -> Self::Output { + Rgb(self.0 * rhs) + } +} + +impl Add<Rgb> for Rgb { + type Output = Rgb; + + fn add(self, rhs: Rgb) -> Self::Output { + Rgb(self.0 + rhs.0) + } +} + +/// Deserialize an Rgb from a hex string. +/// +/// This is *not* the deserialize impl for Rgb since we want a symmetric +/// serialize/deserialize impl for ref tests. +impl<'de> Deserialize<'de> for Rgb { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct RgbVisitor; + + // Used for deserializing reftests. + #[derive(Deserialize)] + struct RgbDerivedDeser { + r: u8, + g: u8, + b: u8, + } + + impl<'a> Visitor<'a> for RgbVisitor { + type Value = Rgb; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("hex color like #ff00ff") + } + + fn visit_str<E>(self, value: &str) -> Result<Rgb, E> + where + E: serde::de::Error, + { + Rgb::from_str(value).map_err(|_| { + E::custom(format!( + "failed to parse rgb color {value}; expected hex color like #ff00ff" + )) + }) + } + } + + // Return an error if the syntax is incorrect. + let value = toml::Value::deserialize(deserializer)?; + + // Attempt to deserialize from struct form. + if let Ok(RgbDerivedDeser { r, g, b }) = RgbDerivedDeser::deserialize(value.clone()) { + return Ok(Rgb::new(r, g, b)); + } + + // Deserialize from hex notation (either 0xff00ff or #ff00ff). + value.deserialize_str(RgbVisitor).map_err(D::Error::custom) + } +} + +impl Display for Rgb { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "#{:02x}{:02x}{:02x}", self.r, self.g, self.b) + } +} + +impl FromStr for Rgb { + type Err = (); + + fn from_str(s: &str) -> Result<Rgb, ()> { + let chars = if s.starts_with("0x") && s.len() == 8 { + &s[2..] + } else if s.starts_with('#') && s.len() == 7 { + &s[1..] + } else { + return Err(()); + }; + + match u32::from_str_radix(chars, 16) { + Ok(mut color) => { + let b = (color & 0xff) as u8; + color >>= 8; + let g = (color & 0xff) as u8; + color >>= 8; + let r = color as u8; + Ok(Rgb::new(r, g, b)) + }, + Err(_) => Err(()), + } + } +} + +/// RGB color optionally referencing the cell's foreground or background. +#[derive(SerdeReplace, Copy, Clone, Debug, PartialEq, Eq)] +pub enum CellRgb { + CellForeground, + CellBackground, + Rgb(Rgb), +} + +impl CellRgb { + pub fn color(self, foreground: Rgb, background: Rgb) -> Rgb { + match self { + Self::CellForeground => foreground, + Self::CellBackground => background, + Self::Rgb(rgb) => rgb, + } + } +} + +impl Default for CellRgb { + fn default() -> Self { + Self::Rgb(Rgb::default()) + } +} + +impl<'de> Deserialize<'de> for CellRgb { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + const EXPECTING: &str = "CellForeground, CellBackground, or hex color like #ff00ff"; + + struct CellRgbVisitor; + impl<'a> Visitor<'a> for CellRgbVisitor { + type Value = CellRgb; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str(EXPECTING) + } + + fn visit_str<E>(self, value: &str) -> Result<CellRgb, E> + where + E: serde::de::Error, + { + // Attempt to deserialize as enum constants. + match value { + "CellForeground" => return Ok(CellRgb::CellForeground), + "CellBackground" => return Ok(CellRgb::CellBackground), + _ => (), + } + + Rgb::from_str(value).map(CellRgb::Rgb).map_err(|_| { + E::custom(format!("failed to parse color {value}; expected {EXPECTING}")) + }) + } + } + + deserializer.deserialize_str(CellRgbVisitor).map_err(D::Error::custom) + } +} diff --git a/alacritty/src/display/content.rs b/alacritty/src/display/content.rs index ba716154..30439fc0 100644 --- a/alacritty/src/display/content.rs +++ b/alacritty/src/display/content.rs @@ -2,18 +2,17 @@ use std::borrow::Cow; use std::ops::Deref; use std::{cmp, mem}; -use alacritty_terminal::ansi::{Color, CursorShape, NamedColor}; use alacritty_terminal::event::EventListener; use alacritty_terminal::grid::{Dimensions, Indexed}; use alacritty_terminal::index::{Column, Line, Point}; use alacritty_terminal::selection::SelectionRange; use alacritty_terminal::term::cell::{Cell, Flags, Hyperlink}; -use alacritty_terminal::term::color::{CellRgb, Rgb}; use alacritty_terminal::term::search::{Match, RegexSearch}; use alacritty_terminal::term::{self, RenderableContent as TerminalContent, Term, TermMode}; +use alacritty_terminal::vte::ansi::{Color, CursorShape, NamedColor}; use crate::config::UiConfig; -use crate::display::color::{List, DIM_FACTOR}; +use crate::display::color::{CellRgb, List, Rgb, DIM_FACTOR}; use crate::display::hint::{self, HintState}; use crate::display::{Display, SizeInfo}; use crate::event::SearchState; @@ -55,7 +54,7 @@ impl<'a> RenderableContent<'a> { || display.ime.preedit().is_some() { CursorShape::Hidden - } else if !term.is_focused && config.terminal_config.cursor.unfocused_hollow { + } else if !term.is_focused && config.cursor.unfocused_hollow { CursorShape::HollowBlock } else { terminal_content.cursor.shape @@ -102,7 +101,7 @@ impl<'a> RenderableContent<'a> { /// Get the RGB value for a color index. pub fn color(&self, color: usize) -> Rgb { - self.terminal_content.colors[color].unwrap_or(self.colors[color]) + self.terminal_content.colors[color].map(Rgb).unwrap_or(self.colors[color]) } pub fn selection_range(&self) -> Option<SelectionRange> { @@ -117,8 +116,8 @@ impl<'a> RenderableContent<'a> { } else { self.config.colors.cursor }; - let cursor_color = - self.terminal_content.colors[NamedColor::Cursor].map_or(color.background, CellRgb::Rgb); + let cursor_color = self.terminal_content.colors[NamedColor::Cursor] + .map_or(color.background, |c| CellRgb::Rgb(Rgb(c))); let text_color = color.foreground; let insufficient_contrast = (!matches!(cursor_color, CellRgb::Rgb(_)) diff --git a/alacritty/src/display/cursor.rs b/alacritty/src/display/cursor.rs index 8a4cc729..65933ccc 100644 --- a/alacritty/src/display/cursor.rs +++ b/alacritty/src/display/cursor.rs @@ -1,8 +1,8 @@ //! Convert a cursor into an iterator of rects. -use alacritty_terminal::ansi::CursorShape; -use alacritty_terminal::term::color::Rgb; +use alacritty_terminal::vte::ansi::CursorShape; +use crate::display::color::Rgb; use crate::display::content::RenderableCursor; use crate::display::SizeInfo; use crate::renderer::rects::RenderRect; diff --git a/alacritty/src/display/hint.rs b/alacritty/src/display/hint.rs index f508d10c..bd09a881 100644 --- a/alacritty/src/display/hint.rs +++ b/alacritty/src/display/hint.rs @@ -590,9 +590,9 @@ impl<'a, T> Iterator for HintPostProcessor<'a, T> { #[cfg(test)] mod tests { - use alacritty_terminal::ansi::Handler; use alacritty_terminal::index::{Column, Line}; use alacritty_terminal::term::test::mock_term; + use alacritty_terminal::vte::ansi::Handler; use super::*; diff --git a/alacritty/src/display/mod.rs b/alacritty/src/display/mod.rs index dfe2809f..1d993af8 100644 --- a/alacritty/src/display/mod.rs +++ b/alacritty/src/display/mod.rs @@ -23,23 +23,22 @@ use winit::window::CursorIcon; use crossfont::{self, Rasterize, Rasterizer}; use unicode_width::UnicodeWidthChar; -use alacritty_terminal::ansi::{CursorShape, NamedColor}; -use alacritty_terminal::config::MAX_SCROLLBACK_LINES; use alacritty_terminal::event::{EventListener, OnResize, WindowSize}; use alacritty_terminal::grid::Dimensions as TermDimensions; use alacritty_terminal::index::{Column, Direction, Line, Point}; use alacritty_terminal::selection::{Selection, SelectionRange}; use alacritty_terminal::term::cell::Flags; -use alacritty_terminal::term::color::Rgb; use alacritty_terminal::term::{self, Term, TermDamage, TermMode, MIN_COLUMNS, MIN_SCREEN_LINES}; +use alacritty_terminal::vte::ansi::{CursorShape, NamedColor}; use crate::config::font::Font; +use crate::config::scrolling::MAX_SCROLLBACK_LINES; use crate::config::window::Dimensions; #[cfg(not(windows))] use crate::config::window::StartupMode; use crate::config::UiConfig; use crate::display::bell::VisualBell; -use crate::display::color::List; +use crate::display::color::{List, Rgb}; use crate::display::content::{RenderableContent, RenderableCursor}; use crate::display::cursor::IntoRects; use crate::display::damage::RenderDamageIterator; @@ -53,13 +52,13 @@ use crate::renderer::{self, GlyphCache, Renderer}; use crate::scheduler::{Scheduler, TimerId, Topic}; use crate::string::{ShortenDirection, StrShortener}; +pub mod color; pub mod content; pub mod cursor; pub mod hint; pub mod window; mod bell; -mod color; mod damage; mod meter; @@ -862,7 +861,7 @@ impl Display { }; // Draw cursor. - rects.extend(cursor.rects(&size_info, config.terminal_config.cursor.thickness())); + rects.extend(cursor.rects(&size_info, config.cursor.thickness())); // Push visual bell after url/underline/strikeout rects. let visual_bell_intensity = self.visual_bell.intensity(); @@ -900,9 +899,7 @@ impl Display { let fg = config.colors.footer_bar_foreground(); let shape = CursorShape::Underline; let cursor = RenderableCursor::new(Point::new(line, column), shape, fg, false); - rects.extend( - cursor.rects(&size_info, config.terminal_config.cursor.thickness()), - ); + rects.extend(cursor.rects(&size_info, config.cursor.thickness())); } Some(Point::new(line, column)) @@ -1144,9 +1141,7 @@ impl Display { let cursor_point = Point::new(point.line, cursor_column); let cursor = RenderableCursor::new(cursor_point, CursorShape::HollowBlock, fg, is_wide); - rects.extend( - cursor.rects(&self.size_info, config.terminal_config.cursor.thickness()), - ); + rects.extend(cursor.rects(&self.size_info, config.cursor.thickness())); cursor_point }, _ => end, @@ -1622,7 +1617,7 @@ fn window_size( ) -> PhysicalSize<u32> { let padding = config.window.padding(scale_factor); - let grid_width = cell_width * dimensions.columns.0.max(MIN_COLUMNS) as f32; + let grid_width = cell_width * dimensions.columns.max(MIN_COLUMNS) as f32; let grid_height = cell_height * dimensions.lines.max(MIN_SCREEN_LINES) as f32; let width = (padding.0).mul_add(2., grid_width).floor(); |