2019-12-16 22:40:10 +00:00
|
|
|
use std::io;
|
|
|
|
use std::io::{stdin, stdout, Write};
|
|
|
|
use termion::input::TermRead;
|
|
|
|
use termion::raw::IntoRawMode;
|
|
|
|
|
2019-12-16 23:54:20 +00:00
|
|
|
use gopher;
|
|
|
|
use gopher::Type;
|
|
|
|
use menu::{Menu, MenuView};
|
|
|
|
|
2019-12-16 22:40:10 +00:00
|
|
|
pub type Key = termion::event::Key;
|
|
|
|
pub type Error = io::Error;
|
2019-12-16 20:45:27 +00:00
|
|
|
|
|
|
|
pub struct UI {
|
2019-12-16 23:54:20 +00:00
|
|
|
pages: Vec<Box<dyn View>>,
|
2019-12-16 20:45:27 +00:00
|
|
|
page: usize,
|
|
|
|
}
|
|
|
|
|
2019-12-16 22:40:10 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum Action {
|
|
|
|
None,
|
|
|
|
Up,
|
|
|
|
Down,
|
|
|
|
PageUp,
|
|
|
|
PageDown,
|
|
|
|
Back,
|
|
|
|
Forward,
|
|
|
|
Open,
|
|
|
|
Quit,
|
|
|
|
Unknown,
|
2019-12-16 23:54:20 +00:00
|
|
|
FollowLink(usize),
|
2019-12-16 22:40:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub trait View {
|
|
|
|
fn process_input(&mut self, c: Key) -> Action;
|
2019-12-17 01:01:23 +00:00
|
|
|
fn render(&self) -> String;
|
2019-12-16 22:40:10 +00:00
|
|
|
}
|
|
|
|
|
2019-12-16 20:45:27 +00:00
|
|
|
impl UI {
|
|
|
|
pub fn new() -> UI {
|
|
|
|
UI {
|
|
|
|
pages: vec![],
|
|
|
|
page: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-16 22:40:10 +00:00
|
|
|
pub fn run(&mut self) {
|
2019-12-16 21:49:06 +00:00
|
|
|
loop {
|
|
|
|
self.print();
|
|
|
|
self.respond_to_user();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn print(&self) {
|
2019-12-16 23:54:20 +00:00
|
|
|
print!("{}", self.render());
|
|
|
|
// print!("{:#?}", self);
|
2019-12-16 21:49:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn render(&self) -> String {
|
2019-12-16 22:40:10 +00:00
|
|
|
// let (cols, rows) = termion::terminal_size().expect("can't get terminal size");
|
2019-12-17 01:01:23 +00:00
|
|
|
if self.pages.len() > 0 && self.page < self.pages.len() {
|
|
|
|
if let Some(page) = self.pages.get(self.page) {
|
|
|
|
return page.render();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
String::from("N/A")
|
2019-12-16 21:49:06 +00:00
|
|
|
}
|
|
|
|
|
2019-12-17 00:36:44 +00:00
|
|
|
pub fn load(&mut self, url: String) {
|
|
|
|
let (typ, host, port, sel) = gopher::parse_url(&url);
|
|
|
|
let response = gopher::fetch(host, port, sel)
|
2019-12-16 23:54:20 +00:00
|
|
|
.map_err(|e| {
|
2019-12-17 00:36:44 +00:00
|
|
|
eprintln!("\x1B[91merror loading \x1b[93m{}: \x1B[0m{}", url, e);
|
2019-12-16 21:25:14 +00:00
|
|
|
std::process::exit(1);
|
2019-12-16 23:54:20 +00:00
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
match typ {
|
|
|
|
Type::Menu => self.add_view(MenuView::from(url, response)),
|
2019-12-17 00:02:23 +00:00
|
|
|
// Type::Text => self.add_view(TextView::from(url, response)),
|
2019-12-16 23:54:20 +00:00
|
|
|
_ => panic!("unknown type"),
|
2019-12-16 21:13:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-16 23:54:20 +00:00
|
|
|
fn add_view<T: View + 'static>(&mut self, view: T) {
|
|
|
|
self.pages.push(Box::from(view));
|
2019-12-16 21:49:06 +00:00
|
|
|
if self.pages.len() > 1 {
|
|
|
|
self.page += 1;
|
2019-12-16 21:13:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-16 22:40:10 +00:00
|
|
|
fn respond_to_user(&mut self) {
|
2019-12-16 22:41:45 +00:00
|
|
|
match self.process_input() {
|
|
|
|
Action::Quit => std::process::exit(1),
|
|
|
|
_ => {}
|
|
|
|
}
|
2019-12-16 22:40:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn process_input(&mut self) -> Action {
|
|
|
|
let stdin = stdin();
|
|
|
|
let mut stdout = stdout().into_raw_mode().unwrap();
|
|
|
|
stdout.flush().unwrap();
|
2019-12-17 00:02:23 +00:00
|
|
|
let page = self.pages.get_mut(self.page).expect("expected Page"); // TODO
|
2019-12-16 22:40:10 +00:00
|
|
|
|
|
|
|
for c in stdin.keys() {
|
2019-12-17 00:02:23 +00:00
|
|
|
let key = c.expect("UI error on stdin.keys"); // TODO
|
2019-12-16 22:40:10 +00:00
|
|
|
match page.process_input(key) {
|
|
|
|
Action::Unknown => match key {
|
|
|
|
Key::Ctrl('q') => return Action::Quit,
|
|
|
|
Key::Up | Key::Ctrl('p') => return Action::Up,
|
|
|
|
Key::Down | Key::Ctrl('n') => return Action::Down,
|
|
|
|
Key::Left => return Action::Back,
|
|
|
|
Key::Right => return Action::Forward,
|
|
|
|
_ => {}
|
|
|
|
},
|
|
|
|
action => return action,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Action::None
|
|
|
|
}
|
2019-12-16 20:45:27 +00:00
|
|
|
}
|