summary refs log tree commit diff
path: root/src/terminal.rs
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2024-03-12 22:06:24 -0700
committerIrene Knapp <ireneista@irenes.space>2024-03-12 22:06:24 -0700
commitf25a79763b9ae493598230a109eb0788def17199 (patch)
treedfcee3742e7086985c7392944b0b98308c89b2c7 /src/terminal.rs
parent7be9acd0bb08901c9fdfa45b694b7d3d5a594e70 (diff)
separate the main from the library, move it to an example HEAD main
Change-Id: I3478f222ee4b24d9d1796f0f58986186119bc2f7
Diffstat (limited to 'src/terminal.rs')
-rw-r--r--src/terminal.rs271
1 files changed, 0 insertions, 271 deletions
diff --git a/src/terminal.rs b/src/terminal.rs
deleted file mode 100644
index 405a719..0000000
--- a/src/terminal.rs
+++ /dev/null
@@ -1,271 +0,0 @@
-#![forbid(unsafe_code)]
-use crate::terminal::prelude::*;
-
-use crate::terminal::decoding::CharBufReader;
-
-use nix::sys::termios::{self, Termios};
-use std::os::unix::io::{AsRawFd, RawFd};
-use std::sync::Arc;
-use tokio::io::{self, AsyncRead, AsyncWriteExt};
-use tokio::signal::unix::{signal, SignalKind};
-use tokio::sync::{mpsc, Mutex};
-use tokio::task;
-
-pub mod decoding;
-pub mod error;
-pub mod prelude;
-
-
-#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)]
-struct Point {
-  x: usize,
-  y: usize,
-}
-
-impl Point {
-  pub fn new(x: usize, y: usize) -> Point {
-    Point {
-      x: x,
-      y: y,
-    }
-  }
-}
-
-
-#[derive(Debug,Eq,PartialEq)]
-struct LineBuffer {
-  lines: Vec<String>,
-  cursor: Point,
-}
-
-impl LineBuffer {
-  pub fn new() -> LineBuffer {
-    LineBuffer {
-      lines: vec![String::new()],
-      cursor: Point::new(0, 0),
-    }
-  }
-
-  pub fn insert(&mut self, input: &str) {
-    let line = &mut self.lines[self.cursor.y];
-    line.replace_range(self.cursor.x .. self.cursor.x, input);
-    self.cursor.x += input.len();
-  }
-
-  pub fn backspace(&mut self) {
-    if self.cursor.x > 0 {
-      let line = &mut self.lines[self.cursor.y];
-      line.replace_range(self.cursor.x - 1 .. self.cursor.x, "");
-      self.cursor.x -= 1;
-    } else if self.cursor.y > 0 {
-      let second_line = self.lines.remove(self.cursor.y);
-      let first_line = &mut self.lines[self.cursor.y - 1];
-
-      self.cursor.x = first_line.len();
-      self.cursor.y -= 1;
-
-      first_line.push_str(&second_line);
-    }
-  }
-
-  pub fn as_string(&self) -> String {
-    self.lines.join("\n")
-  }
-
-  pub fn cursor_to_end_of_line(&self) -> &str {
-    &self.lines[self.cursor.y][self.cursor.x ..]
-  }
-}
-
-
-pub enum Input {
-  String(String),
-  End,
-}
-
-
-#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)]
-enum InputAction {
-  Backspace,
-  Execute,
-}
-
-
-pub struct Terminal<InputStream: AsyncRead + Unpin> {
-  reader: Arc<Mutex<CharBufReader<InputStream>>>,
-  line_buffer: LineBuffer,
-  file_descriptor: RawFd,
-  initial_termios: Termios,
-  interrupt_receiver: mpsc::Receiver<()>,
-}
-
-
-async fn handle_signals(interrupt_sender: mpsc::Sender<()>) -> Result<()>
-{
-  let mut stream = signal(SignalKind::interrupt()).map_err(error::internal)?;
-  /* TODO make it work on other signals:
-    SignalKind::hangup();
-    SignalKind::interrupt();
-    SignalKind::terminate();
-    SignalKind::quit();
-    */
-
-  loop {
-    stream.recv().await;
-    interrupt_sender.send(()).await.map_err(error::internal)?;
-  }
-}
-
-
-impl<InputStream: AsyncRead + AsRawFd + Unpin> Terminal<InputStream> {
-  pub fn init(input_stream: InputStream) -> Result<Terminal<InputStream>> {
-    let (interrupt_sender, interrupt_receiver) = mpsc::channel(1);
-
-    let _ = task::spawn(handle_signals(interrupt_sender));
-
-    let fd = input_stream.as_raw_fd();
-    let termios = termios::tcgetattr(fd).map_err(error::mode_setting)?;
-    let reader = Arc::new(Mutex::new(CharBufReader::new(input_stream)));
-    let line_buffer = LineBuffer::new();
-
-    let terminal = Terminal {
-      reader: reader,
-      line_buffer: line_buffer,
-      file_descriptor: fd,
-      initial_termios: termios,
-      interrupt_receiver: interrupt_receiver,
-    };
-
-    terminal.init_modes()?;
-
-    Ok(terminal)
-  }
-
-
-  pub fn cleanup(self) -> Result<()> {
-    self.cleanup_modes()?;
-
-    Ok(())
-  }
-
-
-  fn init_modes(&self) -> Result<()> {
-    let mut termios = self.initial_termios.clone();
-
-    termios.local_flags.remove(termios::LocalFlags::ECHO);
-    termios.local_flags.remove(termios::LocalFlags::ECHONL);
-    termios.local_flags.remove(termios::LocalFlags::ECHOCTL);
-    termios.local_flags.remove(termios::LocalFlags::ICANON);
-
-    termios.local_flags.insert(termios::LocalFlags::ISIG);
-
-    termios.control_chars[termios::SpecialCharacterIndices::VMIN as usize] = 1;
-    termios.control_chars[termios::SpecialCharacterIndices::VTIME as usize] = 0;
-
-    termios::tcsetattr(self.file_descriptor,
-                       termios::SetArg::TCSANOW,
-                       &termios)
-        .map_err(error::mode_setting)?;
-
-    Ok(())
-  }
-
-
-  pub fn cleanup_modes(&self) -> Result<()> {
-    let termios = self.initial_termios.clone();
-
-    termios::tcsetattr(self.file_descriptor,
-                       termios::SetArg::TCSANOW,
-                       &termios)
-        .map_err(error::mode_setting)?;
-
-    Ok(())
-  }
-
-
-  pub async fn handle_input(&mut self) -> Result<Input>
-  {
-    let mut stdout = io::stdout();
-
-    loop {
-      let mut action: Option<InputAction> = None;
-
-      let string = tokio::select! {
-        result = CharBufReader::fill_buf(Arc::clone(&self.reader)) => {
-          let string: String = result.map_err(error::input)?;
-          string
-        }
-        _ = self.interrupt_receiver.recv() => {
-          return Ok(Input::End);
-        }
-      };
-
-      let mut chars = string.char_indices();
-
-      for (_, c) in &mut chars {
-        match c {
-          '\n' => {
-            action = Some(InputAction::Execute);
-          }
-          '\u{7f}' => {
-            action = Some(InputAction::Backspace);
-          }
-          _ => {
-            self.line_buffer.insert(&c.to_string());
-
-            stdout.write_all(format!("{}", c).as_bytes()).await
-                .map_err(error::internal)?;
-            stdout.flush().await.map_err(error::internal)?;
-          }
-        }
-
-        if action.is_some() {
-          break;
-        }
-      }
-
-      let n_to_consume = match chars.next() {
-        Some((offset, _)) => offset,
-        None => string.len(),
-      };
-
-      Arc::get_mut(&mut self.reader).unwrap().lock().await.consume(n_to_consume);
-
-      match action {
-        Some(InputAction::Execute) => {
-          break;
-        }
-        Some(InputAction::Backspace) => {
-          self.line_buffer.backspace();
-
-          stdout.write_all(format!("\u{08}\u{1b}[1X{}",
-                                   self.line_buffer.cursor_to_end_of_line())
-                           .as_bytes()).await.map_err(error::internal)?;
-          stdout.flush().await.map_err(error::internal)?;
-        }
-        None => { }
-      }
-    }
-
-    println!("line buffer {:?}", self.line_buffer);
-    let input = Input::String(self.line_buffer.as_string());
-    Ok(input)
-  }
-}
-
-
-/*
-#[cfg(test)]
-mod tests {
-  use super::*;
-  use std::io::Cursor;
-
-  #[test]
-  fn test_empty_input() {
-    let buffer = Cursor::new(vec![]);
-    let terminal = Terminal::init(buffer).unwrap();
-    let result = terminal.handle_input();
-    assert!(result.is_ok());
-  }
-}
-*/