aboutsummaryrefslogtreecommitdiff
path: root/src/term/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/term/mod.rs')
-rw-r--r--src/term/mod.rs120
1 files changed, 88 insertions, 32 deletions
diff --git a/src/term/mod.rs b/src/term/mod.rs
index fba509f5..fd2fcf88 100644
--- a/src/term/mod.rs
+++ b/src/term/mod.rs
@@ -763,7 +763,7 @@ pub struct Term {
active_charset: CharsetIndex,
/// Tabstops
- tabs: Vec<bool>,
+ tabs: TabStops,
/// Mode flags
mode: TermMode,
@@ -915,9 +915,7 @@ impl Term {
let alt = Grid::new(num_lines, num_cols, 0 /* scroll history */, Cell::default());
let tabspaces = config.tabspaces();
- let tabs = IndexRange::from(Column(0)..grid.num_cols())
- .map(|i| (*i as usize) % tabspaces == 0)
- .collect::<Vec<bool>>();
+ let tabs = TabStops::new(grid.num_cols(), tabspaces);
let scroll_region = Line(0)..grid.num_lines();
@@ -1014,11 +1012,23 @@ impl Term {
use std::ops::Range;
trait Append : PushChar {
- fn append(&mut self, grid: &Grid<Cell>, line: usize, cols: Range<Column>);
+ fn append(
+ &mut self,
+ grid: &Grid<Cell>,
+ tabs: &TabStops,
+ line: usize,
+ cols: Range<Column>,
+ );
}
impl Append for String {
- fn append(&mut self, grid: &Grid<Cell>, mut line: usize, cols: Range<Column>) {
+ fn append(
+ &mut self,
+ grid: &Grid<Cell>,
+ tabs: &TabStops,
+ mut line: usize,
+ cols: Range<Column>
+ ) {
// Select until last line still within the buffer
line = min(line, grid.len() - 1);
@@ -1029,13 +1039,30 @@ impl Term {
if line_end.0 == 0 && cols.end >= grid.num_cols() - 1 {
self.push('\n');
} else if cols.start < line_end {
- for cell in &grid_line[cols.start..line_end] {
+ let mut tab_mode = false;
+
+ for col in IndexRange::from(cols.start..line_end) {
+ let cell = grid_line[col];
+
+ if tab_mode {
+ // Skip over whitespace until next tab-stop once a tab was found
+ if tabs[col] {
+ tab_mode = false;
+ } else if cell.c == ' ' {
+ continue;
+ }
+ }
+
if !cell.flags.contains(cell::Flags::WIDE_CHAR_SPACER) {
self.push(cell.c);
for c in (&cell.chars()[1..]).iter().filter(|c| **c != ' ') {
self.push(*c);
}
}
+
+ if cell.c == '\t' {
+ tab_mode = true;
+ }
}
if cols.end >= grid.num_cols() - 1 {
@@ -1063,32 +1090,31 @@ impl Term {
match line_count {
// Selection within single line
0 => {
- res.append(&self.grid, start.line, start.col..end.col);
+ res.append(&self.grid, &self.tabs, start.line, start.col..end.col);
},
// Selection ends on line following start
1 => {
// Ending line
- res.append(&self.grid, end.line, end.col..max_col);
+ res.append(&self.grid, &self.tabs, end.line, end.col..max_col);
// Starting line
- res.append(&self.grid, start.line, Column(0)..start.col);
+ res.append(&self.grid, &self.tabs, start.line, Column(0)..start.col);
},
// Multi line selection
_ => {
// Ending line
- res.append(&self.grid, end.line, end.col..max_col);
+ res.append(&self.grid, &self.tabs, end.line, end.col..max_col);
let middle_range = (start.line + 1)..(end.line);
for line in middle_range.rev() {
- res.append(&self.grid, line, Column(0)..max_col);
+ res.append(&self.grid, &self.tabs, line, Column(0)..max_col);
}
// Starting line
- res.append(&self.grid, start.line, Column(0)..start.col);
-
+ res.append(&self.grid, &self.tabs, start.line, Column(0)..start.col);
}
}
@@ -1232,9 +1258,7 @@ impl Term {
self.cursor_save_alt.point.line = min(self.cursor_save_alt.point.line, num_lines - 1);
// Recreate tabs list
- self.tabs = IndexRange::from(Column(0)..self.grid.num_cols())
- .map(|i| (*i as usize) % self.tabspaces == 0)
- .collect::<Vec<bool>>();
+ self.tabs = TabStops::new(self.grid.num_cols(), self.tabspaces);
}
#[inline]
@@ -1553,23 +1577,26 @@ impl ansi::Handler for Term {
fn put_tab(&mut self, mut count: i64) {
trace!("put_tab: {}", count);
- let mut col = self.cursor.point.col;
- while col < self.grid.num_cols() && count != 0 {
+ while self.cursor.point.col < self.grid.num_cols() && count != 0 {
count -= 1;
+
+ let cell = &mut self.grid[&self.cursor.point];
+ *cell = self.cursor.template;
+ cell.c = self.cursor.charsets[self.active_charset].map('\t');
+
loop {
- if (col + 1) == self.grid.num_cols() {
+ if (self.cursor.point.col + 1) == self.grid.num_cols() {
break;
}
- col += 1;
+ self.cursor.point.col += 1;
- if self.tabs[*col as usize] {
+ if self.tabs[self.cursor.point.col] {
break;
}
}
}
- self.cursor.point.col = col;
self.input_needs_wrap = false;
}
@@ -1651,7 +1678,7 @@ impl ansi::Handler for Term {
fn set_horizontal_tabstop(&mut self) {
trace!("set_horizontal_tabstop");
let column = self.cursor.point.col;
- self.tabs[column.0] = true;
+ self.tabs[column] = true;
}
#[inline]
@@ -1731,7 +1758,7 @@ impl ansi::Handler for Term {
for _ in 0..count {
let mut col = self.cursor.point.col;
for i in (0..(col.0)).rev() {
- if self.tabs[i as usize] {
+ if self.tabs[index::Column(i)] {
col = index::Column(i);
break;
}
@@ -1874,15 +1901,10 @@ impl ansi::Handler for Term {
match mode {
ansi::TabulationClearMode::Current => {
let column = self.cursor.point.col;
- self.tabs[column.0] = false;
+ self.tabs[column] = false;
},
ansi::TabulationClearMode::All => {
- let len = self.tabs.len();
- // Safe since false boolean is null, each item occupies only 1
- // byte, and called on the length of the vec.
- unsafe {
- ::std::ptr::write_bytes(self.tabs.as_mut_ptr(), 0, len);
- }
+ self.tabs.clear_all();
}
}
}
@@ -2068,6 +2090,40 @@ impl ansi::Handler for Term {
}
}
+struct TabStops {
+ tabs: Vec<bool>
+}
+
+impl TabStops {
+ fn new(num_cols: Column, tabspaces: usize) -> TabStops {
+ TabStops {
+ tabs: IndexRange::from(Column(0)..num_cols)
+ .map(|i| (*i as usize) % tabspaces == 0)
+ .collect::<Vec<bool>>()
+ }
+ }
+
+ fn clear_all(&mut self) {
+ unsafe {
+ ptr::write_bytes(self.tabs.as_mut_ptr(), 0, self.tabs.len());
+ }
+ }
+}
+
+impl Index<Column> for TabStops {
+ type Output = bool;
+
+ fn index(&self, index: Column) -> &bool {
+ &self.tabs[index.0]
+ }
+}
+
+impl IndexMut<Column> for TabStops {
+ fn index_mut(&mut self, index: Column) -> &mut bool {
+ self.tabs.index_mut(index.0)
+ }
+}
+
#[cfg(test)]
mod tests {
use serde_json;