Complete chapter 4
This commit is contained in:
parent
fd9f504266
commit
0c81912cac
@ -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
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user