Skip to content

Commit 796cdfe

Browse files
committed
Small improvements
1 parent 2ad54ad commit 796cdfe

File tree

4 files changed

+112
-93
lines changed

4 files changed

+112
-93
lines changed

alacritty/src/display/mod.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -487,8 +487,13 @@ impl Display {
487487
let background_color = content.color(NamedColor::Background as usize);
488488
let display_offset = content.display_offset();
489489
let grid_text_runs: Vec<TextRun> = {
490-
TextRunIter::<()>::from_content(&mut content, highlighted_hint, vi_highlighted_hint)
491-
.collect()
490+
let mut vec = Vec::with_capacity(terminal.screen_lines() * 2);
491+
vec.extend(TextRunIter::from_content(
492+
&mut content,
493+
highlighted_hint,
494+
vi_highlighted_hint,
495+
));
496+
vec
492497
};
493498
let cursor = content.cursor();
494499

alacritty/src/renderer/mod.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -954,21 +954,22 @@ impl<'a> RenderApi<'a> {
954954
}
955955

956956
pub fn render_text_run(&mut self, text_run: TextRun, glyph_cache: &mut GlyphCache) {
957-
let TextRunContent { text, zero_widths } = &text_run.content;
958-
959957
// Get font key for cell
960958
let font_key = Self::determine_font_key(text_run.flags, glyph_cache);
961959

962960
let shaped_glyphs = if text_run.flags.contains(Flags::HIDDEN) {
963961
GlyphIter::Hidden
964962
} else {
965963
GlyphIter::Shaped(
966-
glyph_cache.shape_run(text, font_key, self).expect("read font").into_iter(),
964+
glyph_cache
965+
.shape_run(&text_run.content.text, font_key, self)
966+
.expect("read font")
967+
.into_iter(),
967968
)
968969
};
969970

970971
for ((mut cell, glyph), zero_width_chars) in
971-
text_run.cells().zip(shaped_glyphs).zip(zero_widths.iter())
972+
text_run.cells().zip(shaped_glyphs).zip(text_run.content.zero_widths.iter())
972973
{
973974
self.add_render_item(&cell, &glyph);
974975
// Add empty spacer for full width characters

alacritty/src/text_run.rs

Lines changed: 99 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
use std::mem::replace;
2+
13
use alacritty_terminal::index::{Column, Line, Point};
24
use alacritty_terminal::term::cell::Flags;
35
use alacritty_terminal::term::color::Rgb;
46
use alacritty_terminal::term::search::Match;
57

68
use crate::display::content::{RenderableCell, RenderableContent};
79

8-
#[derive(Debug)]
10+
#[derive(Debug, Default, Clone, Copy)]
911
struct RunStart {
1012
line: usize,
1113
column: Column,
@@ -16,14 +18,25 @@ struct RunStart {
1618
}
1719

1820
impl RunStart {
21+
fn new(cell: &RenderableCell) -> Self {
22+
Self {
23+
line: cell.point.line,
24+
column: cell.point.column,
25+
fg: cell.fg,
26+
bg: cell.bg,
27+
bg_alpha: cell.bg_alpha,
28+
flags: cell.flags,
29+
}
30+
}
31+
1932
/// Compare cell and check if it belongs to the same run.
2033
#[inline]
2134
fn belongs_to_text_run(&self, render_cell: &RenderableCell) -> bool {
2235
self.line == render_cell.point.line
2336
&& self.fg == render_cell.fg
24-
&& self.bg == render_cell.bg
25-
&& (self.bg_alpha - render_cell.bg_alpha).abs() < std::f32::EPSILON
2637
&& self.flags == render_cell.flags
38+
&& self.bg == render_cell.bg
39+
&& (self.bg_alpha - render_cell.bg_alpha).abs() < f32::EPSILON
2740
}
2841
}
2942

@@ -80,7 +93,7 @@ impl TextRun {
8093
Point { line: self.line, column: self.span.1 }
8194
}
8295

83-
/// Iterates over each RenderableCell in column range [run.0, run.1]
96+
/// Iterates over each RenderableCell in column range `[run.0, run.1]`
8497
pub fn cells(&self) -> impl Iterator<Item = RenderableCell> + '_ {
8598
let step = if self.flags.contains(Flags::WIDE_CHAR) { 2 } else { 1 };
8699
let (Column(start), Column(end)) = self.span;
@@ -89,14 +102,24 @@ impl TextRun {
89102
}
90103
}
91104

92-
type IsWide = bool;
93-
type LatestCol = (Column, IsWide);
105+
#[derive(Default, Clone, Copy)]
106+
pub struct LatestCol {
107+
column: Column,
108+
is_wide: bool,
109+
}
110+
111+
impl LatestCol {
112+
#[inline]
113+
fn new(cell: &RenderableCell) -> Self {
114+
Self { column: cell.point.column, is_wide: cell.flags.contains(Flags::WIDE_CHAR) }
115+
}
116+
}
94117

95118
/// Wraps an Iterator<Item=RenderableCell> and produces TextRuns to represent batches of cells
96119
pub struct TextRunIter<I> {
97120
iter: I,
98-
run_start: Option<RunStart>,
99-
latest_col: Option<LatestCol>,
121+
run_start: RunStart,
122+
latest_col: LatestCol,
100123
display_offset: usize,
101124
hint: Option<Match>,
102125
vi_hint: Option<Match>,
@@ -107,12 +130,12 @@ pub struct TextRunIter<I> {
107130
type TextRunIterFromContent<'a, 'c> =
108131
TextRunIter<std::iter::Filter<&'a mut RenderableContent<'c>, fn(&RenderableCell) -> bool>>;
109132

110-
impl<I> TextRunIter<I> {
111-
pub fn from_content<'a, 'c>(
133+
impl<'a, 'c> TextRunIterFromContent<'a, 'c> {
134+
pub fn from_content(
112135
content: &'a mut RenderableContent<'c>,
113136
hint: Option<Match>,
114137
vi_hint: Option<Match>,
115-
) -> TextRunIterFromContent<'a, 'c> {
138+
) -> Self {
116139
fn check(cell: &RenderableCell) -> bool {
117140
!cell.flags.contains(Flags::WIDE_CHAR_SPACER)
118141
}
@@ -130,41 +153,60 @@ where
130153
I: Iterator<Item = RenderableCell>,
131154
{
132155
pub fn new(
133-
iter: I,
156+
mut iter: I,
134157
hint: Option<Match>,
135158
vi_hint: Option<Match>,
136159
display_offset: usize,
137160
) -> Self {
138-
TextRunIter {
139-
iter,
140-
latest_col: None,
141-
display_offset,
142-
run_start: None,
143-
buffer_text: String::new(),
144-
buffer_zero_width: Vec::new(),
145-
hint,
146-
vi_hint,
161+
if let Some(cell) = iter.next() {
162+
let latest_col = LatestCol::new(&cell);
163+
let run_start = RunStart::new(&cell);
164+
let buffer_text = cell.character.to_string();
165+
let buffer_zero_width = vec![cell.zerowidth];
166+
167+
TextRunIter {
168+
iter,
169+
run_start,
170+
latest_col,
171+
display_offset,
172+
hint,
173+
vi_hint,
174+
buffer_text,
175+
buffer_zero_width,
176+
}
177+
} else {
178+
// There are no cells in the grid. This rarely happens.
179+
#[cold]
180+
#[inline]
181+
fn dummy<I>(iter: I) -> TextRunIter<I> {
182+
TextRunIter {
183+
iter,
184+
run_start: RunStart::default(),
185+
latest_col: LatestCol::default(),
186+
display_offset: 0,
187+
hint: None,
188+
vi_hint: None,
189+
buffer_text: String::new(),
190+
buffer_zero_width: Vec::new(),
191+
}
192+
}
193+
194+
dummy(iter)
147195
}
148196
}
149197
}
150198
impl<I> TextRunIter<I> {
151199
/// Check if the cell belongs to this text run. Returns `true` if it does not belong.
152200
fn cell_does_not_belong_to_run(&self, render_cell: &RenderableCell) -> bool {
153-
self.run_start
154-
.as_ref()
155-
.map(|run_start| !run_start.belongs_to_text_run(render_cell))
156-
.unwrap_or_default()
201+
!self.run_start.belongs_to_text_run(render_cell)
157202
}
158203

159204
/// Check if the column is not adjacent to the latest column.
160-
fn is_col_not_adjacent(&self, column: Column) -> bool {
161-
self.latest_col
162-
.as_ref()
163-
.map(|&(col, is_wide)| {
164-
let width = if is_wide { 2 } else { 1 };
165-
col + width != column && column + width != col
166-
})
167-
.unwrap_or_default()
205+
fn is_col_not_adjacent(&self, col: Column) -> bool {
206+
let LatestCol { column, is_wide } = self.latest_col;
207+
208+
let width = if is_wide { 2 } else { 1 };
209+
col + width != column && column + width != col
168210
}
169211

170212
/// Check if current run ends at incoming RenderableCell
@@ -184,7 +226,8 @@ impl<I> TextRunIter<I> {
184226
/// Empty out pending buffer producing owned collections that can be moved into a TextRun
185227
fn drain_buffer(&mut self) -> TextRunContent {
186228
use std::mem::take;
187-
let text = take(&mut self.buffer_text);
229+
let text = self.buffer_text.clone();
230+
self.buffer_text.clear();
188231
let zero_widths = take(&mut self.buffer_zero_width);
189232

190233
TextRunContent { text, zero_widths }
@@ -204,40 +247,28 @@ impl<I> TextRunIter<I> {
204247

205248
/// Start a new run by setting latest_col, run_start, and buffering content of rc
206249
/// Returns the previous runs run_start and latest_col data if available.
207-
fn start_run(&mut self, render_cell: RenderableCell) -> (Option<RunStart>, Option<LatestCol>) {
208-
let latest = self
209-
.latest_col
210-
.replace((render_cell.point.column, render_cell.flags.contains(Flags::WIDE_CHAR)));
211-
let start = self.run_start.replace(RunStart {
212-
line: render_cell.point.line,
213-
column: render_cell.point.column,
214-
fg: render_cell.fg,
215-
bg: render_cell.bg,
216-
bg_alpha: render_cell.bg_alpha,
217-
flags: render_cell.flags,
218-
});
250+
fn start_run(&mut self, render_cell: RenderableCell) -> (RunStart, LatestCol) {
251+
let prev_start = replace(&mut self.run_start, RunStart::new(&render_cell));
252+
let prev_latest = replace(&mut self.latest_col, LatestCol::new(&render_cell));
253+
219254
self.buffer_content(render_cell);
220-
(start, latest)
255+
256+
(prev_start, prev_latest)
221257
}
222258

223259
/// Create a run of chars from the current state of the `TextRunIter`.
224260
/// This is a destructive operation, the iterator will be in a new run state after it's
225261
/// completion.
226-
fn produce_char_run(&mut self, render_cell: RenderableCell) -> Option<TextRun> {
262+
fn produce_char_run(&mut self, render_cell: RenderableCell) -> TextRun {
227263
let prev_buffer = self.drain_buffer();
228-
let (start_opt, latest_col_opt) = self.start_run(render_cell);
229-
let start = start_opt?;
230-
let latest_col = latest_col_opt?;
231-
Some(Self::build_text_run(start, latest_col, prev_buffer))
264+
let (start, latest_col) = self.start_run(render_cell);
265+
266+
Self::build_text_run(start, latest_col, prev_buffer)
232267
}
233268

234269
/// Build a TextRun instance from passed state of TextRunIter
235-
fn build_text_run(
236-
start: RunStart,
237-
(latest, is_wide): LatestCol,
238-
content: TextRunContent,
239-
) -> TextRun {
240-
let end_column = if is_wide { latest + 1 } else { latest };
270+
fn build_text_run(start: RunStart, latest_col: LatestCol, content: TextRunContent) -> TextRun {
271+
let end_column = latest_col.column + latest_col.is_wide as usize;
241272
TextRun {
242273
line: start.line,
243274
span: (start.column, end_column),
@@ -257,46 +288,28 @@ where
257288
type Item = TextRun;
258289

259290
fn next(&mut self) -> Option<Self::Item> {
260-
let mut output = None;
261291
while let Some(mut render_cell) = self.iter.next() {
262292
if self.is_hinted(render_cell.point) {
263293
render_cell.flags.insert(Flags::UNDERLINE);
264294
}
265-
if self.latest_col.is_none() || self.run_start.is_none() {
266-
// Initial state, this is should only be hit on the first next() call of
267-
// iterator
268-
269-
self.run_start = Some(RunStart {
270-
line: render_cell.point.line,
271-
column: render_cell.point.column,
272-
fg: render_cell.fg,
273-
bg: render_cell.bg,
274-
bg_alpha: render_cell.bg_alpha,
275-
flags: render_cell.flags,
276-
});
277-
} else if self.is_end_of_run(&render_cell) {
295+
if self.is_end_of_run(&render_cell) {
278296
// If we find a run break,
279297
// return what we have so far and start a new run.
280-
output = self.produce_char_run(render_cell);
281-
break;
298+
return Some(self.produce_char_run(render_cell));
282299
}
283300

284301
// Build up buffer and track the latest column we've seen
285-
self.latest_col =
286-
Some((render_cell.point.column, render_cell.flags.contains(Flags::WIDE_CHAR)));
302+
self.latest_col = LatestCol::new(&render_cell);
287303
self.buffer_content(render_cell);
288304
}
305+
289306
// Check for any remaining buffered content and return it as a text run.
290307
// This is a destructive operation, it will return None after it excutes once.
291-
output.or_else(|| {
292-
if !self.buffer_text.is_empty() || !self.buffer_zero_width.is_empty() {
293-
let start = self.run_start.take()?;
294-
let latest_col = self.latest_col.take()?;
295-
// Save leftover buffer and empty it
296-
Some(Self::build_text_run(start, latest_col, self.drain_buffer()))
297-
} else {
298-
None
299-
}
300-
})
308+
if !self.buffer_text.is_empty() || !self.buffer_zero_width.is_empty() {
309+
// Save leftover buffer and empty it
310+
Some(Self::build_text_run(self.run_start, self.latest_col, self.drain_buffer()))
311+
} else {
312+
None
313+
}
301314
}
302315
}

alacritty_terminal/src/term/cell.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::grid::{self, GridCell};
88
use crate::index::Column;
99

1010
bitflags! {
11-
#[derive(Serialize, Deserialize)]
11+
#[derive(Serialize, Deserialize, Default)]
1212
pub struct Flags: u16 {
1313
const INVERSE = 0b0000_0000_0000_0001;
1414
const BOLD = 0b0000_0000_0000_0010;

0 commit comments

Comments
 (0)