1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-24 05:42:03 +03:00

plumbing for double click selection of wrapped lines

This commit is contained in:
Wez Furlong 2019-05-26 14:52:03 -07:00
parent 038100922a
commit 09f168a0db
3 changed files with 99 additions and 34 deletions

View File

@ -228,6 +228,20 @@ fn write_all(w: &mut std::io::Write, mut buf: &[u8]) -> std::io::Result<()> {
Ok(())
}
fn is_double_click_word(s: &str) -> bool {
// TODO: add configuration for this
if s.len() > 1 {
true
} else if s.len() == 1 {
match s.chars().nth(0).unwrap() {
' ' | '\t' | '\n' | '{' | '[' | '}' | ']' | '(' | ')' | '"' | '\'' => false,
_ => true,
}
} else {
false
}
}
impl TerminalState {
pub fn new(
physical_rows: usize,
@ -429,34 +443,65 @@ impl TerminalState {
let y = event.y as ScrollbackOrVisibleRowIndex
- self.viewport_offset as ScrollbackOrVisibleRowIndex;
let idx = self.screen().scrollback_or_visible_row(y);
let click_range = self.screen().lines[idx].compute_double_click_range(event.x, |s| {
// TODO: add configuration for this
if s.len() > 1 {
true
} else if s.len() == 1 {
match s.chars().nth(0).unwrap() {
' ' | '\t' | '\n' | '{' | '[' | '}' | ']' | '(' | ')' | '"' | '\'' => false,
_ => true,
}
} else {
false
}
});
let selection_range = match self.screen().lines[idx]
.compute_double_click_range(event.x, is_double_click_word)
{
DoubleClickRange::Range(click_range) => SelectionRange {
start: SelectionCoordinate {
x: click_range.start,
y,
},
end: SelectionCoordinate {
x: click_range.end,
y,
},
},
DoubleClickRange::RangeWithWrap(range_start) => {
let start_coord = SelectionCoordinate {
x: range_start.start,
y,
};
let mut end_coord = SelectionCoordinate {
x: range_start.end,
y,
};
for y_cont in idx + 1..self.screen().lines.len() {
match self.screen().lines[y_cont]
.compute_double_click_range(0, is_double_click_word)
{
DoubleClickRange::Range(range_end) => {
if range_end.end > range_end.start {
end_coord = SelectionCoordinate {
x: range_end.end,
y: y + (y_cont - idx) as i32,
};
}
break;
}
DoubleClickRange::RangeWithWrap(range_end) => {
end_coord = SelectionCoordinate {
x: range_end.end,
y: y + (y_cont - idx) as i32,
};
}
}
}
SelectionRange {
start: start_coord,
end: end_coord,
}
}
};
// TODO: if selection_range.start.x == 0, search backwards for wrapping
// lines too.
self.selection_start = Some(selection_range.start);
self.selection_range = Some(selection_range);
self.selection_start = Some(SelectionCoordinate {
x: click_range.start,
y,
});
self.selection_range = Some(SelectionRange {
start: SelectionCoordinate {
x: click_range.start,
y,
},
end: SelectionCoordinate {
x: click_range.end,
y,
},
});
self.dirty_selection_lines();
let text = self.get_selection_text();
debug!(

View File

@ -63,16 +63,27 @@ fn triple_click_selection() {
assert_eq!(term.get_clipboard().unwrap(), "hello worl");
}
/// Test double click on wrapped line selects across the line boundary
#[test]
fn double_click_wrapped_selection() {
let mut term = TestTerm::new(3, 10, 0);
term.print("hello world");
assert_visible_contents(&term, &["hello worl", "d ", " "]);
term.click_n(7, 0, MouseButton::Left, 2);
assert_eq!(term.get_clipboard().unwrap(), "worl\nd");
}
/// Make sure that we adjust for the viewport offset when scrolling
#[test]
fn selection_in_scrollback() {
let mut term = TestTerm::new(2, 1, 4);
term.print("1234");
assert_all_contents(&term, &["1", "2", "3", "4"]);
let mut term = TestTerm::new(2, 2, 4);
term.print("1 2 3 4");
assert_all_contents(&term, &["1 ", "2 ", "3 ", "4 "]);
// Scroll back one line
term.scroll_viewport(-1);
term.assert_viewport_contents(&["2", "3"]);
term.assert_viewport_contents(&["2 ", "3 "]);
term.click_n(0, 0, MouseButton::Left, 2);
assert_eq!(term.get_clipboard().unwrap(), "2");

View File

@ -30,6 +30,11 @@ pub struct Line {
cells: Vec<Cell>,
}
pub enum DoubleClickRange {
Range(Range<usize>),
RangeWithWrap(Range<usize>),
}
impl Line {
pub fn with_width(width: usize) -> Self {
let mut cells = Vec::with_capacity(width);
@ -186,7 +191,7 @@ impl Line {
&self,
click_col: usize,
is_word: fn(s: &str) -> bool,
) -> Range<usize> {
) -> DoubleClickRange {
let mut lower = click_col;
let mut upper = click_col;
@ -196,7 +201,7 @@ impl Line {
if !is_word(cell.str()) {
break;
}
upper = idx;
upper = idx + 1;
}
for (idx, cell) in self.cells.iter().enumerate().rev() {
if idx > click_col {
@ -208,7 +213,11 @@ impl Line {
lower = idx;
}
lower..upper
if upper == self.cells().len() {
DoubleClickRange::RangeWithWrap(lower..upper)
} else {
DoubleClickRange::Range(lower..upper)
}
}
/// Returns a substring from the line.