WIP switching from Rustbox to Termion for terminal handling.

This commit is contained in:
Nathan Vegdahl 2017-12-31 16:55:27 -08:00
parent 6ccba0510b
commit c11aee9bf6
4 changed files with 297 additions and 499 deletions

188
Cargo.lock generated
View File

@ -4,9 +4,9 @@ version = "0.0.2"
dependencies = [
"docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ropey 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rustbox 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -19,16 +19,6 @@ dependencies = [
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "docopt"
version = "0.8.1"
@ -41,38 +31,6 @@ dependencies = [
"strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-zircon"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-zircon-sys"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gag"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "0.2.11"
@ -96,91 +54,24 @@ dependencies = [
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-bigint 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"num-complex 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
"num-rational 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-bigint"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-complex"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-iter"
version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-rational"
version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-bigint 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "quote"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rand"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fuchsia-zircon 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "0.2.5"
@ -207,22 +98,6 @@ dependencies = [
"unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustbox"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gag 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"termbox-sys 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-serialize"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.27"
@ -276,22 +151,15 @@ dependencies = [
]
[[package]]
name = "tempfile"
version = "2.2.0"
name = "termion"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termbox-sys"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "thread_local"
version = "0.3.5"
@ -334,44 +202,19 @@ name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
"checksum bitflags 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a41f80ec2e140d19e789764fdf22d0f2da98fe7e55d26f99db59cb3d2605d327"
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
"checksum docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b5b93718f8b3e5544fcc914c43de828ca6c6ace23e0332c6080a2977b49787a"
"checksum fuchsia-zircon 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd510087c325af53ba24f3be8f1c081b0982319adcb8b03cad764512923ccc19"
"checksum fuchsia-zircon-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "08b3a6f13ad6b96572b53ce7af74543132f1a7055ccceb6d073dd36c54481859"
"checksum gag 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c606f5c0da18075916377e73de8aec7c140e1b6110a3cf26ae1f47873529b47e"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
"checksum libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "36fbc8a8929c632868295d0178dd8f63fc423fd7537ad0738372bd010b3ac9b0"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
"checksum num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cc4083e14b542ea3eb9b5f33ff48bd373a92d78687e74f4cc0a30caeb754f0ca"
"checksum num-bigint 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "bdc1494b5912f088f260b775799468d9b9209ac60885d8186a547a0476289e23"
"checksum num-complex 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "58de7b4bf7cf5dbecb635a5797d489864eadd03b107930cbccf9e0fd7428b47c"
"checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba"
"checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01"
"checksum num-rational 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "0c7cb72a95250d8a370105c828f388932373e0e94414919891a0f945222310fe"
"checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "9e7944d95d25ace8f377da3ac7068ce517e4c646754c43a1b1849177bbf72e59"
"checksum redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "07b8f011e3254d5a9b318fde596d409a0001c9ae4c6e7907520c2eaa4d988c99"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa"
"checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e"
"checksum ropey 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6eb4b74f76bc72338d8aebb193e9575398703552530e329dae718e38e4bf2ca0"
"checksum rustbox 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acc40f390f6c5e2d47ff358020103deb6ebd0e98f2df2cec3cb15e054f403ed8"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "db99f3919e20faa51bb2996057f5031d8685019b5a06139b1ce761da671b8526"
"checksum serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ba7591cfe93755e89eeecdbcc668885624829b020050e6aec99c2a03bd3fd0"
"checksum serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e03f1c9530c3fb0a0a5c9b826bdd9246a5921ae995d75f512ac917fc4dd55b5"
@ -379,8 +222,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "11ce2fe9db64b842314052e2421ac61a73ce41b898dc8e3750398b219c5fc1e0"
"checksum termbox-sys 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "e32daa27881ea4b2ef36e4972d6cdefb241c19ac48d318381b688d1a631b8760"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
"checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946"
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
@ -388,5 +230,3 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"

View File

@ -15,4 +15,4 @@ unicode-width = "0.1"
serde = "1.*"
serde_derive = "1.*"
docopt = "0.8"
rustbox = "0.9"
termion = "1.5"

View File

@ -1,9 +1,9 @@
extern crate docopt;
extern crate ropey;
extern crate rustbox;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate termion;
extern crate unicode_segmentation;
extern crate unicode_width;
@ -50,6 +50,7 @@ fn main() {
};
// Initialize and start UI
let mut ui = TermUI::new_from_editor(editor);
let mut stdin = std::io::stdin();
let mut ui = TermUI::new_from_editor(&mut stdin, editor);
ui.main_ui_loop();
}

View File

@ -1,315 +1,288 @@
#![allow(dead_code)]
use rustbox;
use rustbox::Color;
use editor::Editor;
use std::time::Duration;
use formatter::{block_index_and_offset, LineFormatter, LINE_BLOCK_LENGTH};
use std::char;
use std::default::Default;
use std::cell::RefCell;
use std::cmp::min;
use std::io;
use std::io::Write;
use termion;
use termion::event::{Event, Key};
use termion::input::TermRead;
use termion::color;
use termion::raw::{IntoRawMode, RawTerminal};
use editor::Editor;
use formatter::{block_index_and_offset, LineFormatter, LINE_BLOCK_LENGTH};
use self::formatter::ConsoleLineFormatter;
use string_utils::{is_line_ending, line_ending_to_str, LineEnding};
use utils::digit_count;
use self::formatter::ConsoleLineFormatter;
pub mod formatter;
// Key codes
const K_ENTER: u16 = 13;
const K_TAB: u16 = 9;
const K_SPACE: u16 = 32;
const K_BACKSPACE: u16 = 127;
const K_DELETE: u16 = 65522;
const K_PAGEUP: u16 = 65519;
const K_PAGEDOWN: u16 = 65518;
const K_UP: u16 = 65517;
const K_DOWN: u16 = 65516;
const K_LEFT: u16 = 65515;
const K_RIGHT: u16 = 65514;
const K_ESC: u16 = 27;
const K_CTRL_L: u16 = 12;
const K_CTRL_O: u16 = 15;
const K_CTRL_Q: u16 = 17;
const K_CTRL_S: u16 = 19;
const K_CTRL_Y: u16 = 25;
const K_CTRL_Z: u16 = 26;
/// Generalized ui loop.
macro_rules! ui_loop {
($term_ui:ident, draw $draw:block, key_press($key:ident) $key_press:block) => {
let mut stop = false;
pub struct TermUI {
rb: rustbox::RustBox,
loop {
// Draw the editor to screen
{$draw};
$term_ui.present();
// Handle input
match $term_ui.inp.next() {
Some(Ok(Event::Key($key))) => {
let status = || -> LoopStatus {
$key_press
}();
if status == LoopStatus::Done {
stop = true;
// break;
}
}
_ => {
// break;
}
}
// Check for screen resize
let (w, h) = termion::terminal_size().unwrap();
if $term_ui.width != w as usize || $term_ui.height != h as usize {
$term_ui.width = w as usize;
$term_ui.height = h as usize;
$term_ui.editor.update_dim($term_ui.height - 1, $term_ui.width);
}
if stop || $term_ui.quit {
break;
}
}
};
}
pub struct TermUI<'a> {
inp: termion::input::Events<io::StdinLock<'a>>,
out: RefCell<RawTerminal<io::Stdout>>,
editor: Editor<ConsoleLineFormatter>,
width: usize,
height: usize,
quit: bool,
}
impl TermUI {
pub fn new() -> TermUI {
let rb = match rustbox::RustBox::init(rustbox::InitOptions {
buffer_stderr: true,
..Default::default()
}) {
Ok(rbox) => rbox,
Err(_) => panic!("Could not create Rustbox instance."),
};
let w = rb.width();
let h = rb.height();
let mut editor = Editor::new(ConsoleLineFormatter::new(4));
editor.update_dim(h - 1, w);
#[derive(Debug, Copy, Clone, PartialEq)]
enum LoopStatus {
Done,
Continue,
}
TermUI {
rb: rb,
editor: editor,
width: w,
height: h,
}
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> {
pub fn new<'b>(stdin: &'b mut io::Stdin) -> TermUI<'b> {
TermUI::new_from_editor(stdin, Editor::new(ConsoleLineFormatter::new(4)))
}
pub fn new_from_editor(ed: Editor<ConsoleLineFormatter>) -> TermUI {
let rb = match rustbox::RustBox::init(rustbox::InitOptions {
buffer_stderr: true,
..Default::default()
}) {
Ok(rbox) => rbox,
Err(_) => panic!("Could not create Rustbox instance."),
};
let w = rb.width();
let h = rb.height();
pub fn new_from_editor<'b>(
stdin: &'b mut io::Stdin,
ed: Editor<ConsoleLineFormatter>,
) -> TermUI<'b> {
let out = io::stdout().into_raw_mode().unwrap();
let (w, h) = termion::terminal_size().unwrap();
let mut editor = ed;
editor.update_dim(h - 1, w);
editor.update_dim(h as usize - 1, w as usize);
TermUI {
rb: rb,
inp: stdin.lock().events(),
out: RefCell::new(out),
editor: editor,
width: w,
height: h,
width: w as usize,
height: h as usize,
quit: false,
}
}
pub fn main_ui_loop(&mut self) {
// Quitting flag
let mut quit = false;
let mut resize: Option<(usize, usize)> = None;
// Hide cursor
write!(self.out.borrow_mut(), "{}", termion::cursor::Hide).unwrap();
self.editor.update_dim(self.height - 1, self.width);
self.editor.formatter.set_wrap_width(self.width as usize);
loop {
// Draw the editor to screen
self.editor.update_view_dim();
self.editor.formatter.set_wrap_width(self.editor.view_dim.1);
self.rb.clear();
self.draw_editor(&self.editor, (0, 0), (self.height - 1, self.width - 1));
self.rb.present();
ui_loop!(
self,
// Handle events. We block on the first event, so that the
// program doesn't loop like crazy, but then continue pulling
// events in a non-blocking way until we run out of events
// to handle.
let mut e = self.rb.poll_event(true); // Block until we get an event
loop {
match e {
Ok(rustbox::Event::KeyEventRaw(_, key, character)) => {
// println!(" {} {} {}", modifier, key, character);
match key {
K_CTRL_Q => {
quit = true;
break;
}
// Draw
draw {
self.editor.update_view_dim();
self.editor.formatter.set_wrap_width(self.editor.view_dim.1);
self.clear();
self.draw_editor(&self.editor, (0, 0), (self.height - 1, self.width - 1));
},
K_CTRL_S => {
self.editor.save_if_dirty();
}
K_CTRL_Z => {
self.editor.undo();
}
K_CTRL_Y => {
self.editor.redo();
}
K_CTRL_L => {
self.go_to_line_ui_loop();
}
K_PAGEUP => {
self.editor.page_up();
}
K_PAGEDOWN => {
self.editor.page_down();
}
K_UP => {
self.editor.cursor_up(1);
}
K_DOWN => {
self.editor.cursor_down(1);
}
K_LEFT => {
self.editor.cursor_left(1);
}
K_RIGHT => {
self.editor.cursor_right(1);
}
K_ENTER => {
let nl = line_ending_to_str(self.editor.line_ending_type);
self.editor.insert_text_at_cursor(nl);
}
K_SPACE => {
self.editor.insert_text_at_cursor(" ");
}
K_TAB => {
self.editor.insert_tab_at_cursor();
}
K_BACKSPACE => {
self.editor.backspace_at_cursor();
}
K_DELETE => {
self.editor.remove_text_in_front_of_cursor(1);
}
// Character
0 => {
if let Option::Some(c) = char::from_u32(character) {
self.editor.insert_text_at_cursor(&c.to_string()[..]);
}
}
_ => {}
}
// Handle input
key_press(key) {
match key {
Key::Ctrl('q') => {
self.quit = true;
return LoopStatus::Done;
}
Ok(rustbox::Event::ResizeEvent(w, h)) => {
resize = Some((h as usize, w as usize));
Key::Ctrl('s') => {
self.editor.save_if_dirty();
}
_ => {
break;
Key::Ctrl('z') => {
self.editor.undo();
}
Key::Ctrl('y') => {
self.editor.redo();
}
Key::Ctrl('l') => {
self.go_to_line_ui_loop();
}
Key::PageUp => {
self.editor.page_up();
}
Key::PageDown => {
self.editor.page_down();
}
Key::Up => {
self.editor.cursor_up(1);
}
Key::Down => {
self.editor.cursor_down(1);
}
Key::Left => {
self.editor.cursor_left(1);
}
Key::Right => {
self.editor.cursor_right(1);
}
Key::Char('\n') => {
let nl = line_ending_to_str(self.editor.line_ending_type);
self.editor.insert_text_at_cursor(nl);
}
Key::Char(' ') => {
self.editor.insert_text_at_cursor(" ");
}
Key::Char('\t') => {
self.editor.insert_tab_at_cursor();
}
Key::Backspace => {
self.editor.backspace_at_cursor();
}
Key::Delete => {
self.editor.remove_text_in_front_of_cursor(1);
}
// Character
Key::Char(c) => {
self.editor.insert_text_at_cursor(&c.to_string()[..]);
}
k => {
println!("{:?}", k);
}
}
e = self.rb.peek_event(Duration::from_millis(0), true); // Get next event (if any)
LoopStatus::Continue
}
if let Some((h, w)) = resize {
self.width = w as usize;
self.height = h as usize;
self.editor.update_dim(self.height, self.width);
}
resize = None;
// Quit if quit flag is set
if quit {
break;
}
}
);
}
fn go_to_line_ui_loop(&mut self) {
let foreground = Color::Black;
let background = Color::Cyan;
let foreground = color::Black;
let background = color::Cyan;
let mut cancel = false;
let mut confirm = false;
let prefix = "Jump to line: ";
let mut line = String::new();
loop {
// Draw the editor to screen
self.editor.update_view_dim();
self.editor.formatter.set_wrap_width(self.editor.view_dim.1);
self.rb.clear();
self.draw_editor(&self.editor, (0, 0), (self.height - 1, self.width - 1));
for i in 0..self.width {
self.rb
.print(i, 0, rustbox::RB_NORMAL, foreground, background, " ");
}
self.rb
.print(1, 0, rustbox::RB_NORMAL, foreground, background, prefix);
self.rb.print(
prefix.len() + 1,
0,
rustbox::RB_NORMAL,
foreground,
background,
&line[..],
);
self.rb.present();
ui_loop!(
self,
// Handle events. We block on the first event, so that the
// program doesn't loop like crazy, but then continue pulling
// events in a non-blocking way until we run out of events
// to handle.
let mut e = self.rb.poll_event(true); // Block until we get an event
loop {
match e {
Ok(rustbox::Event::KeyEventRaw(_, key, character)) => {
match key {
K_ESC => {
cancel = true;
break;
}
// Draw
draw {
self.editor.update_view_dim();
self.editor.formatter.set_wrap_width(self.editor.view_dim.1);
self.clear();
self.draw_editor(&self.editor, (0, 0), (self.height - 1, self.width - 1));
for i in 0..self.width {
self.draw(i, 0, " ", foreground, background);
}
self.draw(1, 0, prefix, foreground, background);
self.draw(
prefix.len() + 1,
0,
&line[..],
foreground,
background,
);
},
K_ENTER => {
confirm = true;
break;
}
// Handle input
key_press(key) {
match key {
Key::Esc => {
cancel = true;
return LoopStatus::Done;
}
K_BACKSPACE => {
line.pop();
}
Key::Char('\n') => {
return LoopStatus::Done;
}
// Character
0 => {
if let Option::Some(c) = char::from_u32(character) {
if c.is_numeric() {
line.push(c);
}
}
}
Key::Backspace => {
line.pop();
}
_ => {}
// Character
Key::Char(c) => {
if c.is_numeric() {
line.push(c);
}
}
Ok(rustbox::Event::ResizeEvent(w, h)) => {
self.width = w as usize;
self.height = h as usize;
self.editor.update_dim(self.height - 1, self.width);
}
_ => {
break;
}
_ => {}
}
e = self.rb.peek_event(Duration::from_millis(0), true); // Get next event (if any)
return LoopStatus::Continue;
}
);
// Cancel if flag is set
if cancel {
break;
}
// Jump to line!
if confirm {
if let Ok(n) = line.parse() {
let n2: usize = n; // Weird work-around: the type of n wasn't being inferred
if n2 > 0 {
self.editor.jump_to_line(n2 - 1);
} else {
self.editor.jump_to_line(0);
}
// Jump to line!
if !cancel {
if let Ok(n) = line.parse() {
let n2: usize = n; // Weird work-around: the type of n wasn't being inferred
if n2 > 0 {
self.editor.jump_to_line(n2 - 1);
} else {
self.editor.jump_to_line(0);
}
break;
}
}
}
@ -320,27 +293,19 @@ impl TermUI {
c1: (usize, usize),
c2: (usize, usize),
) {
let foreground = Color::Black;
let background = Color::Cyan;
let fg = color::Black;
let bg = color::Cyan;
// Fill in top row with info line color
for i in c1.1..(c2.1 + 1) {
self.rb
.print(i, c1.0, rustbox::RB_NORMAL, foreground, background, " ");
self.draw(i, c1.0, " ", fg, bg);
}
// Filename and dirty marker
let filename = editor.file_path.display();
let dirty_char = if editor.dirty { "*" } else { "" };
let name = format!("{}{}", filename, dirty_char);
self.rb.print(
c1.1 + 1,
c1.0,
rustbox::RB_NORMAL,
foreground,
background,
&name[..],
);
self.draw(c1.1 + 1, c1.0, &name[..], fg, bg);
// Percentage position in document
// TODO: use view instead of cursor for calculation if there is more
@ -352,14 +317,7 @@ impl TermUI {
100
};
let pstring = format!("{}%", percentage);
self.rb.print(
c2.1 - pstring.len(),
c1.0,
rustbox::RB_NORMAL,
foreground,
background,
&pstring[..],
);
self.draw(c2.1 - pstring.len(), c1.0, &pstring[..], fg, bg);
// Text encoding info and tab style
let nl = match editor.line_ending_type {
@ -378,14 +336,7 @@ impl TermUI {
"UTF8:{} {}:{}",
nl, soft_tabs_str, editor.soft_tab_width as usize
);
self.rb.print(
c2.1 - 30,
c1.0,
rustbox::RB_NORMAL,
foreground,
background,
&info_line[..],
);
self.draw(c2.1 - 30, c1.0, &info_line[..], fg, bg);
// Draw main text editing area
self.draw_editor_text(editor, (c1.0 + 1, c1.1), c2);
@ -424,8 +375,7 @@ impl TermUI {
// Fill in the gutter with the appropriate background
for y in c1.0..(c2.0 + 1) {
for x in c1.1..(c1.1 + gutter_width - 1) {
self.rb
.print(x, y, rustbox::RB_NORMAL, Color::White, Color::Blue, " ");
self.draw(x, y, " ", color::White, color::Blue);
}
}
@ -436,13 +386,12 @@ impl TermUI {
let lnx = c1.1 + (gutter_width - 1 - digit_count(line_num as u32, 10) as usize);
let lny = screen_line as usize;
if lny >= c1.0 && lny <= c2.0 {
self.rb.print(
self.draw(
lnx,
lny,
rustbox::RB_NORMAL,
Color::White,
Color::Blue,
&format!("{}", line_num)[..],
color::White,
color::Blue,
);
}
}
@ -488,59 +437,42 @@ impl TermUI {
// Actually print the character
if is_line_ending(g) {
if at_cursor {
self.rb.print(
self.draw(
px as usize,
py as usize,
rustbox::RB_NORMAL,
Color::Black,
Color::White,
" ",
color::White,
color::Black,
);
}
} else if g == "\t" {
for i in 0..width {
let tpx = px as usize + i;
if tpx <= c2.1 {
self.rb.print(
self.draw(
tpx as usize,
py as usize,
rustbox::RB_NORMAL,
Color::White,
Color::Black,
" ",
color::White,
color::Black,
);
}
}
if at_cursor {
self.rb.print(
self.draw(
px as usize,
py as usize,
rustbox::RB_NORMAL,
Color::Black,
Color::White,
" ",
color::Black,
color::White,
);
}
} else {
if at_cursor {
self.rb.print(
px as usize,
py as usize,
rustbox::RB_NORMAL,
Color::Black,
Color::White,
g,
);
self.draw(px as usize, py as usize, g, color::Black, color::White);
} else {
self.rb.print(
px as usize,
py as usize,
rustbox::RB_NORMAL,
Color::White,
Color::Black,
g,
);
self.draw(px as usize, py as usize, g, color::White, color::Black);
}
}
}
@ -591,15 +523,40 @@ impl TermUI {
if (px >= c1.1 as isize) && (py >= c1.0 as isize) && (px <= c2.1 as isize)
&& (py <= c2.0 as isize)
{
self.rb.print(
px as usize,
py as usize,
rustbox::RB_NORMAL,
Color::Black,
Color::White,
" ",
);
self.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();
}
}