You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
phetch/src/ui.rs

122 lines
3.0 KiB
Rust

5 years ago
use std::io;
use std::io::{stdin, stdout, Write};
use termion::input::TermRead;
use termion::raw::IntoRawMode;
use gopher;
use gopher::Type;
use menu::{Menu, MenuView};
5 years ago
pub type Key = termion::event::Key;
pub type Error = io::Error;
5 years ago
pub struct UI {
pages: Vec<Box<dyn View>>,
5 years ago
page: usize,
}
5 years ago
#[derive(Debug)]
pub enum Action {
None,
Up,
Down,
PageUp,
PageDown,
Back,
Forward,
Open,
Quit,
Unknown,
5 years ago
Input, // redraw the input bar
FollowLink(usize),
5 years ago
}
pub trait View {
fn process_input(&mut self, c: Key) -> Action;
5 years ago
fn render(&self) -> String;
5 years ago
}
5 years ago
impl UI {
pub fn new() -> UI {
UI {
pages: vec![],
page: 0,
}
}
5 years ago
pub fn run(&mut self) {
5 years ago
loop {
self.print();
self.respond_to_user();
}
}
pub fn print(&self) {
print!("{}", self.render());
// print!("{:#?}", self);
5 years ago
}
pub fn render(&self) -> String {
5 years ago
// let (cols, rows) = termion::terminal_size().expect("can't get terminal size");
5 years ago
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")
5 years ago
}
5 years ago
pub fn load(&mut self, url: &str) {
let (typ, host, port, sel) = gopher::parse_url(url);
5 years ago
let response = gopher::fetch(host, port, sel)
.map_err(|e| {
5 years ago
eprintln!("\x1B[91merror loading \x1b[93m{}: \x1B[0m{}", url, e);
5 years ago
std::process::exit(1);
})
.unwrap();
match typ {
5 years ago
Type::Menu => self.add_view(MenuView::from(url.to_string(), response)),
5 years ago
// Type::Text => self.add_view(TextView::from(url, response)),
5 years ago
_ => panic!("unknown type: {:?}", typ),
5 years ago
}
}
fn add_view<T: View + 'static>(&mut self, view: T) {
self.pages.push(Box::from(view));
5 years ago
if self.pages.len() > 1 {
self.page += 1;
5 years ago
}
}
5 years ago
fn respond_to_user(&mut self) {
5 years ago
match self.process_input() {
Action::Quit => std::process::exit(1),
_ => {}
}
5 years ago
}
fn process_input(&mut self) -> Action {
let stdin = stdin();
let mut stdout = stdout().into_raw_mode().unwrap();
stdout.flush().unwrap();
5 years ago
let page = self.pages.get_mut(self.page).expect("expected Page"); // TODO
5 years ago
for c in stdin.keys() {
5 years ago
let key = c.expect("UI error on stdin.keys"); // TODO
5 years ago
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
}
5 years ago
}