# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
+crossterm = "0.27.0"
+termion = "3.0.0"
--- /dev/null
+use crate::Terminal;
+use termion::event::Key;
+
+fn die(e: std::io::Error) {
+ Terminal::clear_screen();
+ panic!("{:?}", e);
+}
+
+pub struct Editor {
+ should_quit: bool,
+ terminal: Terminal,
+}
+
+impl Editor {
+ pub fn run(&mut self) {
+ loop {
+ if let Err(error) = self.refresh_screen() {
+ die(error);
+ }
+ if self.should_quit {
+ break;
+ }
+ if let Err(error) = self.process_keypress() {
+ die(error);
+ }
+ }
+ }
+ pub fn default() -> Self {
+ Self {
+ should_quit: false,
+ terminal: Terminal::default().expect("Failed to create terminal"),
+ }
+ }
+
+ fn refresh_screen(&self) -> Result<(), std::io::Error> {
+ Terminal::clear_screen();
+ Terminal::cursor_position(0, 0);
+ if self.should_quit {
+ println!("Goodbye.\r");
+ } else {
+ self.draw_rows();
+ Terminal::cursor_position(0, 0);
+ }
+ Terminal::flush()
+ }
+
+ fn process_keypress(&mut self) -> Result<(), std::io::Error> {
+ let pressed_key = Terminal::read_key()?;
+ match pressed_key {
+ Key::Ctrl('q') => self.should_quit = true,
+ _ => (),
+ };
+ Ok(())
+ }
+ fn draw_rows(&self) {
+ for _ in 0..self.terminal.size().height {
+ println!("~\r");
+ }
+ }
+}
+#![warn(clippy::all, clippy::pedantic)]
+mod editor;
+mod terminal;
+use editor::Editor;
+pub use terminal::Terminal;
+
fn main() {
- println!("Hello, world!");
+ Editor::default().run();
}
--- /dev/null
+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;
+ }
+ }
+ }
+}