2
0
mirror of https://github.com/xvxx/phetch synced 2024-11-15 00:12:50 +00:00
phetch/src/ui.rs

131 lines
3.3 KiB
Rust
Raw Normal View History

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;
2019-12-17 02:50:49 +00:00
use menu::MenuView;
2019-12-16 23:54:20 +00:00
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-17 04:56:49 +00:00
dirty: bool, // redraw?
2019-12-16 20:45:27 +00:00
}
2019-12-16 22:40:10 +00:00
#[derive(Debug)]
pub enum Action {
2019-12-17 04:56:49 +00:00
None, // do nothing
Back, // back in history
Forward, // also history
2019-12-17 02:50:49 +00:00
Open(String), // url
Input, // redraw the input bar
2019-12-17 04:56:49 +00:00
Quit, // yup
Unknown, // handler doesn't know what to do
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-17 04:56:49 +00:00
dirty: true,
2019-12-16 20:45:27 +00:00
}
}
2019-12-16 22:40:10 +00:00
pub fn run(&mut self) {
2019-12-16 21:49:06 +00:00
loop {
2019-12-17 02:50:49 +00:00
self.draw();
self.update();
2019-12-16 21:49:06 +00:00
}
}
2019-12-17 04:56:49 +00:00
pub fn draw(&mut self) {
if self.dirty {
print!("{}", self.render());
self.dirty = false;
}
2019-12-17 03:11:47 +00:00
}
pub fn update(&mut self) {
match self.process_input() {
Action::Quit => std::process::exit(1),
_ => {}
}
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 02:50:49 +00:00
pub fn open(&mut self, url: &str) {
2019-12-17 05:06:25 +00:00
self.dirty = true;
2019-12-17 01:57:37 +00:00
let (typ, host, port, sel) = gopher::parse_url(url);
2019-12-17 00:36:44 +00:00
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 {
2019-12-17 02:50:49 +00:00
Type::Menu => self.add_page(MenuView::from(url.to_string(), response)),
// Type::Text => self.add_page(TextView::from(url, response)),
2019-12-17 01:53:34 +00:00
_ => panic!("unknown type: {:?}", typ),
2019-12-16 21:13:00 +00:00
}
}
2019-12-17 02:50:49 +00:00
fn add_page<T: View + 'static>(&mut self, view: T) {
2019-12-16 23:54:20 +00:00
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 process_input(&mut self) -> Action {
let mut stdout = stdout().into_raw_mode().unwrap();
stdout.flush().unwrap();
2019-12-17 04:56:49 +00:00
match self.process_page_input() {
Action::Open(url) => {
self.open(&url);
Action::None
}
a => a,
}
}
fn process_page_input(&mut self) -> Action {
let stdin = stdin();
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 {
2019-12-17 03:11:47 +00:00
Key::Ctrl('q') | Key::Ctrl('c') => return Action::Quit,
2019-12-16 22:40:10 +00:00
Key::Left => return Action::Back,
Key::Right => return Action::Forward,
_ => {}
},
action => return action,
}
}
Action::None
}
2019-12-16 20:45:27 +00:00
}