aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2019-11-05 10:26:19 -0500
committerJesse Luehrs <doy@tozt.net>2019-11-05 10:26:19 -0500
commit665238f5318bee40f254fe43aa158e61bdd25392 (patch)
tree19d2c6828a6263ec3b2b9ee44363774ecdaaca5c
parentb24d69d51b3567f75630bb1b3a6875dac6e1c647 (diff)
downloadvt100-rust-665238f5318bee40f254fe43aa158e61bdd25392.tar.gz
vt100-rust-665238f5318bee40f254fe43aa158e61bdd25392.zip
contents_formatted should return a Vec<u8>
the overall terminal escape sequence byte stream is not necessarily utf8-safe, even if individual cell contents are
-rw-r--r--src/attrs.rs19
-rw-r--r--src/grid.rs23
-rw-r--r--src/row.rs10
-rw-r--r--src/screen.rs2
-rw-r--r--tests/escape.rs12
-rw-r--r--tests/init.rs2
-rw-r--r--tests/split-escapes.rs2
-rw-r--r--tests/window_contents.rs16
8 files changed, 52 insertions, 34 deletions
diff --git a/src/attrs.rs b/src/attrs.rs
index f1b59a6..95a5e76 100644
--- a/src/attrs.rs
+++ b/src/attrs.rs
@@ -87,11 +87,11 @@ impl Attrs {
}
}
- pub fn escape_code_diff(&self, other: &Self) -> String {
+ pub fn escape_code_diff(&self, other: &Self) -> Vec<u8> {
let mut opts = vec![];
if self != other && self == &Self::default() {
- return "\x1b[m".to_string();
+ return b"\x1b[m".to_vec();
}
if self.fgcolor != other.fgcolor {
@@ -159,8 +159,17 @@ impl Attrs {
opts.push(if self.inverse() { 7 } else { 27 });
}
- let strs: Vec<_> =
- opts.iter().map(std::string::ToString::to_string).collect();
- format!("\x1b[{}m", strs.join(";"))
+ let mut bytes = b"\x1b[".to_vec();
+ let mut first = true;
+ for opt in opts {
+ if first {
+ first = false;
+ } else {
+ bytes.push(b';');
+ }
+ bytes.extend(opt.to_string().as_bytes());
+ }
+ bytes.push(b'm');
+ bytes
}
}
diff --git a/src/grid.rs b/src/grid.rs
index a5bca31..50942f4 100644
--- a/src/grid.rs
+++ b/src/grid.rs
@@ -139,18 +139,27 @@ impl Grid {
col_start: u16,
row_end: u16,
col_end: u16,
- ) -> String {
- let mut contents = String::new();
+ ) -> 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) {
- let (new_contents, new_attrs) =
- &row.contents_formatted(col_start, col_end, prev_attrs);
- contents += new_contents;
- prev_attrs = *new_attrs;
+ let (mut new_contents, new_attrs) =
+ row.contents_formatted(col_start, col_end, prev_attrs);
+ contents.append(&mut new_contents);
+ prev_attrs = new_attrs;
}
- contents.trim_end().to_string()
+
+ let mut idx = None;
+ for (i, b) in contents.iter().enumerate().rev() {
+ if !(*b as char).is_whitespace() {
+ idx = Some(i + 1);
+ break;
+ }
+ }
+ contents.truncate(idx.unwrap_or(0));
+ contents
}
pub fn erase_all(&mut self) {
diff --git a/src/row.rs b/src/row.rs
index 220cc0c..4246d33 100644
--- a/src/row.rs
+++ b/src/row.rs
@@ -91,9 +91,9 @@ impl Row {
col_start: u16,
col_end: u16,
attrs: crate::attrs::Attrs,
- ) -> (String, crate::attrs::Attrs) {
+ ) -> (Vec<u8>, crate::attrs::Attrs) {
let mut prev_was_wide = false;
- let mut contents = String::new();
+ 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)) {
@@ -106,7 +106,7 @@ impl Row {
let attrs = cell.attrs();
if &prev_attrs != attrs {
- contents += &attrs.escape_code_diff(&prev_attrs);
+ contents.append(&mut attrs.escape_code_diff(&prev_attrs));
prev_attrs = *attrs;
}
@@ -116,13 +116,13 @@ impl Row {
} else {
cell_contents
};
- contents += cell_contents;
+ contents.extend(cell_contents.as_bytes());
prev_was_wide = cell.is_wide();
}
}
if !self.wrapped {
- contents += "\r\n";
+ contents.extend(b"\r\n");
}
(contents, prev_attrs)
}
diff --git a/src/screen.rs b/src/screen.rs
index 63d7205..a1bf53b 100644
--- a/src/screen.rs
+++ b/src/screen.rs
@@ -151,7 +151,7 @@ impl Screen {
col_start: u16,
row_end: u16,
col_end: u16,
- ) -> String {
+ ) -> Vec<u8> {
self.grid()
.contents_formatted(row_start, col_start, row_end, col_end)
}
diff --git a/tests/escape.rs b/tests/escape.rs
index d2dd5b1..2c7d745 100644
--- a/tests/escape.rs
+++ b/tests/escape.rs
@@ -26,7 +26,7 @@ fn ris() {
assert_eq!(cell.contents(), "");
assert_eq!(parser.screen().contents(0, 0, 23, 79), "");
- assert_eq!(parser.screen().contents_formatted(0, 0, 23, 79), "");
+ assert_eq!(parser.screen().contents_formatted(0, 0, 23, 79), b"");
assert_eq!(parser.screen().title(), "");
assert_eq!(parser.screen().icon_name(), "");
@@ -64,7 +64,7 @@ fn ris() {
assert_eq!(parser.screen().contents(0, 0, 23, 79), "foo");
assert_eq!(
parser.screen().contents_formatted(0, 0, 23, 79),
- "f\x1b[31;47;1;3;4moo"
+ b"f\x1b[31;47;1;3;4moo"
);
assert_eq!(parser.screen().title(), "window title");
@@ -100,7 +100,7 @@ fn ris() {
assert_eq!(cell.contents(), "");
assert_eq!(parser.screen().contents(0, 0, 23, 79), "");
- assert_eq!(parser.screen().contents_formatted(0, 0, 23, 79), "");
+ assert_eq!(parser.screen().contents_formatted(0, 0, 23, 79), b"");
// title and icon name don't change with reset
assert_eq!(parser.screen().title(), "window title");
@@ -168,20 +168,20 @@ fn decsc() {
assert_eq!(parser.screen().cursor_position(), (4, 3));
assert_eq!(
parser.screen().contents_formatted(0, 0, 23, 79),
- "\r\n\r\n\r\n\r\n\x1b[31mfoo"
+ b"\r\n\r\n\r\n\r\n\x1b[31mfoo"
);
parser.process(b"\x1b[32m\x1b[?6lbar");
assert_eq!(parser.screen().cursor_position(), (0, 3));
assert_eq!(
parser.screen().contents_formatted(0, 0, 23, 79),
- "\x1b[32mbar\r\n\r\n\r\n\r\n\x1b[31mfoo"
+ b"\x1b[32mbar\r\n\r\n\r\n\r\n\x1b[31mfoo"
);
parser.process(b"\x1b8\x1b[Hz");
assert_eq!(parser.screen().cursor_position(), (4, 1));
assert_eq!(
parser.screen().contents_formatted(0, 0, 23, 79),
- "\x1b[32mbar\r\n\r\n\r\n\r\n\x1b[31mzoo"
+ b"\x1b[32mbar\r\n\r\n\r\n\r\n\x1b[31mzoo"
);
}
diff --git a/tests/init.rs b/tests/init.rs
index cf9d146..61395e4 100644
--- a/tests/init.rs
+++ b/tests/init.rs
@@ -16,7 +16,7 @@ fn init() {
assert!(cell.is_none());
assert_eq!(parser.screen().contents(0, 0, 23, 79), "");
- assert_eq!(parser.screen().contents_formatted(0, 0, 23, 79), "");
+ assert_eq!(parser.screen().contents_formatted(0, 0, 23, 79), b"");
assert_eq!(parser.screen().title(), "");
assert_eq!(parser.screen().icon_name(), "");
diff --git a/tests/split-escapes.rs b/tests/split-escapes.rs
index 36a9eaa..157ff29 100644
--- a/tests/split-escapes.rs
+++ b/tests/split-escapes.rs
@@ -7,7 +7,7 @@ fn get_file_contents(name: &str) -> Vec<u8> {
buf
}
-fn write_to_parser(chunks: &mut Vec<Vec<u8>>) -> (String, String) {
+fn write_to_parser(chunks: &mut Vec<Vec<u8>>) -> (String, Vec<u8>) {
let mut parser = vt100::Parser::new(37, 193);
for chunk in chunks.iter_mut() {
parser.process(&chunk);
diff --git a/tests/window_contents.rs b/tests/window_contents.rs
index 898351e..5fe0cda 100644
--- a/tests/window_contents.rs
+++ b/tests/window_contents.rs
@@ -2,7 +2,7 @@
fn formatted() {
let mut parser = vt100::Parser::new(24, 80);
compare_formatted(&parser);
- assert_eq!(parser.screen().contents_formatted(0, 0, 23, 79), "");
+ assert_eq!(parser.screen().contents_formatted(0, 0, 23, 79), b"");
parser.process(b"foobar");
compare_formatted(&parser);
@@ -10,7 +10,7 @@ fn formatted() {
assert!(!parser.screen().cell(0, 3).unwrap().bold());
assert!(!parser.screen().cell(0, 4).unwrap().bold());
assert!(!parser.screen().cell(0, 5).unwrap().bold());
- assert_eq!(parser.screen().contents_formatted(0, 0, 23, 79), "foobar");
+ assert_eq!(parser.screen().contents_formatted(0, 0, 23, 79), b"foobar");
parser.process(b"\x1b[1;4H\x1b[1;7m\x1b[33mb");
compare_formatted(&parser);
@@ -20,7 +20,7 @@ fn formatted() {
assert!(!parser.screen().cell(0, 5).unwrap().bold());
assert_eq!(
parser.screen().contents_formatted(0, 0, 23, 79),
- "foo\x1b[33;1;7mb\x1b[mar"
+ b"foo\x1b[33;1;7mb\x1b[mar"
);
parser.process(b"\x1b[1;5H\x1b[22;42ma");
@@ -31,27 +31,27 @@ fn formatted() {
assert!(!parser.screen().cell(0, 5).unwrap().bold());
assert_eq!(
parser.screen().contents_formatted(0, 0, 23, 79),
- "foo\x1b[33;1;7mb\x1b[42;22ma\x1b[mr"
+ b"foo\x1b[33;1;7mb\x1b[42;22ma\x1b[mr"
);
parser.process(b"\x1b[1;6H\x1b[35mr\r\nquux");
compare_formatted(&parser);
assert_eq!(
parser.screen().contents_formatted(0, 0, 23, 79),
- "foo\x1b[33;1;7mb\x1b[42;22ma\x1b[35mr\r\nquux"
+ &b"foo\x1b[33;1;7mb\x1b[42;22ma\x1b[35mr\r\nquux"[..]
);
parser.process(b"\x1b[2;1H\x1b[45mquux");
compare_formatted(&parser);
assert_eq!(
parser.screen().contents_formatted(0, 0, 23, 79),
- "foo\x1b[33;1;7mb\x1b[42;22ma\x1b[35mr\r\n\x1b[45mquux"
+ &b"foo\x1b[33;1;7mb\x1b[42;22ma\x1b[35mr\r\n\x1b[45mquux"[..]
);
parser
.process(b"\x1b[2;2H\x1b[38;2;123;213;231mu\x1b[38;5;254mu\x1b[39mx");
compare_formatted(&parser);
- assert_eq!(parser.screen().contents_formatted(0, 0 ,23, 79), "foo\x1b[33;1;7mb\x1b[42;22ma\x1b[35mr\r\n\x1b[45mq\x1b[38;2;123;213;231mu\x1b[38;5;254mu\x1b[39mx");
+ assert_eq!(parser.screen().contents_formatted(0, 0 ,23, 79), &b"foo\x1b[33;1;7mb\x1b[42;22ma\x1b[35mr\r\n\x1b[45mq\x1b[38;2;123;213;231mu\x1b[38;5;254mu\x1b[39mx"[..]);
}
fn compare_formatted(parser: &vt100::Parser) {
@@ -59,7 +59,7 @@ fn compare_formatted(parser: &vt100::Parser) {
let contents =
parser.screen().contents_formatted(0, 0, rows - 1, cols - 1);
let mut parser2 = vt100::Parser::new(rows, cols);
- parser2.process(contents.as_bytes());
+ parser2.process(&contents);
compare_cells(parser, &parser2);
}