diff options
author | Christian Duerr <contact@christianduerr.com> | 2020-08-12 16:05:22 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-08-12 19:05:22 +0300 |
commit | b904207b1979bb86f86c2a7db1720ce04571508a (patch) | |
tree | e0961c9f8c087f11ceb81061ebd468972a3d4cda /alacritty/src/renderer/rects.rs | |
parent | 96ea5c445ecc25a5b2d400b11f0ff843e9cbdd7a (diff) | |
download | r-alacritty-b904207b1979bb86f86c2a7db1720ce04571508a.tar.gz r-alacritty-b904207b1979bb86f86c2a7db1720ce04571508a.tar.bz2 r-alacritty-b904207b1979bb86f86c2a7db1720ce04571508a.zip |
Add support for double underlines
This adds support for double underlines using the colon separated escape
sequence `CSI 4 : 2 m`.
Alacritty will now also always fallback to the normal underline in case
any of the other underlines like the undercurl are specified. The escape
sequence `CSI 4 : 0 m` can now be used to clear all underlines.
Some terminals support `CSI 21 m` for double underline, but since
Alacritty already uses that as cancel bold which is a little more
consistent, that behavior has not changed. So the colon separated
variant must be used.
Diffstat (limited to 'alacritty/src/renderer/rects.rs')
-rw-r--r-- | alacritty/src/renderer/rects.rs | 134 |
1 files changed, 91 insertions, 43 deletions
diff --git a/alacritty/src/renderer/rects.rs b/alacritty/src/renderer/rects.rs index 5cd856ab..e8bd867f 100644 --- a/alacritty/src/renderer/rects.rs +++ b/alacritty/src/renderer/rects.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use crossfont::Metrics; -use alacritty_terminal::index::{Column, Point}; +use alacritty_terminal::index::{Line, Point}; use alacritty_terminal::term::cell::Flags; use alacritty_terminal::term::color::Rgb; use alacritty_terminal::term::{RenderableCell, SizeInfo}; @@ -35,51 +35,91 @@ impl RenderLine { let mut rects = Vec::new(); let mut start = self.start; - while start.line < self.end.line { - let mut end = start; - end.col = size.cols() - 1; - rects.push(Self::create_rect(metrics, size, flag, start, end, self.color)); + for line in start.line.0..=self.end.line.0 { + let mut end = Point::new(Line(line), self.end.col); + if line != self.end.line.0 { + end.col = size.cols() - 1; + } - start.col = Column(0); - start.line += 1; - } + Self::push_rects(&mut rects, metrics, size, flag, start, end, self.color); - rects.push(Self::create_rect(metrics, size, flag, start, self.end, self.color)); + start.col.0 = 0; + } rects } - fn create_rect( + /// Push all rects required to draw the cell's line. + fn push_rects( + rects: &mut Vec<RenderRect>, metrics: &Metrics, size: &SizeInfo, flag: Flags, start: Point, end: Point, color: Rgb, - ) -> RenderRect { - let start_x = start.col.0 as f32 * size.cell_width; - let end_x = (end.col.0 + 1) as f32 * size.cell_width; - let width = end_x - start_x; - - let (position, mut height) = match flag { + ) { + let (position, thickness) = match flag { + Flags::DOUBLE_UNDERLINE => { + // Position underlines so each one has 50% of descent available. + let top_pos = 0.25 * metrics.descent; + let bottom_pos = 0.75 * metrics.descent; + + rects.push(Self::create_rect( + size, + metrics.descent, + start, + end, + top_pos, + metrics.underline_thickness, + color, + )); + + (bottom_pos, metrics.underline_thickness) + }, Flags::UNDERLINE => (metrics.underline_position, metrics.underline_thickness), Flags::STRIKEOUT => (metrics.strikeout_position, metrics.strikeout_thickness), _ => unimplemented!("Invalid flag for cell line drawing specified"), }; + rects.push(Self::create_rect( + size, + metrics.descent, + start, + end, + position, + thickness, + color, + )); + } + + /// Create a line's rect at a position relative to the baseline. + fn create_rect( + size: &SizeInfo, + descent: f32, + start: Point, + end: Point, + position: f32, + mut thickness: f32, + color: Rgb, + ) -> RenderRect { + let start_x = start.col.0 as f32 * size.cell_width; + let end_x = (end.col.0 + 1) as f32 * size.cell_width; + let width = end_x - start_x; + // Make sure lines are always visible. - height = height.max(1.); + thickness = thickness.max(1.); let line_bottom = (start.line.0 as f32 + 1.) * size.cell_height; - let baseline = line_bottom + metrics.descent; + let baseline = line_bottom + descent; - let mut y = (baseline - position - height / 2.).ceil(); - let max_y = line_bottom - height; + let mut y = (baseline - position - thickness / 2.).ceil(); + let max_y = line_bottom - thickness; if y > max_y { y = max_y; } - RenderRect::new(start_x + size.padding_x, y + size.padding_y, width, height, color, 1.) + RenderRect::new(start_x + size.padding_x, y + size.padding_y, width, thickness, color, 1.) } } @@ -90,10 +130,12 @@ pub struct RenderLines { } impl RenderLines { + #[inline] pub fn new() -> Self { Self::default() } + #[inline] pub fn rects(&self, metrics: &Metrics, size: &SizeInfo) -> Vec<RenderRect> { self.inner .iter() @@ -105,32 +147,38 @@ impl RenderLines { } /// Update the stored lines with the next cell info. + #[inline] pub fn update(&mut self, cell: RenderableCell) { - for flag in &[Flags::UNDERLINE, Flags::STRIKEOUT] { - if !cell.flags.contains(*flag) { - continue; - } + self.update_flag(cell, Flags::UNDERLINE); + self.update_flag(cell, Flags::DOUBLE_UNDERLINE); + self.update_flag(cell, Flags::STRIKEOUT); + } - // Check if there's an active line. - if let Some(line) = self.inner.get_mut(flag).and_then(|lines| lines.last_mut()) { - if cell.fg == line.color - && cell.column == line.end.col + 1 - && cell.line == line.end.line - { - // Update the length of the line. - line.end = cell.into(); - continue; - } - } + /// Update the lines for a specific flag. + fn update_flag(&mut self, cell: RenderableCell, flag: Flags) { + if !cell.flags.contains(flag) { + return; + } - // Start new line if there currently is none. - let line = RenderLine { start: cell.into(), end: cell.into(), color: cell.fg }; - match self.inner.get_mut(flag) { - Some(lines) => lines.push(line), - None => { - self.inner.insert(*flag, vec![line]); - }, + // Check if there's an active line. + if let Some(line) = self.inner.get_mut(&flag).and_then(|lines| lines.last_mut()) { + if cell.fg == line.color + && cell.column == line.end.col + 1 + && cell.line == line.end.line + { + // Update the length of the line. + line.end = cell.into(); + return; } } + + // Start new line if there currently is none. + let line = RenderLine { start: cell.into(), end: cell.into(), color: cell.fg }; + match self.inner.get_mut(&flag) { + Some(lines) => lines.push(line), + None => { + self.inner.insert(flag, vec![line]); + }, + } } } |