mirror of
https://github.com/wez/wezterm.git
synced 2024-12-25 22:33:52 +03:00
add some tests for a double-width selection bug
This commit is contained in:
parent
adc11f303a
commit
d0de936f62
@ -166,6 +166,10 @@ impl Cell {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn str(&self) -> &str {
|
||||||
|
str::from_utf8(self.bytes()).unwrap_or("?")
|
||||||
|
}
|
||||||
|
|
||||||
pub fn width(&self) -> usize {
|
pub fn width(&self) -> usize {
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
str::from_utf8(self.bytes()).unwrap_or("").width()
|
str::from_utf8(self.bytes()).unwrap_or("").width()
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use std::ops::Range;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -63,7 +64,20 @@ impl Line {
|
|||||||
pub fn as_str(&self) -> String {
|
pub fn as_str(&self) -> String {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
for c in self.cells.iter() {
|
for c in self.cells.iter() {
|
||||||
s.push_str(str::from_utf8(c.bytes()).unwrap_or("?"));
|
s.push_str(c.str());
|
||||||
|
}
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a substring from the line.
|
||||||
|
pub fn columns_as_str(&self, range: Range<usize>) -> String {
|
||||||
|
let mut s = String::new();
|
||||||
|
let limit = range.end - range.start;
|
||||||
|
for (n, c) in self.cells.iter().skip(range.start).enumerate() {
|
||||||
|
if n >= limit {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
s.push_str(c.str());
|
||||||
}
|
}
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
@ -74,7 +88,7 @@ impl Line {
|
|||||||
let mut clusters = Vec::new();
|
let mut clusters = Vec::new();
|
||||||
|
|
||||||
for (cell_idx, c) in self.cells.iter().enumerate() {
|
for (cell_idx, c) in self.cells.iter().enumerate() {
|
||||||
let cell_str = str::from_utf8(c.bytes()).unwrap_or("?");
|
let cell_str = c.str();
|
||||||
|
|
||||||
last_cluster = match last_cluster.take() {
|
last_cluster = match last_cluster.take() {
|
||||||
None => {
|
None => {
|
||||||
|
@ -129,15 +129,11 @@ impl TerminalState {
|
|||||||
let screen = self.screen();
|
let screen = self.screen();
|
||||||
for y in sel.rows() {
|
for y in sel.rows() {
|
||||||
let idx = screen.scrollback_or_visible_row(y);
|
let idx = screen.scrollback_or_visible_row(y);
|
||||||
let line = screen.lines[idx].as_str();
|
|
||||||
let cols = sel.cols_for_row(y);
|
let cols = sel.cols_for_row(y);
|
||||||
let end = cols.end.min(line.len());
|
|
||||||
let col_range = cols.start..end;
|
|
||||||
let selected = &line[col_range].trim_right();
|
|
||||||
if s.len() > 0 {
|
if s.len() > 0 {
|
||||||
s.push('\n');
|
s.push('\n');
|
||||||
}
|
}
|
||||||
s.push_str(selected);
|
s.push_str(&screen.lines[idx].columns_as_str(cols).trim_right());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
//! processing routines.
|
//! processing routines.
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
mod selection;
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
struct TestHost {
|
struct TestHost {
|
||||||
@ -111,6 +112,69 @@ impl TestTerm {
|
|||||||
self.print(CSI);
|
self.print(CSI);
|
||||||
self.print("!p");
|
self.print("!p");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mouse(&mut self, event: MouseEvent) -> Result<(), Error> {
|
||||||
|
self.term.mouse_event(event, &mut self.host)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_clipboard(&self) -> Option<&String> {
|
||||||
|
self.host.clip.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inject n_times clicks of the button at the specified coordinates
|
||||||
|
fn click_n(&mut self, x: usize, y: i64, button: MouseButton, n_times: usize) {
|
||||||
|
for _ in 0..n_times {
|
||||||
|
self.mouse(MouseEvent {
|
||||||
|
kind: MouseEventKind::Press,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
button,
|
||||||
|
modifiers: KeyModifiers::default(),
|
||||||
|
}).unwrap();
|
||||||
|
self.mouse(MouseEvent {
|
||||||
|
kind: MouseEventKind::Release,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
button,
|
||||||
|
modifiers: KeyModifiers::default(),
|
||||||
|
}).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Left mouse button drag from the start to the end coordinates
|
||||||
|
fn drag_select(&mut self, start_x: usize, start_y: i64, end_x: usize, end_y: i64) {
|
||||||
|
// Break any outstanding click streak that might falsely trigger due to
|
||||||
|
// this unit test happening much faster than the CLICK_INTERVAL allows.
|
||||||
|
self.click_n(0, 0, MouseButton::Right, 1);
|
||||||
|
|
||||||
|
// Now inject the appropriate left click events
|
||||||
|
|
||||||
|
self.mouse(MouseEvent {
|
||||||
|
kind: MouseEventKind::Press,
|
||||||
|
x: start_x,
|
||||||
|
y: start_y,
|
||||||
|
button: MouseButton::Left,
|
||||||
|
modifiers: KeyModifiers::default(),
|
||||||
|
}).unwrap();
|
||||||
|
assert!(self.host.clip.is_none());
|
||||||
|
|
||||||
|
self.mouse(MouseEvent {
|
||||||
|
kind: MouseEventKind::Move,
|
||||||
|
x: end_x,
|
||||||
|
y: end_y,
|
||||||
|
button: MouseButton::None,
|
||||||
|
modifiers: KeyModifiers::default(),
|
||||||
|
}).unwrap();
|
||||||
|
assert!(self.host.clip.is_none());
|
||||||
|
|
||||||
|
self.mouse(MouseEvent {
|
||||||
|
kind: MouseEventKind::Release,
|
||||||
|
x: end_x,
|
||||||
|
y: end_y,
|
||||||
|
button: MouseButton::Left,
|
||||||
|
modifiers: KeyModifiers::default(),
|
||||||
|
}).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for TestTerm {
|
impl Deref for TestTerm {
|
||||||
|
58
term/src/test/selection.rs
Normal file
58
term/src/test/selection.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// Test basic dragging to select some text
|
||||||
|
#[test]
|
||||||
|
fn drag_selection() {
|
||||||
|
let mut term = TestTerm::new(3, 12, 0);
|
||||||
|
term.print("hello world\n");
|
||||||
|
assert_visible_contents(&term, &["hello world ", " ", " "]);
|
||||||
|
|
||||||
|
term.drag_select(1, 0, 4, 0);
|
||||||
|
assert_eq!(term.get_clipboard().unwrap(), "ello");
|
||||||
|
|
||||||
|
// Now check that we respect double-width boundaries reasonably sanely;
|
||||||
|
// here we're dragging from the middle of the skull emoji
|
||||||
|
term.print("\u{1F480}skull\n");
|
||||||
|
assert_visible_contents(
|
||||||
|
&term,
|
||||||
|
&["hello world ", "\u{1F480}skull ", " "],
|
||||||
|
);
|
||||||
|
term.drag_select(1, 1, 5, 1);
|
||||||
|
assert_eq!(term.get_clipboard().unwrap(), "skul");
|
||||||
|
|
||||||
|
// Let's include the start of it this time
|
||||||
|
term.drag_select(0, 1, 5, 1);
|
||||||
|
assert_eq!(term.get_clipboard().unwrap(), "\u{1F480}skul");
|
||||||
|
|
||||||
|
// Multi-line selection
|
||||||
|
term.drag_select(1, 0, 6, 1);
|
||||||
|
assert_eq!(term.get_clipboard().unwrap(), "ello world\n\u{1F480}skull");
|
||||||
|
|
||||||
|
term.drag_select(0, 0, 0, 2);
|
||||||
|
assert_eq!(
|
||||||
|
term.get_clipboard().unwrap(),
|
||||||
|
"hello world\n\u{1F480}skull\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test double click to select a word
|
||||||
|
#[test]
|
||||||
|
fn double_click_selection() {
|
||||||
|
let mut term = TestTerm::new(3, 10, 0);
|
||||||
|
term.print("hello world");
|
||||||
|
|
||||||
|
term.click_n(1, 0, MouseButton::Left, 2);
|
||||||
|
|
||||||
|
assert_eq!(term.get_clipboard().unwrap(), "hello");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test triple click to select a line
|
||||||
|
#[test]
|
||||||
|
fn triple_click_selection() {
|
||||||
|
let mut term = TestTerm::new(3, 10, 0);
|
||||||
|
term.print("hello world");
|
||||||
|
assert_visible_contents(&term, &["hello worl", "d ", " "]);
|
||||||
|
term.click_n(1, 0, MouseButton::Left, 3);
|
||||||
|
|
||||||
|
assert_eq!(term.get_clipboard().unwrap(), "hello worl");
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user