From 831afb5ba777cbec15b380953699281027687d10 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 30 Jun 2022 20:34:06 -0700 Subject: [PATCH 1/7] Fixed a major bug and now use the same cursor paint logic as the editor --- crates/editor/src/element.rs | 22 ++++++++++-- crates/terminal/src/terminal.rs | 3 +- crates/terminal/src/terminal_element.rs | 48 +++++++++++++++---------- 3 files changed, 51 insertions(+), 22 deletions(-) diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 19226c6472c3c0fd4dcd2a5964fe3dcbcfbd693a..348ce57ef37b957d9bef86bf114fe8956eb7cce2 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1630,7 +1630,7 @@ impl Default for CursorShape { } } -struct Cursor { +pub struct Cursor { origin: Vector2F, block_width: f32, line_height: f32, @@ -1640,7 +1640,25 @@ struct Cursor { } impl Cursor { - fn paint(&self, cx: &mut PaintContext) { + pub fn new( + origin: Vector2F, + block_width: f32, + line_height: f32, + color: Color, + shape: CursorShape, + block_text: Option, + ) -> Cursor { + Cursor { + origin, + block_width, + line_height, + color, + shape, + block_text, + } + } + + pub fn paint(&self, cx: &mut PaintContext) { let bounds = match self.shape { CursorShape::Bar => RectF::new(self.origin, vec2f(2.0, self.line_height)), CursorShape::Block => { diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 984f8837468af2427946ac4bb43abe18c70a3988..134cf5be6e5afb51aed482ca86712550c7e88d2b 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -262,8 +262,7 @@ impl Terminal { .active_entry() .and_then(|entry_id| project.worktree_for_entry(entry_id, cx)) .and_then(|worktree_handle| worktree_handle.read(cx).as_local()) - .map(|wt| wt.abs_path().to_path_buf()) - .or_else(|| Some("~".into())); + .map(|wt| wt.abs_path().to_path_buf()); workspace.add_item(Box::new(cx.add_view(|cx| Terminal::new(cx, abs_path))), cx); } diff --git a/crates/terminal/src/terminal_element.rs b/crates/terminal/src/terminal_element.rs index ac964dca052d4a767441385a97072cd353a397d4..697a0abed95fb7774df8212c4b6ba0088bf15203 100644 --- a/crates/terminal/src/terminal_element.rs +++ b/crates/terminal/src/terminal_element.rs @@ -7,11 +7,15 @@ use alacritty_terminal::{ SizeInfo, }, }; +use editor::{Cursor, CursorShape}; use gpui::{ color::Color, elements::*, fonts::{HighlightStyle, TextStyle, Underline}, - geometry::{rect::RectF, vector::vec2f}, + geometry::{ + rect::RectF, + vector::{vec2f, Vector2F}, + }, json::json, text_layout::Line, Event, FontCache, MouseRegion, PaintContext, Quad, SizeConstraint, WeakViewHandle, @@ -74,7 +78,7 @@ pub struct LayoutState { lines: Vec, line_height: LineHeight, em_width: CellWidth, - cursor: Option<(RectF, Color)>, + cursor: Option<(Vector2F, Color)>, cur_size: SizeInfo, background_color: Color, background_rects: Vec<(RectF, Color)>, //Vec index == Line index for the LineSpan @@ -138,12 +142,11 @@ impl Element for TerminalEl { .collect(); let background_rects = make_background_rects(backgrounds, &shaped_lines, &line_height); - let cursor = make_cursor_rect( + let cursor = get_cursor_position( content.cursor.point, &shaped_lines, content.display_offset, &line_height, - &cell_width, ) .map(|cursor_rect| (cursor_rect, terminal_theme.cursor)); @@ -179,6 +182,16 @@ impl Element for TerminalEl { ..Default::default() }); + //TODO: Implement cursor region based styling + // cx.scene.push_cursor_region(CursorRegion { + // bounds, + // style: if !view.link_go_to_definition_state.definitions.is_empty() { + // CursorStyle::PointingHand + // } else { + // CursorStyle::IBeam + // }, + // }); + let origin = bounds.origin() + vec2f(layout.em_width.0, 0.); //Start us off with a nice simple background color @@ -212,13 +225,16 @@ impl Element for TerminalEl { //Draw cursor if let Some((c, color)) = layout.cursor { - let new_origin = origin + c.origin(); - cx.scene.push_quad(Quad { - bounds: RectF::new(new_origin, c.size()), - background: Some(color), - border: Default::default(), - corner_radius: 0., - }); + let editor_cursor = Cursor::new( + origin + c, + layout.em_width.0, + layout.line_height.0, + color, + CursorShape::Block, + None, //TODO fix this + ); + + editor_cursor.paint(cx); } #[cfg(debug_assertions)] @@ -374,20 +390,16 @@ fn make_background_rects( } ///Create the rectangle for a cursor, exactly positioned according to the text -fn make_cursor_rect( +fn get_cursor_position( cursor_point: Point, shaped_lines: &Vec, display_offset: usize, line_height: &LineHeight, - cell_width: &CellWidth, -) -> Option { +) -> Option { let cursor_line = cursor_point.line.0 as usize + display_offset; shaped_lines.get(cursor_line).map(|layout_line| { let cursor_x = layout_line.x_for_index(cursor_point.column.0); - RectF::new( - vec2f(cursor_x, cursor_line as f32 * line_height.0), - vec2f(cell_width.0, line_height.0), - ) + vec2f(cursor_x, cursor_line as f32 * line_height.0) }) } From ae836e14658b278e4c14481c446a3bbb590ac027 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 30 Jun 2022 20:34:06 -0700 Subject: [PATCH 2/7] Fixed a major bug and now use the same cursor paint logic as the editor --- crates/editor/src/element.rs | 22 ++++++++++-- crates/terminal/src/terminal_element.rs | 48 +++++++++++++++---------- 2 files changed, 50 insertions(+), 20 deletions(-) diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 19226c6472c3c0fd4dcd2a5964fe3dcbcfbd693a..348ce57ef37b957d9bef86bf114fe8956eb7cce2 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1630,7 +1630,7 @@ impl Default for CursorShape { } } -struct Cursor { +pub struct Cursor { origin: Vector2F, block_width: f32, line_height: f32, @@ -1640,7 +1640,25 @@ struct Cursor { } impl Cursor { - fn paint(&self, cx: &mut PaintContext) { + pub fn new( + origin: Vector2F, + block_width: f32, + line_height: f32, + color: Color, + shape: CursorShape, + block_text: Option, + ) -> Cursor { + Cursor { + origin, + block_width, + line_height, + color, + shape, + block_text, + } + } + + pub fn paint(&self, cx: &mut PaintContext) { let bounds = match self.shape { CursorShape::Bar => RectF::new(self.origin, vec2f(2.0, self.line_height)), CursorShape::Block => { diff --git a/crates/terminal/src/terminal_element.rs b/crates/terminal/src/terminal_element.rs index ac964dca052d4a767441385a97072cd353a397d4..697a0abed95fb7774df8212c4b6ba0088bf15203 100644 --- a/crates/terminal/src/terminal_element.rs +++ b/crates/terminal/src/terminal_element.rs @@ -7,11 +7,15 @@ use alacritty_terminal::{ SizeInfo, }, }; +use editor::{Cursor, CursorShape}; use gpui::{ color::Color, elements::*, fonts::{HighlightStyle, TextStyle, Underline}, - geometry::{rect::RectF, vector::vec2f}, + geometry::{ + rect::RectF, + vector::{vec2f, Vector2F}, + }, json::json, text_layout::Line, Event, FontCache, MouseRegion, PaintContext, Quad, SizeConstraint, WeakViewHandle, @@ -74,7 +78,7 @@ pub struct LayoutState { lines: Vec, line_height: LineHeight, em_width: CellWidth, - cursor: Option<(RectF, Color)>, + cursor: Option<(Vector2F, Color)>, cur_size: SizeInfo, background_color: Color, background_rects: Vec<(RectF, Color)>, //Vec index == Line index for the LineSpan @@ -138,12 +142,11 @@ impl Element for TerminalEl { .collect(); let background_rects = make_background_rects(backgrounds, &shaped_lines, &line_height); - let cursor = make_cursor_rect( + let cursor = get_cursor_position( content.cursor.point, &shaped_lines, content.display_offset, &line_height, - &cell_width, ) .map(|cursor_rect| (cursor_rect, terminal_theme.cursor)); @@ -179,6 +182,16 @@ impl Element for TerminalEl { ..Default::default() }); + //TODO: Implement cursor region based styling + // cx.scene.push_cursor_region(CursorRegion { + // bounds, + // style: if !view.link_go_to_definition_state.definitions.is_empty() { + // CursorStyle::PointingHand + // } else { + // CursorStyle::IBeam + // }, + // }); + let origin = bounds.origin() + vec2f(layout.em_width.0, 0.); //Start us off with a nice simple background color @@ -212,13 +225,16 @@ impl Element for TerminalEl { //Draw cursor if let Some((c, color)) = layout.cursor { - let new_origin = origin + c.origin(); - cx.scene.push_quad(Quad { - bounds: RectF::new(new_origin, c.size()), - background: Some(color), - border: Default::default(), - corner_radius: 0., - }); + let editor_cursor = Cursor::new( + origin + c, + layout.em_width.0, + layout.line_height.0, + color, + CursorShape::Block, + None, //TODO fix this + ); + + editor_cursor.paint(cx); } #[cfg(debug_assertions)] @@ -374,20 +390,16 @@ fn make_background_rects( } ///Create the rectangle for a cursor, exactly positioned according to the text -fn make_cursor_rect( +fn get_cursor_position( cursor_point: Point, shaped_lines: &Vec, display_offset: usize, line_height: &LineHeight, - cell_width: &CellWidth, -) -> Option { +) -> Option { let cursor_line = cursor_point.line.0 as usize + display_offset; shaped_lines.get(cursor_line).map(|layout_line| { let cursor_x = layout_line.x_for_index(cursor_point.column.0); - RectF::new( - vec2f(cursor_x, cursor_line as f32 * line_height.0), - vec2f(cell_width.0, line_height.0), - ) + vec2f(cursor_x, cursor_line as f32 * line_height.0) }) } From 8e4c54ab61cc763d19aa0cc71066da98bf27f22e Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 1 Jul 2022 11:38:12 -0700 Subject: [PATCH 3/7] Checkpointing after some debugging --- crates/terminal/src/terminal.rs | 1 + crates/terminal/src/terminal_element.rs | 29 +++++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 134cf5be6e5afb51aed482ca86712550c7e88d2b..2c0edb1d31fd0809b4a761d712017a8a6b679872 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -484,6 +484,7 @@ mod tests { let (chunks, _) = build_chunks( term.lock().renderable_content().display_iter, &Default::default(), + 0., ); let content = chunks.iter().map(|e| e.0.trim()).collect::(); content.contains("7") diff --git a/crates/terminal/src/terminal_element.rs b/crates/terminal/src/terminal_element.rs index 697a0abed95fb7774df8212c4b6ba0088bf15203..082296e751d76d6a1549d5976dcf1d4f89ec997e 100644 --- a/crates/terminal/src/terminal_element.rs +++ b/crates/terminal/src/terminal_element.rs @@ -1,6 +1,6 @@ use alacritty_terminal::{ ansi::Color as AnsiColor, - grid::{GridIterator, Indexed}, + grid::{Dimensions, GridIterator, Indexed}, index::Point, term::{ cell::{Cell, Flags}, @@ -121,8 +121,13 @@ impl Element for TerminalEl { let term = view_handle.read(cx).term.lock(); let content = term.renderable_content(); + //TODO: Remove + // dbg!("*******"); + // dbg!(cur_size.columns()); + //And we're off! Begin layouting - let (chunks, line_count) = build_chunks(content.display_iter, &terminal_theme); + let (chunks, line_count) = + build_chunks(content.display_iter, &terminal_theme, cell_width.0); let shaped_lines = layout_highlighted_chunks( chunks @@ -135,6 +140,11 @@ impl Element for TerminalEl { line_count, ); + //TODO: Remove + // for shaped_line in &shaped_lines { + // dbg!(shaped_line.width()); + // } + let backgrounds = chunks .iter() .filter(|(_, _, line_span)| line_span != &RectSpan::default()) @@ -290,6 +300,7 @@ impl Element for TerminalEl { } } +///Configures a text style from the current settings. fn make_text_style(font_cache: &FontCache, settings: &Settings) -> TextStyle { TextStyle { color: settings.theme.editor.text_color, @@ -304,6 +315,7 @@ fn make_text_style(font_cache: &FontCache, settings: &Settings) -> TextStyle { } } +///Configures a size info object from the given information. fn make_new_size( constraint: SizeConstraint, cell_width: &CellWidth, @@ -324,6 +336,7 @@ fn make_new_size( pub(crate) fn build_chunks( grid_iterator: GridIterator, theme: &TerminalStyle, + em_width: f32, ) -> (Vec<(String, Option, RectSpan)>, usize) { let mut line_count: usize = 0; //Every `group_by()` -> `into_iter()` pair needs to be seperated by a local variable so @@ -356,8 +369,16 @@ pub(crate) fn build_chunks( .chain(iter::once(("\n".to_string(), None, Default::default()))) .collect::, RectSpan)>>() }) - //We have a Vec> (Vec of lines of styled chunks), flatten to just Vec<> (the styled chunks) + //TODO: Remove + // .inspect(|line_chunks| { + // let mut line_len = 0; + // for chunk in line_chunks { + // line_len += chunk.0.len(); + // } + // dbg!((line_len, line_len as f32 * em_width)); + // }) .flatten() + //We have a Vec> (Vec of lines of styled chunks), flatten to just Vec<> (the styled chunks) .collect::, RectSpan)>>(); (result, line_count) } @@ -398,7 +419,7 @@ fn get_cursor_position( ) -> Option { let cursor_line = cursor_point.line.0 as usize + display_offset; shaped_lines.get(cursor_line).map(|layout_line| { - let cursor_x = layout_line.x_for_index(cursor_point.column.0); + let cursor_x = layout_line.x_for_index(cursor_point.column.0 + 3); vec2f(cursor_x, cursor_line as f32 * line_height.0) }) } From ce60a9a50a6b321a6bef97e859e56fa39bd2f4de Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 1 Jul 2022 11:39:43 -0700 Subject: [PATCH 4/7] Cleaned up debugging code --- crates/terminal/src/terminal.rs | 1 - crates/terminal/src/terminal_element.rs | 33 ++----------------------- 2 files changed, 2 insertions(+), 32 deletions(-) diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 2c0edb1d31fd0809b4a761d712017a8a6b679872..134cf5be6e5afb51aed482ca86712550c7e88d2b 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -484,7 +484,6 @@ mod tests { let (chunks, _) = build_chunks( term.lock().renderable_content().display_iter, &Default::default(), - 0., ); let content = chunks.iter().map(|e| e.0.trim()).collect::(); content.contains("7") diff --git a/crates/terminal/src/terminal_element.rs b/crates/terminal/src/terminal_element.rs index 082296e751d76d6a1549d5976dcf1d4f89ec997e..1df95c3b9660bc253056b9a660dbbf2223aabf0f 100644 --- a/crates/terminal/src/terminal_element.rs +++ b/crates/terminal/src/terminal_element.rs @@ -1,6 +1,6 @@ use alacritty_terminal::{ ansi::Color as AnsiColor, - grid::{Dimensions, GridIterator, Indexed}, + grid::{GridIterator, Indexed}, index::Point, term::{ cell::{Cell, Flags}, @@ -121,13 +121,8 @@ impl Element for TerminalEl { let term = view_handle.read(cx).term.lock(); let content = term.renderable_content(); - //TODO: Remove - // dbg!("*******"); - // dbg!(cur_size.columns()); - //And we're off! Begin layouting - let (chunks, line_count) = - build_chunks(content.display_iter, &terminal_theme, cell_width.0); + let (chunks, line_count) = build_chunks(content.display_iter, &terminal_theme); let shaped_lines = layout_highlighted_chunks( chunks @@ -140,11 +135,6 @@ impl Element for TerminalEl { line_count, ); - //TODO: Remove - // for shaped_line in &shaped_lines { - // dbg!(shaped_line.width()); - // } - let backgrounds = chunks .iter() .filter(|(_, _, line_span)| line_span != &RectSpan::default()) @@ -192,16 +182,6 @@ impl Element for TerminalEl { ..Default::default() }); - //TODO: Implement cursor region based styling - // cx.scene.push_cursor_region(CursorRegion { - // bounds, - // style: if !view.link_go_to_definition_state.definitions.is_empty() { - // CursorStyle::PointingHand - // } else { - // CursorStyle::IBeam - // }, - // }); - let origin = bounds.origin() + vec2f(layout.em_width.0, 0.); //Start us off with a nice simple background color @@ -336,7 +316,6 @@ fn make_new_size( pub(crate) fn build_chunks( grid_iterator: GridIterator, theme: &TerminalStyle, - em_width: f32, ) -> (Vec<(String, Option, RectSpan)>, usize) { let mut line_count: usize = 0; //Every `group_by()` -> `into_iter()` pair needs to be seperated by a local variable so @@ -369,14 +348,6 @@ pub(crate) fn build_chunks( .chain(iter::once(("\n".to_string(), None, Default::default()))) .collect::, RectSpan)>>() }) - //TODO: Remove - // .inspect(|line_chunks| { - // let mut line_len = 0; - // for chunk in line_chunks { - // line_len += chunk.0.len(); - // } - // dbg!((line_len, line_len as f32 * em_width)); - // }) .flatten() //We have a Vec> (Vec of lines of styled chunks), flatten to just Vec<> (the styled chunks) .collect::, RectSpan)>>(); From f4ac694ad8366243f26169c28738ec433bf80a92 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 1 Jul 2022 11:48:50 -0700 Subject: [PATCH 5/7] Fixed debug offset I added to terminal --- crates/terminal/src/terminal_element.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/terminal/src/terminal_element.rs b/crates/terminal/src/terminal_element.rs index 1df95c3b9660bc253056b9a660dbbf2223aabf0f..c3918c21a7c7bedd571c444c1c6c3443fb1fc4bb 100644 --- a/crates/terminal/src/terminal_element.rs +++ b/crates/terminal/src/terminal_element.rs @@ -119,6 +119,9 @@ impl Element for TerminalEl { //Now that we're done with the mutable portion, grab the immutable settings and view again let terminal_theme = &(cx.global::()).theme.terminal; let term = view_handle.read(cx).term.lock(); + + dbg!(term.grid()); + let content = term.renderable_content(); //And we're off! Begin layouting @@ -390,7 +393,7 @@ fn get_cursor_position( ) -> Option { let cursor_line = cursor_point.line.0 as usize + display_offset; shaped_lines.get(cursor_line).map(|layout_line| { - let cursor_x = layout_line.x_for_index(cursor_point.column.0 + 3); + let cursor_x = layout_line.x_for_index(cursor_point.column.0); vec2f(cursor_x, cursor_line as f32 * line_height.0) }) } From 62939322d377ac7df77fc675d2fe766cde2fe5cd Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 1 Jul 2022 13:03:26 -0700 Subject: [PATCH 6/7] rendering cursor correctly --- crates/editor/src/element.rs | 2 +- crates/gpui/src/text_layout.rs | 2 +- crates/terminal/src/terminal_element.rs | 40 ++++++++++++++++++++----- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 348ce57ef37b957d9bef86bf114fe8956eb7cce2..778f42f0941f9e699266cf2b1ce1f4ffe106c778 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -490,7 +490,7 @@ impl EditorElement { } let block_text = - if matches!(self.cursor_shape, CursorShape::Block) { + if let CursorShape::Block = self.cursor_shape { layout.snapshot.chars_at(cursor_position).next().and_then( |character| { let font_id = diff --git a/crates/gpui/src/text_layout.rs b/crates/gpui/src/text_layout.rs index 2d8672aab3dc9e283e7d3faee856bc22a31b54fc..50f16cb995e9f64ecfc75f1df2db2ca0974b70fc 100644 --- a/crates/gpui/src/text_layout.rs +++ b/crates/gpui/src/text_layout.rs @@ -164,7 +164,7 @@ impl<'a> Hash for CacheKeyRef<'a> { } } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct Line { layout: Arc, style_runs: SmallVec<[(u32, Color, Underline); 32]>, diff --git a/crates/terminal/src/terminal_element.rs b/crates/terminal/src/terminal_element.rs index c3918c21a7c7bedd571c444c1c6c3443fb1fc4bb..e389261a636d7ea76a06839b693a840d0cb34568 100644 --- a/crates/terminal/src/terminal_element.rs +++ b/crates/terminal/src/terminal_element.rs @@ -17,7 +17,7 @@ use gpui::{ vector::{vec2f, Vector2F}, }, json::json, - text_layout::Line, + text_layout::{Line, RunStyle}, Event, FontCache, MouseRegion, PaintContext, Quad, SizeConstraint, WeakViewHandle, }; use itertools::Itertools; @@ -78,7 +78,7 @@ pub struct LayoutState { lines: Vec, line_height: LineHeight, em_width: CellWidth, - cursor: Option<(Vector2F, Color)>, + cursor: Option<(Vector2F, Color, Option)>, cur_size: SizeInfo, background_color: Color, background_rects: Vec<(RectF, Color)>, //Vec index == Line index for the LineSpan @@ -120,7 +120,13 @@ impl Element for TerminalEl { let terminal_theme = &(cx.global::()).theme.terminal; let term = view_handle.read(cx).term.lock(); - dbg!(term.grid()); + // let cursor_char = term.grid().cursor_cell().c.to_string(); + + let cursor_text = { + let grid = term.grid(); + let cursor_point = grid.cursor.point; + grid[cursor_point.line][cursor_point.column].c.to_string() + }; let content = term.renderable_content(); @@ -145,13 +151,25 @@ impl Element for TerminalEl { .collect(); let background_rects = make_background_rects(backgrounds, &shaped_lines, &line_height); + let block_text = cx.text_layout_cache.layout_str( + &cursor_text, + text_style.font_size, + &[( + cursor_text.len(), + RunStyle { + font_id: text_style.font_id, + color: terminal_theme.background, + underline: Default::default(), + }, + )], + ); let cursor = get_cursor_position( content.cursor.point, &shaped_lines, content.display_offset, &line_height, ) - .map(|cursor_rect| (cursor_rect, terminal_theme.cursor)); + .map(|cursor_rect| (cursor_rect, terminal_theme.cursor, Some(block_text))); ( constraint.max, @@ -188,6 +206,7 @@ impl Element for TerminalEl { let origin = bounds.origin() + vec2f(layout.em_width.0, 0.); //Start us off with a nice simple background color + cx.scene.push_layer(Some(visible_bounds)); cx.scene.push_quad(Quad { bounds: RectF::new(bounds.origin(), bounds.size()), background: Some(layout.background_color), @@ -205,8 +224,10 @@ impl Element for TerminalEl { corner_radius: 0., }) } + cx.scene.pop_layer(); //Draw text + cx.scene.push_layer(Some(visible_bounds)); let mut line_origin = origin.clone(); for line in &layout.lines { let boundaries = RectF::new(line_origin, vec2f(bounds.width(), layout.line_height.0)); @@ -215,20 +236,23 @@ impl Element for TerminalEl { } line_origin.set_y(boundaries.max_y()); } + cx.scene.pop_layer(); //Draw cursor - if let Some((c, color)) = layout.cursor { + cx.scene.push_layer(Some(visible_bounds)); + if let Some((c, color, block_text)) = &layout.cursor { let editor_cursor = Cursor::new( - origin + c, + origin + *c, layout.em_width.0, layout.line_height.0, - color, + *color, CursorShape::Block, - None, //TODO fix this + block_text.clone(), //TODO fix this ); editor_cursor.paint(cx); } + cx.scene.pop_layer(); #[cfg(debug_assertions)] if DEBUG_GRID { From 6ac5cc0d2a14b2f532e68f547b2db55df864722b Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 1 Jul 2022 14:53:19 -0700 Subject: [PATCH 7/7] Fixed cursor positioning bugs in multi-byte charcters. Still have at least one though :/ --- crates/editor/src/element.rs | 20 ++--- crates/terminal/src/terminal.rs | 5 +- crates/terminal/src/terminal_element.rs | 107 ++++++++++++++++-------- 3 files changed, 86 insertions(+), 46 deletions(-) diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 778f42f0941f9e699266cf2b1ce1f4ffe106c778..faa821f20d5e2bbdb818bda0a81a63f1ef7c55f3 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -520,7 +520,7 @@ impl EditorElement { cursors.push(Cursor { color: selection_style.cursor, block_width, - origin: content_origin + vec2f(x, y), + origin: vec2f(x, y), line_height: layout.line_height, shape: self.cursor_shape, block_text, @@ -546,13 +546,12 @@ impl EditorElement { cx.scene.push_layer(Some(bounds)); for cursor in cursors { - cursor.paint(cx); + cursor.paint(content_origin, cx); } cx.scene.pop_layer(); if let Some((position, context_menu)) = layout.context_menu.as_mut() { cx.scene.push_stacking_context(None); - let cursor_row_layout = &layout.line_layouts[(position.row() - start_row) as usize]; let x = cursor_row_layout.x_for_index(position.column() as usize) - scroll_left; let y = (position.row() + 1) as f32 * layout.line_height - scroll_top; @@ -1658,14 +1657,15 @@ impl Cursor { } } - pub fn paint(&self, cx: &mut PaintContext) { + pub fn paint(&self, origin: Vector2F, cx: &mut PaintContext) { let bounds = match self.shape { - CursorShape::Bar => RectF::new(self.origin, vec2f(2.0, self.line_height)), - CursorShape::Block => { - RectF::new(self.origin, vec2f(self.block_width, self.line_height)) - } + CursorShape::Bar => RectF::new(self.origin + origin, vec2f(2.0, self.line_height)), + CursorShape::Block => RectF::new( + self.origin + origin, + vec2f(self.block_width, self.line_height), + ), CursorShape::Underscore => RectF::new( - self.origin + Vector2F::new(0.0, self.line_height - 2.0), + self.origin + origin + Vector2F::new(0.0, self.line_height - 2.0), vec2f(self.block_width, 2.0), ), }; @@ -1678,7 +1678,7 @@ impl Cursor { }); if let Some(block_text) = &self.block_text { - block_text.paint(self.origin, bounds, self.line_height, cx); + block_text.paint(self.origin + origin, bounds, self.line_height, cx); } } } diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 134cf5be6e5afb51aed482ca86712550c7e88d2b..6ea4ca5f73750764fb423a5aadfeca9c2908f4a5 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -464,7 +464,7 @@ fn to_alac_rgb(color: Color) -> AlacRgb { #[cfg(test)] mod tests { use super::*; - use crate::terminal_element::build_chunks; + use crate::terminal_element::{build_chunks, BuiltChunks}; use gpui::TestAppContext; ///Basic integration test, can we get the terminal to show up, execute a command, @@ -481,9 +481,10 @@ mod tests { terminal .condition(cx, |terminal, _cx| { let term = terminal.term.clone(); - let (chunks, _) = build_chunks( + let BuiltChunks { chunks, .. } = build_chunks( term.lock().renderable_content().display_iter, &Default::default(), + Default::default(), ); let content = chunks.iter().map(|e| e.0.trim()).collect::(); content.contains("7") diff --git a/crates/terminal/src/terminal_element.rs b/crates/terminal/src/terminal_element.rs index e389261a636d7ea76a06839b693a840d0cb34568..42d4386fa6d6c5d64ef8459f51d6551237b7bd94 100644 --- a/crates/terminal/src/terminal_element.rs +++ b/crates/terminal/src/terminal_element.rs @@ -78,7 +78,7 @@ pub struct LayoutState { lines: Vec, line_height: LineHeight, em_width: CellWidth, - cursor: Option<(Vector2F, Color, Option)>, + cursor: Option, cur_size: SizeInfo, background_color: Color, background_rects: Vec<(RectF, Color)>, //Vec index == Line index for the LineSpan @@ -120,18 +120,18 @@ impl Element for TerminalEl { let terminal_theme = &(cx.global::()).theme.terminal; let term = view_handle.read(cx).term.lock(); - // let cursor_char = term.grid().cursor_cell().c.to_string(); - - let cursor_text = { - let grid = term.grid(); - let cursor_point = grid.cursor.point; - grid[cursor_point.line][cursor_point.column].c.to_string() - }; + let grid = term.grid(); + let cursor_point = grid.cursor.point; + let cursor_text = grid[cursor_point.line][cursor_point.column].c.to_string(); let content = term.renderable_content(); //And we're off! Begin layouting - let (chunks, line_count) = build_chunks(content.display_iter, &terminal_theme); + let BuiltChunks { + chunks, + line_count, + cursor_index, + } = build_chunks(content.display_iter, &terminal_theme, cursor_point); let shaped_lines = layout_highlighted_chunks( chunks @@ -163,13 +163,30 @@ impl Element for TerminalEl { }, )], ); + let cursor = get_cursor_position( - content.cursor.point, + content.cursor.point.line.0 as usize, + cursor_index, &shaped_lines, content.display_offset, &line_height, ) - .map(|cursor_rect| (cursor_rect, terminal_theme.cursor, Some(block_text))); + .map(move |(cursor_position, block_width)| { + let block_width = if block_width != 0.0 { + block_width + } else { + cell_width.0 + }; + + Cursor::new( + cursor_position, + block_width, + line_height.0, + terminal_theme.cursor, + CursorShape::Block, + Some(block_text.clone()), + ) + }); ( constraint.max, @@ -239,20 +256,11 @@ impl Element for TerminalEl { cx.scene.pop_layer(); //Draw cursor - cx.scene.push_layer(Some(visible_bounds)); - if let Some((c, color, block_text)) = &layout.cursor { - let editor_cursor = Cursor::new( - origin + *c, - layout.em_width.0, - layout.line_height.0, - *color, - CursorShape::Block, - block_text.clone(), //TODO fix this - ); - - editor_cursor.paint(cx); + if let Some(cursor) = &layout.cursor { + cx.scene.push_layer(Some(visible_bounds)); + cursor.paint(origin, cx); + cx.scene.pop_layer(); } - cx.scene.pop_layer(); #[cfg(debug_assertions)] if DEBUG_GRID { @@ -339,21 +347,30 @@ fn make_new_size( ) } +pub struct BuiltChunks { + pub chunks: Vec<(String, Option, RectSpan)>, + pub line_count: usize, + pub cursor_index: usize, +} + ///In a single pass, this function generates the background and foreground color info for every item in the grid. pub(crate) fn build_chunks( grid_iterator: GridIterator, theme: &TerminalStyle, -) -> (Vec<(String, Option, RectSpan)>, usize) { + cursor_point: Point, +) -> BuiltChunks { let mut line_count: usize = 0; + let mut cursor_index: usize = 0; //Every `group_by()` -> `into_iter()` pair needs to be seperated by a local variable so //rust knows where to put everything. //Start by grouping by lines let lines = grid_iterator.group_by(|i| i.point.line.0); let result = lines .into_iter() - .map(|(_, line)| { + .map(|(_line_grid_index, line)| { line_count += 1; let mut col_index = 0; + //Setup a variable //Then group by style let chunks = line.group_by(|i| cell_style(&i, theme)); @@ -361,9 +378,20 @@ pub(crate) fn build_chunks( .into_iter() .map(|(style, fragment)| { //And assemble the styled fragment into it's background and foreground information - let str_fragment = fragment.map(|indexed| indexed.c).collect::(); + let mut str_fragment = String::new(); + for indexed_cell in fragment { + if cursor_point.line.0 == indexed_cell.point.line.0 + && indexed_cell.point.column < cursor_point.column.0 + { + cursor_index += indexed_cell.c.to_string().len(); + } + str_fragment.push(indexed_cell.c); + } + let start = col_index; let end = start + str_fragment.len() as i32; + + //munge it here col_index = end; ( str_fragment, @@ -378,7 +406,12 @@ pub(crate) fn build_chunks( .flatten() //We have a Vec> (Vec of lines of styled chunks), flatten to just Vec<> (the styled chunks) .collect::, RectSpan)>>(); - (result, line_count) + + BuiltChunks { + chunks: result, + line_count, + cursor_index, + } } ///Convert a RectSpan in terms of character offsets, into RectFs of exact offsets @@ -408,17 +441,23 @@ fn make_background_rects( .collect::>() } -///Create the rectangle for a cursor, exactly positioned according to the text +// Compute the cursor position and expected block width, may return a zero width if x_for_index returns +// the same position for sequential indexes. Use em_width instead fn get_cursor_position( - cursor_point: Point, + line: usize, + line_index: usize, shaped_lines: &Vec, display_offset: usize, line_height: &LineHeight, -) -> Option { - let cursor_line = cursor_point.line.0 as usize + display_offset; +) -> Option<(Vector2F, f32)> { + let cursor_line = line + display_offset; shaped_lines.get(cursor_line).map(|layout_line| { - let cursor_x = layout_line.x_for_index(cursor_point.column.0); - vec2f(cursor_x, cursor_line as f32 * line_height.0) + let cursor_x = layout_line.x_for_index(line_index); + let next_char_x = layout_line.x_for_index(line_index + 1); + ( + vec2f(cursor_x, cursor_line as f32 * line_height.0), + next_char_x - cursor_x, + ) }) }