extern crate pancurses;
use pancurses::{Window, Input, initscr};
pub struct Terminal {
win: Window
}
#[derive(Debug, PartialEq)]
pub enum Key {
Alpha(char),
Enter,
Space,
Backspace,
ArrowUp,
ArrowDown,
ArrowLeft,
ArrowRight,
F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,F11,F12
}
impl Terminal {
pub fn new() -> Terminal {
let win = initscr();
win.keypad(true);
Terminal { win }
}
pub fn out(&self, s: String) {
self.win.printw(s);
self.win.refresh();
}
pub fn outln(&self, s: String) {
self.win.printw(s);
self.outbr();
}
pub fn outbr(&self) {
self.win.printw(String::from("\n"));
self.win.refresh();
}
pub fn raw_out(&self, s: String) {
self.win.printw(s);
}
pub fn raw_outln(&self, s: String) {
self.win.printw(s);
self.raw_br();
}
pub fn raw_br(&self) {
self.win.printw(String::from("\n"));
}
pub fn raw_refresh(&self) {
self.win.refresh();
}
pub fn raw_posxy(&self) -> (i32, i32) {
(self.win.get_cur_x(), self.win.get_cur_y())
}
pub fn raw_posx(&self) -> i32 {
self.win.get_cur_x()
}
pub fn raw_posy(&self) -> i32 {
self.win.get_cur_y()
}
pub fn raw_move(&self, x: i32, y: i32) {
self.win.mv(y, x);
}
pub fn raw_move_offset(&self, xoffs: i32, yoffs: i32) {
self.raw_move(self.raw_posx() + xoffs, self.raw_posy() + yoffs);
}
pub fn raw_move_first(&self) {
self.raw_move(0, self.raw_posy());
}
pub fn raw_move_prev(&self) {
self.raw_move_offset(-1, 0);
}
pub fn raw_move_next(&self) {
self.raw_move_offset(1, 0);
}
pub fn raw_delete(&self) {
self.win.delch();
}
pub fn raw_delete_prev(&self) {
self.raw_move_prev();
self.raw_delete();
}
pub fn raw_delete_offset(&self, xoffs: i32) {
let offs = xoffs / xoffs.abs(); let here = self.raw_posx();
while self.raw_posx() != here + xoffs {
self.raw_move_offset(offs, 0);
self.raw_delete();
}
}
pub fn raw_delete_from(&self, chars: usize) {
self.raw_move_first();
self.raw_move_offset(chars as i32, 0);
self.raw_delete_to(0);
}
pub fn raw_delete_to(&self, x: i32) {
let offs = if x > self.raw_posx() {
1
} else {
-1
};
while self.raw_posx() != x {
self.raw_move_offset(offs, 0);
self.raw_delete();
}
}
pub fn get_char(&self) -> Option<Key> {
match self.win.getch() {
Some(Input::Character('\n')) | Some(Input::Character('\r')) => Some(Key::Enter),
Some(Input::Character('\x08')) => Some(Key::Backspace),
Some(Input::Character(' ')) => Some(Key::Space),
Some(Input::Character(c)) => Some(Key::Alpha(c)),
Some(Input::KeyUp) => Some(Key::ArrowUp),
Some(Input::KeyDown) => Some(Key::ArrowDown),
Some(Input::KeyLeft) => Some(Key::ArrowLeft),
Some(Input::KeyRight) => Some(Key::ArrowRight),
Some(Input::KeyF1) => Some(Key::F1),
Some(Input::KeyF2) => Some(Key::F2),
Some(Input::KeyF3) => Some(Key::F3),
Some(Input::KeyF4) => Some(Key::F4),
Some(Input::KeyF5) => Some(Key::F5),
Some(Input::KeyF6) => Some(Key::F6),
Some(Input::KeyF7) => Some(Key::F7),
Some(Input::KeyF8) => Some(Key::F8),
Some(Input::KeyF9) => Some(Key::F9),
Some(Input::KeyF10) => Some(Key::F10),
Some(Input::KeyF11) => Some(Key::F11),
Some(Input::KeyF12) => Some(Key::F12),
None => None,
_ => None,
}
}
pub fn ask(&self, prefix: String) -> String {
self.out(prefix);
let mut r = String::new();
let mut x = 0;
while let Some(i) = self.get_char() {
match i {
Key::Enter => break,
Key::Backspace => {
if x != 0 { x -= 1; } else { self.raw_move_next(); continue; }
self.raw_delete();
r.pop();
},
Key::Alpha(c) => {
self.raw_delete_prev();
x += 1;
r.push(c);
self.out(c.to_string());
},
_ => continue
}
}
r
}
pub fn choices(&self, prefix: String, strs: Vec<String>) -> String {
let mut y: i32 = 0;
let here = self.raw_posxy();
let mut i = 0;
for str in strs.clone() {
if i == 0 {
self.out(prefix.clone());
}
self.outln(str);
i += 1;
}
self.raw_move(here.0 + (prefix.len() + strs[0].clone().len()) as i32, here.1);
while let Some(i) = self.get_char() {
match i {
Key::Enter => break,
Key::ArrowDown => {
if y + 1 >= strs.len() as i32 {
continue;
}
y += 1;
self.raw_delete_to(0);
self.out(strs[(y - 1) as usize].clone());
self.raw_move_offset(0, 1);
self.raw_delete_from(prefix.clone().len() + strs[y as usize].clone().len());
self.out(prefix.clone());
self.out(strs[y as usize].clone());
},
Key::ArrowUp => {
if (y - 1) < 0 {
continue;
}
y -= 1;
self.raw_delete_to(0);
self.out(strs[(y + 1) as usize].clone());
self.raw_move_offset(0, -1);
self.raw_delete_from(prefix.clone().len() + strs[y as usize].clone().len());
self.out(prefix.clone());
self.out(strs[y as usize].clone());
},
_ => continue,
}
}
self.raw_move_offset(0, strs.len() as i32 - y - 1);
strs[y as usize].clone()
}
}