Fill the screen with tilde lines
This commit is contained in:
parent
40477ec7ca
commit
04369ca796
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -36,6 +36,7 @@ dependencies = [
|
||||
name = "rs-kilo"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -7,5 +7,6 @@ edition = "2018"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
# Rust wrappers for C/POSIX headers
|
||||
nix = "0.15.0"
|
||||
|
@ -1,23 +1,28 @@
|
||||
//! Editor functionality
|
||||
use crate::helpers::*;
|
||||
|
||||
use nix::sys::termios::Termios;
|
||||
use nix::unistd::read;
|
||||
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::io::{BufReader, Error, Stdin};
|
||||
use std::str::Chars;
|
||||
use std::io::BufReader;
|
||||
|
||||
/// Main structure for the editor
|
||||
///
|
||||
/// impl blocks are split similarly to the original C implementation
|
||||
pub struct Editor {}
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Editor {
|
||||
screen_cols: u16,
|
||||
screen_rows: u16,
|
||||
}
|
||||
|
||||
// init
|
||||
impl Editor {
|
||||
pub fn new() -> Self {
|
||||
Editor {}
|
||||
let mut instance = Self::default();
|
||||
let size = instance.get_window_size();
|
||||
instance.screen_cols = size.cols;
|
||||
instance.screen_rows = size.rows;
|
||||
|
||||
instance
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,10 +47,41 @@ impl Editor {
|
||||
|
||||
return Some(output);
|
||||
}
|
||||
|
||||
fn get_cursor_position(&mut self) -> TermSize {
|
||||
let stdout = io::stdout();
|
||||
let mut handle = stdout.lock();
|
||||
let buffer = String::from("\x1b[6n").into_bytes();
|
||||
handle.write(&buffer).unwrap();
|
||||
|
||||
let stdin = io::stdin();
|
||||
let stdin = stdin.lock();
|
||||
let mut in_buf = String::new().into_bytes();
|
||||
let mut input = BufReader::with_capacity(32, stdin);
|
||||
input.read_until('R' as u8, &mut in_buf).unwrap();
|
||||
|
||||
// @TODO Find a solution to retrieve the cursor coordinates
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn get_window_size(&mut self) -> TermSize {
|
||||
match get_term_size() {
|
||||
Some(size) => size,
|
||||
None => {
|
||||
let stdout = io::stdout();
|
||||
let mut handle = stdout.lock();
|
||||
let buffer = String::from("\x1b[999C\x1b[999B").into_bytes();
|
||||
handle.write(&buffer).unwrap();
|
||||
|
||||
self.get_cursor_position()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Input
|
||||
impl Editor {
|
||||
/// Route user input to the appropriate handler method
|
||||
pub fn process_keypress(&mut self) -> Option<()> {
|
||||
match self.read_key() {
|
||||
// Just continue the input loop on an "empty" keypress
|
||||
@ -54,6 +90,8 @@ impl Editor {
|
||||
let first = chars[0];
|
||||
|
||||
if first == ctrl_key('q') {
|
||||
clear_and_reset();
|
||||
|
||||
// Break out of the input loop
|
||||
return None;
|
||||
}
|
||||
@ -69,11 +107,29 @@ impl Editor {
|
||||
|
||||
// Output
|
||||
impl Editor {
|
||||
pub fn refresh_screen() {
|
||||
fn draw_rows(&mut self) {
|
||||
let stdout = io::stdout();
|
||||
let mut handle = stdout.lock();
|
||||
let buffer = String::from("~\r\n").into_bytes();
|
||||
|
||||
for _ in 0..self.screen_rows as usize {
|
||||
handle.write(&buffer).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn refresh_screen(&mut self) {
|
||||
let stdout = io::stdout();
|
||||
let mut handle = stdout.lock();
|
||||
|
||||
// Clear screen
|
||||
let mut buffer = String::from("\x1b[2J").into_bytes();
|
||||
handle.write_all(&mut buffer).unwrap();
|
||||
|
||||
// Reposition cursor
|
||||
let mut buffer = String::from("\x1b[H").into_bytes();
|
||||
handle.write_all(&mut buffer).unwrap();
|
||||
|
||||
self.draw_rows();
|
||||
|
||||
handle.write_all(&mut buffer).unwrap();
|
||||
}
|
||||
|
@ -1,15 +1,37 @@
|
||||
use libc::ioctl;
|
||||
/// Helper functions, especially to reproduce C std/posix functions
|
||||
use libc::{c_ushort, STDOUT_FILENO, TIOCGWINSZ};
|
||||
|
||||
use nix::errno::*;
|
||||
use nix::sys::termios;
|
||||
use nix::sys::termios::{
|
||||
ControlFlags, InputFlags, LocalFlags, OutputFlags, SpecialCharacterIndices, Termios,
|
||||
};
|
||||
use nix::Error as NixError;
|
||||
|
||||
use std::io::Error;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::process::exit;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TermSize {
|
||||
/// number of rows
|
||||
pub rows: u16,
|
||||
/// number of columns
|
||||
pub cols: u16,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
struct UnixTermSize {
|
||||
/// number of rows
|
||||
pub rows: c_ushort,
|
||||
/// number of columns
|
||||
pub cols: c_ushort,
|
||||
x: c_ushort,
|
||||
y: c_ushort,
|
||||
}
|
||||
|
||||
// Redefine the posix constants for rust land
|
||||
|
||||
/// The value of the raw file descriptor for STDIN
|
||||
@ -33,6 +55,8 @@ pub fn ctrl_key(c: char) -> char {
|
||||
}
|
||||
|
||||
pub fn die(code: &Errno, msg: &str) -> ! {
|
||||
clear_and_reset();
|
||||
|
||||
eprintln!("{:?} ({})", code, msg);
|
||||
|
||||
exit(1)
|
||||
@ -86,3 +110,36 @@ pub fn enable_raw_mode() {
|
||||
pub fn disable_raw_mode(original: &Termios) {
|
||||
termios::tcsetattr(STDIN_FILENO, termios::SetArg::TCSAFLUSH, original).unwrap();
|
||||
}
|
||||
|
||||
pub fn clear_and_reset() {
|
||||
let stdout = io::stdout();
|
||||
let mut handle = stdout.lock();
|
||||
|
||||
// Clear screen
|
||||
let mut buffer = String::from("\x1b[2J").into_bytes();
|
||||
handle.write_all(&mut buffer).unwrap();
|
||||
|
||||
// Reposition cursor
|
||||
let mut buffer = String::from("\x1b[H").into_bytes();
|
||||
handle.write_all(&mut buffer).unwrap();
|
||||
}
|
||||
|
||||
pub fn get_term_size() -> Option<TermSize> {
|
||||
let raw = UnixTermSize {
|
||||
rows: 0,
|
||||
cols: 0,
|
||||
x: 0,
|
||||
y: 0,
|
||||
};
|
||||
|
||||
let r = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ.into(), &raw) };
|
||||
|
||||
if r == 0 {
|
||||
Some(TermSize {
|
||||
rows: raw.rows,
|
||||
cols: raw.cols,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,12 @@ fn main() {
|
||||
// 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() {
|
||||
// loop
|
||||
loop {
|
||||
editor.refresh_screen();
|
||||
|
||||
if editor.process_keypress().is_none() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore previous terminal flags before exit
|
||||
|
Loading…
Reference in New Issue
Block a user