From: Sondre Wold Date: Sun, 21 Apr 2024 05:21:15 +0000 (+0200) Subject: Editor and Terminal basics X-Git-Url: https://letsjmore.com/?a=commitdiff_plain;h=3008a92048b72ca03e6352769683e955ba61b212;p=octo.git Editor and Terminal basics --- diff --git a/octo/Cargo.toml b/octo/Cargo.toml index 17e593b..bc088c1 100644 --- a/octo/Cargo.toml +++ b/octo/Cargo.toml @@ -6,3 +6,5 @@ edition = "2021" # 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" diff --git a/octo/src/.editor.rs.swp b/octo/src/.editor.rs.swp new file mode 100644 index 0000000..e95abb7 Binary files /dev/null and b/octo/src/.editor.rs.swp differ diff --git a/octo/src/.terminal.rs.swp b/octo/src/.terminal.rs.swp new file mode 100644 index 0000000..58f6258 Binary files /dev/null and b/octo/src/.terminal.rs.swp differ diff --git a/octo/src/editor.rs b/octo/src/editor.rs new file mode 100644 index 0000000..bef7795 --- /dev/null +++ b/octo/src/editor.rs @@ -0,0 +1,60 @@ +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"); + } + } +} diff --git a/octo/src/main.rs b/octo/src/main.rs index e7a11a9..0637681 100644 --- a/octo/src/main.rs +++ b/octo/src/main.rs @@ -1,3 +1,9 @@ +#![warn(clippy::all, clippy::pedantic)] +mod editor; +mod terminal; +use editor::Editor; +pub use terminal::Terminal; + fn main() { - println!("Hello, world!"); + Editor::default().run(); } diff --git a/octo/src/terminal.rs b/octo/src/terminal.rs new file mode 100644 index 0000000..599d873 --- /dev/null +++ b/octo/src/terminal.rs @@ -0,0 +1,52 @@ +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, +} + +impl Terminal { + pub fn default() -> Result { + 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 { + loop { + if let Some(key) = io::stdin().lock().keys().next() { + return key; + } + } + } +}