Another ugly commit, tweak handling of input
This commit is contained in:
parent
f08f5f3cae
commit
40477ec7ca
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -15,11 +15,6 @@ name = "cfg-if"
|
|||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lazy_static"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.62"
|
version = "0.2.62"
|
||||||
@ -42,15 +37,6 @@ name = "rs-kilo"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"term-parser 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "term-parser"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -62,8 +48,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
|
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
|
||||||
"checksum cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "b548a4ee81fccb95919d4e22cfea83c7693ebfd78f0495493178db20b3139da7"
|
"checksum cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "b548a4ee81fccb95919d4e22cfea83c7693ebfd78f0495493178db20b3139da7"
|
||||||
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
|
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
|
||||||
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
|
|
||||||
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
|
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
|
||||||
"checksum nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229"
|
"checksum nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229"
|
||||||
"checksum term-parser 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c483a684059c71636d0e4ff927bd5feb5f2a533e7a8f16a0008dd33c8752cbc"
|
|
||||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||||
|
@ -7,5 +7,5 @@ edition = "2018"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
# Rust wrappers for C/POSIX headers
|
||||||
nix = "0.15.0"
|
nix = "0.15.0"
|
||||||
term-parser = "0.2.0"
|
|
@ -9,18 +9,15 @@ use std::io::prelude::*;
|
|||||||
use std::io::{BufReader, Error, Stdin};
|
use std::io::{BufReader, Error, Stdin};
|
||||||
use std::str::Chars;
|
use std::str::Chars;
|
||||||
|
|
||||||
use term_parser::{Action, ActionIter};
|
|
||||||
|
|
||||||
/// Main structure for the editor
|
/// Main structure for the editor
|
||||||
pub struct Editor {
|
///
|
||||||
|
/// impl blocks are split similarly to the original C implementation
|
||||||
}
|
pub struct Editor {}
|
||||||
|
|
||||||
// init
|
// init
|
||||||
impl Editor {
|
impl Editor {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Editor {
|
Editor {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,8 +25,9 @@ impl Editor {
|
|||||||
impl Editor {
|
impl Editor {
|
||||||
fn read_key(&mut self) -> Option<Vec<char>> {
|
fn read_key(&mut self) -> Option<Vec<char>> {
|
||||||
let stdin = io::stdin();
|
let stdin = io::stdin();
|
||||||
|
let stdin = stdin.lock();
|
||||||
let mut in_str = String::new();
|
let mut in_str = String::new();
|
||||||
let mut input = BufReader::new(stdin.take(1));
|
let mut input = BufReader::with_capacity(3, stdin);
|
||||||
input.read_to_string(&mut in_str).unwrap();
|
input.read_to_string(&mut in_str).unwrap();
|
||||||
|
|
||||||
let mut output: Vec<char> = vec![];
|
let mut output: Vec<char> = vec![];
|
||||||
@ -39,68 +37,44 @@ impl Editor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if output.len() == 0 {
|
if output.len() == 0 {
|
||||||
return None
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Some(output)
|
return Some(output);
|
||||||
}
|
|
||||||
|
|
||||||
fn read_term_code(&mut self) -> ActionIter<BufReader<Stdin>> {
|
|
||||||
let stdin = io::stdin();
|
|
||||||
let buffer = BufReader::new(stdin);
|
|
||||||
let term_code_iter = ActionIter::new(buffer);
|
|
||||||
|
|
||||||
/*
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
term_code_iter
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
impl Editor {
|
impl Editor {
|
||||||
pub fn process_keypress(&mut self) -> Option<()> {
|
pub fn process_keypress(&mut self) -> Option<()> {
|
||||||
let chars= self.read_key();
|
match self.read_key() {
|
||||||
|
// Just continue the input loop on an "empty" keypress
|
||||||
|
None => Some(()),
|
||||||
|
Some(chars) => {
|
||||||
|
let first = chars[0];
|
||||||
|
|
||||||
// No input, just continue
|
if first == ctrl_key('q') {
|
||||||
if chars.is_none() {
|
|
||||||
return Some(())
|
|
||||||
}
|
|
||||||
let chars = chars.unwrap();
|
|
||||||
|
|
||||||
if chars.len() == 1 {
|
|
||||||
let char = chars[0];
|
|
||||||
|
|
||||||
if char == CTRL_KEY('q') {
|
|
||||||
// Break out of the input loop
|
// Break out of the input loop
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Echo characters
|
|
||||||
if char.is_ascii_control() {
|
|
||||||
print!("{}\r\n", char as u8);
|
|
||||||
} else {
|
|
||||||
print!("{} ('{}')\r\n", char as u8, char);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
print!("{:?}\r\n", chars);
|
print!("{:?}\r\n", chars);
|
||||||
// Handle escape sequences
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Continue the main input loop
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn CTRL_KEY(c: char) -> char {
|
// Output
|
||||||
let key = c as u8;
|
impl Editor {
|
||||||
|
pub fn refresh_screen() {
|
||||||
|
let stdout = io::stdout();
|
||||||
|
let mut handle = stdout.lock();
|
||||||
|
|
||||||
(key & 0x1f) as char
|
let mut buffer = String::from("\x1b[2J").into_bytes();
|
||||||
|
|
||||||
|
handle.write_all(&mut buffer).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,21 +11,40 @@ use std::os::unix::io::RawFd;
|
|||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
|
||||||
// Redefine the posix constants for rust land
|
// Redefine the posix constants for rust land
|
||||||
|
|
||||||
|
/// The value of the raw file descriptor for STDIN
|
||||||
pub const STDIN_FILENO: i32 = 0;
|
pub const STDIN_FILENO: i32 = 0;
|
||||||
// pub const STDOUT_FILENO: i32 = 1;
|
// pub const STDOUT_FILENO: i32 = 1;
|
||||||
// pub const STDERR_FILENO: i32 = 2;
|
// pub const STDERR_FILENO: i32 = 2;
|
||||||
|
|
||||||
|
/// Convert Ctrl+letter chords to their
|
||||||
|
/// ASCII table equivalents
|
||||||
|
#[inline]
|
||||||
|
pub fn ctrl_key(c: char) -> char {
|
||||||
|
let key = c as u8;
|
||||||
|
|
||||||
|
if !c.is_ascii() {
|
||||||
|
panic!("CTRL_KEY only accepts ASCII characters");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intentionally "overflow" u8 to wrap around to the
|
||||||
|
// beginning of the ASCII table. Ctrl+a is 1, Ctrl+b is 2, etc.
|
||||||
|
(key & 0x1f) as char
|
||||||
|
}
|
||||||
|
|
||||||
pub fn die(code: &Errno, msg: &str) -> ! {
|
pub fn die(code: &Errno, msg: &str) -> ! {
|
||||||
eprintln!("{:?} ({})", code, msg);
|
eprintln!("{:?} ({})", code, msg);
|
||||||
|
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a `Termios` struct, for getting/setting terminal flags
|
||||||
pub fn get_termios(fd: RawFd) -> Termios {
|
pub fn get_termios(fd: RawFd) -> Termios {
|
||||||
termios::tcgetattr(fd).unwrap()
|
termios::tcgetattr(fd).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_raw_mode() -> Result<(), Error> {
|
/// Put terminal into raw mode so there is full control of terminal output
|
||||||
|
pub fn enable_raw_mode() {
|
||||||
let mut raw = get_termios(STDIN_FILENO);
|
let mut raw = get_termios(STDIN_FILENO);
|
||||||
|
|
||||||
raw.input_flags.remove(
|
raw.input_flags.remove(
|
||||||
@ -59,21 +78,11 @@ pub fn enable_raw_mode() -> Result<(), Error> {
|
|||||||
raw.control_chars[SpecialCharacterIndices::VMIN as usize] = 0;
|
raw.control_chars[SpecialCharacterIndices::VMIN as usize] = 0;
|
||||||
raw.control_chars[SpecialCharacterIndices::VTIME as usize] = 1;
|
raw.control_chars[SpecialCharacterIndices::VTIME as usize] = 1;
|
||||||
|
|
||||||
match termios::tcsetattr(STDIN_FILENO, termios::SetArg::TCSAFLUSH, &raw) {
|
// Raw mode or bust!
|
||||||
Ok(()) => Ok(()),
|
termios::tcsetattr(STDIN_FILENO, termios::SetArg::TCSAFLUSH, &raw).unwrap();
|
||||||
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> {
|
/// Restore terminal to "cooked"/canonical mode
|
||||||
match termios::tcsetattr(STDIN_FILENO, termios::SetArg::TCSAFLUSH, original) {
|
pub fn disable_raw_mode(original: &Termios) {
|
||||||
Ok(()) => Ok(()),
|
termios::tcsetattr(STDIN_FILENO, termios::SetArg::TCSAFLUSH, original).unwrap();
|
||||||
Err(E) => match E.as_errno() {
|
|
||||||
Some(errno) => die(&errno, "tcsetattr"),
|
|
||||||
None => panic!("Failed to disable raw mode"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
11
src/main.rs
11
src/main.rs
@ -5,15 +5,22 @@ use crate::editor::Editor;
|
|||||||
use crate::helpers::*;
|
use crate::helpers::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
// Save original terminal flags
|
||||||
let original_termios = get_termios(STDIN_FILENO);
|
let original_termios = get_termios(STDIN_FILENO);
|
||||||
|
|
||||||
enable_raw_mode().unwrap();
|
// Disable canonical/"cooked" terminal mode
|
||||||
|
enable_raw_mode();
|
||||||
|
|
||||||
|
// Initialize the editor
|
||||||
let mut editor = Editor::new();
|
let mut editor = Editor::new();
|
||||||
|
|
||||||
|
// Main input loop. Editor::process_keypress uses an Option Enum as a sentinel.
|
||||||
|
// `None` is returned on a quit action, in other cases, `Some(())` is returned,
|
||||||
|
// continuing the loop
|
||||||
while editor.process_keypress().is_some() {
|
while editor.process_keypress().is_some() {
|
||||||
// loop
|
// loop
|
||||||
}
|
}
|
||||||
|
|
||||||
disable_raw_mode(&original_termios).unwrap();
|
// Restore previous terminal flags before exit
|
||||||
|
disable_raw_mode(&original_termios);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user