Moving screen drawing handling to a submodule.

This commit is contained in:
Nathan Vegdahl 2017-12-31 17:30:21 -08:00
parent c11aee9bf6
commit c7adf195f7
2 changed files with 110 additions and 69 deletions

View File

@ -1,15 +1,12 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::cell::RefCell;
use std::cmp::min; use std::cmp::min;
use std::io; use std::io;
use std::io::Write;
use termion; use termion;
use termion::event::{Event, Key}; use termion::event::{Event, Key};
use termion::input::TermRead; use termion::input::TermRead;
use termion::color; use termion::color;
use termion::raw::{IntoRawMode, RawTerminal};
use editor::Editor; use editor::Editor;
use formatter::{block_index_and_offset, LineFormatter, LINE_BLOCK_LENGTH}; use formatter::{block_index_and_offset, LineFormatter, LINE_BLOCK_LENGTH};
@ -18,6 +15,9 @@ use string_utils::{is_line_ending, line_ending_to_str, LineEnding};
use utils::digit_count; use utils::digit_count;
pub mod formatter; pub mod formatter;
mod screen;
use self::screen::Screen;
/// Generalized ui loop. /// Generalized ui loop.
macro_rules! ui_loop { macro_rules! ui_loop {
@ -27,7 +27,7 @@ macro_rules! ui_loop {
loop { loop {
// Draw the editor to screen // Draw the editor to screen
{$draw}; {$draw};
$term_ui.present(); $term_ui.screen.present();
// Handle input // Handle input
match $term_ui.inp.next() { match $term_ui.inp.next() {
@ -63,7 +63,7 @@ macro_rules! ui_loop {
pub struct TermUI<'a> { pub struct TermUI<'a> {
inp: termion::input::Events<io::StdinLock<'a>>, inp: termion::input::Events<io::StdinLock<'a>>,
out: RefCell<RawTerminal<io::Stdout>>, screen: Screen,
editor: Editor<ConsoleLineFormatter>, editor: Editor<ConsoleLineFormatter>,
width: usize, width: usize,
height: usize, height: usize,
@ -76,18 +76,6 @@ enum LoopStatus {
Continue, Continue,
} }
impl<'a> Drop for TermUI<'a> {
fn drop(&mut self) {
self.clear();
write!(
self.out.borrow_mut(),
"{}{}",
termion::cursor::Show,
termion::cursor::Goto(0, 0),
).unwrap();
}
}
impl<'a> TermUI<'a> { impl<'a> TermUI<'a> {
pub fn new<'b>(stdin: &'b mut io::Stdin) -> TermUI<'b> { pub fn new<'b>(stdin: &'b mut io::Stdin) -> TermUI<'b> {
TermUI::new_from_editor(stdin, Editor::new(ConsoleLineFormatter::new(4))) TermUI::new_from_editor(stdin, Editor::new(ConsoleLineFormatter::new(4)))
@ -97,14 +85,13 @@ impl<'a> TermUI<'a> {
stdin: &'b mut io::Stdin, stdin: &'b mut io::Stdin,
ed: Editor<ConsoleLineFormatter>, ed: Editor<ConsoleLineFormatter>,
) -> TermUI<'b> { ) -> TermUI<'b> {
let out = io::stdout().into_raw_mode().unwrap();
let (w, h) = termion::terminal_size().unwrap(); let (w, h) = termion::terminal_size().unwrap();
let mut editor = ed; let mut editor = ed;
editor.update_dim(h as usize - 1, w as usize); editor.update_dim(h as usize - 1, w as usize);
TermUI { TermUI {
inp: stdin.lock().events(), inp: stdin.lock().events(),
out: RefCell::new(out), screen: Screen::new(),
editor: editor, editor: editor,
width: w as usize, width: w as usize,
height: h as usize, height: h as usize,
@ -114,7 +101,7 @@ impl<'a> TermUI<'a> {
pub fn main_ui_loop(&mut self) { pub fn main_ui_loop(&mut self) {
// Hide cursor // Hide cursor
write!(self.out.borrow_mut(), "{}", termion::cursor::Hide).unwrap(); self.screen.hide_cursor();
self.editor.update_dim(self.height - 1, self.width); self.editor.update_dim(self.height - 1, self.width);
self.editor.formatter.set_wrap_width(self.width as usize); self.editor.formatter.set_wrap_width(self.width as usize);
@ -126,7 +113,7 @@ impl<'a> TermUI<'a> {
draw { draw {
self.editor.update_view_dim(); self.editor.update_view_dim();
self.editor.formatter.set_wrap_width(self.editor.view_dim.1); self.editor.formatter.set_wrap_width(self.editor.view_dim.1);
self.clear(); self.screen.clear();
self.draw_editor(&self.editor, (0, 0), (self.height - 1, self.width - 1)); self.draw_editor(&self.editor, (0, 0), (self.height - 1, self.width - 1));
}, },
@ -229,13 +216,13 @@ impl<'a> TermUI<'a> {
draw { draw {
self.editor.update_view_dim(); self.editor.update_view_dim();
self.editor.formatter.set_wrap_width(self.editor.view_dim.1); self.editor.formatter.set_wrap_width(self.editor.view_dim.1);
self.clear(); self.screen.clear();
self.draw_editor(&self.editor, (0, 0), (self.height - 1, self.width - 1)); self.draw_editor(&self.editor, (0, 0), (self.height - 1, self.width - 1));
for i in 0..self.width { for i in 0..self.width {
self.draw(i, 0, " ", foreground, background); self.screen.draw(i, 0, " ", foreground, background);
} }
self.draw(1, 0, prefix, foreground, background); self.screen.draw(1, 0, prefix, foreground, background);
self.draw( self.screen.draw(
prefix.len() + 1, prefix.len() + 1,
0, 0,
&line[..], &line[..],
@ -298,14 +285,14 @@ impl<'a> TermUI<'a> {
// Fill in top row with info line color // Fill in top row with info line color
for i in c1.1..(c2.1 + 1) { for i in c1.1..(c2.1 + 1) {
self.draw(i, c1.0, " ", fg, bg); self.screen.draw(i, c1.0, " ", fg, bg);
} }
// Filename and dirty marker // Filename and dirty marker
let filename = editor.file_path.display(); let filename = editor.file_path.display();
let dirty_char = if editor.dirty { "*" } else { "" }; let dirty_char = if editor.dirty { "*" } else { "" };
let name = format!("{}{}", filename, dirty_char); let name = format!("{}{}", filename, dirty_char);
self.draw(c1.1 + 1, c1.0, &name[..], fg, bg); self.screen.draw(c1.1 + 1, c1.0, &name[..], fg, bg);
// Percentage position in document // Percentage position in document
// TODO: use view instead of cursor for calculation if there is more // TODO: use view instead of cursor for calculation if there is more
@ -317,7 +304,8 @@ impl<'a> TermUI<'a> {
100 100
}; };
let pstring = format!("{}%", percentage); let pstring = format!("{}%", percentage);
self.draw(c2.1 - pstring.len(), c1.0, &pstring[..], fg, bg); self.screen
.draw(c2.1 - pstring.len(), c1.0, &pstring[..], fg, bg);
// Text encoding info and tab style // Text encoding info and tab style
let nl = match editor.line_ending_type { let nl = match editor.line_ending_type {
@ -336,7 +324,7 @@ impl<'a> TermUI<'a> {
"UTF8:{} {}:{}", "UTF8:{} {}:{}",
nl, soft_tabs_str, editor.soft_tab_width as usize nl, soft_tabs_str, editor.soft_tab_width as usize
); );
self.draw(c2.1 - 30, c1.0, &info_line[..], fg, bg); self.screen.draw(c2.1 - 30, c1.0, &info_line[..], fg, bg);
// Draw main text editing area // Draw main text editing area
self.draw_editor_text(editor, (c1.0 + 1, c1.1), c2); self.draw_editor_text(editor, (c1.0 + 1, c1.1), c2);
@ -375,7 +363,7 @@ impl<'a> TermUI<'a> {
// Fill in the gutter with the appropriate background // Fill in the gutter with the appropriate background
for y in c1.0..(c2.0 + 1) { for y in c1.0..(c2.0 + 1) {
for x in c1.1..(c1.1 + gutter_width - 1) { for x in c1.1..(c1.1 + gutter_width - 1) {
self.draw(x, y, " ", color::White, color::Blue); self.screen.draw(x, y, " ", color::White, color::Blue);
} }
} }
@ -386,7 +374,7 @@ impl<'a> TermUI<'a> {
let lnx = c1.1 + (gutter_width - 1 - digit_count(line_num as u32, 10) as usize); let lnx = c1.1 + (gutter_width - 1 - digit_count(line_num as u32, 10) as usize);
let lny = screen_line as usize; let lny = screen_line as usize;
if lny >= c1.0 && lny <= c2.0 { if lny >= c1.0 && lny <= c2.0 {
self.draw( self.screen.draw(
lnx, lnx,
lny, lny,
&format!("{}", line_num)[..], &format!("{}", line_num)[..],
@ -437,7 +425,7 @@ impl<'a> TermUI<'a> {
// Actually print the character // Actually print the character
if is_line_ending(g) { if is_line_ending(g) {
if at_cursor { if at_cursor {
self.draw( self.screen.draw(
px as usize, px as usize,
py as usize, py as usize,
" ", " ",
@ -449,7 +437,7 @@ impl<'a> TermUI<'a> {
for i in 0..width { for i in 0..width {
let tpx = px as usize + i; let tpx = px as usize + i;
if tpx <= c2.1 { if tpx <= c2.1 {
self.draw( self.screen.draw(
tpx as usize, tpx as usize,
py as usize, py as usize,
" ", " ",
@ -460,7 +448,7 @@ impl<'a> TermUI<'a> {
} }
if at_cursor { if at_cursor {
self.draw( self.screen.draw(
px as usize, px as usize,
py as usize, py as usize,
" ", " ",
@ -470,9 +458,21 @@ impl<'a> TermUI<'a> {
} }
} else { } else {
if at_cursor { if at_cursor {
self.draw(px as usize, py as usize, g, color::Black, color::White); self.screen.draw(
px as usize,
py as usize,
g,
color::Black,
color::White,
);
} else { } else {
self.draw(px as usize, py as usize, g, color::White, color::Black); self.screen.draw(
px as usize,
py as usize,
g,
color::White,
color::Black,
);
} }
} }
} }
@ -523,40 +523,9 @@ impl<'a> TermUI<'a> {
if (px >= c1.1 as isize) && (py >= c1.0 as isize) && (px <= c2.1 as isize) if (px >= c1.1 as isize) && (py >= c1.0 as isize) && (px <= c2.1 as isize)
&& (py <= c2.0 as isize) && (py <= c2.0 as isize)
{ {
self.draw(px as usize, py as usize, " ", color::Black, color::White); self.screen
.draw(px as usize, py as usize, " ", color::Black, color::White);
} }
} }
} }
fn clear(&self) {
write!(
self.out.borrow_mut(),
"{}{}",
color::Bg(color::Black),
termion::clear::All
).unwrap();
self.out.borrow_mut().flush().unwrap();
}
fn present(&self) {
// TODO
}
fn draw<C1: color::Color, C2: color::Color>(
&self,
x: usize,
y: usize,
text: &str,
fg: C1,
bg: C2,
) {
write!(
self.out.borrow_mut(),
"{}{}{}{}",
termion::cursor::Goto((x + 1) as u16, (y + 1) as u16),
color::Fg(fg),
color::Bg(bg),
text
).unwrap();
}
} }

72
src/term_ui/screen.rs Normal file
View File

@ -0,0 +1,72 @@
use std::cell::RefCell;
use std::io;
use std::io::Write;
use termion;
use termion::screen::AlternateScreen;
use termion::color;
use termion::raw::{IntoRawMode, RawTerminal};
pub(crate) struct Screen {
out: RefCell<AlternateScreen<RawTerminal<io::Stdout>>>,
}
impl Screen {
pub(crate) fn new() -> Self {
Screen {
out: RefCell::new(AlternateScreen::from(io::stdout().into_raw_mode().unwrap())),
}
}
pub(crate) fn clear(&self) {
write!(
self.out.borrow_mut(),
"{}{}",
color::Bg(color::Black),
termion::clear::All
).unwrap();
}
pub(crate) fn present(&self) {
self.out.borrow_mut().flush().unwrap();
}
pub(crate) fn draw<C1: color::Color, C2: color::Color>(
&self,
x: usize,
y: usize,
text: &str,
fg: C1,
bg: C2,
) {
write!(
self.out.borrow_mut(),
"{}{}{}{}",
termion::cursor::Goto((x + 1) as u16, (y + 1) as u16),
color::Fg(fg),
color::Bg(bg),
text
).unwrap();
}
pub(crate) fn hide_cursor(&self) {
write!(self.out.borrow_mut(), "{}", termion::cursor::Hide).unwrap();
}
pub(crate) fn show_cursor(&self) {
write!(self.out.borrow_mut(), "{}", termion::cursor::Show).unwrap();
}
}
impl Drop for Screen {
fn drop(&mut self) {
write!(
self.out.borrow_mut(),
"{}{}",
color::Fg(color::Reset),
color::Bg(color::Reset)
).unwrap();
self.clear();
self.show_cursor();
}
}