aboutsummaryrefslogtreecommitdiff
path: root/alacritty_terminal/src/term/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'alacritty_terminal/src/term/mod.rs')
-rw-r--r--alacritty_terminal/src/term/mod.rs93
1 files changed, 73 insertions, 20 deletions
diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs
index ddba07ef..57733bf5 100644
--- a/alacritty_terminal/src/term/mod.rs
+++ b/alacritty_terminal/src/term/mod.rs
@@ -281,6 +281,49 @@ impl<'a, C> RenderableCellsIter<'a, C> {
cursor_style,
}
}
+
+ /// Check selection state of a cell.
+ fn is_selected(&self, point: Point) -> bool {
+ let selection = match self.selection {
+ Some(selection) => selection,
+ None => return false,
+ };
+
+ // Point itself is selected
+ if selection.contains(point.col, point.line) {
+ return true;
+ }
+
+ let num_cols = self.grid.num_cols().0;
+ let cell = self.grid[&point];
+
+ // Check if wide char's spacers are selected
+ if cell.flags.contains(Flags::WIDE_CHAR) {
+ let prevprev = point.sub(num_cols, 2);
+ let prev = point.sub(num_cols, 1);
+ let next = point.add(num_cols, 1);
+
+ // Check trailing spacer
+ selection.contains(next.col, next.line)
+ // Check line-wrapping, leading spacer
+ || (self.grid[&prev].flags.contains(Flags::WIDE_CHAR_SPACER)
+ && !self.grid[&prevprev].flags.contains(Flags::WIDE_CHAR)
+ && selection.contains(prev.col, prev.line))
+ } else if cell.flags.contains(Flags::WIDE_CHAR_SPACER) {
+ // Check if spacer's wide char is selected
+ let prev = point.sub(num_cols, 1);
+
+ if self.grid[&prev].flags.contains(Flags::WIDE_CHAR) {
+ // Check previous cell for trailing spacer
+ self.is_selected(prev)
+ } else {
+ // Check next cell for line-wrapping, leading spacer
+ self.is_selected(point.add(num_cols, 1))
+ }
+ } else {
+ false
+ }
+ }
}
#[derive(Copy, Clone, Debug)]
@@ -414,11 +457,7 @@ impl<'a, C> Iterator for RenderableCellsIter<'a, C> {
fn next(&mut self) -> Option<Self::Item> {
loop {
if self.cursor_offset == self.inner.offset() && self.inner.column() == self.cursor.col {
- let selected = self
- .selection
- .as_ref()
- .map(|range| range.contains(self.cursor.col, self.cursor.line))
- .unwrap_or(false);
+ let selected = self.is_selected(Point::new(self.cursor.line, self.cursor.col));
// Handle cursor
if let Some(cursor_key) = self.cursor_key.take() {
@@ -458,11 +497,7 @@ impl<'a, C> Iterator for RenderableCellsIter<'a, C> {
} else {
let cell = self.inner.next()?;
- let selected = self
- .selection
- .as_ref()
- .map(|range| range.contains(cell.column, cell.line))
- .unwrap_or(false);
+ let selected = self.is_selected(Point::new(cell.line, cell.column));
if !cell.is_empty() || selected {
return Some(RenderableCell::new(self.config, self.colors, cell, selected));
@@ -949,9 +984,9 @@ impl<T> Term<T> {
if is_block {
for line in (end.line + 1..=start.line).rev() {
- res += &(self.line_to_string(line, start.col..end.col) + "\n");
+ res += &(self.line_to_string(line, start.col..end.col, start.col.0 != 0) + "\n");
}
- res += &self.line_to_string(end.line, start.col..end.col);
+ res += &self.line_to_string(end.line, start.col..end.col, true);
} else {
res = self.bounds_to_string(start, end);
}
@@ -967,23 +1002,31 @@ impl<T> Term<T> {
let start_col = if line == start.line { start.col } else { Column(0) };
let end_col = if line == end.line { end.col } else { self.cols() - 1 };
- res += &self.line_to_string(line, start_col..end_col);
+ res += &self.line_to_string(line, start_col..end_col, line == end.line);
}
res
}
/// Convert a single line in the grid to a String.
- fn line_to_string(&self, line: usize, cols: Range<Column>) -> String {
+ fn line_to_string(
+ &self,
+ line: usize,
+ mut cols: Range<Column>,
+ include_wrapped_wide: bool,
+ ) -> String {
let mut text = String::new();
let grid_line = &self.grid[line];
- let line_length = grid_line.line_length();
- let line_end = min(line_length, cols.end + 1);
+ let line_length = min(grid_line.line_length(), cols.end + 1);
- let mut tab_mode = false;
+ // Include wide char when trailing spacer is selected
+ if grid_line[cols.start].flags.contains(Flags::WIDE_CHAR_SPACER) {
+ cols.start -= 1;
+ }
- for col in IndexRange::from(cols.start..line_end) {
+ let mut tab_mode = false;
+ for col in IndexRange::from(cols.start..line_length) {
let cell = grid_line[col];
// Skip over cells until next tab-stop once a tab was found
@@ -1011,12 +1054,22 @@ impl<T> Term<T> {
}
if cols.end >= self.cols() - 1
- && (line_end == Column(0)
- || !self.grid[line][line_end - 1].flags.contains(Flags::WRAPLINE))
+ && (line_length.0 == 0
+ || !self.grid[line][line_length - 1].flags.contains(Flags::WRAPLINE))
{
text.push('\n');
}
+ // If wide char is not part of the selection, but leading spacer is, include it
+ if line_length == self.grid.num_cols()
+ && line_length.0 >= 2
+ && grid_line[line_length - 1].flags.contains(Flags::WIDE_CHAR_SPACER)
+ && !grid_line[line_length - 2].flags.contains(Flags::WIDE_CHAR)
+ && include_wrapped_wide
+ {
+ text.push(self.grid[line - 1][Column(0)].c);
+ }
+
text
}