aboutsummaryrefslogtreecommitdiff
path: root/alacritty_terminal/src/selection.rs
diff options
context:
space:
mode:
authorChristian Duerr <contact@christianduerr.com>2020-03-18 02:35:08 +0000
committerGitHub <noreply@github.com>2020-03-18 02:35:08 +0000
commit1a8cd172e520e493bacc9c6a2ae6f80de086eaa3 (patch)
tree0b837f1f52f72fe00e258afc34094d60b5d18f04 /alacritty_terminal/src/selection.rs
parent64db7d3daaed4e06fb8292227622bbc4cdaa2cf0 (diff)
downloadalacritty-1a8cd172e520e493bacc9c6a2ae6f80de086eaa3.tar.gz
alacritty-1a8cd172e520e493bacc9c6a2ae6f80de086eaa3.zip
Add modal keyboard motion mode
This implements a basic mode for navigating inside of Alacritty's history with keyboard bindings. They're bound by default to vi's motion shortcuts but are fully customizable. Since this relies on key bindings only single key bindings are currently supported (so no `ge`, or repetition). Other than navigating the history and moving the viewport, this mode should enable making use of all available selection modes to copy content to the clipboard and launch URLs below the cursor. This also changes the rendering of the block cursor at the side of selections, since previously it could be inverted to be completely invisible. Since that would have caused some troubles with this keyboard selection mode, the block cursor now is no longer inverted when it is at the edges of a selection. Fixes #262.
Diffstat (limited to 'alacritty_terminal/src/selection.rs')
-rw-r--r--alacritty_terminal/src/selection.rs106
1 files changed, 55 insertions, 51 deletions
diff --git a/alacritty_terminal/src/selection.rs b/alacritty_terminal/src/selection.rs
index f663417f..369846cf 100644
--- a/alacritty_terminal/src/selection.rs
+++ b/alacritty_terminal/src/selection.rs
@@ -27,7 +27,7 @@ use crate::term::{Search, Term};
/// A Point and side within that point.
#[derive(Debug, Copy, Clone, PartialEq)]
-pub struct Anchor {
+struct Anchor {
point: Point<usize>,
side: Side,
}
@@ -67,7 +67,7 @@ impl<L> SelectionRange<L> {
/// Different kinds of selection.
#[derive(Debug, Copy, Clone, PartialEq)]
-enum SelectionType {
+pub enum SelectionType {
Simple,
Block,
Semantic,
@@ -94,48 +94,20 @@ enum SelectionType {
/// [`update`]: enum.Selection.html#method.update
#[derive(Debug, Clone, PartialEq)]
pub struct Selection {
+ pub ty: SelectionType,
region: Range<Anchor>,
- ty: SelectionType,
}
impl Selection {
- pub fn simple(location: Point<usize>, side: Side) -> Selection {
+ pub fn new(ty: SelectionType, location: Point<usize>, side: Side) -> Selection {
Self {
region: Range { start: Anchor::new(location, side), end: Anchor::new(location, side) },
- ty: SelectionType::Simple,
+ ty,
}
}
- pub fn block(location: Point<usize>, side: Side) -> Selection {
- Self {
- region: Range { start: Anchor::new(location, side), end: Anchor::new(location, side) },
- ty: SelectionType::Block,
- }
- }
-
- pub fn semantic(location: Point<usize>) -> Selection {
- Self {
- region: Range {
- start: Anchor::new(location, Side::Left),
- end: Anchor::new(location, Side::Right),
- },
- ty: SelectionType::Semantic,
- }
- }
-
- pub fn lines(location: Point<usize>) -> Selection {
- Self {
- region: Range {
- start: Anchor::new(location, Side::Left),
- end: Anchor::new(location, Side::Right),
- },
- ty: SelectionType::Lines,
- }
- }
-
- pub fn update(&mut self, location: Point<usize>, side: Side) {
- self.region.end.point = location;
- self.region.end.side = side;
+ pub fn update(&mut self, point: Point<usize>, side: Side) {
+ self.region.end = Anchor::new(point, side);
}
pub fn rotate(
@@ -233,6 +205,24 @@ impl Selection {
}
}
+ /// Expand selection sides to include all cells.
+ pub fn include_all(&mut self) {
+ let (start, end) = (self.region.start.point, self.region.end.point);
+ let (start_side, end_side) = match self.ty {
+ SelectionType::Block
+ if start.col > end.col || (start.col == end.col && start.line < end.line) =>
+ {
+ (Side::Right, Side::Left)
+ },
+ SelectionType::Block => (Side::Left, Side::Right),
+ _ if Self::points_need_swap(start, end) => (Side::Right, Side::Left),
+ _ => (Side::Left, Side::Right),
+ };
+
+ self.region.start.side = start_side;
+ self.region.end.side = end_side;
+ }
+
/// Convert selection to grid coordinates.
pub fn to_range<T>(&self, term: &Term<T>) -> Option<SelectionRange> {
let grid = term.grid();
@@ -392,7 +382,8 @@ impl Selection {
/// look like [ B] and [E ].
#[cfg(test)]
mod tests {
- use super::{Selection, SelectionRange};
+ use super::*;
+
use crate::clipboard::Clipboard;
use crate::config::MockConfig;
use crate::event::{Event, EventListener};
@@ -425,7 +416,7 @@ mod tests {
#[test]
fn single_cell_left_to_right() {
let location = Point { line: 0, col: Column(0) };
- let mut selection = Selection::simple(location, Side::Left);
+ let mut selection = Selection::new(SelectionType::Simple, location, Side::Left);
selection.update(location, Side::Right);
assert_eq!(selection.to_range(&term(1, 1)).unwrap(), SelectionRange {
@@ -443,7 +434,7 @@ mod tests {
#[test]
fn single_cell_right_to_left() {
let location = Point { line: 0, col: Column(0) };
- let mut selection = Selection::simple(location, Side::Right);
+ let mut selection = Selection::new(SelectionType::Simple, location, Side::Right);
selection.update(location, Side::Left);
assert_eq!(selection.to_range(&term(1, 1)).unwrap(), SelectionRange {
@@ -460,7 +451,8 @@ mod tests {
/// 3. [ B][E ]
#[test]
fn between_adjacent_cells_left_to_right() {
- let mut selection = Selection::simple(Point::new(0, Column(0)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Simple, Point::new(0, Column(0)), Side::Right);
selection.update(Point::new(0, Column(1)), Side::Left);
assert_eq!(selection.to_range(&term(2, 1)), None);
@@ -473,7 +465,8 @@ mod tests {
/// 3. [ E][B ]
#[test]
fn between_adjacent_cells_right_to_left() {
- let mut selection = Selection::simple(Point::new(0, Column(1)), Side::Left);
+ let mut selection =
+ Selection::new(SelectionType::Simple, Point::new(0, Column(1)), Side::Left);
selection.update(Point::new(0, Column(0)), Side::Right);
assert_eq!(selection.to_range(&term(2, 1)), None);
@@ -489,7 +482,8 @@ mod tests {
/// [XX][XE][ ][ ][ ]
#[test]
fn across_adjacent_lines_upward_final_cell_exclusive() {
- let mut selection = Selection::simple(Point::new(1, Column(1)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Simple, Point::new(1, Column(1)), Side::Right);
selection.update(Point::new(0, Column(1)), Side::Right);
assert_eq!(selection.to_range(&term(5, 2)).unwrap(), SelectionRange {
@@ -511,7 +505,8 @@ mod tests {
/// [XX][XB][ ][ ][ ]
#[test]
fn selection_bigger_then_smaller() {
- let mut selection = Selection::simple(Point::new(0, Column(1)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Simple, Point::new(0, Column(1)), Side::Right);
selection.update(Point::new(1, Column(1)), Side::Right);
selection.update(Point::new(1, Column(0)), Side::Right);
@@ -526,7 +521,8 @@ mod tests {
fn line_selection() {
let num_lines = 10;
let num_cols = 5;
- let mut selection = Selection::lines(Point::new(0, Column(1)));
+ let mut selection =
+ Selection::new(SelectionType::Lines, Point::new(0, Column(1)), Side::Left);
selection.update(Point::new(5, Column(1)), Side::Right);
selection = selection.rotate(num_lines, num_cols, &(Line(0)..Line(num_lines)), 7).unwrap();
@@ -541,7 +537,8 @@ mod tests {
fn semantic_selection() {
let num_lines = 10;
let num_cols = 5;
- let mut selection = Selection::semantic(Point::new(0, Column(3)));
+ let mut selection =
+ Selection::new(SelectionType::Semantic, Point::new(0, Column(3)), Side::Left);
selection.update(Point::new(5, Column(1)), Side::Right);
selection = selection.rotate(num_lines, num_cols, &(Line(0)..Line(num_lines)), 7).unwrap();
@@ -556,7 +553,8 @@ mod tests {
fn simple_selection() {
let num_lines = 10;
let num_cols = 5;
- let mut selection = Selection::simple(Point::new(0, Column(3)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Simple, Point::new(0, Column(3)), Side::Right);
selection.update(Point::new(5, Column(1)), Side::Right);
selection = selection.rotate(num_lines, num_cols, &(Line(0)..Line(num_lines)), 7).unwrap();
@@ -571,7 +569,8 @@ mod tests {
fn block_selection() {
let num_lines = 10;
let num_cols = 5;
- let mut selection = Selection::block(Point::new(0, Column(3)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Block, Point::new(0, Column(3)), Side::Right);
selection.update(Point::new(5, Column(1)), Side::Right);
selection = selection.rotate(num_lines, num_cols, &(Line(0)..Line(num_lines)), 7).unwrap();
@@ -584,7 +583,8 @@ mod tests {
#[test]
fn simple_is_empty() {
- let mut selection = Selection::simple(Point::new(0, Column(0)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Simple, Point::new(0, Column(0)), Side::Right);
assert!(selection.is_empty());
selection.update(Point::new(0, Column(1)), Side::Left);
assert!(selection.is_empty());
@@ -594,7 +594,8 @@ mod tests {
#[test]
fn block_is_empty() {
- let mut selection = Selection::block(Point::new(0, Column(0)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Block, Point::new(0, Column(0)), Side::Right);
assert!(selection.is_empty());
selection.update(Point::new(0, Column(1)), Side::Left);
assert!(selection.is_empty());
@@ -612,7 +613,8 @@ mod tests {
fn rotate_in_region_up() {
let num_lines = 10;
let num_cols = 5;
- let mut selection = Selection::simple(Point::new(2, Column(3)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Simple, Point::new(2, Column(3)), Side::Right);
selection.update(Point::new(5, Column(1)), Side::Right);
selection =
selection.rotate(num_lines, num_cols, &(Line(1)..Line(num_lines - 1)), 4).unwrap();
@@ -628,7 +630,8 @@ mod tests {
fn rotate_in_region_down() {
let num_lines = 10;
let num_cols = 5;
- let mut selection = Selection::simple(Point::new(5, Column(3)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Simple, Point::new(5, Column(3)), Side::Right);
selection.update(Point::new(8, Column(1)), Side::Left);
selection =
selection.rotate(num_lines, num_cols, &(Line(1)..Line(num_lines - 1)), -5).unwrap();
@@ -644,7 +647,8 @@ mod tests {
fn rotate_in_region_up_block() {
let num_lines = 10;
let num_cols = 5;
- let mut selection = Selection::block(Point::new(2, Column(3)), Side::Right);
+ let mut selection =
+ Selection::new(SelectionType::Block, Point::new(2, Column(3)), Side::Right);
selection.update(Point::new(5, Column(1)), Side::Right);
selection =
selection.rotate(num_lines, num_cols, &(Line(1)..Line(num_lines - 1)), 4).unwrap();