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"
|
name = "rs-kilo"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
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)",
|
"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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
libc = "0.2"
|
||||||
# Rust wrappers for C/POSIX headers
|
# Rust wrappers for C/POSIX headers
|
||||||
nix = "0.15.0"
|
nix = "0.15.0"
|
||||||
|
@ -1,23 +1,28 @@
|
|||||||
//! Editor functionality
|
//! Editor functionality
|
||||||
use crate::helpers::*;
|
use crate::helpers::*;
|
||||||
|
|
||||||
use nix::sys::termios::Termios;
|
|
||||||
use nix::unistd::read;
|
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::io::{BufReader, Error, Stdin};
|
use std::io::BufReader;
|
||||||
use std::str::Chars;
|
|
||||||
|
|
||||||
/// Main structure for the editor
|
/// Main structure for the editor
|
||||||
///
|
///
|
||||||
/// impl blocks are split similarly to the original C implementation
|
/// 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
|
// init
|
||||||
impl Editor {
|
impl Editor {
|
||||||
pub fn new() -> Self {
|
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);
|
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
|
// Input
|
||||||
impl Editor {
|
impl Editor {
|
||||||
|
/// Route user input to the appropriate handler method
|
||||||
pub fn process_keypress(&mut self) -> Option<()> {
|
pub fn process_keypress(&mut self) -> Option<()> {
|
||||||
match self.read_key() {
|
match self.read_key() {
|
||||||
// Just continue the input loop on an "empty" keypress
|
// Just continue the input loop on an "empty" keypress
|
||||||
@ -54,6 +90,8 @@ impl Editor {
|
|||||||
let first = chars[0];
|
let first = chars[0];
|
||||||
|
|
||||||
if first == ctrl_key('q') {
|
if first == ctrl_key('q') {
|
||||||
|
clear_and_reset();
|
||||||
|
|
||||||
// Break out of the input loop
|
// Break out of the input loop
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -69,11 +107,29 @@ impl Editor {
|
|||||||
|
|
||||||
// Output
|
// Output
|
||||||
impl Editor {
|
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 stdout = io::stdout();
|
||||||
let mut handle = stdout.lock();
|
let mut handle = stdout.lock();
|
||||||
|
|
||||||
|
// Clear screen
|
||||||
let mut buffer = String::from("\x1b[2J").into_bytes();
|
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();
|
handle.write_all(&mut buffer).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,37 @@
|
|||||||
|
use libc::ioctl;
|
||||||
/// Helper functions, especially to reproduce C std/posix functions
|
/// Helper functions, especially to reproduce C std/posix functions
|
||||||
|
use libc::{c_ushort, STDOUT_FILENO, TIOCGWINSZ};
|
||||||
|
|
||||||
use nix::errno::*;
|
use nix::errno::*;
|
||||||
use nix::sys::termios;
|
use nix::sys::termios;
|
||||||
use nix::sys::termios::{
|
use nix::sys::termios::{
|
||||||
ControlFlags, InputFlags, LocalFlags, OutputFlags, SpecialCharacterIndices, 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::os::unix::io::RawFd;
|
||||||
use std::process::exit;
|
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
|
// Redefine the posix constants for rust land
|
||||||
|
|
||||||
/// The value of the raw file descriptor for STDIN
|
/// 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) -> ! {
|
pub fn die(code: &Errno, msg: &str) -> ! {
|
||||||
|
clear_and_reset();
|
||||||
|
|
||||||
eprintln!("{:?} ({})", code, msg);
|
eprintln!("{:?} ({})", code, msg);
|
||||||
|
|
||||||
exit(1)
|
exit(1)
|
||||||
@ -86,3 +110,36 @@ pub fn enable_raw_mode() {
|
|||||||
pub fn disable_raw_mode(original: &Termios) {
|
pub fn disable_raw_mode(original: &Termios) {
|
||||||
termios::tcsetattr(STDIN_FILENO, termios::SetArg::TCSAFLUSH, original).unwrap();
|
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.
|
// 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,
|
// `None` is returned on a quit action, in other cases, `Some(())` is returned,
|
||||||
// continuing the loop
|
// 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
|
// Restore previous terminal flags before exit
|
||||||
|
Loading…
Reference in New Issue
Block a user