Complete chapter 4

This commit is contained in:
Timothy Warren 2019-08-29 14:13:09 -04:00
parent fd9f504266
commit 0c81912cac
2 changed files with 65 additions and 8 deletions

View File

@ -6,7 +6,7 @@ use std::fs::File;
use std::io; use std::io;
use std::io::prelude::*; use std::io::prelude::*;
use std::io::BufReader; use std::io::BufReader;
use std::string::ToString; use std::time::{Duration, Instant};
use self::EditorKey::*; use self::EditorKey::*;
@ -30,7 +30,7 @@ impl EditorRow {
/// Main structure for the editor /// Main structure for the editor
/// `EditorConfig` struct in C version /// `EditorConfig` struct in C version
#[derive(Debug, Default)] #[derive(Debug)]
pub struct Editor { pub struct Editor {
cursor_x: usize, cursor_x: usize,
cursor_y: usize, cursor_y: usize,
@ -41,6 +41,8 @@ pub struct Editor {
screen_rows: usize, screen_rows: usize,
rows: Vec<EditorRow>, rows: Vec<EditorRow>,
filename: String, filename: String,
status_message: String,
status_message_time: Instant,
output_buffer: String, output_buffer: String,
} }
@ -72,6 +74,25 @@ impl EditorKey<char> {
} }
} }
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 { impl Editor {
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Init // Init
@ -79,12 +100,11 @@ impl Editor {
pub fn new() -> Self { pub fn new() -> Self {
let mut instance = Self::default(); let mut instance = Self::default();
let size = instance.get_window_size(); 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_cols = size.cols as usize;
instance.screen_rows = (size.rows - 1) as usize; instance.screen_rows = (size.rows - 2) as usize;
instance instance
} }
@ -414,7 +434,6 @@ impl Editor {
let mut len = left_message.len(); let mut len = left_message.len();
let mut rlen = right_message.len(); let mut rlen = right_message.len();
if len > self.screen_cols { if len > self.screen_cols {
len = self.screen_cols; len = self.screen_cols;
left_message.truncate(len); left_message.truncate(len);
} }
@ -428,6 +447,22 @@ impl Editor {
self.append_out(" "); self.append_out(" ");
} }
self.append_out("\x1b[m"); 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<()> { pub fn refresh_screen(&mut self) -> io::Result<()> {
@ -440,11 +475,12 @@ impl Editor {
self.draw_rows(); self.draw_rows();
self.draw_status_bar(); self.draw_status_bar();
self.draw_message_bar();
// Move cursor to state position // Move cursor to state position
let y = (self.cursor_y - self.row_offset) + 1; let y = (self.cursor_y - self.row_offset) + 1;
let x = (self.render_x - self.col_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); self.append_out(&cursor_code);
// Show cursor // Show cursor
@ -455,6 +491,25 @@ impl Editor {
handle.write_all(&self.output_buffer.as_bytes()) 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 // Row Operations
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

View File

@ -25,6 +25,8 @@ fn main() -> Result<(), Error> {
editor.open(&args[1])?; 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. // 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