summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--Cargo.lock7
-rw-r--r--Cargo.toml1
-rw-r--r--font/src/lib.rs2
-rw-r--r--src/cursor.rs98
-rw-r--r--src/display.rs4
-rw-r--r--src/lib.rs1
-rw-r--r--src/renderer/mod.rs17
-rw-r--r--src/renderer/rects.rs4
-rw-r--r--src/term/mod.rs339
10 files changed, 251 insertions, 224 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9dd71e5a..97f46d2e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,6 +23,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Resize events are not send to the shell anymore if dimensions haven't changed
- Minor performance issues with underline and strikeout checks
- Rare bug which would extend underline and strikeout beyond the end of line
+- Cursors not spanning two lines when over double-width characters
+- Incorrect cursor dimensions if the font offset isn't `0`
## Version 0.3.0
diff --git a/Cargo.lock b/Cargo.lock
index 43cee938..77e6be5c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -33,7 +33,6 @@ dependencies = [
name = "alacritty"
version = "0.3.0"
dependencies = [
- "arraydeque 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -130,11 +129,6 @@ dependencies = [
]
[[package]]
-name = "arraydeque"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
name = "arrayvec"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2863,7 +2857,6 @@ dependencies = [
"checksum approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3"
"checksum arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "bc4662175ead9cd84451d5c35070517777949a2ed84551764129cedb88384841"
"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392"
-"checksum arraydeque 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f0ffd3d69bd89910509a5d31d1f1353f38ccffdd116dd0099bbd6627f7bd8ad8"
"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
diff --git a/Cargo.toml b/Cargo.toml
index d1ad1bc6..f0206d19 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -41,7 +41,6 @@ log = "0.4"
clap = "2"
fnv = "1"
unicode-width = "0.1"
-arraydeque = "0.4"
glutin = { version = "0.21.0-rc2", features = ["icon_loading"] }
env_logger = "0.6.0"
base64 = "0.10.0"
diff --git a/font/src/lib.rs b/font/src/lib.rs
index f23d0a0f..38a6f82f 100644
--- a/font/src/lib.rs
+++ b/font/src/lib.rs
@@ -213,6 +213,7 @@ impl ::std::ops::Add for Size {
}
}
+#[derive(Clone)]
pub struct RasterizedGlyph {
pub c: char,
pub width: i32,
@@ -314,6 +315,7 @@ impl fmt::Debug for RasterizedGlyph {
}
}
+#[derive(Copy, Clone)]
pub struct Metrics {
pub average_advance: f64,
pub line_height: f64,
diff --git a/src/cursor.rs b/src/cursor.rs
new file mode 100644
index 00000000..268f35fa
--- /dev/null
+++ b/src/cursor.rs
@@ -0,0 +1,98 @@
+// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Helpers for creating different cursor glyphs from font metrics
+
+use std::cmp;
+
+use font::{Metrics, RasterizedGlyph};
+
+use crate::ansi::CursorStyle;
+
+/// Width/Height of the cursor relative to the font width
+pub const CURSOR_WIDTH_PERCENTAGE: i32 = 15;
+
+pub fn get_cursor_glyph(
+ cursor: CursorStyle,
+ metrics: Metrics,
+ offset_x: i8,
+ offset_y: i8,
+ is_wide: bool,
+) -> RasterizedGlyph {
+ // Calculate the cell metrics
+ let height = metrics.line_height as i32 + i32::from(offset_y);
+ let mut width = metrics.average_advance as i32 + i32::from(offset_x);
+ let line_width = cmp::max(width * CURSOR_WIDTH_PERCENTAGE / 100, 1);
+
+ // Double the cursor width if it's above a double-width glyph
+ if is_wide {
+ width *= 2;
+ }
+
+ match cursor {
+ CursorStyle::HollowBlock => get_box_cursor_glyph(height, width, line_width),
+ CursorStyle::Underline => get_underline_cursor_glyph(width, line_width),
+ CursorStyle::Beam => get_beam_cursor_glyph(height, line_width),
+ CursorStyle::Block => get_block_cursor_glyph(height, width),
+ }
+}
+
+// Returns a custom underline cursor character
+pub fn get_underline_cursor_glyph(width: i32, line_width: i32) -> RasterizedGlyph {
+ // Create a new rectangle, the height is relative to the font width
+ let buf = vec![255u8; (width * line_width * 3) as usize];
+
+ // Create a custom glyph with the rectangle data attached to it
+ RasterizedGlyph { c: ' ', top: line_width, left: 0, height: line_width, width, buf }
+}
+
+// Returns a custom beam cursor character
+pub fn get_beam_cursor_glyph(height: i32, line_width: i32) -> RasterizedGlyph {
+ // Create a new rectangle that is at least one pixel wide
+ let buf = vec![255u8; (line_width * height * 3) as usize];
+
+ // Create a custom glyph with the rectangle data attached to it
+ RasterizedGlyph { c: ' ', top: height, left: 0, height, width: line_width, buf }
+}
+
+// Returns a custom box cursor character
+pub fn get_box_cursor_glyph(height: i32, width: i32, line_width: i32) -> RasterizedGlyph {
+ // Create a new box outline rectangle
+ let mut buf = Vec::with_capacity((width * height * 3) as usize);
+ for y in 0..height {
+ for x in 0..width {
+ if y < line_width
+ || y >= height - line_width
+ || x < line_width
+ || x >= width - line_width
+ {
+ buf.append(&mut vec![255u8; 3]);
+ } else {
+ buf.append(&mut vec![0u8; 3]);
+ }
+ }
+ }
+
+ // Create a custom glyph with the rectangle data attached to it
+ RasterizedGlyph { c: ' ', top: height, left: 0, height, width, buf }
+}
+
+// Returns a custom block cursor character
+pub fn get_block_cursor_glyph(height: i32, width: i32) -> RasterizedGlyph {
+ // Create a completely filled glyph
+ let buf = vec![255u8; (width * height * 3) as usize];
+
+ // Create a custom glyph with the rectangle data attached to it
+ RasterizedGlyph { c: ' ', top: height, left: 0, height, width, buf }
+}
diff --git a/src/display.rs b/src/display.rs
index 9e902b94..07ffdd0f 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -435,10 +435,11 @@ impl Display {
let size_info = *terminal.size_info();
let visual_bell_intensity = terminal.visual_bell.intensity();
let background_color = terminal.background_color();
+ let metrics = self.glyph_cache.font_metrics();
let window_focused = self.window.is_focused;
let grid_cells: Vec<RenderableCell> =
- terminal.renderable_cells(config, window_focused).collect();
+ terminal.renderable_cells(config, window_focused, metrics).collect();
// Get message from terminal to ignore modifications after lock is dropped
let message_buffer = terminal.message_buffer_mut().message();
@@ -479,7 +480,6 @@ impl Display {
{
let glyph_cache = &mut self.glyph_cache;
- let metrics = glyph_cache.font_metrics();
let mut rects = Rects::new(&metrics, &size_info);
// Draw grid
diff --git a/src/lib.rs b/src/lib.rs
index 92ccb5a7..10c1faa6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -31,6 +31,7 @@ pub mod macros;
pub mod ansi;
pub mod cli;
pub mod config;
+mod cursor;
pub mod display;
pub mod event;
pub mod event_loop;
diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs
index 47851224..5182a6f6 100644
--- a/src/renderer/mod.rs
+++ b/src/renderer/mod.rs
@@ -32,7 +32,7 @@ use crate::gl::types::*;
use crate::index::{Column, Line};
use crate::renderer::rects::{Rect, Rects};
use crate::term::color::Rgb;
-use crate::term::{self, cell, RenderableCell};
+use crate::term::{self, cell, RenderableCell, RenderableCellContent};
pub mod rects;
@@ -950,11 +950,11 @@ impl<'a> RenderApi<'a> {
.map(|(i, c)| RenderableCell {
line,
column: col + i,
- chars: {
+ inner: RenderableCellContent::Chars({
let mut chars = [' '; cell::MAX_ZEROWIDTH_CHARS + 1];
chars[0] = c;
chars
- },
+ }),
bg: color.unwrap_or(Rgb { r: 0, g: 0, b: 0 }),
fg: Rgb { r: 0, g: 0, b: 0 },
flags: cell::Flags::empty(),
@@ -983,6 +983,13 @@ impl<'a> RenderApi<'a> {
}
pub fn render_cell(&mut self, cell: RenderableCell, glyph_cache: &mut GlyphCache) {
+ // loader.load_glyph(&rasterized)
+ if let RenderableCellContent::Raw(ref raw) = cell.inner {
+ let glyph = self.load_glyph(raw);
+ self.add_render_item(&cell, &glyph);
+ return;
+ }
+
// Get font key for cell
// FIXME this is super inefficient.
let font_key = if cell.flags.contains(cell::Flags::BOLD) {
@@ -996,8 +1003,10 @@ impl<'a> RenderApi<'a> {
// Don't render text of HIDDEN cells
let mut chars = if cell.flags.contains(cell::Flags::HIDDEN) {
[' '; cell::MAX_ZEROWIDTH_CHARS + 1]
+ } else if let RenderableCellContent::Chars(chars) = cell.inner {
+ chars
} else {
- cell.chars
+ unimplemented!();
};
// Render tabs as spaces in case the font doesn't support it
diff --git a/src/renderer/rects.rs b/src/renderer/rects.rs
index 2e5cd85b..b4f8a012 100644
--- a/src/renderer/rects.rs
+++ b/src/renderer/rects.rs
@@ -96,7 +96,7 @@ impl<'a> Rects<'a> {
// Start a new line if the flag is present
if cell.flags.contains(line.flag) {
- *start = *cell;
+ *start = cell.clone();
*end = cell.into();
} else {
line.range = None;
@@ -105,7 +105,7 @@ impl<'a> Rects<'a> {
// Check for new start of line
None => {
if cell.flags.contains(line.flag) {
- line.range = Some((*cell, cell.into()));
+ line.range = Some((cell.clone(), cell.into()));
}
},
};
diff --git a/src/term/mod.rs b/src/term/mod.rs
index 48eedef1..9e879ada 100644
--- a/src/term/mod.rs
+++ b/src/term/mod.rs
@@ -18,7 +18,8 @@ use std::ops::{Index, IndexMut, Range, RangeInclusive};
use std::time::{Duration, Instant};
use std::{io, mem, ptr};
-use arraydeque::ArrayDeque;
+use copypasta::{Clipboard, Load, Store};
+use font::{self, RasterizedGlyph, Size};
use glutin::MouseCursor;
use unicode_width::UnicodeWidthChar;
@@ -26,6 +27,7 @@ use crate::ansi::{
self, Attr, CharsetIndex, Color, CursorStyle, Handler, NamedColor, StandardCharset,
};
use crate::config::{Config, VisualBellAnimation};
+use crate::cursor;
use crate::grid::{
BidirectionalIterator, DisplayIter, Grid, GridCell, IndexRegion, Indexed, Scroll,
ViewportPosition,
@@ -37,8 +39,6 @@ use crate::selection::{self, Locations, Selection};
use crate::term::cell::{Cell, Flags, LineLength};
use crate::term::color::Rgb;
use crate::url::{Url, UrlParser};
-use copypasta::{Clipboard, Load, Store};
-use font::{self, Size};
#[cfg(windows)]
use crate::tty;
@@ -158,12 +158,12 @@ pub struct RenderableCellsIter<'a> {
grid: &'a Grid<Cell>,
cursor: &'a Point,
cursor_offset: usize,
- mode: TermMode,
+ cursor_cell: Option<RasterizedGlyph>,
+ cursor_style: CursorStyle,
config: &'a Config,
colors: &'a color::List,
selection: Option<RangeInclusive<index::Linear>>,
url_highlight: &'a Option<RangeInclusive<index::Linear>>,
- cursor_cells: ArrayDeque<[Indexed<Cell>; 3]>,
}
impl<'a> RenderableCellsIter<'a> {
@@ -176,6 +176,7 @@ impl<'a> RenderableCellsIter<'a> {
config: &'b Config,
selection: Option<Locations>,
cursor_style: CursorStyle,
+ metrics: font::Metrics,
) -> RenderableCellsIter<'b> {
let grid = &term.grid;
@@ -224,203 +225,143 @@ impl<'a> RenderableCellsIter<'a> {
}
}
+ // Load cursor glyph
+ let cursor = &term.cursor.point;
+ let cursor_cell =
+ if term.mode.contains(mode::TermMode::SHOW_CURSOR) && grid.contains(cursor) {
+ let offset_x = config.font().offset().x;
+ let offset_y = config.font().offset().y;
+
+ let is_wide = grid[cursor].flags.contains(cell::Flags::WIDE_CHAR)
+ && (cursor.col + 1) < grid.num_cols();
+ Some(cursor::get_cursor_glyph(cursor_style, metrics, offset_x, offset_y, is_wide))
+ } else {
+ None
+ };
+
RenderableCellsIter {
- cursor: &term.cursor.point,
+ cursor,
cursor_offset,
grid,
inner,
- mode: term.mode,
selection: selection_range,
url_highlight: &grid.url_highlight,
config,
colors: &term.colors,
- cursor_cells: ArrayDeque::new(),
+ cursor_cell,
+ cursor_style,
}
- .initialize(cursor_style)
- }
-
- fn push_cursor_cells(&mut self, original: Cell, cursor: Cell, wide: Cell) {
- // Prints the char under the cell if cursor is situated on a non-empty cell
- self.cursor_cells
- .push_back(Indexed { line: self.cursor.line, column: self.cursor.col, inner: original })
- .expect("won't exceed capacity");
-
- // Prints the cursor
- self.cursor_cells
- .push_back(Indexed { line: self.cursor.line, column: self.cursor.col, inner: cursor })
- .expect("won't exceed capacity");
-
- // If cursor is over a wide (2 cell size) character,
- // print the second cursor cell
- if self.is_wide_cursor(&cursor) {
- self.cursor_cells
- .push_back(Indexed {
- line: self.cursor.line,
- column: self.cursor.col + 1,
- inner: wide,
- })
- .expect("won't exceed capacity");
- }
- }
-
- fn populate_block_cursor(&mut self) {
- let cell = &self.grid[self.cursor];
- let text_color = self.config.cursor_text_color().unwrap_or(cell.bg);
- let cursor_color = self.config.cursor_cursor_color().unwrap_or(cell.fg);
-
- let original_cell = self.grid[self.cursor];
-
- let mut cursor_cell = self.grid[self.cursor];
- cursor_cell.fg = text_color;
- cursor_cell.bg = cursor_color;
-
- let mut wide_cell = cursor_cell;
- wide_cell.c = ' ';
-
- self.push_cursor_cells(original_cell, cursor_cell, wide_cell);
- }
-
- fn populate_char_cursor(&mut self, cursor_cell_char: char, wide_cell_char: char) {
- let original_cell = self.grid[self.cursor];
-
- let mut cursor_cell = self.grid[self.cursor];
- let cursor_color = self.config.cursor_cursor_color().unwrap_or(cursor_cell.fg);
- cursor_cell.c = cursor_cell_char;
- cursor_cell.fg = cursor_color;
-
- let mut wide_cell = cursor_cell;
- wide_cell.c = wide_cell_char;
-
- self.push_cursor_cells(original_cell, cursor_cell, wide_cell);
- }
-
- fn populate_underline_cursor(&mut self) {
- self.populate_char_cursor(font::UNDERLINE_CURSOR_CHAR, font::UNDERLINE_CURSOR_CHAR);
- }
-
- fn populate_beam_cursor(&mut self) {
- self.populate_char_cursor(font::BEAM_CURSOR_CHAR, ' ');
- }
-
- fn populate_box_cursor(&mut self) {
- self.populate_char_cursor(font::BOX_CURSOR_CHAR, ' ');
}
+}
- #[inline]
- fn is_wide_cursor(&self, cell: &Cell) -> bool {
- cell.flags.contains(cell::Flags::WIDE_CHAR) && (self.cursor.col + 1) < self.grid.num_cols()
- }
+#[derive(Clone, Debug)]
+pub enum RenderableCellContent {
+ Chars([char; cell::MAX_ZEROWIDTH_CHARS + 1]),
+ Raw(RasterizedGlyph),
+}
- /// Populates list of cursor cells with the original cell
- fn populate_no_cursor(&mut self) {
- self.cursor_cells
- .push_back(Indexed {
- line: self.cursor.line,
- column: self.cursor.col,
- inner: self.grid[self.cursor],
- })
- .expect("won't exceed capacity");
- }
+#[derive(Clone, Debug)]
+pub struct RenderableCell {
+ /// A _Display_ line (not necessarily an _Active_ line)
+ pub line: Line,
+ pub column: Column,
+ pub inner: RenderableCellContent,
+ pub fg: Rgb,
+ pub bg: Rgb,
+ pub bg_alpha: f32,
+ pub flags: cell::Flags,
+}
- fn initialize(mut self, cursor_style: CursorStyle) -> Self {
- if self.cursor_is_visible() {
- match cursor_style {
- CursorStyle::HollowBlock => {
- self.populate_box_cursor();
- },
- CursorStyle::Block => {
- self.populate_block_cursor();
- },
- CursorStyle::Beam => {
- self.populate_beam_cursor();
- },
- CursorStyle::Underline => {
- self.populate_underline_cursor();
- },
- }
+impl RenderableCell {
+ fn new(config: &Config, colors: &color::List, cell: Indexed<Cell>, selected: bool) -> Self {
+ // Lookup RGB values
+ let mut fg_rgb = Self::compute_fg_rgb(config, colors, cell.fg, cell.flags);
+ let mut bg_rgb = Self::compute_bg_rgb(colors, cell.bg);
+
+ let selection_background = config.colors().selection.background;
+ let bg_alpha = if let (true, Some(col)) = (selected, selection_background) {
+ // Override selection background with config colors
+ bg_rgb = col;
+ 1.0
+ } else if selected ^ cell.inverse() {
+ // Invert cell fg and bg colors
+ mem::swap(&mut fg_rgb, &mut bg_rgb);
+ Self::compute_bg_alpha(cell.fg)
} else {
- self.populate_no_cursor();
+ Self::compute_bg_alpha(cell.bg)
+ };
+
+ // Override selection text with config colors
+ if let (true, Some(col)) = (selected, config.colors().selection.text) {
+ fg_rgb = col;
}
- self
- }
- /// Check if the cursor should be rendered.
- #[inline]
- fn cursor_is_visible(&self) -> bool {
- self.mode.contains(mode::TermMode::SHOW_CURSOR) && self.grid.contains(self.cursor)
+ RenderableCell {
+ line: cell.line,
+ column: cell.column,
+ inner: RenderableCellContent::Chars(cell.chars()),
+ fg: fg_rgb,
+ bg: bg_rgb,
+ bg_alpha,
+ flags: cell.flags,
+ }
}
- fn compute_fg_rgb(&self, fg: Color, cell: &Cell) -> Rgb {
+ fn compute_fg_rgb(config: &Config, colors: &color::List, fg: Color, flags: cell::Flags) -> Rgb {
match fg {
Color::Spec(rgb) => rgb,
Color::Named(ansi) => {
- match (
- self.config.draw_bold_text_with_bright_colors(),
- cell.flags & Flags::DIM_BOLD,
- ) {
+ match (config.draw_bold_text_with_bright_colors(), flags & Flags::DIM_BOLD) {
// If no bright foreground is set, treat it like the BOLD flag doesn't exist
- (_, self::cell::Flags::DIM_BOLD)
+ (_, cell::Flags::DIM_BOLD)
if ansi == NamedColor::Foreground
- && self.config.colors().primary.bright_foreground.is_none() =>
+ && config.colors().primary.bright_foreground.is_none() =>
{
- self.colors[NamedColor::DimForeground]
+ colors[NamedColor::DimForeground]
},
// Draw bold text in bright colors *and* contains bold flag.
- (true, self::cell::Flags::BOLD) => self.colors[ansi.to_bright()],
+ (true, cell::Flags::BOLD) => colors[ansi.to_bright()],
// Cell is marked as dim and not bold
- (_, self::cell::Flags::DIM) | (false, self::cell::Flags::DIM_BOLD) => {
- self.colors[ansi.to_dim()]
- },
+ (_, cell::Flags::DIM) | (false, cell::Flags::DIM_BOLD) => colors[ansi.to_dim()],
// None of the above, keep original color.
- _ => self.colors[ansi],
+ _ => colors[ansi],
}
},
Color::Indexed(idx) => {
let idx = match (
- self.config.draw_bold_text_with_bright_colors(),
- cell.flags & Flags::DIM_BOLD,
+ config.draw_bold_text_with_bright_colors(),
+ flags & Flags::DIM_BOLD,
idx,
) {
- (true, self::cell::Flags::BOLD, 0..=7) => idx as usize + 8,
- (false, self::cell::Flags::DIM, 8..=15) => idx as usize - 8,
- (false, self::cell::Flags::DIM, 0..=7) => idx as usize + 260,
+ (true, cell::Flags::BOLD, 0..=7) => idx as usize + 8,
+ (false, cell::Flags::DIM, 8..=15) => idx as usize - 8,
+ (false, cell::Flags::DIM, 0..=7) => idx as usize + 260,
_ => idx as usize,
};
- self.colors[idx]
+ colors[idx]
},
}
}
#[inline]
- fn compute_bg_alpha(&self, bg: Color) -> f32 {
+ fn compute_bg_alpha(bg: Color) -> f32 {
match bg {
Color::Named(NamedColor::Background) => 0.0,
_ => 1.0,
}
}
- fn compute_bg_rgb(&self, bg: Color) -> Rgb {
+ #[inline]
+ fn compute_bg_rgb(colors: &color::List, bg: Color) -> Rgb {
match bg {
Color::Spec(rgb) => rgb,
- Color::Named(ansi) => self.colors[ansi],
- Color::Indexed(idx) => self.colors[idx],
+ Color::Named(ansi) => colors[ansi],
+ Color::Indexed(idx) => colors[idx],
}
}
}
-#[derive(Copy, Clone, Debug)]
-pub struct RenderableCell {
- /// A _Display_ line (not necessarily an _Active_ line)
- pub line: Line,
- pub column: Column,
- pub chars: [char; cell::MAX_ZEROWIDTH_CHARS + 1],
- pub fg: Rgb,
- pub bg: Rgb,
- pub bg_alpha: f32,
- pub flags: cell::Flags,
-}
-
impl<'a> Iterator for RenderableCellsIter<'a> {
type Item = RenderableCell;
@@ -431,23 +372,32 @@ impl<'a> Iterator for RenderableCellsIter<'a> {
#[inline]
fn next(&mut self) -> Option<Self::Item> {
loop {
- // Handle cursor
- let (cell, selected, highlighted) = if self.cursor_offset == self.inner.offset()
- && self.inner.column() == self.cursor.col
- {
- // Cursor cell
- let mut cell = self.cursor_cells.pop_front().unwrap();
- cell.line = self.inner.line();
-
- // Since there may be multiple cursor cells (for a wide
- // char), only update iteration position after all cursor
- // cells have been drawn.
- if self.cursor_cells.is_empty() {
- self.inner.next();
+ if self.cursor_offset == self.inner.offset() && self.inner.column() == self.cursor.col {
+ // Handle cursor
+ if let Some(cursor_cell) = self.cursor_cell.take() {
+ let cell = Indexed {
+ inner: self.grid[self.cursor],
+ column: self.cursor.col,
+ line: self.cursor.line,
+ };
+ let mut renderable_cell =
+ RenderableCell::new(self.config, self.colors, cell, false);
+
+ renderable_cell.inner = RenderableCellContent::Raw(cursor_cell);
+
+ return Some(renderable_cell);
+ } else {
+ let mut cell =
+ RenderableCell::new(self.config, self.colors, self.inner.next()?, false);
+
+ if self.cursor_style == CursorStyle::Block {
+ std::mem::swap(&mut cell.bg, &mut cell.fg);
+ }
+
+ return Some(cell);
}
- (cell, false, false)
} else {
- let cell = self.inner.next()?;
+ let mut cell = self.inner.next()?;
let index = Linear::new(self.grid.num_cols(), cell.column, cell.line);
@@ -460,51 +410,13 @@ impl<'a> Iterator for RenderableCellsIter<'a> {
}
// Underline URL highlights
- let highlighted = self
- .url_highlight
- .as_ref()
- .map(|range| range.contains_(index))
- .unwrap_or(false);
-
- (cell, selected, highlighted)
- };
-
- // Lookup RGB values
- let mut fg_rgb = self.compute_fg_rgb(cell.fg, &cell);
- let mut bg_rgb = self.compute_bg_rgb(cell.bg);
-
- let selection_background = self.config.colors().selection.background;
- let bg_alpha = if let (true, Some(col)) = (selected, selection_background) {
- // Override selection background with config colors
- bg_rgb = col;
- 1.0
- } else if selected ^ cell.inverse() {
- // Invert cell fg and bg colors
- mem::swap(&mut fg_rgb, &mut bg_rgb);
- self.compute_bg_alpha(cell.fg)
- } else {
- self.compute_bg_alpha(cell.bg)
- };
-
- // Override selection text with config colors
- if let (true, Some(col)) = (selected, self.config.colors().selection.text) {
- fg_rgb = col;
- }
+ if self.url_highlight.as_ref().map(|range| range.contains_(index)).unwrap_or(false)
+ {
+ cell.inner.flags.insert(Flags::UNDERLINE);
+ }
- let mut flags = cell.flags;
- if highlighted {
- flags.insert(Flags::UNDERLINE);
+ return Some(RenderableCell::new(self.config, self.colors, cell, selected));
}
-
- return Some(RenderableCell {
- line: cell.line,
- column: cell.column,
- chars: cell.chars(),
- fg: fg_rgb,
- bg: bg_rgb,
- bg_alpha,
- flags,
- });
}
}
}
@@ -1174,6 +1086,7 @@ impl Term {
&'b self,
config: &'b Config,
window_focused: bool,
+ metrics: font::Metrics,
) -> RenderableCellsIter<'_> {
let alt_screen = self.mode.contains(TermMode::ALT_SCREEN);
let selection = self
@@ -1189,7 +1102,7 @@ impl Term {
CursorStyle::HollowBlock
};
- RenderableCellsIter::new(&self, config, selection, cursor)
+ RenderableCellsIter::new(&self, config, selection, cursor, metrics)
}
/// Resize terminal to new dimensions
@@ -2497,8 +2410,18 @@ mod benches {
let mut terminal = Term::new(&config, size, MessageBuffer::new());
mem::swap(&mut terminal.grid, &mut grid);
+ let metrics = font::Metrics {
+ descent: 0.,
+ line_height: 0.,
+ average_advance: 0.,
+ underline_position: 0.,
+ underline_thickness: 0.,
+ strikeout_position: 0.,
+ strikeout_thickness: 0.,
+ };
+
b.iter(|| {
- let iter = terminal.renderable_cells(&config, false);
+ let iter = terminal.renderable_cells(&config, false, metrics);
for cell in iter {
test::black_box(cell);
}