From 9450ea62d8f35279a77120d38e64018666b85ffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Vald=C3=A9s?= Date: Mon, 3 Feb 2020 18:05:36 +0100 Subject: [PATCH] Better external API for EditorGrid, returning Option<&mut GridCell> for external code to modify the cells --- src/editor/grid.rs | 30 +++++++++++++++++++++--------- src/editor/mod.rs | 23 +++++++++++++---------- src/renderer/cursor_renderer.rs | 16 ++++++++-------- 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/src/editor/grid.rs b/src/editor/grid.rs index b474676..5ae67c8 100644 --- a/src/editor/grid.rs +++ b/src/editor/grid.rs @@ -3,15 +3,15 @@ use log::trace; use super::style::Style; -type GridCell = Option<(String, Option>)>; +pub type GridCell = Option<(String, Option>)>; pub struct CharacterGrid { - pub characters: Vec, pub width: u64, pub height: u64, pub should_clear: bool, dirty: Vec, + characters: Vec, } impl CharacterGrid { @@ -25,22 +25,25 @@ impl CharacterGrid { } } - pub fn resize(&mut self, new_size: (u64, u64)) { + pub fn resize(&mut self, width: u64, height: u64) { trace!("Editor resized"); - self.width = new_size.0; - self.height = new_size.1; + self.width = width; + self.height = height; self.clear(); } pub fn clear(&mut self) { trace!("Editor cleared"); + self.characters.clear(); + self.dirty.clear(); + let cell_count = (self.width * self.height) as usize; - self.characters = vec![None; cell_count]; - self.dirty = vec![true; cell_count]; + self.characters.resize_with(cell_count, || None); + self.dirty.resize_with(cell_count, || true); self.should_clear = true; } - pub fn cell_index(&self, x: u64, y: u64) -> Option { + fn cell_index(&self, x: u64, y: u64) -> Option { if x >= self.width || y >= self.height { None } else { @@ -48,6 +51,14 @@ impl CharacterGrid { } } + pub fn get_cell<'a>(&'a self, x: u64, y: u64) -> Option<&'a GridCell> { + self.cell_index(x,y).map(|idx| &self.characters[idx]) + } + + pub fn get_cell_mut<'a>(&'a mut self, x: u64, y: u64) -> Option<&'a mut GridCell> { + self.cell_index(x,y).map(move |idx| &mut self.characters[idx]) + } + pub fn is_dirty_cell(&self, x: u64, y: u64) -> bool { if let Some(idx) = self.cell_index(x, y) { self.dirty[idx] @@ -63,7 +74,8 @@ impl CharacterGrid { } pub fn set_dirty_all(&mut self, value: bool) { - self.dirty.resize(self.dirty.len(), value); + self.dirty.clear(); + self.dirty.resize_with((self.width * self.height) as usize, || value); } pub fn rows<'a>(&'a self) -> Vec<&'a [GridCell]> { diff --git a/src/editor/mod.rs b/src/editor/mod.rs index 492d358..a53d54c 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -80,7 +80,7 @@ impl Editor { trace!("Image flushed"); REDRAW_SCHEDULER.queue_next_frame(); }, - RedrawEvent::Resize { width, height, .. } => self.grid.resize((width, height)), + RedrawEvent::Resize { width, height, .. } => self.grid.resize(width, height), RedrawEvent::DefaultColorsSet { colors } => self.default_style = Arc::new(Style::new(colors)), RedrawEvent::HighlightAttributesDefine { id, style } => { self.defined_styles.insert(id, Arc::new(style)); }, RedrawEvent::GridLine { row, column_start, cells, .. } => self.draw_grid_line(row, column_start, cells), @@ -179,14 +179,16 @@ impl Editor { } if text.is_empty() { - let cell_index = self.grid.cell_index(*column_pos, row_index).expect("Should not paint outside of grid"); - self.grid.characters[cell_index] = Some(("".to_string(), style.clone())); // TODO -- Encapsulate 'characters' better + if let Some(cell) = self.grid.get_cell_mut(*column_pos, row_index) { + *cell = Some(("".to_string(), style.clone())); + } + self.grid.set_dirty_cell(*column_pos, row_index); *column_pos = *column_pos + 1; } else { for (i, character) in text.graphemes(true).enumerate() { - if let Some(cell_index) = self.grid.cell_index(i as u64 + *column_pos, row_index) { - self.grid.characters[cell_index] = Some((character.to_string(), style.clone())); // TODO -- Encapsulate 'characters' better + if let Some(cell) = self.grid.get_cell_mut(i as u64 + *column_pos, row_index) { + *cell = Some((character.to_string(), style.clone())); self.grid.set_dirty_cell(*column_pos, row_index); } } @@ -228,12 +230,13 @@ impl Editor { for x in x_iter { let dest_x = x - cols; - let source_idx = self.grid.cell_index(x as u64, y as u64); - let dest_idx = self.grid.cell_index(dest_x as u64, dest_y as u64); + let cell_data = self.grid.get_cell(x as u64, y as u64).cloned(); - if let (Some(source_idx), Some(dest_idx)) = (source_idx, dest_idx) { - self.grid.characters[dest_idx] = self.grid.characters[source_idx].clone(); // TODO -- Encapsulate 'characters' better - self.grid.set_dirty_cell(dest_x as u64, dest_y as u64); + if let Some(cell_data) = cell_data.clone() { + if let Some(dest_cell) = self.grid.get_cell_mut(dest_x as u64, dest_y as u64) { + *dest_cell = cell_data.clone(); + self.grid.set_dirty_cell(dest_x as u64, dest_y as u64); + } } } } diff --git a/src/renderer/cursor_renderer.rs b/src/renderer/cursor_renderer.rs index 8952e72..3649075 100644 --- a/src/renderer/cursor_renderer.rs +++ b/src/renderer/cursor_renderer.rs @@ -201,15 +201,15 @@ impl CursorRenderer { let (character, font_dimensions): (String, Point) = { let editor = EDITOR.lock().unwrap(); - let character = editor.grid.cell_index(grid_x, grid_y) - .and_then(|idx| editor.grid.characters[idx].as_ref()) - .map(|(character, _)| character.clone()) - .unwrap_or_else(|| ' '.to_string()); + let character = match editor.grid.get_cell(grid_x, grid_y) { + Some(Some((character, _))) => character.clone(), + _ => ' '.to_string(), + }; - let is_double = editor.grid.cell_index(grid_x + 1, grid_y) - .and_then(|idx| editor.grid.characters[idx].as_ref()) - .map(|(character, _)| character.is_empty()) - .unwrap_or(false); + let is_double = match editor.grid.get_cell(grid_x + 1, grid_y) { + Some(Some((character, _))) => character.is_empty(), + _ => false, + }; let font_width = match (is_double, &cursor.shape) { (true, CursorShape::Block) => font_width * 2.0,