Add support for double-click bracket-pair selection
This commit is contained in:
parent
ca9724a5ef
commit
1656aff85e
|
@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Config option `working_directory`
|
- Config option `working_directory`
|
||||||
- Config group `debug` with the options `debug.log_level`, `debug.print_events`
|
- Config group `debug` with the options `debug.log_level`, `debug.print_events`
|
||||||
and `debug.ref_test`
|
and `debug.ref_test`
|
||||||
|
- Select until next matching bracket when double-clicking a bracket
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
@ -188,14 +188,20 @@ impl Selection {
|
||||||
Selection::alt_screen_clamp(&mut start, &mut end, lines, cols)?;
|
Selection::alt_screen_clamp(&mut start, &mut end, lines, cols)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut start, mut end) = if start < end && start.line == end.line {
|
let (mut start, mut end) = if start == end {
|
||||||
|
if let Some(end) = grid.bracket_search(start.into()) {
|
||||||
|
(start.into(), end)
|
||||||
|
} else {
|
||||||
|
(grid.semantic_search_right(start.into()), grid.semantic_search_left(end.into()))
|
||||||
|
}
|
||||||
|
} else if start < end && start.line == end.line {
|
||||||
(grid.semantic_search_left(start.into()), grid.semantic_search_right(end.into()))
|
(grid.semantic_search_left(start.into()), grid.semantic_search_right(end.into()))
|
||||||
} else {
|
} else {
|
||||||
(grid.semantic_search_right(start.into()), grid.semantic_search_left(end.into()))
|
(grid.semantic_search_right(start.into()), grid.semantic_search_left(end.into()))
|
||||||
};
|
};
|
||||||
|
|
||||||
if start > end {
|
if start > end {
|
||||||
::std::mem::swap(&mut start, &mut end);
|
std::mem::swap(&mut start, &mut end);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Span { start, end })
|
Some(Span { start, end })
|
||||||
|
|
|
@ -46,6 +46,9 @@ use crate::tty;
|
||||||
pub mod cell;
|
pub mod cell;
|
||||||
pub mod color;
|
pub mod color;
|
||||||
|
|
||||||
|
/// Used to match equal brackets, when performing a bracket-pair selection.
|
||||||
|
const BRACKET_PAIRS: [(char, char); 4] = [('(', ')'), ('[', ']'), ('{', '}'), ('<', '>')];
|
||||||
|
|
||||||
/// A type that can expand a given point to a region
|
/// A type that can expand a given point to a region
|
||||||
///
|
///
|
||||||
/// Usually this is implemented for some 2-D array type since
|
/// Usually this is implemented for some 2-D array type since
|
||||||
|
@ -57,6 +60,8 @@ pub trait Search {
|
||||||
fn semantic_search_right(&self, _: Point<usize>) -> Point<usize>;
|
fn semantic_search_right(&self, _: Point<usize>) -> Point<usize>;
|
||||||
/// Find the nearest URL boundary in both directions.
|
/// Find the nearest URL boundary in both directions.
|
||||||
fn url_search(&self, _: Point<usize>) -> Option<Url>;
|
fn url_search(&self, _: Point<usize>) -> Option<Url>;
|
||||||
|
/// Find the nearest matching bracket.
|
||||||
|
fn bracket_search(&self, _: Point<usize>) -> Option<Point<usize>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Search for Term {
|
impl Search for Term {
|
||||||
|
@ -137,6 +142,49 @@ impl Search for Term {
|
||||||
}
|
}
|
||||||
url_parser.url()
|
url_parser.url()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bracket_search(&self, point: Point<usize>) -> Option<Point<usize>> {
|
||||||
|
let start_char = self.grid[point.line][point.col].c;
|
||||||
|
|
||||||
|
// Find the matching bracket we're looking for
|
||||||
|
let (forwards, end_char) = BRACKET_PAIRS.iter().find_map(|(open, close)| {
|
||||||
|
if open == &start_char {
|
||||||
|
Some((true, *close))
|
||||||
|
} else if close == &start_char {
|
||||||
|
Some((false, *open))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let mut iter = self.grid.iter_from(point);
|
||||||
|
|
||||||
|
// For every character match that equals the starting bracket, we
|
||||||
|
// ignore one bracket of the opposite type.
|
||||||
|
let mut skip_pairs = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// Check the next cell
|
||||||
|
let cell = if forwards { iter.next() } else { iter.prev() };
|
||||||
|
|
||||||
|
// Break if there are no more cells
|
||||||
|
let c = match cell {
|
||||||
|
Some(cell) => cell.c,
|
||||||
|
None => break,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if the bracket matches
|
||||||
|
if c == end_char && skip_pairs == 0 {
|
||||||
|
return Some(iter.cur);
|
||||||
|
} else if c == start_char {
|
||||||
|
skip_pairs += 1;
|
||||||
|
} else if c == end_char {
|
||||||
|
skip_pairs -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl selection::Dimensions for Term {
|
impl selection::Dimensions for Term {
|
||||||
|
|
Loading…
Reference in New Issue