aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml1
-rw-r--r--src/cell.rs13
-rw-r--r--src/grid.rs4
-rw-r--r--src/lib.rs1
-rw-r--r--src/row.rs18
-rw-r--r--src/screen.rs52
-rw-r--r--src/unicode.rs14
7 files changed, 96 insertions, 7 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 105dfc6..d9d8642 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,4 +12,5 @@ keywords = ["terminal", "vt100"]
license = "MIT"
[dependencies]
+unicode-width = "0.1"
vte = "0.3"
diff --git a/src/cell.rs b/src/cell.rs
index 2dc1ee4..3d2a9fa 100644
--- a/src/cell.rs
+++ b/src/cell.rs
@@ -14,6 +14,15 @@ impl Cell {
self.attrs = a;
}
+ pub(crate) fn append(&mut self, c: char) {
+ self.contents.push(c);
+ }
+
+ pub(crate) fn reset(&mut self) {
+ self.contents = String::new();
+ self.attrs = crate::attrs::Attrs::default();
+ }
+
pub fn contents(&self) -> &str {
&self.contents
}
@@ -22,6 +31,10 @@ impl Cell {
self.contents != ""
}
+ pub fn is_wide(&self) -> bool {
+ crate::unicode::str_width(&self.contents) > 1
+ }
+
pub fn fgcolor(&self) -> crate::color::Color {
self.attrs.fgcolor
}
diff --git a/src/grid.rs b/src/grid.rs
index 7d6d487..8b03dac 100644
--- a/src/grid.rs
+++ b/src/grid.rs
@@ -276,8 +276,8 @@ impl Grid {
self.col_clamp();
}
- pub fn col_wrap(&mut self) {
- if self.pos.col > self.size.cols - 1 {
+ pub fn col_wrap(&mut self, width: u16) {
+ if self.pos.col > self.size.cols - width {
self.current_row_mut().unwrap().wrap(true);
self.pos.col = 0;
self.row_inc_scroll(1);
diff --git a/src/lib.rs b/src/lib.rs
index 3956b7a..b77b5e1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -9,6 +9,7 @@ mod color;
mod grid;
mod row;
mod screen;
+mod unicode;
pub use cell::Cell;
pub use color::Color;
diff --git a/src/row.rs b/src/row.rs
index 65f3cd2..1d9df56 100644
--- a/src/row.rs
+++ b/src/row.rs
@@ -40,25 +40,39 @@ impl Row {
self.wrapped = wrap;
}
+ pub fn wrapped(&self) -> bool {
+ self.wrapped
+ }
+
pub fn contents(&self, col_start: u16, col_end: u16) -> String {
+ let mut prev_was_wide = false;
// XXX very inefficient
let mut max_col = None;
for (col, cell) in self.cells.iter().enumerate() {
- if cell.has_contents() {
+ if cell.has_contents() || prev_was_wide {
max_col = Some(col);
+ prev_was_wide = cell.is_wide();
}
}
+ prev_was_wide = false;
let mut contents = String::new();
if let Some(max_col) = max_col {
for col in col_start..=(col_end.min(max_col as u16)) {
- let cell_contents = self.cells[col as usize].contents();
+ if prev_was_wide {
+ prev_was_wide = false;
+ continue;
+ }
+
+ let cell = &self.cells[col as usize];
+ let cell_contents = cell.contents();
let cell_contents = if cell_contents == "" {
" "
} else {
cell_contents
};
contents += cell_contents;
+ prev_was_wide = cell.is_wide();
}
}
if !self.wrapped {
diff --git a/src/screen.rs b/src/screen.rs
index f26d8a7..cf7ab82 100644
--- a/src/screen.rs
+++ b/src/screen.rs
@@ -56,6 +56,10 @@ impl State {
}
}
+ fn row(&self, pos: crate::grid::Pos) -> Option<&crate::row::Row> {
+ self.grid().row(pos)
+ }
+
fn cell(&self, pos: crate::grid::Pos) -> Option<&crate::cell::Cell> {
self.grid().cell(pos)
}
@@ -89,11 +93,53 @@ impl State {
// control codes
fn text(&mut self, c: char) {
+ let pos = *self.grid().pos();
+ if pos.col > 0 {
+ let prev_cell = self
+ .cell_mut(crate::grid::Pos {
+ row: pos.row,
+ col: pos.col - 1,
+ })
+ .unwrap();
+ if prev_cell.is_wide() {
+ prev_cell.reset();
+ }
+ }
+
+ let width = crate::unicode::char_width(c);
let attrs = self.attrs;
- self.grid_mut().col_wrap();
+ self.grid_mut().col_wrap(width as u16);
if let Some(cell) = self.current_cell_mut() {
- cell.set(c.to_string(), attrs);
- self.grid_mut().col_inc(1);
+ if width == 0 {
+ if pos.col > 0 {
+ let prev_cell = self
+ .cell_mut(crate::grid::Pos {
+ row: pos.row,
+ col: pos.col - 1,
+ })
+ .unwrap();
+ prev_cell.append(c);
+ } else if pos.row > 0 {
+ let prev_row = self
+ .row(crate::grid::Pos {
+ row: pos.row - 1,
+ col: 0,
+ })
+ .unwrap();
+ if prev_row.wrapped() {
+ let prev_cell = self
+ .cell_mut(crate::grid::Pos {
+ row: pos.row - 1,
+ col: self.grid().size().cols - 1,
+ })
+ .unwrap();
+ prev_cell.append(c);
+ }
+ }
+ } else {
+ cell.set(c.to_string(), attrs);
+ self.grid_mut().col_inc(width as u16);
+ }
} else {
panic!("couldn't find current cell")
}
diff --git a/src/unicode.rs b/src/unicode.rs
new file mode 100644
index 0000000..5cf597e
--- /dev/null
+++ b/src/unicode.rs
@@ -0,0 +1,14 @@
+use unicode_width::UnicodeWidthChar as _;
+
+// soft hyphen is defined as width 1, but in a terminal setting it should
+// always be width 0
+pub fn char_width(c: char) -> usize {
+ match c {
+ '\u{00ad}' => 0,
+ _ => c.width().unwrap_or(0),
+ }
+}
+
+pub fn str_width(s: &str) -> usize {
+ s.chars().map(char_width).sum()
+}