aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2019-11-05 12:53:25 -0500
committerJesse Luehrs <doy@tozt.net>2019-11-05 13:26:49 -0500
commit2e7f1686d719497d9b2d2d2c8ffba20e6c8214bd (patch)
tree8f31cb37faaec73bdf4a5253f0c34bceb3cc6d6f /src
parente12f9d9ee4e6b902436d0282e4a1e47ed7d54d6c (diff)
downloadvt100-rust-2e7f1686d719497d9b2d2d2c8ffba20e6c8214bd.tar.gz
vt100-rust-2e7f1686d719497d9b2d2d2c8ffba20e6c8214bd.zip
adjust the way window contents are reported
contents and contents_formatted now only allow getting the entire terminal contents, and for any other uses we now provide rows and rows_formatted. the reasoning here is that it wasn't particularly useful to return newline (or crlf) separated lines when not drawing the full terminal, since it's not like you can send those to the terminal in any meaningful way anyway (like, if you wanted to draw a subset of the terminal state, you'll almost certainly need to be doing explicit positioning on your own, since crlf is only actually correct if you're drawing the screen subset in the upper left hand corner of the screen). with this, you can draw each (subset of a) line individually, and reposition the cursor in whatever way makes sense in between drawing the lines.
Diffstat (limited to 'src')
-rw-r--r--src/grid.rs43
-rw-r--r--src/row.rs116
-rw-r--r--src/screen.rs65
3 files changed, 117 insertions, 107 deletions
diff --git a/src/grid.rs b/src/grid.rs
index d7abbad..14a3eae 100644
--- a/src/grid.rs
+++ b/src/grid.rs
@@ -123,48 +123,33 @@ impl Grid {
.expect("cursor not pointing to a cell")
}
- pub fn contents(
- &self,
- row_start: u16,
- col_start: u16,
- row_end: u16,
- col_end: u16,
- ) -> String {
+ pub fn contents(&self) -> String {
let mut contents = String::new();
- let row_start = row_start as usize;
- let row_end = row_end as usize;
- for row in self.rows().skip(row_start).take(row_end - row_start + 1) {
- contents += &row.contents(col_start, col_end);
+ for row in self.rows() {
+ contents += &row.contents(0, self.size.cols);
+ if !row.wrapped() {
+ contents += "\n";
+ }
}
contents.trim_end().to_string()
}
- pub fn contents_formatted(
- &self,
- row_start: u16,
- col_start: u16,
- row_end: u16,
- col_end: u16,
- ) -> Vec<u8> {
+ pub fn contents_formatted(&self) -> Vec<u8> {
let mut contents = vec![];
let mut prev_attrs = crate::attrs::Attrs::default();
- let row_start = row_start as usize;
- let row_end = row_end as usize;
- for row in self.rows().skip(row_start).take(row_end - row_start + 1) {
+ for row in self.rows() {
let (mut new_contents, new_attrs) =
- row.contents_formatted(col_start, col_end, prev_attrs);
+ row.contents_formatted(0, self.size.cols, prev_attrs);
contents.append(&mut new_contents);
+ if !row.wrapped() {
+ contents.extend(b"\r\n");
+ }
prev_attrs = new_attrs;
}
- let mut idx = None;
- for (i, b) in contents.iter().enumerate().rev() {
- if !(*b as char).is_whitespace() {
- idx = Some(i + 1);
- break;
- }
+ while contents.ends_with(b"\r\n") {
+ contents.truncate(contents.len() - 2);
}
- contents.truncate(idx.unwrap_or(0));
contents
}
diff --git a/src/row.rs b/src/row.rs
index cf668ce..ade6408 100644
--- a/src/row.rs
+++ b/src/row.rs
@@ -21,6 +21,10 @@ impl Row {
self.wrapped = false;
}
+ fn cells(&self) -> impl Iterator<Item = &crate::cell::Cell> {
+ self.cells.iter()
+ }
+
pub fn cells_mut(
&mut self,
) -> impl Iterator<Item = &mut crate::cell::Cell> {
@@ -59,84 +63,78 @@ impl Row {
self.wrapped
}
- pub fn contents(&self, col_start: u16, col_end: u16) -> String {
+ pub fn contents(&self, start: u16, width: u16) -> String {
let mut prev_was_wide = false;
let mut contents = String::new();
- if let Some(max_col) = self.max_col() {
- for col in col_start..=(col_end.min(max_col)) {
- 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();
+
+ for cell in self
+ .cells()
+ .skip(start as usize)
+ .take(width.min(self.content_width(start)) as usize)
+ {
+ if prev_was_wide {
+ prev_was_wide = false;
+ continue;
}
+
+ contents += if cell.has_contents() {
+ cell.contents()
+ } else {
+ " "
+ };
+ prev_was_wide = cell.is_wide();
}
- if !self.wrapped {
- contents += "\n";
- }
- contents
+
+ contents.trim_end().to_string()
}
pub fn contents_formatted(
&self,
- col_start: u16,
- col_end: u16,
+ start: u16,
+ width: u16,
attrs: crate::attrs::Attrs,
) -> (Vec<u8>, crate::attrs::Attrs) {
let mut prev_was_wide = false;
let mut contents = vec![];
let mut prev_attrs = attrs;
- if let Some(max_col) = self.max_col() {
- for col in col_start..=(col_end.min(max_col)) {
- if prev_was_wide {
- prev_was_wide = false;
- continue;
- }
-
- let cell = &self.cells[col as usize];
-
- let attrs = cell.attrs();
- if &prev_attrs != attrs {
- contents.append(&mut attrs.escape_code_diff(&prev_attrs));
- prev_attrs = *attrs;
- }
-
- let cell_contents = cell.contents();
- let cell_contents = if cell_contents == "" {
- "\x1b[C"
- } else {
- cell_contents
- };
- contents.extend(cell_contents.as_bytes());
-
- prev_was_wide = cell.is_wide();
+
+ for cell in self
+ .cells()
+ .skip(start as usize)
+ .take(width.min(self.content_width(start)) as usize)
+ {
+ if prev_was_wide {
+ prev_was_wide = false;
+ continue;
}
+
+ let attrs = cell.attrs();
+ if &prev_attrs != attrs {
+ contents.append(&mut attrs.escape_code_diff(&prev_attrs));
+ prev_attrs = *attrs;
+ }
+
+ contents.extend(if cell.has_contents() {
+ cell.contents().as_bytes()
+ } else {
+ b"\x1b[C"
+ });
+
+ prev_was_wide = cell.is_wide();
}
- if !self.wrapped {
- contents.extend(b"\r\n");
- }
+
(contents, prev_attrs)
}
- fn max_col(&self) -> Option<u16> {
- 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() || prev_was_wide {
- max_col = Some(col.try_into().unwrap());
- prev_was_wide = cell.is_wide();
+ fn content_width(&self, start: u16) -> u16 {
+ for (col, cell) in
+ self.cells.iter().skip(start as usize).enumerate().rev()
+ {
+ if cell.has_contents() {
+ let width: u16 = col.try_into().unwrap();
+ return width + 1;
}
}
- max_col
+ 0
}
}
diff --git a/src/screen.rs b/src/screen.rs
index a1bf53b..dd30b19 100644
--- a/src/screen.rs
+++ b/src/screen.rs
@@ -122,38 +122,65 @@ impl Screen {
(size.rows, size.cols)
}
- /// Returns the text contents of the subset of the terminal given by the
- /// parameters.
+ /// Returns the text contents of the terminal.
///
/// This will not include any formatting information, and will be in plain
/// text format.
- pub fn contents(
+ pub fn contents(&self) -> String {
+ self.grid().contents()
+ }
+
+ /// Returns the text contents of the terminal by row, restricted to the
+ /// given subset of columns.
+ ///
+ /// This will not include any formatting information, and will be in plain
+ /// text format.
+ ///
+ /// Newlines will not be included.
+ pub fn rows(
&self,
- row_start: u16,
- col_start: u16,
- row_end: u16,
- col_end: u16,
- ) -> String {
- self.grid().contents(row_start, col_start, row_end, col_end)
+ start: u16,
+ width: u16,
+ ) -> impl Iterator<Item = String> + '_ {
+ self.grid()
+ .rows()
+ .map(move |row| row.contents(start, width))
}
- /// Returns the formatted contents of the subset of the terminal given by
- /// the parameters.
+ /// Returns the formatted contents of the terminal.
///
/// Formatting information will be included inline as terminal escape
/// codes. The result will be suitable for feeding directly to a raw
/// terminal parser, and will result in the same visual output. Internal
/// terminal modes (such as application keypad mode or alternate screen
/// mode) will not be included here.
- pub fn contents_formatted(
+ pub fn contents_formatted(&self) -> Vec<u8> {
+ self.grid().contents_formatted()
+ }
+
+ /// Returns the formatted contents of the terminal by row, restricted to
+ /// the given subset of columns.
+ ///
+ /// Formatting information will be included inline as terminal escape
+ /// codes. The result will be suitable for feeding directly to a raw
+ /// terminal parser, and will result in the same visual output. Internal
+ /// terminal modes (such as application keypad mode or alternate screen
+ /// mode) will not be included here.
+ ///
+ /// CRLF at the end of lines will not be included.
+ pub fn rows_formatted(
&self,
- row_start: u16,
- col_start: u16,
- row_end: u16,
- col_end: u16,
- ) -> Vec<u8> {
- self.grid()
- .contents_formatted(row_start, col_start, row_end, col_end)
+ start: u16,
+ width: u16,
+ ) -> impl Iterator<Item = Vec<u8>> + '_ {
+ self.grid().rows().map(move |row| {
+ let (contents, _) = row.contents_formatted(
+ start,
+ width,
+ crate::attrs::Attrs::default(),
+ );
+ contents
+ })
}
/// Returns the `Cell` object at the given location in the terminal, if it