diff --git a/src/editor.rs b/src/editor.rs index d4aebac..ee279fb 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -1,11 +1,71 @@ //! Editor functionality +use crate::helpers::*; -pub struct Editor {} +use nix::sys::termios::Termios; +use nix::unistd::read; + +use std::io; +use std::io::{BufReader, Error, Stdin}; +use std::io::prelude::*; + +use term_parser::{Action, ActionIter}; + +/// Main structure for the editor +pub struct Editor { + /// Reference to terminal settings before setting up raw mode + original_termios: Termios, +} impl Editor { pub fn new() -> Self { Editor { - + original_termios: get_termios(STDIN_FILENO) } } + + fn read_key(&mut self) -> char { + let stdin = io::stdin(); + let mut in_str = String::new(); + let mut input = BufReader::new(stdin.take(1)); + input.read_to_string(&mut in_str).unwrap(); + + let mut chars = in_str.chars(); + chars.next().unwrap() + } + + fn read_term_code(&mut self) -> ActionIter> { + let stdin = io::stdin(); + let buffer = BufReader::new(stdin); + let term_code_iter = ActionIter::new(buffer); + + term_code_iter + } + + pub fn process_keypress(&mut self) -> Option<()> { + for term_code in self.read_term_code() { + let term_code = match term_code { + Ok(code) => code, + Err(e) => panic!("{:?}\r\n", e), + }; + print!("{:?}\r\n", term_code); + } + + /* let char = self.read_key(); + + if char == 'q' { + disable_raw_mode(&self.original_termios)?; + + // Break out of the input loop + return None; + } + + // Echo characters + if is_cntrl(char) { + print!("{}\r\n", char as u8); + } else { + print!("{} ('{}')\r\n", char as u8, char); + } */ + + Some(()) + } } \ No newline at end of file diff --git a/src/helpers.rs b/src/helpers.rs index 6fb3b1a..aba1f3b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,7 +1,25 @@ /// Helper functions, especially to reproduce C std/posix functions use nix::errno::*; +use nix::Error as NixError; +use nix::sys::termios; +use nix::sys::termios::{ + ControlFlags, + InputFlags, + LocalFlags, + OutputFlags, + SpecialCharacterIndices, + Termios +}; + +use std::io::Error; +use std::os::unix::io::RawFd; use std::process::exit; +// Redefine the posix constants for rust land +pub const STDIN_FILENO: i32 = 0; +// pub const STDOUT_FILENO: i32 = 1; +// pub const STDERR_FILENO: i32 = 2; + /// Is this character an ASCII control character? pub fn is_cntrl(c: char) -> bool { let code = c as u8; @@ -13,4 +31,63 @@ pub fn die(code: &Errno, msg: &str) -> ! { eprintln!("{:?} ({})", code, msg); exit(1) +} + +pub fn get_termios(fd: RawFd) -> Termios { + termios::tcgetattr(fd).unwrap() +} + +pub fn enable_raw_mode() -> Result<(), Error> { + let mut raw = get_termios(STDIN_FILENO); + + raw.input_flags.remove( + InputFlags::BRKINT & + InputFlags::IGNCR & + InputFlags::IGNBRK & + InputFlags::ICRNL & + InputFlags::INLCR & + InputFlags::INPCK & + InputFlags::ISTRIP & + InputFlags::IXON & + InputFlags::PARMRK + ); + + raw.output_flags.remove(OutputFlags::OPOST); + + raw.local_flags.remove( + LocalFlags::ECHO & + LocalFlags::ECHONL & + LocalFlags::ICANON & + LocalFlags::IEXTEN & + LocalFlags::ISIG + ); + + raw.control_flags.remove( + ControlFlags::CSIZE & + ControlFlags::PARENB + ); + + // 8 bit characters + raw.control_flags |= termios::ControlFlags::CS8; + + raw.control_chars[SpecialCharacterIndices::VMIN as usize] = 0; + raw.control_chars[SpecialCharacterIndices::VTIME as usize] = 1; + + match termios::tcsetattr(STDIN_FILENO, termios::SetArg::TCSAFLUSH, &raw) { + Ok(()) => Ok(()), + Err(e) => match e.as_errno() { + Some(errno) => die(&errno, "tcsetattr"), + None => panic!("Failed to enable raw mode") + } + } +} + +pub fn disable_raw_mode(original: &Termios) -> Result<(), Error> { + match termios::tcsetattr(STDIN_FILENO, termios::SetArg::TCSAFLUSH, original) { + Ok(()) => Ok(()), + Err(E) => match E.as_errno() { + Some(errno) => die(&errno, "tcsetattr"), + None => panic!("Failed to disable raw mode") + } + } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 0b1ffc3..a4d5fa4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,108 +1,15 @@ -use nix::Error as NixError; -use nix::sys::termios; -use nix::sys::termios::{InputFlags, LocalFlags, OutputFlags, SpecialCharacterIndices, Termios}; - -use std::io; -use std::io::{BufReader, Error}; -use std::io::prelude::*; - -use term_parser::ActionIter; - mod editor; mod helpers; -// use crate::editor::Editor; -use crate::helpers::*; +use crate::editor::Editor; +use crate::helpers::{STDIN_FILENO, enable_raw_mode}; -// Redefine the posix constants for rust land -const STDIN_FILENO: i32 = 0; -// const STDOUT_FILENO: i32 = 1; -// const STDERR_FILENO: i32 = 2; +fn main() { + enable_raw_mode().unwrap(); -fn disable_raw_mode(original: &Termios) -> Result<(), Error> { - match termios::tcsetattr(STDIN_FILENO, termios::SetArg::TCSAFLUSH, original) { - Ok(()) => Ok(()), - Err(E) => match E.as_errno() { - Some(errno) => die(&errno, "tcsetattr"), - None => panic!("Failed to disable raw mode") - } + let mut editor = Editor::new(); + + while editor.process_keypress().is_some() { + // loop } } - -fn enable_raw_mode() -> Result<(), Error> { - let mut raw = termios::tcgetattr(STDIN_FILENO).unwrap(); - - raw.input_flags.remove( - InputFlags::BRKINT & - InputFlags::ICRNL & - InputFlags::INPCK & - InputFlags::ISTRIP & - InputFlags::IXON - ); - - raw.output_flags.remove(OutputFlags::OPOST); - - raw.local_flags.remove( - LocalFlags::ECHO & - LocalFlags::ICANON & - LocalFlags::IEXTEN & - LocalFlags::ISIG - ); - - // 8 bit characters - raw.control_flags |= termios::ControlFlags::CS8; - - raw.control_chars[SpecialCharacterIndices::VMIN as usize] = 0; - raw.control_chars[SpecialCharacterIndices::VTIME as usize] = 1; - - match termios::tcsetattr(STDIN_FILENO, termios::SetArg::TCSAFLUSH, &raw) { - Ok(()) => Ok(()), - Err(e) => match e.as_errno() { - Some(errno) => die(&errno, "tcsetattr"), - None => panic!("Failed to enable raw mode") - } - } -} - -fn main() -> Result<(), Error> { - let orig_termios = termios::tcgetattr(STDIN_FILENO).unwrap(); - - enable_raw_mode()?; - - let stdin = io::stdin(); - let buffer = BufReader::new(stdin); - let term_code_iter = ActionIter::new(buffer); - - for term_code in term_code_iter { - let term_code = match term_code { - Ok(code) => code, - Err(e) => panic!("{:?}", e), - }; - println!("\r{:?}", term_code); - } - - Ok(()) - -// loop { -// let stdin = io::stdin(); -// let mut in_str = String::new(); -// let mut input = BufReader::new(stdin.take(1)); -// input.read_to_string(&mut in_str)?; -// -// let mut chars = in_str.chars(); -// let char = chars.next().unwrap(); -// -// if char == 'q' { -// return disable_raw_mode(&orig_termios); -// } -// -// // Echo characters -// if is_cntrl(char) { -// print!("{}\r\n", char as u8); -// continue; -// } else { -// print!("{} ('{}')\r\n", char as u8, char); -// continue; -// } -// } -}