From e8cb1ef8639fb5ef16cd28c5fd404a50993e4392 Mon Sep 17 00:00:00 2001 From: Jon Valdes Date: Mon, 3 Feb 2020 13:24:02 +0100 Subject: [PATCH] WIP Extraction of Editor::grid into its own file and struct --- src/editor/grid.rs | 75 +++++++++++++++++++++++++ src/editor/mod.rs | 98 ++++++++------------------------- src/renderer/cursor_renderer.rs | 8 +-- 3 files changed, 103 insertions(+), 78 deletions(-) create mode 100644 src/editor/grid.rs diff --git a/src/editor/grid.rs b/src/editor/grid.rs new file mode 100644 index 0000000..241c897 --- /dev/null +++ b/src/editor/grid.rs @@ -0,0 +1,75 @@ +use std::sync::Arc; + +use super::style::Style; + +type GridCell = Option<(String, Option>)>; + +pub struct CharacterGrid { + pub characters: Vec, + pub width: u64, + pub height: u64, + pub should_clear: bool, + + dirty: Vec, +} + +impl CharacterGrid { + pub fn new() -> CharacterGrid { + CharacterGrid { + characters: vec![], + dirty: vec![], + width: 0, + height: 0, + should_clear: true, + } + } + + pub fn resize(&mut self, new_size: (u64, u64)) { + trace!("Editor resized"); + self.width = new_size.0; + self.height = new_size.1; + self.clear(); + } + + pub fn clear(&mut self) { + trace!("Editor cleared"); + let cell_count = (self.width * self.height) as usize; + self.characters = vec![None; cell_count]; + self.dirty = vec![true; cell_count]; + self.should_clear = true; + } + + pub fn cell_index(&self, x: u64, y: u64) -> Option { + if x >= self.width || y >= self.height { + None + } else { + Some((x + y * self.width) as usize) + } + } + + pub fn is_dirty_cell(&self, x: u64, y: u64) -> bool { + if let Some(idx) = self.cell_index(x, y) { + self.dirty[idx] + } else { + false + } + } + + pub fn set_dirty_cell(&mut self, x: u64, y: u64) { + if let Some(idx) = self.cell_index(x, y) { + self.dirty[idx] = true; + } + } + + pub fn set_dirty_all(&mut self, value: bool) { + self.dirty.resize(self.dirty.len(), value); + } + + pub fn rows<'a>(&'a self) -> Vec<&'a [GridCell]> { + (0..self.height) + .map(|row| { + &self.characters[(row * self.width) as usize..((row + 1) * self.width) as usize] + }) + .collect() + } +} diff --git a/src/editor/mod.rs b/src/editor/mod.rs index 2ac4aa0..492d358 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -1,5 +1,6 @@ mod cursor; mod style; +mod grid; use std::collections::HashMap; use std::sync::{Arc, Mutex}; @@ -10,6 +11,7 @@ use log::trace; pub use cursor::{Cursor, CursorShape, CursorMode}; pub use style::{Colors, Style}; +pub use grid::CharacterGrid; use crate::bridge::{GridLineCell, GuiOption, RedrawEvent}; use crate::redraw_scheduler::REDRAW_SCHEDULER; use crate::INITIAL_DIMENSIONS; @@ -18,8 +20,6 @@ lazy_static! { pub static ref EDITOR: Arc> = Arc::new(Mutex::new(Editor::new())); } -pub type GridCell = Option<(String, Option>)>; - #[derive(new, Debug, Clone)] pub struct DrawCommand { pub text: String, @@ -31,10 +31,7 @@ pub struct DrawCommand { } pub struct Editor { - pub grid: Vec, - pub dirty: Vec, - pub should_clear: bool, - + pub grid: CharacterGrid, pub title: String, pub size: (u64, u64), pub font_name: Option, @@ -48,9 +45,7 @@ pub struct Editor { impl Editor { pub fn new() -> Editor { let mut editor = Editor { - grid: Vec::new(), - dirty: Vec::new(), - should_clear: true, + grid: CharacterGrid::new(), title: "Neovide".to_string(), size: INITIAL_DIMENSIONS, @@ -62,39 +57,10 @@ impl Editor { previous_style: None }; - editor.clear(); + editor.grid.clear(); editor } - pub fn cell_index(&self, x: u64, y: u64) -> Option { - let (width, height) = self.size; - if x >= width || y >= height { - None - }else{ - Some((x + y * width) as usize) - } - } - - pub fn is_dirty_cell(&self, x: u64, y: u64) -> bool{ - if let Some(idx) = self.cell_index(x, y) { - self.dirty[idx] - }else{ - false - } - } - - pub fn set_dirty_cell(&mut self, x: u64, y: u64) { - if let Some(idx) = self.cell_index(x, y) { - self.dirty[idx] = true; - } - } - - fn rows<'a> (&'a self) -> Vec<&'a [GridCell]> { - let (width, height) = self.size; - (0..height).map(|row| { - &self.grid[(row * width) as usize .. ((row+1) * width) as usize] - }).collect() - } pub fn handle_redraw_event(&mut self, event: RedrawEvent) { match event { @@ -114,11 +80,11 @@ impl Editor { trace!("Image flushed"); REDRAW_SCHEDULER.queue_next_frame(); }, - RedrawEvent::Resize { width, height, .. } => self.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), - RedrawEvent::Clear { .. } => self.clear(), + RedrawEvent::Clear { .. } => self.grid.clear(), RedrawEvent::CursorGoto { row, column, .. } => self.cursor.position = (row, column), RedrawEvent::Scroll { top, bottom, left, right, rows, columns, .. } => self.scroll_region(top, bottom, left, right, rows, columns), _ => {} @@ -127,7 +93,7 @@ impl Editor { pub fn build_draw_commands(&mut self) -> (Vec, bool) { let mut draw_commands = Vec::new(); - for (row_index, row) in self.rows().iter().enumerate() { + for (row_index, row) in self.grid.rows().iter().enumerate() { let mut command = None; fn add_command(commands_list: &mut Vec, command: Option) { @@ -178,25 +144,23 @@ impl Editor { } add_command(&mut draw_commands, command); } - let should_clear = self.should_clear; + let should_clear = self.grid.should_clear; - let (width, height) = self.size; - let draw_commands = draw_commands.into_iter().filter(|command| { let (x, y) = command.grid_position; let min = (x as i64 - 1).max(0) as u64; - let max = (x + command.cell_width + 1).min(width); + let max = (x + command.cell_width + 1).min(self.grid.width); for char_index in min..max { - if self.is_dirty_cell(char_index, y) { + if self.grid.is_dirty_cell(char_index, y) { return true; } } return false; }).collect::>(); - self.dirty = vec![false; (width * height) as usize]; - self.should_clear = false; + self.grid.set_dirty_all(false); + self.grid.should_clear = false; trace!("Draw commands sent"); (draw_commands, should_clear) @@ -215,15 +179,15 @@ impl Editor { } if text.is_empty() { - let cell_index = self.cell_index(*column_pos, row_index).expect("Should not paint outside of grid"); - self.grid[cell_index] = Some(("".to_string(), style.clone())); - self.set_dirty_cell(*column_pos, row_index); + 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 + 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.cell_index(i as u64 + *column_pos, row_index) { - self.grid[cell_index] = Some((character.to_string(), style.clone())); - self.set_dirty_cell(*column_pos, row_index); + 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 + self.grid.set_dirty_cell(*column_pos, row_index); } } *column_pos = *column_pos + text.graphemes(true).count() as u64; @@ -232,7 +196,7 @@ impl Editor { } fn draw_grid_line(&mut self, row: u64, column_start: u64, cells: Vec) { - if row < self.grid.len() as u64 { + if row < self.grid.height { let mut column_pos = column_start; for cell in cells { self.draw_grid_line_cell(row, &mut column_pos, cell); @@ -264,12 +228,12 @@ impl Editor { for x in x_iter { let dest_x = x - cols; - let source_idx = self.cell_index(x as u64, y as u64); - let dest_idx = self.cell_index(dest_x as u64, dest_y as u64); + 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); if let (Some(source_idx), Some(dest_idx)) = (source_idx, dest_idx) { - self.grid[dest_idx] = self.grid[source_idx].clone(); - self.set_dirty_cell(dest_x as u64, dest_y as u64); + 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); } } } @@ -277,20 +241,6 @@ impl Editor { trace!("Region scrolled"); } - fn resize(&mut self, new_size: (u64, u64)) { - trace!("Editor resized"); - self.size = new_size; - self.clear(); - } - - fn clear(&mut self) { - trace!("Editor cleared"); - let (width, height) = self.size; - self.grid = vec![None; (width * height) as usize]; - self.dirty = vec![true; (width * height) as usize]; - self.should_clear = true; - } - fn set_option(&mut self, gui_option: GuiOption) { trace!("Option set {:?}", &gui_option); match gui_option { diff --git a/src/renderer/cursor_renderer.rs b/src/renderer/cursor_renderer.rs index d6a2dd3..8952e72 100644 --- a/src/renderer/cursor_renderer.rs +++ b/src/renderer/cursor_renderer.rs @@ -201,13 +201,13 @@ impl CursorRenderer { let (character, font_dimensions): (String, Point) = { let editor = EDITOR.lock().unwrap(); - let character = editor.cell_index(grid_x, grid_y) - .and_then(|idx| editor.grid[idx].as_ref()) + 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 is_double = editor.cell_index(grid_x + 1, grid_y) - .and_then(|idx| editor.grid[idx].as_ref()) + 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);