use crate::{Document, Row, Terminal};
use std::env;
+use std::time::Duration;
+use std::time::Instant;
+use termion::color;
use termion::event::Key;
+const STATUS_FG_COLOR: color::Rgb = color::Rgb(63, 63, 63);
+const STATUS_BG_COLOR: color::Rgb = color::Rgb(239, 239, 239);
const VERSION: &str = env!("CARGO_PKG_VERSION");
fn die(e: std::io::Error) {
pub y: usize,
}
+struct StatusMessage {
+ text: String,
+ time: Instant,
+}
+
+impl StatusMessage {
+ fn from(message: String) -> Self {
+ Self {
+ text: message,
+ time: Instant::now(),
+ }
+ }
+}
+
pub struct Editor {
should_quit: bool,
terminal: Terminal,
current_position: Position,
offset: Position,
document: Document,
+ status_message: StatusMessage,
}
impl Editor {
}
pub fn default() -> Self {
let args: Vec<String> = env::args().collect();
+ let mut initial_status = String::from("HELP: Ctrl-Q = quit");
let document = if args.len() > 1 {
let file_name = &args[1];
- Document::open(&file_name).unwrap_or_default()
+ let doc = Document::open(&file_name);
+ if doc.is_ok() {
+ doc.unwrap()
+ } else {
+ initial_status = format!("Error: failed to open file: {}", file_name);
+ Document::default()
+ }
} else {
Document::default()
};
document,
current_position: Position::default(),
offset: Position::default(),
+ status_message: StatusMessage::from(initial_status),
}
}
println!("Goodbye.\r");
} else {
self.draw_rows();
+ self.draw_status_bar();
+ self.draw_message_bar();
Terminal::cursor_position(&Position {
x: self.current_position.x.saturating_sub(self.offset.x),
y: self.current_position.y.saturating_sub(self.offset.y),
fn draw_rows(&self) {
let height = self.terminal.size().height;
- for terminal_row in 0..height - 1 {
+ for terminal_row in 0..height {
Terminal::clear_current_line();
if let Some(row) = self.document.row(terminal_row as usize + self.offset.y) {
self.draw_row(row);
}
}
}
+
+ fn draw_status_bar(&self) {
+ let mut status;
+ let width = self.terminal.size().width as usize;
+ let mut file_name = "[No Name]".to_string();
+ if let Some(name) = &self.document.file_name {
+ file_name = name.clone();
+ file_name.truncate(20);
+ }
+ status = format!("{} - {} lines", file_name, self.document.len());
+ let line_indicator = format!(
+ "{}/{}",
+ self.current_position.y.saturating_add(1),
+ self.document.len()
+ );
+ let len = status.len() + line_indicator.len();
+ if width > len {
+ status.push_str(&" ".repeat(width - len));
+ }
+ status = format!("{}{}", status, line_indicator);
+ status.truncate(width);
+ Terminal::set_fg_color(STATUS_FG_COLOR);
+ println!("{}\r", status);
+ Terminal::reset_fg_color();
+ Terminal::reset_bg_color();
+ }
+
+ fn draw_message_bar(&self) {
+ Terminal::clear_current_line();
+ let message = &self.status_message;
+ if Instant::now() - message.time < Duration::new(5, 0) {
+ let mut text = message.text.clone();
+ text.truncate(self.terminal.size().width as usize);
+ print!("{}", text);
+ }
+ }
}
use crate::Position;
use std::io::{self, stdout, Write};
+use termion::color;
use termion::event::Key;
use termion::input::TermRead;
use termion::raw::{IntoRawMode, RawTerminal};
Ok(Self {
size: Size {
width: size.0,
- height: size.1,
+ height: size.1.saturating_sub(2),
},
_stdout: stdout().into_raw_mode()?,
})
}
pub fn cursor_position(position: &Position) {
- let Position{mut x, mut y} = position;
+ let Position { mut x, mut y } = position;
x = x.saturating_add(1);
y = y.saturating_add(1);
let x = x as u16;
}
}
}
+ pub fn set_bg_color(color: color::Rgb) {
+ print!("{}", color::Bg(color));
+ }
+
+ pub fn reset_bg_color() {
+ print!("{}", color::Bg(color::Reset));
+ }
+
+ pub fn set_fg_color(color: color::Rgb) {
+ print!("{}", color::Bg(color));
+ }
+
+ pub fn reset_fg_color() {
+ print!("{}", color::Bg(color::Reset));
+ }
}