diff options
author | Joe Wilm <joe@jwilm.com> | 2018-03-05 09:57:34 -0800 |
---|---|---|
committer | Joe Wilm <joe@jwilm.com> | 2018-03-07 09:51:06 -0800 |
commit | 2cfdd595f11377fbd91536a428e87d949ed9a05e (patch) | |
tree | 95ea005517dd55f7b16d474df765d15e234798ad | |
parent | 69f533d19e282c8b2c808be081a562119052d081 (diff) | |
download | alacritty-2cfdd595f11377fbd91536a428e87d949ed9a05e.tar.gz alacritty-2cfdd595f11377fbd91536a428e87d949ed9a05e.zip |
Move selection into Grid
Supporting selections with scrollback has two major components:
1. Grid needs access to Selection so that it may update the scroll
position as the terminal text changes.
2. Selection needs to be implemented in terms of buffer offsets -- NOT
lines -- and be updated when Storage is rotated.
This commit implements the first part.
-rw-r--r-- | src/display.rs | 5 | ||||
-rw-r--r-- | src/event.rs | 67 | ||||
-rw-r--r-- | src/grid/mod.rs | 22 | ||||
-rw-r--r-- | src/grid/row.rs | 2 | ||||
-rw-r--r-- | src/main.rs | 2 | ||||
-rw-r--r-- | src/selection.rs | 2 | ||||
-rw-r--r-- | src/term/mod.rs | 21 |
7 files changed, 68 insertions, 53 deletions
diff --git a/src/display.rs b/src/display.rs index 418f616e..e5ae8fb4 100644 --- a/src/display.rs +++ b/src/display.rs @@ -24,7 +24,6 @@ use config::Config; use font::{self, Rasterize}; use meter::Meter; use renderer::{self, GlyphCache, QuadRenderer}; -use selection::Selection; use term::{Term, SizeInfo}; use window::{self, Size, Pixels, Window, SetInnerSize}; @@ -318,7 +317,7 @@ impl Display { /// A reference to Term whose state is being drawn must be provided. /// /// This call may block if vsync is enabled - pub fn draw(&mut self, mut terminal: MutexGuard<Term>, config: &Config, selection: Option<&Selection>) { + pub fn draw(&mut self, mut terminal: MutexGuard<Term>, config: &Config) { // Clear dirty flag terminal.dirty = !terminal.visual_bell.completed(); @@ -366,7 +365,7 @@ impl Display { // Draw the grid api.render_cells( - terminal.renderable_cells(config, selection, window_focused), + terminal.renderable_cells(config, window_focused), glyph_cache, ); }); diff --git a/src/event.rs b/src/event.rs index 0c8a26f4..aa193e63 100644 --- a/src/event.rs +++ b/src/event.rs @@ -33,10 +33,8 @@ pub trait Notify { pub struct ActionContext<'a, N: 'a> { pub notifier: &'a mut N, pub terminal: &'a mut Term, - pub selection: &'a mut Option<Selection>, pub size_info: &'a SizeInfo, pub mouse: &'a mut Mouse, - pub selection_modified: bool, pub received_count: &'a mut usize, pub suppress_chars: &'a mut bool, pub last_modifiers: &'a mut ModifiersState, @@ -64,31 +62,35 @@ impl<'a, N: Notify + 'a> input::ActionContext for ActionContext<'a, N> { } fn copy_selection(&self, buffer: ::copypasta::Buffer) { - if let Some(ref selection) = *self.selection { - selection.to_span(self.terminal) - .map(|span| { - let buf = self.terminal.string_from_selection(&span); - if !buf.is_empty() { - Clipboard::new() - .and_then(|mut clipboard| clipboard.store(buf, buffer)) - .unwrap_or_else(|err| { - warn!("Error storing selection to clipboard. {}", Red(err)); - }); - } - }); - } + self.terminal + .selection_to_string() + .map(|selected| { + if !selected.is_empty() { + Clipboard::new() + .and_then(|mut clipboard| clipboard.store(selected, buffer)) + .unwrap_or_else(|err| { + warn!("Error storing selection to clipboard. {}", Red(err)); + }); + } + }); } fn clear_selection(&mut self) { - *self.selection = None; - self.selection_modified = true; + *self.terminal.selection_mut() = None; + self.terminal.dirty = true; } fn update_selection(&mut self, point: Point, side: Side) { - self.selection_modified = true; + // Update selection if one exists - if let Some(ref mut selection) = *self.selection { + let mut had_selection = false; // borrowck + if let Some(ref mut selection) = *self.terminal.selection_mut() { selection.update(point, side); + had_selection = true; + } + + if had_selection { // borrowck + self.terminal.dirty = true; return; } @@ -97,18 +99,18 @@ impl<'a, N: Notify + 'a> input::ActionContext for ActionContext<'a, N> { } fn simple_selection(&mut self, point: Point, side: Side) { - *self.selection = Some(Selection::simple(point, side)); - self.selection_modified = true; + *self.terminal.selection_mut() = Some(Selection::simple(point, side)); + self.terminal.dirty = true; } fn semantic_selection(&mut self, point: Point) { - *self.selection = Some(Selection::semantic(point, self.terminal)); - self.selection_modified = true; + *self.terminal.selection_mut() = Some(Selection::semantic(point, &*self.terminal)); + self.terminal.dirty = true; } fn line_selection(&mut self, point: Point) { - *self.selection = Some(Selection::lines(point)); - self.selection_modified = true; + *self.terminal.selection_mut() = Some(Selection::lines(point)); + self.terminal.dirty = true; } fn mouse_coords(&self) -> Option<Point> { @@ -197,7 +199,6 @@ pub struct Processor<N> { resize_tx: mpsc::Sender<(u32, u32)>, ref_test: bool, size_info: SizeInfo, - pub selection: Option<Selection>, hide_cursor_when_typing: bool, hide_cursor: bool, received_count: usize, @@ -212,7 +213,6 @@ pub struct Processor<N> { impl<N> OnResize for Processor<N> { fn on_resize(&mut self, size: &SizeInfo) { self.size_info = size.to_owned(); - self.selection = None; } } @@ -239,8 +239,7 @@ impl<N: Notify> Processor<N> { resize_tx, ref_test, mouse: Default::default(), - selection: None, - size_info, + size_info: size_info, hide_cursor_when_typing: config.hide_cursor_when_typing(), hide_cursor: false, received_count: 0, @@ -318,10 +317,6 @@ impl<N: Notify> Processor<N> { *hide_cursor = false; processor.mouse_moved(x as u32, y as u32, modifiers); - - if !processor.ctx.selection.is_none() { - processor.ctx.terminal.dirty = true; - } }, MouseWheel { delta, phase, .. } => { *hide_cursor = false; @@ -392,10 +387,8 @@ impl<N: Notify> Processor<N> { context = ActionContext { terminal: &mut terminal, notifier: &mut self.notifier, - selection: &mut self.selection, mouse: &mut self.mouse, size_info: &self.size_info, - selection_modified: false, received_count: &mut self.received_count, suppress_chars: &mut self.suppress_chars, last_modifiers: &mut self.last_modifiers, @@ -440,10 +433,6 @@ impl<N: Notify> Processor<N> { } window.is_focused = window_is_focused; - - if processor.ctx.selection_modified { - processor.ctx.terminal.dirty = true; - } } self.wait_for_event = !terminal.dirty; diff --git a/src/grid/mod.rs b/src/grid/mod.rs index ca43471d..cf66a420 100644 --- a/src/grid/mod.rs +++ b/src/grid/mod.rs @@ -18,6 +18,7 @@ use std::cmp::{min, max, Ordering}; use std::ops::{Deref, Range, Index, IndexMut, RangeTo, RangeFrom, RangeFull}; use index::{self, Point, Line, Column, IndexRange, RangeInclusive}; +use selection::Selection; mod row; pub use self::row::Row; @@ -54,8 +55,16 @@ impl<T> Deref for Indexed<T> { } } +impl<T: PartialEq> ::std::cmp::PartialEq for Grid<T> { + fn eq(&self, other: &Self) -> bool { + self.cols.eq(&other.cols) && + self.lines.eq(&other.lines) && + self.raw.eq(&other.raw) + } +} + /// Represents the terminal display contents -#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct Grid<T> { /// Lines in the grid. Each row holds a list of cells corresponding to the /// columns in that row. @@ -73,14 +82,13 @@ pub struct Grid<T> { /// /// This is used to quickly populate new lines and clear recycled lines /// during scroll wrapping. + #[serde(skip)] template_row: Row<T>, /// Template cell for populating template_row + #[serde(skip)] template: T, - /// Temporary row storage for scrolling with a region - temp: Vec<Row<T>>, - /// Offset of displayed area /// /// If the displayed region isn't at the bottom of the screen, it stays @@ -90,6 +98,10 @@ pub struct Grid<T> { /// An limit on how far back it's possible to scroll scroll_limit: usize, + + /// Selected region + #[serde(skip)] + pub selection: Option<Selection>, } pub struct GridIterator<'a, T: 'a> { @@ -117,9 +129,9 @@ impl<T: Copy + Clone> Grid<T> { lines, template_row, template, - temp: Vec::new(), display_offset: 0, scroll_limit: 0, + selection: None, } } diff --git a/src/grid/row.rs b/src/grid/row.rs index 6b6af7c8..f6b2a20e 100644 --- a/src/grid/row.rs +++ b/src/grid/row.rs @@ -21,7 +21,7 @@ use std::slice; use index::Column; /// A row in the grid -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] +#[derive(Default, Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] pub struct Row<T>(Vec<T>); impl<T: Copy + Clone> Row<T> { diff --git a/src/main.rs b/src/main.rs index 4b24b1a5..b31f0764 100644 --- a/src/main.rs +++ b/src/main.rs @@ -200,7 +200,7 @@ fn run(mut config: Config, options: &cli::Options) -> Result<(), Box<Error>> { display.handle_resize(&mut terminal, &config, &mut [&mut pty, &mut processor]); // Draw the current state of the terminal - display.draw(terminal, &config, processor.selection.as_ref()); + display.draw(terminal, &config); } // Begin shutdown if the flag was raised. diff --git a/src/selection.rs b/src/selection.rs index 64cee8c2..b5bf5493 100644 --- a/src/selection.rs +++ b/src/selection.rs @@ -39,6 +39,7 @@ use grid::ToRange; /// [`simple`]: enum.Selection.html#method.simple /// [`semantic`]: enum.Selection.html#method.semantic /// [`lines`]: enum.Selection.html#method.lines +#[derive(Debug, Clone)] pub enum Selection { Simple { /// The region representing start and end of cursor movement @@ -64,6 +65,7 @@ pub enum Selection { } /// A Point and side within that point. +#[derive(Debug, Clone)] pub struct Anchor { point: Point, side: Side, diff --git a/src/term/mod.rs b/src/term/mod.rs index cb5e5740..e9a4582a 100644 --- a/src/term/mod.rs +++ b/src/term/mod.rs @@ -768,6 +768,14 @@ impl SizeInfo { impl Term { + pub fn selection(&self) -> &Option<Selection> { + &self.grid.selection + } + + pub fn selection_mut(&mut self) -> &mut Option<Selection> { + &mut self.grid.selection + } + #[inline] pub fn get_next_title(&mut self) -> Option<String> { self.next_title.take() @@ -864,7 +872,7 @@ impl Term { self.dirty } - pub fn string_from_selection(&self, span: &Span) -> String { + pub fn selection_to_string(&self) -> Option<String> { /// Need a generic push() for the Append trait trait PushChar { fn push_char(&mut self, c: char); @@ -919,6 +927,9 @@ impl Term { } } + let selection = self.grid.selection.clone()?; + let span = selection.to_span(self)?; + let mut res = String::new(); let (start, end) = span.to_locations(); @@ -955,7 +966,7 @@ impl Term { } } - res + Some(res) } /// Convert the given pixel values to a grid coordinate @@ -984,10 +995,9 @@ impl Term { pub fn renderable_cells<'b>( &'b self, config: &'b Config, - selection: Option<&'b Selection>, window_focused: bool, ) -> RenderableCellsIter { - let selection = selection.and_then(|s| s.to_span(self)) + let selection = self.grid.selection.as_ref().and_then(|s| s.to_span(self)) .map(|span| span.to_range()); let cursor = if window_focused { self.cursor_style.unwrap_or(self.default_cursor_style) @@ -1029,6 +1039,9 @@ impl Term { return; } + self.grid.selection = None; + self.alt_grid.selection = None; + // Should not allow less than 1 col, causes all sorts of checks to be required. if num_cols <= Column(1) { num_cols = Column(2); |