diff --git a/src/editor.rs b/src/editor.rs index 9d2f853..1a0acc8 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -6,7 +6,7 @@ use std::fs::File; use std::io; use std::io::prelude::*; use std::io::BufReader; -use std::string::ToString; +use std::time::{Duration, Instant}; use self::EditorKey::*; @@ -30,7 +30,7 @@ impl EditorRow { /// Main structure for the editor /// `EditorConfig` struct in C version -#[derive(Debug, Default)] +#[derive(Debug)] pub struct Editor { cursor_x: usize, cursor_y: usize, @@ -41,6 +41,8 @@ pub struct Editor { screen_rows: usize, rows: Vec, filename: String, + status_message: String, + status_message_time: Instant, output_buffer: String, } @@ -72,6 +74,25 @@ impl EditorKey { } } +impl Default for Editor { + fn default() -> Self { + Editor { + cursor_x: 0, + cursor_y: 0, + render_x: 0, + col_offset: 0, + row_offset: 0, + screen_cols: 0, + screen_rows: 0, + rows: vec![], + filename: String::new(), + status_message: String::new(), + status_message_time: Instant::now(), + output_buffer: String::new(), + } + } +} + impl Editor { // ------------------------------------------------------------------------ // Init @@ -79,12 +100,11 @@ impl Editor { pub fn new() -> Self { let mut instance = Self::default(); + let size = instance.get_window_size(); - instance.rows = vec![]; - instance.cursor_x = 0; - instance.cursor_y = 0; + instance.screen_cols = size.cols as usize; - instance.screen_rows = (size.rows - 1) as usize; + instance.screen_rows = (size.rows - 2) as usize; instance } @@ -414,7 +434,6 @@ impl Editor { let mut len = left_message.len(); let mut rlen = right_message.len(); if len > self.screen_cols { - len = self.screen_cols; left_message.truncate(len); } @@ -428,6 +447,22 @@ impl Editor { self.append_out(" "); } self.append_out("\x1b[m"); + self.append_out("\r\n"); + } + + fn draw_message_bar(&mut self) { + self.append_out("\x1b[K"); + + let mut message = self.status_message.clone(); + let message_len = message.len(); + if message_len > self.screen_cols { + message.truncate(self.screen_cols); + } + + let five_seconds = Duration::from_secs(5); + if message_len > 0 && self.status_message_time.elapsed() < five_seconds { + self.append_out(&message); + } } pub fn refresh_screen(&mut self) -> io::Result<()> { @@ -440,11 +475,12 @@ impl Editor { self.draw_rows(); self.draw_status_bar(); + self.draw_message_bar(); // Move cursor to state position let y = (self.cursor_y - self.row_offset) + 1; let x = (self.render_x - self.col_offset) + 1; - let cursor_code = format!("\x1b[{y};{x}H", y=y, x=x); + let cursor_code = format!("\x1b[{y};{x}H", y = y, x = x); self.append_out(&cursor_code); // Show cursor @@ -455,6 +491,25 @@ impl Editor { handle.write_all(&self.output_buffer.as_bytes()) } + /// Set the status bar message + /// + /// To avoid creating a macro that would just forward to + /// the `format!` macro, this method only accepts a pre-formatted + /// string. + /// + /// # Example + /// + /// ```no-run + /// # use rs-kilo::editor::Editor; + /// # let editor = Editor::new(); + /// let message = format!("{} is {}", key, status); + /// editor.set_status_message(&message); + /// ``` + pub fn set_status_message(&mut self, message: &str) { + self.status_message = message.to_owned(); + self.status_message_time = Instant::now(); + } + // ------------------------------------------------------------------------ // Row Operations // ------------------------------------------------------------------------ diff --git a/src/main.rs b/src/main.rs index 364f83d..393fd4e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,8 @@ fn main() -> Result<(), Error> { editor.open(&args[1])?; } + editor.set_status_message("HELP: Ctrl-Q = quit"); + // 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