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:
parent
038100922a
commit
09f168a0db
@ -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!(
|
||||
|
@ -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");
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user