Switched to hybrid iterator and while loop grid processor. Still hairy but much more managable. Not finished compiling yet.

This commit is contained in:
Mikayla Maki 2022-07-16 22:17:20 -07:00
parent c9584a9d0c
commit 9d063ae6d8

View file

@ -1,6 +1,7 @@
mod terminal_layout_context; mod terminal_layout_context;
use alacritty_terminal::{ use alacritty_terminal::{
ansi::{Color::Named, NamedColor},
grid::{Dimensions, GridIterator, Indexed, Scroll}, grid::{Dimensions, GridIterator, Indexed, Scroll},
index::{Column as GridCol, Line as GridLine, Point, Side}, index::{Column as GridCol, Line as GridLine, Point, Side},
selection::{Selection, SelectionRange, SelectionType}, selection::{Selection, SelectionRange, SelectionType},
@ -55,11 +56,6 @@ pub struct TerminalEl {
pub struct CellWidth(f32); pub struct CellWidth(f32);
pub struct LineHeight(f32); pub struct LineHeight(f32);
struct LayoutLine {
cells: Vec<LayoutCell>,
highlighted_range: Option<Range<usize>>,
}
///New type pattern to ensure that we use adjusted mouse positions throughout the code base, rather than ///New type pattern to ensure that we use adjusted mouse positions throughout the code base, rather than
struct PaneRelativePos(Vector2F); struct PaneRelativePos(Vector2F);
@ -68,26 +64,11 @@ fn relative_pos(mouse_position: Vector2F, origin: Vector2F) -> PaneRelativePos {
PaneRelativePos(mouse_position.sub(origin)) //Avoid the extra allocation by mutating PaneRelativePos(mouse_position.sub(origin)) //Avoid the extra allocation by mutating
} }
#[derive(Clone, Debug, Default)]
struct LayoutCell {
point: Point<i32, i32>,
text: Line, //NOTE TO SELF THIS IS BAD PERFORMANCE RN!
background_color: Color,
}
impl LayoutCell {
fn new(point: Point<i32, i32>, text: Line, background_color: Color) -> LayoutCell {
LayoutCell {
point,
text,
background_color,
}
}
}
///The information generated during layout that is nescessary for painting ///The information generated during layout that is nescessary for painting
pub struct LayoutState { pub struct LayoutState {
layout_lines: Vec<LayoutLine>, cells: Vec<LayoutCell>,
rects: Vec<LayoutRect>,
highlights: Vec<RelativeHighlightedRange>,
line_height: LineHeight, line_height: LineHeight,
em_width: CellWidth, em_width: CellWidth,
cursor: Option<Cursor>, cursor: Option<Cursor>,
@ -225,19 +206,9 @@ impl Element for TerminalEl {
let content = term.renderable_content(); let content = term.renderable_content();
/*
* TODO for layouts:
* - Refactor this whole process to produce 'text cells', 'background rects', and 'selections' which know
* how to paint themselves
* - Rather than doing everything per cell, map each cell into a tuple and then unzip the streams
* - For efficiency:
* - filter out all background colored background rects
* - filter out all text cells which just contain ' '
* - Smoosh together rectangles on same line
*/
//Layout grid cells //Layout grid cells
let layout_lines = layout_lines(
let (cells, rects, highlights) = layout_grid(
content.display_iter, content.display_iter,
&tcx.text_style, &tcx.text_style,
tcx.terminal_theme, tcx.terminal_theme,
@ -267,12 +238,14 @@ impl Element for TerminalEl {
( (
constraint.max, constraint.max,
LayoutState { LayoutState {
layout_lines,
line_height: tcx.line_height, line_height: tcx.line_height,
em_width: tcx.cell_width, em_width: tcx.cell_width,
cursor, cursor,
background_color, background_color,
selection_color: tcx.selection_color, selection_color: tcx.selection_color,
cells,
rects,
highlights,
}, },
) )
} }
@ -310,7 +283,7 @@ impl Element for TerminalEl {
}); });
//Draw cell backgrounds //Draw cell backgrounds
for layout_line in &layout.layout_lines { for layout_line in &layout.layout_cells {
for layout_cell in &layout_line.cells { for layout_cell in &layout_line.cells {
let position = vec2f( let position = vec2f(
(origin.x() + layout_cell.point.column as f32 * layout.em_width.0) (origin.x() + layout_cell.point.column as f32 * layout.em_width.0)
@ -333,7 +306,7 @@ impl Element for TerminalEl {
cx.paint_layer(clip_bounds, |cx| { cx.paint_layer(clip_bounds, |cx| {
let mut highlight_y = None; let mut highlight_y = None;
let highlight_lines = layout let highlight_lines = layout
.layout_lines .layout_cells
.iter() .iter()
.filter_map(|line| { .filter_map(|line| {
if let Some(range) = &line.highlighted_range { if let Some(range) = &line.highlighted_range {
@ -370,7 +343,7 @@ impl Element for TerminalEl {
}); });
cx.paint_layer(clip_bounds, |cx| { cx.paint_layer(clip_bounds, |cx| {
for layout_line in &layout.layout_lines { for layout_line in &layout.layout_cells {
for layout_cell in &layout_line.cells { for layout_cell in &layout_line.cells {
let point = layout_cell.point; let point = layout_cell.point;
@ -549,57 +522,155 @@ fn make_new_size(
) )
} }
fn layout_lines( #[derive(Clone, Debug, Default)]
struct LayoutCell {
point: Point<i32, i32>,
text: Line,
}
impl LayoutCell {
fn new(point: Point<i32, i32>, text: Line) -> LayoutCell {
LayoutCell { point, text }
}
}
#[derive(Clone, Debug, Default)]
struct LayoutRect {
pos: Point<i32, i32>,
num_of_cells: usize,
color: Color,
}
impl LayoutRect {
fn new(pos: Point<i32, i32>, num_of_cells: usize, color: Color) -> LayoutRect {
LayoutRect {
pos,
num_of_cells,
color,
}
}
fn extend(&mut self) {
self.num_of_cells += 1;
}
}
struct RelativeHighlightedRange {
line_index: usize,
range: Range<usize>,
}
impl RelativeHighlightedRange {
fn new(line_index: usize, range: Range<usize>) -> Self {
RelativeHighlightedRange { line_index, range }
}
}
fn layout_grid(
grid: GridIterator<Cell>, grid: GridIterator<Cell>,
text_style: &TextStyle, text_style: &TextStyle,
terminal_theme: &TerminalStyle, terminal_theme: &TerminalStyle,
text_layout_cache: &TextLayoutCache, text_layout_cache: &TextLayoutCache,
modal: bool, modal: bool,
selection_range: Option<SelectionRange>, selection_range: Option<SelectionRange>,
) -> Vec<LayoutLine> { ) -> (
let lines = grid.group_by(|i| i.point.line); Vec<LayoutCell>,
lines Vec<LayoutRect>,
.into_iter() Vec<RelativeHighlightedRange>,
.enumerate() ) {
.map(|(line_index, (_, line))| { let mut cells = vec![];
let mut highlighted_range = None; let mut rects = vec![];
let cells = line let mut highlight_ranges = vec![];
.enumerate()
.map(|(x_index, indexed_cell)| { let mut cur_rect: Option<LayoutRect> = None;
if selection_range let mut cur_alac_color = None;
.map(|range| range.contains(indexed_cell.point)) let mut highlighted_range = None;
.unwrap_or(false)
{ let linegroups = grid.group_by(|i| i.point.line);
let mut range = highlighted_range.take().unwrap_or(x_index..x_index); for (line_index, (_, line)) in linegroups.into_iter().enumerate() {
range.end = range.end.max(x_index); for (x_index, cell) in line.enumerate() {
highlighted_range = Some(range); //Increase selection range
{
if selection_range
.map(|range| range.contains(cell.point))
.unwrap_or(false)
{
let mut range = highlighted_range.take().unwrap_or(x_index..x_index);
range.end = range.end.max(x_index);
highlighted_range = Some(range);
}
}
//Expand background rect range
{
match (cell.bg, cur_alac_color) {
(Named(NamedColor::Background), Some(_)) => {
//Skip color, end background
cur_alac_color = None;
rects.push(cur_rect.take().unwrap());
} }
(bg, Some(cur_color)) => {
//If they're the same, extend the match
if bg == cur_color {
cur_rect.unwrap().extend()
} else {
//If they differ, end background and restart
cur_alac_color = None;
rects.push(cur_rect.take().unwrap());
let cell_text = &indexed_cell.c.to_string(); cur_alac_color = Some(bg);
cur_rect = Some(LayoutRect::new(
Point::new(line_index as i32, cell.point.column.0 as i32),
1,
convert_color(&bg, &terminal_theme.colors, modal),
));
}
}
(bg, None) if !matches!(bg, Named(NamedColor::Background)) => {
//install new background
cur_alac_color = Some(bg);
cur_rect = Some(LayoutRect::new(
Point::new(line_index as i32, cell.point.column.0 as i32),
1,
convert_color(&bg, &terminal_theme.colors, modal),
));
}
(_, _) => {} //Only happens when bg is NamedColor::Background
}
}
let cell_style = cell_style(&indexed_cell, terminal_theme, text_style, modal); //Layout current cell text
{
let cell_text = &cell.c.to_string();
if cell_text != " " {
let cell_style = cell_style(&cell, terminal_theme, text_style, modal);
//This is where we might be able to get better performance
let layout_cell = text_layout_cache.layout_str( let layout_cell = text_layout_cache.layout_str(
cell_text, cell_text,
text_style.font_size, text_style.font_size,
&[(cell_text.len(), cell_style)], &[(cell_text.len(), cell_style)],
); );
LayoutCell::new( cells.push(LayoutCell::new(
Point::new(line_index as i32, indexed_cell.point.column.0 as i32), Point::new(line_index as i32, cell.point.column.0 as i32),
layout_cell, layout_cell,
convert_color(&indexed_cell.bg, &terminal_theme.colors, modal), ))
) }
}) };
.collect::<Vec<LayoutCell>>(); }
LayoutLine { if highlighted_range.is_some() {
cells, highlight_ranges.push(RelativeHighlightedRange::new(
highlighted_range, line_index,
} highlighted_range.take().unwrap(),
}) ))
.collect::<Vec<LayoutLine>>() }
if cur_rect.is_some() {
rects.push(cur_rect.take().unwrap());
}
}
(cells, rects, highlight_ranges)
} }
// Compute the cursor position and expected block width, may return a zero width if x_for_index returns // Compute the cursor position and expected block width, may return a zero width if x_for_index returns