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.
This commit is contained in:
Joe Wilm 2016-12-29 10:43:58 -05:00
parent 0f1c742857
commit 115a4085b4
2 changed files with 54 additions and 11 deletions

View File

@ -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<Cell> {
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));
}
}

View File

@ -311,43 +311,63 @@ impl Term {
}
pub fn string_from_selection(&self, span: &Span) -> String {
trait Append<T> {
fn append(&mut self, grid: &Grid<Cell>, 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<Cell>, 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<T> : PushChar {
fn append(&mut self, grid: &Grid<Cell>, line: Line, cols: T) -> Range<Column> ;
}
use std::ops::{Range, RangeTo, RangeFrom, RangeFull};
impl Append<Range<Column>> for String {
fn append(&mut self, grid: &Grid<Cell>, line: Line, cols: Range<Column>) {
fn append(&mut self, grid: &Grid<Cell>, line: Line, cols: Range<Column>) -> Range<Column> {
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<RangeTo<Column>> for String {
#[inline]
fn append(&mut self, grid: &Grid<Cell>, line: Line, cols: RangeTo<Column>) {
self.append(grid, line, Column(0)..cols.end);
fn append(&mut self, grid: &Grid<Cell>, line: Line, cols: RangeTo<Column>) -> Range<Column> {
self.append(grid, line, Column(0)..cols.end)
}
}
impl Append<RangeFrom<Column>> for String {
#[inline]
fn append(&mut self, grid: &Grid<Cell>, line: Line, cols: RangeFrom<Column>) {
self.append(grid, line, cols.start..Column(usize::max_value() - 1));
self.push('\n');
fn append(&mut self, grid: &Grid<Cell>, line: Line, cols: RangeFrom<Column>) -> Range<Column> {
let range = self.append(grid, line, cols.start..Column(usize::max_value() - 1));
self.maybe_newline(grid, line, range.end);
range
}
}
impl Append<RangeFull> for String {
#[inline]
fn append(&mut self, grid: &Grid<Cell>, line: Line, _: RangeFull) {
self.append(grid, line, Column(0)..Column(usize::max_value() - 1));
self.push('\n');
fn append(&mut self, grid: &Grid<Cell>, line: Line, _: RangeFull) -> Range<Column> {
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 {