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/menu.rs

180 lines
6.1 KiB
Rust

use gopher;
use gopher::Type;
5 years ago
use std::io;
5 years ago
use ui::{Action, Key, View};
#[derive(Debug)]
pub struct MenuView {
5 years ago
pub input: String, // user's inputted value
pub menu: Menu, // data
5 years ago
pub line: usize, // selected line
pub scroll: usize, // scrolling offset
}
#[derive(Debug)]
pub struct Menu {
5 years ago
url: String, // gopher url
5 years ago
lines: Vec<Line>, // lines
raw: String, // raw gopher response
}
5 years ago
#[derive(Debug)]
5 years ago
pub struct Line {
5 years ago
name: String,
5 years ago
host: String,
5 years ago
port: String,
5 years ago
selector: String,
typ: Type,
}
impl View for MenuView {
5 years ago
fn render(&self) -> String {
let mut out = self.menu.raw.to_string();
out.push('\n');
out.push_str(&format!("{:#?}", self));
out
}
5 years ago
fn process_input(&mut self, key: Key) -> Action {
match key {
5 years ago
Key::Char('\n') => Action::Open,
5 years ago
Key::Backspace => {
if self.input.is_empty() {
Action::Back
} else {
self.input.pop();
5 years ago
Action::Input
5 years ago
}
}
Key::Delete => {
self.input.pop();
5 years ago
Action::Input
5 years ago
}
Key::Ctrl('c') => {
if self.input.len() > 0 {
self.input.clear();
5 years ago
Action::Input
5 years ago
} else {
Action::Quit
}
}
Key::Char('-') => {
if self.input.is_empty() {
Action::PageUp
} else {
self.input.push('-');
5 years ago
Action::Input
5 years ago
}
}
Key::Char(' ') => {
if self.input.is_empty() {
return Action::PageDown;
} else {
self.input.push(' ');
5 years ago
Action::Input
5 years ago
}
}
Key::Char(c) => {
self.input.push(c);
for (i, link) in self.menu.lines.iter().enumerate() {
5 years ago
// jump to number
let count = self.menu.lines.len();
5 years ago
if count < 10 && c == '1' && i == 0 {
return Action::FollowLink(i);
} else if count < 20 && c == '2' && i == 1 {
return Action::FollowLink(i);
} else if count < 30 && c == '3' && i == 2 {
return Action::FollowLink(i);
} else if count < 40 && c == '4' && i == 3 {
return Action::FollowLink(i);
} else if count < 50 && c == '5' && i == 4 {
return Action::FollowLink(i);
} else if count < 60 && c == '6' && i == 5 {
return Action::FollowLink(i);
} else if count < 70 && c == '7' && i == 6 {
return Action::FollowLink(i);
} else if count < 80 && c == '8' && i == 7 {
return Action::FollowLink(i);
} else if count < 90 && c == '9' && i == 8 {
return Action::FollowLink(i);
} else if self.input.len() > 1 && self.input == (i + 1).to_string() {
return Action::FollowLink(i);
} else if self.input.len() == 1 && self.input == (i + 1).to_string() {
return Action::FollowLink(i);
} else {
if link
.name
.to_ascii_lowercase()
.contains(&self.input.to_ascii_lowercase())
{
return Action::FollowLink(i);
}
}
}
5 years ago
Action::Input
5 years ago
}
5 years ago
_ => Action::Unknown,
5 years ago
}
}
}
impl MenuView {
pub fn from(url: String, response: String) -> MenuView {
MenuView {
menu: Menu::from(url, response),
5 years ago
input: String::new(),
line: 0,
scroll: 0,
}
}
5 years ago
}
5 years ago
impl Menu {
pub fn from(url: String, gopher_response: String) -> Menu {
Self::parse(url, gopher_response)
5 years ago
}
fn parse(url: String, raw: String) -> Menu {
5 years ago
let mut lines = vec![];
for line in raw.split_terminator("\n") {
if let Some(c) = line.chars().nth(0) {
let typ = match c {
'0' => Type::Text,
'1' => Type::Menu,
5 years ago
'2' => panic!("CSOEntity not supported"), // TODO
'3' => Type::Error,
5 years ago
'4' => panic!("Binhex not supported"), // TODO
'5' => panic!("DOSFile not supported"), // TODO
'6' => panic!("UUEncoded not supported"), // TODO
'7' => panic!("Search not supported"), // TODO
'8' => panic!("Telnet not supported"), // TODO
'9' => panic!("Binary not supported"), // TODO
'+' => panic!("Mirrors not supported"), // TODO
'g' => panic!("GIF not supported"), // TODO
'T' => panic!("Telnet3270 not supported"), // TODO
'h' => Type::HTML,
'i' => Type::Info,
5 years ago
's' => panic!("Sound not supported"), // TODO
'd' => panic!("Document not supported"), // TODO
5 years ago
'\n' => continue,
5 years ago
_ => {
eprintln!("unknown line type: {}", c);
continue;
5 years ago
}
};
let parts: Vec<&str> = line.split_terminator("\t").collect();
lines.push(Line {
name: parts[0][1..].to_string(),
selector: parts[1].to_string(),
host: parts[2].to_string(),
port: parts[3].trim_end_matches('\r').to_string(),
typ,
});
5 years ago
}
}
Menu { raw, url, lines }
5 years ago
}
5 years ago
}