From 115a4085b4806e289c23ab296585f2f22b42efb7 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Thu, 29 Dec 2016 10:43:58 -0500 Subject: [PATCH] Fix selection copy for long lines Long lines were previously broken at the terminal width. Now, a wrapping marker is kept on the final cell so that extra newlines are not inserted. --- src/term/cell.rs | 14 +++++++++++++ src/term/mod.rs | 51 +++++++++++++++++++++++++++++++++++++----------- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/term/cell.rs b/src/term/cell.rs index a95875bf..db0cebcc 100644 --- a/src/term/cell.rs +++ b/src/term/cell.rs @@ -24,6 +24,7 @@ bitflags! { const BOLD = 0b00000010, const ITALIC = 0b00000100, const UNDERLINE = 0b00001000, + const WRAPLINE = 0b00010000, } } @@ -45,6 +46,10 @@ impl LineLength for grid::Row { fn line_length(&self) -> Column { let mut length = Column(0); + if self[Column(self.len() - 1)].flags.contains(WRAPLINE) { + return Column(self.len()); + } + for (index, cell) in self[..].iter().rev().enumerate() { if cell.c != ' ' { length = Column(self.len() - index); @@ -105,4 +110,13 @@ mod tests { assert_eq!(row.line_length(), Column(6)); } + + #[test] + fn line_length_works_with_wrapline() { + let template = Cell::new(' ', Color::Indexed(0), Color::Indexed(0)); + let mut row = Row::new(Column(10), &template); + row[Column(9)].flags.insert(super::WRAPLINE); + + assert_eq!(row.line_length(), Column(10)); + } } diff --git a/src/term/mod.rs b/src/term/mod.rs index 28e73b19..a3cb4ecd 100644 --- a/src/term/mod.rs +++ b/src/term/mod.rs @@ -311,43 +311,63 @@ impl Term { } pub fn string_from_selection(&self, span: &Span) -> String { - trait Append { - fn append(&mut self, grid: &Grid, line: Line, cols: T); + /// Need a generic push() for the Append trait + trait PushChar { + fn push_char(&mut self, c: char); + fn maybe_newline(&mut self, grid: &Grid, line: Line, ending: Column) { + if ending != Column(0) && !grid[line][ending - 1].flags.contains(cell::WRAPLINE) { + self.push_char('\n'); + } + } + } + + impl PushChar for String { + #[inline] + fn push_char(&mut self, c: char) { + self.push(c); + } + } + trait Append : PushChar { + fn append(&mut self, grid: &Grid, line: Line, cols: T) -> Range ; } use std::ops::{Range, RangeTo, RangeFrom, RangeFull}; impl Append> for String { - fn append(&mut self, grid: &Grid, line: Line, cols: Range) { + fn append(&mut self, grid: &Grid, line: Line, cols: Range) -> Range { let line = &grid[line]; let line_length = line.line_length(); let line_end = cmp::min(line_length, cols.end + 1); for cell in &line[cols.start..line_end] { self.push(cell.c); } + + cols.start..line_end } } impl Append> for String { #[inline] - fn append(&mut self, grid: &Grid, line: Line, cols: RangeTo) { - self.append(grid, line, Column(0)..cols.end); + fn append(&mut self, grid: &Grid, line: Line, cols: RangeTo) -> Range { + self.append(grid, line, Column(0)..cols.end) } } impl Append> for String { #[inline] - fn append(&mut self, grid: &Grid, line: Line, cols: RangeFrom) { - self.append(grid, line, cols.start..Column(usize::max_value() - 1)); - self.push('\n'); + fn append(&mut self, grid: &Grid, line: Line, cols: RangeFrom) -> Range { + let range = self.append(grid, line, cols.start..Column(usize::max_value() - 1)); + self.maybe_newline(grid, line, range.end); + range } } impl Append for String { #[inline] - fn append(&mut self, grid: &Grid, line: Line, _: RangeFull) { - self.append(grid, line, Column(0)..Column(usize::max_value() - 1)); - self.push('\n'); + fn append(&mut self, grid: &Grid, line: Line, _: RangeFull) -> Range { + let range = self.append(grid, line, Column(0)..Column(usize::max_value() - 1)); + self.maybe_newline(grid, line, range.end); + range } } @@ -564,6 +584,15 @@ impl ansi::Handler for Term { fn input(&mut self, c: char) { if self.cursor.col == self.grid.num_cols() { debug_println!("wrapping"); + { + let location = Cursor { + line: self.cursor.line, + col: self.cursor.col - 1 + }; + + let cell = &mut self.grid[&location]; + cell.flags.insert(cell::WRAPLINE); + } if (self.cursor.line + 1) >= self.scroll_region.end { self.linefeed(); } else {