Draw a welcome message

This commit is contained in:
Timothy Warren 2021-03-05 16:36:39 -05:00
parent 221512f80c
commit 93d3501223
3 changed files with 110 additions and 13 deletions

View File

@ -1,48 +1,77 @@
use std::io::{self, stdout}; use crate::Terminal;
use termion::event::Key; use termion::event::Key;
use termion::input::TermRead;
use termion::raw::IntoRawMode; const VERSION: &str = env!("CARGO_PKG_VERSION");
pub struct Editor { pub struct Editor {
should_quit: bool, should_quit: bool,
terminal: Terminal,
} }
impl Editor { impl Editor {
pub fn run(&mut self) { pub fn run(&mut self) {
let _stdout = stdout().into_raw_mode().unwrap();
loop { loop {
if let Err(error) = self.process_keypress() { if let Err(error) = self.refresh_screen() {
die(error); die(error);
} }
if self.should_quit { if self.should_quit {
break; break;
} }
if let Err(error) = self.process_keypress() {
die(error);
}
} }
} }
pub fn default() -> Self { pub fn default() -> Self {
Self { should_quit: false } Self {
should_quit: false,
terminal: Terminal::default().expect("Failed to initialize terminal"),
}
}
fn refresh_screen(&self) -> Result<(), std::io::Error> {
Terminal::cursor_hide();
Terminal::cursor_position(0, 0);
if self.should_quit {
Terminal::clear_screen();
println!("Goodbye.\r");
} else {
self.draw_rows();
Terminal::cursor_position(0, 0);
}
Terminal::cursor_show();
Terminal::flush()
} }
fn process_keypress(&mut self) -> Result<(), std::io::Error> { fn process_keypress(&mut self) -> Result<(), std::io::Error> {
let pressed_key = read_key()?; let pressed_key = Terminal::read_key()?;
match pressed_key { match pressed_key {
Key::Ctrl('q') => self.should_quit = true, Key::Ctrl('q') => self.should_quit = true,
_ => (), _ => (),
} }
Ok(()) Ok(())
} }
}
fn read_key() -> Result<Key, std::io::Error> { fn draw_rows(&self) {
loop { let height = self.terminal.size().height;
if let Some(key) = io::stdin().lock().keys().next() {
return key; for row in 0..height - 1 {
Terminal::clear_current_line();
if row == height / 3 {
let welcome_message = format!("Hecto editor -- version {}", VERSION);
let width = std::cmp::min(self.terminal.size() as usize, welcome_message.len());
println!("{}\r", &welcome_message[..width]);
} else {
println!("~\r");
}
} }
} }
} }
fn die(e: std::io::Error) { fn die(e: std::io::Error) {
Terminal::clear_screen();
panic!(e); panic!(e);
} }

View File

@ -1,7 +1,9 @@
#![warn(clippy::all, clippy::pedantic)] #![warn(clippy::all, clippy::pedantic)]
mod editor; mod editor;
mod terminal;
use editor::Editor; use editor::Editor;
pub use terminal::Terminal;
fn main() { fn main() {
Editor::default().run(); Editor::default().run();

66
src/terminal.rs Normal file
View File

@ -0,0 +1,66 @@
use std::io::{self, stdout, Write};
use termion::event::Key;
use termion::input::TermRead;
use termion::raw::{IntoRawMode, RawTerminal};
pub struct Size {
pub width: u16,
pub height: u16,
}
pub struct Terminal {
size: Size,
_stdout: RawTerminal<std::io::Stdout>,
}
impl Terminal {
pub fn default() -> Result<Self, std::io::Error> {
let size = termion::terminal_size()?;
Ok(Self {
size: Size {
width: size.0,
height: size.1,
},
_stdout: stdout().into_raw_mode()?,
})
}
pub fn size(&self) -> &Size {
&self.size
}
pub fn clear_screen() {
print!("{}", termion::clear::All);
}
pub fn cursor_position(x: u16, y: u16) {
let x = x.saturating_add(1);
let y = y.saturating_add(1);
print!("{}", termion::cursor::Goto(x, y));
}
pub fn flush() -> Result<(), std::io::Error> {
io::stdout().flush()
}
pub fn read_key() -> Result<Key, std::io::Error> {
loop {
if let Some(key) = io::stdin().lock().keys().next() {
return key;
}
}
}
pub fn cursor_hide() {
print!("{}", termion::cursor::Hide);
}
pub fn cursor_show() {
print!("{}", termion::cursor::Show);
}
pub fn clear_current_line() {
print!("{}", termion::clear::CurrentLine);
}
}