fix(copy): rejoin wrapped lines (#1069)

When copying wrapped lines do not treat them as separate lines.
This commit is contained in:
Thomas Linford 2022-02-21 17:58:54 +01:00 committed by GitHub
parent 0ac524b295
commit a3e69fe6da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 54 additions and 14 deletions

10
src/tests/fixtures/grid_copy_wrapped vendored Executable file
View File

@ -0,0 +1,10 @@
Welcome to fish, the friendly interactive shell
Type `help` for instructions on how to use fish
[?2004h]0;fish /home/thomas/Projects/zellij(B 
zellij on  main [$!?] is 📦 v0.25.0 via 🦀 v1.58.1 
   c c (Bargo make run --debug (Bargo make run --debug (Bt(B cat (B lorem.txt (B lorem.txt (B lorem.txt (B 
(B[?2004l]0;cat lorem.txt /home/thomas/Projects/zellij(B Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
⏎(B ⏎ [?2004h]0;fish /home/thomas/Projects/zellij(B
zellij on  main [$!?] is 📦 v0.25.0 via 🦀 v1.58.1 
  
(B(B[?2004l

View File

@ -1291,27 +1291,27 @@ impl Grid {
self.preceding_char = Some(terminal_character);
}
pub fn start_selection(&mut self, start: &Position) {
let old_selection = self.selection.clone();
let old_selection = self.selection;
self.selection.start(*start);
self.update_selected_lines(&old_selection, &self.selection.clone());
self.mark_for_rerender();
}
pub fn update_selection(&mut self, to: &Position) {
let old_selection = self.selection.clone();
let old_selection = self.selection;
self.selection.to(*to);
self.update_selected_lines(&old_selection, &self.selection.clone());
self.mark_for_rerender();
}
pub fn end_selection(&mut self, end: Option<&Position>) {
let old_selection = self.selection.clone();
let old_selection = self.selection;
self.selection.end(end);
self.update_selected_lines(&old_selection, &self.selection.clone());
self.mark_for_rerender();
}
pub fn reset_selection(&mut self) {
let old_selection = self.selection.clone();
let old_selection = self.selection;
self.selection.reset();
self.update_selected_lines(&old_selection, &self.selection.clone());
self.mark_for_rerender();
@ -1366,24 +1366,30 @@ impl Grid {
continue;
};
let excess_width = row.excess_width();
let mut line: Vec<TerminalCharacter> = row.columns.iter().copied().collect();
// pad line
line.resize(
self.width.saturating_sub(excess_width),
EMPTY_TERMINAL_CHARACTER,
);
let mut terminal_col = 0;
for terminal_character in line {
for terminal_character in &row.columns {
if (start_column..end_column).contains(&terminal_col) {
line_selection.push(terminal_character.character);
}
terminal_col += terminal_character.width;
}
selection.push(String::from(line_selection.trim_end()));
if row.is_canonical {
selection.push(line_selection);
} else {
// rejoin wrapped lines if possible
match selection.last_mut() {
Some(previous_line) => previous_line.push_str(&line_selection),
None => selection.push(line_selection),
}
}
}
// TODO: distinguish whitespace that was output explicitly vs implicitly (e.g add_newline)
// for example: echo " " vs empty lines
// for now trim after building the selection to handle whitespace in wrapped lines
let selection: Vec<_> = selection.iter().map(|l| l.trim_end()).collect();
Some(selection.join("\n"))
}

View File

@ -859,6 +859,30 @@ fn copy_selected_text_from_viewport() {
);
}
#[test]
fn copy_wrapped_selected_text_from_viewport() {
let mut vte_parser = vte::Parser::new();
let mut grid = Grid::new(
22,
73,
Palette::default(),
Rc::new(RefCell::new(LinkHandler::new())),
);
let fixture_name = "grid_copy_wrapped";
let content = read_fixture(fixture_name);
for byte in content {
vte_parser.advance(&mut grid, byte);
}
grid.start_selection(&Position::new(5, 0));
grid.end_selection(Some(&Position::new(8, 42)));
let text = grid.get_selected_text();
assert_eq!(
text.unwrap(),
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
);
}
#[test]
fn copy_selected_text_from_lines_above() {
let mut vte_parser = vte::Parser::new();