aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2021-03-06 18:45:50 -0500
committerJesse Luehrs <doy@tozt.net>2021-03-06 18:45:50 -0500
commita4bca446049fd488af29dd5ec26f953845e8e4fe (patch)
treefa7f129e5b27c00f29b4f33edbc31f2c68d89fda /src
parente358c58826b1732763970848c0c6d77f12ef5e5a (diff)
downloadtextmode-a4bca446049fd488af29dd5ec26f953845e8e4fe.tar.gz
textmode-a4bca446049fd488af29dd5ec26f953845e8e4fe.zip
split into sync and async implementations
Diffstat (limited to 'src')
-rw-r--r--src/async.rs67
-rw-r--r--src/lib.rs91
-rw-r--r--src/sync.rs65
3 files changed, 163 insertions, 60 deletions
diff --git a/src/async.rs b/src/async.rs
new file mode 100644
index 0000000..a384da8
--- /dev/null
+++ b/src/async.rs
@@ -0,0 +1,67 @@
+use futures_lite::io::AsyncWriteExt as _;
+
+use super::private::TextmodeImpl as _;
+
+pub struct Textmode {
+ cur: vt100::Parser,
+ next: vt100::Parser,
+}
+
+impl super::private::TextmodeImpl for Textmode {
+ fn cur(&self) -> &vt100::Parser {
+ &self.cur
+ }
+
+ fn cur_mut(&mut self) -> &mut vt100::Parser {
+ &mut self.cur
+ }
+
+ fn next(&self) -> &vt100::Parser {
+ &self.next
+ }
+
+ fn next_mut(&mut self) -> &mut vt100::Parser {
+ &mut self.next
+ }
+}
+
+impl super::Textmode for Textmode {}
+
+impl Textmode {
+ pub async fn new() -> std::io::Result<Self> {
+ let (rows, cols) = match terminal_size::terminal_size() {
+ Some((terminal_size::Width(w), terminal_size::Height(h))) => {
+ (h, w)
+ }
+ _ => (24, 80),
+ };
+ let cur = vt100::Parser::new(rows, cols, 0);
+ let next = vt100::Parser::new(rows, cols, 0);
+
+ let self_ = Self { cur, next };
+ self_
+ .write_stdout(b"\x1b7\x1b[?47h\x1b[2J\x1b[H\x1b[?25h")
+ .await?;
+ Ok(self_)
+ }
+
+ // TODO: without async drop or async closures, i'm not sure how to do
+ // better than this
+ pub async fn cleanup(&mut self) -> std::io::Result<()> {
+ self.write_stdout(b"\x1b[?47l\x1b8\x1b[?25h").await
+ }
+
+ pub async fn refresh(&mut self) -> std::io::Result<()> {
+ let diff = self.next().screen().contents_diff(self.cur().screen());
+ self.write_stdout(&diff).await?;
+ self.cur_mut().process(&diff);
+ Ok(())
+ }
+
+ async fn write_stdout(&self, buf: &[u8]) -> std::io::Result<()> {
+ let mut stdout = blocking::Unblock::new(std::io::stdout());
+ stdout.write_all(buf).await?;
+ stdout.flush().await?;
+ Ok(())
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 39c201b..fcee1e9 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,53 +1,47 @@
-use std::io::Write as _;
-
pub mod color;
-pub struct Textmode {
- cur: vt100::Parser,
- next: vt100::Parser,
-}
+#[cfg(feature = "async")]
+pub mod r#async;
+pub mod sync;
-impl Textmode {
- pub fn new() -> std::io::Result<Self> {
- let (rows, cols) = match terminal_size::terminal_size() {
- Some((terminal_size::Width(w), terminal_size::Height(h))) => {
- (h, w)
- }
- _ => (24, 80),
- };
- let cur = vt100::Parser::new(rows, cols, 0);
- let next = vt100::Parser::new(rows, cols, 0);
+mod private {
+ pub trait TextmodeImpl {
+ fn cur(&self) -> &vt100::Parser;
+ fn cur_mut(&mut self) -> &mut vt100::Parser;
+ fn next(&self) -> &vt100::Parser;
+ fn next_mut(&mut self) -> &mut vt100::Parser;
- let self_ = Self { cur, next };
- self_.write_stdout(b"\x1b7\x1b[?47h\x1b[2J\x1b[H\x1b[?25h")?;
- Ok(self_)
- }
+ fn write_u16(&mut self, i: u16) {
+ // unwrap is fine because vt100::Parser::write can never fail
+ itoa::write(self.next_mut(), i).unwrap();
+ }
- pub fn cursor_position(&self) -> (u16, u16) {
- self.next.screen().cursor_position()
+ fn write_u8(&mut self, i: u8) {
+ // unwrap is fine because vt100::Parser::write can never fail
+ itoa::write(self.next_mut(), i).unwrap();
+ }
}
+}
- pub fn write(&mut self, buf: &[u8]) {
- self.next.process(buf);
+pub trait Textmode: private::TextmodeImpl {
+ fn cursor_position(&self) -> (u16, u16) {
+ self.next().screen().cursor_position()
}
- pub fn refresh(&mut self) -> std::io::Result<()> {
- let diff = self.next.screen().contents_diff(self.cur.screen());
- self.write_stdout(&diff)?;
- self.cur.process(&diff);
- Ok(())
+ fn write(&mut self, buf: &[u8]) {
+ self.next_mut().process(buf);
}
- pub fn set_size(&mut self, rows: u16, cols: u16) {
- self.cur.set_size(rows, cols);
- self.next.set_size(rows, cols);
+ fn set_size(&mut self, rows: u16, cols: u16) {
+ self.cur_mut().set_size(rows, cols);
+ self.next_mut().set_size(rows, cols);
}
- pub fn write_str(&mut self, text: &str) {
+ fn write_str(&mut self, text: &str) {
self.write(text.as_bytes());
}
- pub fn move_to(&mut self, row: u16, col: u16) {
+ fn move_to(&mut self, row: u16, col: u16) {
self.write(b"\x1b[");
self.write_u16(row);
self.write(b";");
@@ -55,11 +49,11 @@ impl Textmode {
self.write(b"H");
}
- pub fn clear(&mut self) {
+ fn clear(&mut self) {
self.write(b"\x1b[2J");
}
- pub fn set_fgcolor(&mut self, color: vt100::Color) {
+ fn set_fgcolor(&mut self, color: vt100::Color) {
match color {
vt100::Color::Default => {
self.write(b"\x1b[39m");
@@ -87,7 +81,7 @@ impl Textmode {
}
}
- pub fn set_bgcolor(&mut self, color: vt100::Color) {
+ fn set_bgcolor(&mut self, color: vt100::Color) {
match color {
vt100::Color::Default => {
self.write(b"\x1b[49m");
@@ -114,27 +108,4 @@ impl Textmode {
}
}
}
-
- fn write_u16(&mut self, i: u16) {
- // unwrap is fine because vt100::Parser::write can never fail
- itoa::write(&mut self.next, i).unwrap();
- }
-
- fn write_u8(&mut self, i: u8) {
- // unwrap is fine because vt100::Parser::write can never fail
- itoa::write(&mut self.next, i).unwrap();
- }
-
- fn write_stdout(&self, buf: &[u8]) -> std::io::Result<()> {
- let mut stdout = std::io::stdout();
- stdout.write_all(buf)?;
- stdout.flush()?;
- Ok(())
- }
-}
-
-impl Drop for Textmode {
- fn drop(&mut self) {
- let _ = self.write_stdout(b"\x1b[?47l\x1b8\x1b[?25h");
- }
}
diff --git a/src/sync.rs b/src/sync.rs
new file mode 100644
index 0000000..047036d
--- /dev/null
+++ b/src/sync.rs
@@ -0,0 +1,65 @@
+use std::io::Write as _;
+
+use super::private::TextmodeImpl as _;
+
+pub struct Textmode {
+ cur: vt100::Parser,
+ next: vt100::Parser,
+}
+
+impl super::private::TextmodeImpl for Textmode {
+ fn cur(&self) -> &vt100::Parser {
+ &self.cur
+ }
+
+ fn cur_mut(&mut self) -> &mut vt100::Parser {
+ &mut self.cur
+ }
+
+ fn next(&self) -> &vt100::Parser {
+ &self.next
+ }
+
+ fn next_mut(&mut self) -> &mut vt100::Parser {
+ &mut self.next
+ }
+}
+
+impl super::Textmode for Textmode {}
+
+impl Textmode {
+ pub fn new() -> std::io::Result<Self> {
+ let (rows, cols) = match terminal_size::terminal_size() {
+ Some((terminal_size::Width(w), terminal_size::Height(h))) => {
+ (h, w)
+ }
+ _ => (24, 80),
+ };
+ let cur = vt100::Parser::new(rows, cols, 0);
+ let next = vt100::Parser::new(rows, cols, 0);
+
+ let self_ = Self { cur, next };
+ self_.write_stdout(b"\x1b7\x1b[?47h\x1b[2J\x1b[H\x1b[?25h")?;
+ Ok(self_)
+ }
+
+ pub fn refresh(&mut self) -> std::io::Result<()> {
+ let diff = self.next().screen().contents_diff(self.cur().screen());
+ self.write_stdout(&diff)?;
+ self.cur_mut().process(&diff);
+ Ok(())
+ }
+
+ fn write_stdout(&self, buf: &[u8]) -> std::io::Result<()> {
+ let mut stdout = std::io::stdout();
+ stdout.write_all(buf)?;
+ stdout.flush()?;
+ Ok(())
+ }
+}
+
+impl Drop for Textmode {
+ fn drop(&mut self) {
+ let _ = self.write_stdout(b"\x1b[?47l\x1b8\x1b[?25h");
+ }
+}