summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/encoding.rs28
-rw-r--r--src/main.rs53
-rw-r--r--src/terminal.rs32
-rw-r--r--src/types.rs1
4 files changed, 100 insertions, 14 deletions
diff --git a/src/encoding.rs b/src/encoding.rs
new file mode 100644
index 0000000..7d5326e
--- /dev/null
+++ b/src/encoding.rs
@@ -0,0 +1,28 @@
+#![forbid(unsafe_code)]
+
+
+#[derive(Clone, Copy, Debug)]
+pub enum UTF8ByteType {
+  Single,
+  Introducer(u8),
+  Continuation,
+  Invalid,
+}
+
+
+pub fn get_utf8_byte_type(b: u8) -> UTF8ByteType {
+  if b & 0x80 == 0 {
+    UTF8ByteType::Single
+  } else if b & 0xC0 == 0x80 {
+    UTF8ByteType::Continuation
+  } else if b & 0xE0 == 0xC0 {
+    UTF8ByteType::Introducer(2)
+  } else if b & 0xF0 == 0xE0 {
+    UTF8ByteType::Introducer(3)
+  } else if b & 0xF8 == 0xF0 {
+    UTF8ByteType::Introducer(4)
+  } else {
+    UTF8ByteType::Invalid
+  }
+}
+
diff --git a/src/main.rs b/src/main.rs
index d0c07e9..1753688 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,14 +2,13 @@
 use crate::types::*;
 use smol::prelude::*;
 
-use smol::Timer;
 use smol::fs::File;
 use smol::lock::RwLock;
 use std::path::PathBuf;
 use std::process::ExitCode;
 use std::ops::Range;
-use std::time::Duration;
 
+mod encoding;
 mod terminal;
 mod types;
 
@@ -50,24 +49,39 @@ impl Ivy {
   }
 
   async fn run(mut self) -> Result<()> {
+    /* The awkward structure here is because it's important that cleanup still
+     * happen even if something fails in the middle.
+     */
     let mut error = None;
 
-    error = error.or(self.init_arguments().await.err());
-    error = error.or(self.init_editor().await.err());
+    error = error.or(self.init().await.err());
+    error = error.or(self.interact().await.err());
+    error = error.or(self.zap().await.err());
 
-    error = error.or(self.terminal.write().await
-                         .init_termios().await.err());
-    error = error.or(self.terminal.write().await
-                         .init_full_screen().await.err());
+    if let Some(error) = error {
+      Err(error)
+    } else {
+      Ok(())
+    }
+  }
 
-    error = error.or(self.draw().await.err());
+  async fn init(&mut self) -> Result<()> {
+    self.init_arguments().await?;
+    self.init_editor().await?;
 
-    Timer::after(Duration::from_millis(1000)).await;
+    self.terminal.write().await.init_termios().await?;
+    self.terminal.write().await.init_full_screen().await?;
 
-    error = error.or(self.terminal.write().await
-                         .zap_full_screen().await.err());
-    error = error.or(self.terminal.write().await
-                         .zap_termios().await.err());
+    Ok(())
+  }
+
+  async fn zap(&mut self) -> Result<()> {
+    let mut error = None;
+
+    error = error.or(
+        self.terminal.write().await.zap_full_screen().await.err());
+    error = error.or(
+        self.terminal.write().await.zap_termios().await.err());
 
     if let Some(error) = error {
       Err(error)
@@ -100,6 +114,17 @@ impl Ivy {
     Ok(())
   }
 
+  async fn interact(&mut self) -> Result<()> {
+    self.draw().await?;
+
+    loop {
+      let c = self.terminal.write().await.read_char().await;
+      println!("c {:?}", c);
+      smol::Timer::after(std::time::Duration::from_millis(1000)).await;
+      return Ok(());
+    }
+  }
+
   async fn draw(&mut self) -> Result<()> {
     let mut terminal = self.terminal.write().await;
     let buffer = self.buffer.read().await;
diff --git a/src/terminal.rs b/src/terminal.rs
index 78727c8..d812069 100644
--- a/src/terminal.rs
+++ b/src/terminal.rs
@@ -2,6 +2,8 @@
 use crate::types::*;
 use smol::prelude::*;
 
+use crate::encoding;
+
 use smol::{ unblock, Unblock };
 use smol::lock::{ OnceCell, RwLock };
 use std::fmt::Display;
@@ -88,6 +90,36 @@ impl Terminal {
     Ok(())
   }
 
+  pub async fn read_char(&mut self) -> Result<char> {
+    let mut buf = vec![0; 4];
+
+    loop {
+      self.stdin.read_exact(&mut buf[0 .. 1]).await?;
+
+      match encoding::get_utf8_byte_type(buf[0]) {
+        UTF8ByteType::Single => { },
+        UTF8ByteType::Introducer(2) => {
+          self.stdin.read_exact(&mut buf[1 .. 2]).await?;
+        },
+        UTF8ByteType::Introducer(3) => {
+          self.stdin.read_exact(&mut buf[1 .. 3]).await?;
+        },
+        UTF8ByteType::Introducer(4) => {
+          self.stdin.read_exact(&mut buf[1 .. 4]).await?;
+        },
+
+        /* If it's not the start of a valid character, ignore it. */
+        _ => continue,
+      }
+
+      if let Ok(string) = std::str::from_utf8(&buf)
+         && let Some(c) = string.chars().next()
+      {
+        return Ok(c);
+      }
+    }
+  }
+
   pub async fn do_escape(&mut self, escape_type: EscapeType, code: &str,
                          parameters: &[impl Display])
       -> Result<()>
diff --git a/src/types.rs b/src/types.rs
index ef45492..1f74216 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -1,4 +1,5 @@
 #![forbid(unsafe_code)]
+pub use crate::encoding::UTF8ByteType;
 pub use crate::terminal::Terminal;
 
 pub type Error = std::io::Error;