oh oh pee

pull/6/head
dvkt 5 years ago
parent 3f94de41d2
commit 2896973024

@ -2,6 +2,7 @@
extern crate termion;
use std::collections::HashMap;
use std::io::{stdin, stdout, Read, Write};
use std::net::TcpStream;
@ -10,17 +11,28 @@ use termion::input::TermRead;
use termion::raw::IntoRawMode;
#[derive(Debug)]
struct Link<'res> {
name: &'res str,
host: &'res str,
port: &'res str,
selector: &'res str,
struct App {
pages: HashMap<String, Page>,
cursor: String,
}
struct Cursor {
link: usize,
#[derive(Debug)]
struct Page {
body: String,
cursor: usize,
url: String,
links: Vec<Link>,
}
#[derive(Debug)]
struct Link {
name: String,
host: String,
port: String,
selector: String,
}
#[derive(Debug)]
enum Action {
None,
Up,
@ -30,95 +42,205 @@ enum Action {
}
fn main() {
phetch_and_print("phkt.io", "70", "/");
let mut app = App {
pages: HashMap::new(),
cursor: String::new(),
};
app.load("phkt.io", "70", "/");
loop {
app.render();
app.respond();
}
}
fn phetch_and_print(host: &str, port: &str, selector: &str) {
let response = phetch(host, port, selector);
let links = parse_links(&response);
println!("{:?}", links);
let mut cursor = Cursor { link: 0 };
loop {
render(&response, &cursor);
match user_input() {
Action::Up => {
if cursor.link > 0 {
cursor.link -= 1;
}
}
Action::Down => {
if cursor.link < links.len() {
cursor.link += 1;
}
}
Action::Open => {
if cursor.link > 0 && cursor.link - 1 < links.len() {
println!("OPEN: {:?}", links[cursor.link - 1]);
let link = &links[cursor.link - 1];
phetch_and_print(link.host, link.port, link.selector);
impl App {
fn load(&mut self, host: &str, port: &str, selector: &str) {
let mut page = self.fetch(host, port, selector);
page.parse_links();
self.pages.insert(page.url.to_string(), page);
self.cursor = format!("{}:{}{}", host, port, selector);
}
fn render(&self) {
if let Some(page) = self.pages.get(&self.cursor) {
print!("\x1B[2J\x1B[H{}", page.draw());
} else {
println!("{}", "<render error>");
}
}
fn fetch(&self, host: &str, port: &str, selector: &str) -> Page {
let mut body = String::new();
TcpStream::connect(format!("{}:{}", host, port))
.and_then(|mut stream| {
stream.write(format!("{}\r\n", selector).as_ref());
Ok(stream)
})
.and_then(|mut stream| {
stream.read_to_string(&mut body);
Ok(())
})
.map_err(|err| {
eprintln!("err: {}", err);
});
Page {
body: body,
cursor: 0,
url: format!("{}:{}{}", host, port, selector),
links: Vec::new(),
}
}
fn respond(&mut self) {
match self.pages.get_mut(&self.cursor) {
None => return,
Some(page) => match term_input() {
Action::Up => page.cursor_up(),
Action::Down => page.cursor_down(),
Action::Open => {
if page.cursor > 0 && page.cursor - 1 < page.links.len() {
println!("OPEN: {:?}", page.links[page.cursor - 1]);
std::process::exit(0);
}
}
}
Action::Quit => return,
_ => {}
Action::Quit => return,
_ => {}
},
}
}
}
fn phetch(host: &str, port: &str, selector: &str) -> String {
let mut out = String::new();
TcpStream::connect(format!("{}:{}", host, port))
.and_then(|mut stream| {
stream.write(format!("{}\r\n", selector).as_ref());
Ok(stream)
})
.and_then(|mut stream| {
stream.read_to_string(&mut out);
Ok(())
})
.map_err(|err| {
eprintln!("err: {}", err);
});
out
}
impl Page {
fn cursor_up(&mut self) {
if self.cursor > 0 {
self.cursor -= 1;
}
}
fn cursor_down(&mut self) {
if self.cursor < self.links.len() {
self.cursor += 1;
}
}
fn parse_links<'res>(response: &'res str) -> Vec<Link> {
let mut links: Vec<Link> = Vec::new();
let mut start = true;
let mut is_link = false;
let mut link = (0, 0);
for (i, c) in response.chars().enumerate() {
if start {
match c {
'0' | '1' => {
is_link = true;
link.0 = i + 1;
fn parse_links(&mut self) {
if self.links.len() > 0 {
self.links.clear();
}
let mut start = true;
let mut is_link = false;
let mut link = (0, 0);
for (i, c) in self.body.chars().enumerate() {
if start {
match c {
'0' | '1' => {
is_link = true;
link.0 = i + 1;
}
'\n' => continue,
_ => is_link = false,
}
start = false;
} else if c == '\n' {
start = true;
if is_link && i > link.0 {
link.1 = i;
let mut line = Vec::new();
for s in self.body[link.0..link.1].split('\t') {
line.push(s);
}
self.links.push(Link {
name: line[0].to_string(),
selector: line[1].to_string(),
host: line[2].to_string(),
port: line[3].trim_end_matches('\r').to_string(),
});
is_link = false;
}
'\n' => continue,
_ => is_link = false,
}
start = false;
} else if c == '\n' {
start = true;
if is_link && i > link.0 {
link.1 = i;
let mut line = Vec::new();
for s in response[link.0..link.1].split('\t') {
line.push(s);
}
}
fn draw(&self) -> String {
let mut start = true;
let mut skip_to_end = false;
let mut links = 0;
let mut out = String::with_capacity(self.body.len() * 2);
let mut prefix = "";
for (i, c) in self.body.chars().enumerate() {
let mut is_link = false;
if start {
match c {
'i' => {
prefix = "\x1B[93m";
is_link = false;
}
'h' => {
prefix = "\x1B[96m";
links += 1;
is_link = true;
}
'0' => {
prefix = "\x1B[94m";
links += 1;
is_link = true;
}
'1' => {
prefix = "\x1B[94m";
links += 1;
is_link = true;
}
'.' => {
if self.body.len() > i + 2
&& self.body[i..].chars().next().unwrap() == '\r'
&& self.body[i + 1..].chars().next().unwrap() == '\n'
{
continue;
}
}
'\r' => continue,
'\n' => continue,
_ => prefix = "",
}
if is_link && self.cursor > 0 && self.cursor == links {
out.push_str("\x1b[92;1m*\x1b[0m");
} else {
out.push(' ');
}
out.push_str(" ");
if is_link {
out.push_str("\x1B[95m");
if links < 10 {
out.push(' ');
}
out.push_str(&links.to_string());
out.push_str(". \x1B[0m");
} else {
out.push(' ');
out.push_str("\x1B[0m");
out.push_str(" ");
}
out.push_str(prefix);
start = false
} else if skip_to_end {
if c == '\n' {
out.push_str("\r\n\x1B[0m");
start = true;
skip_to_end = false;
}
} else if c == '\t' {
skip_to_end = true;
} else {
out.push(c);
if c == '\n' {
start = true;
}
links.push(Link {
name: line[0],
selector: line[1],
host: line[2],
port: line[3].trim_end_matches('\r'),
});
is_link = false;
}
}
out
}
links
}
fn user_input() -> Action {
fn term_input() -> Action {
let stdin = stdin();
let mut stdout = stdout().into_raw_mode().unwrap();
let mut y = 1;
@ -163,88 +285,3 @@ fn user_input() -> Action {
}
Action::None
}
fn render(buf: &str, cur: &Cursor) {
// let clear = "";
let clear = "\x1B[2J\x1B[H";
print!("{}{}", clear, draw(buf, cur));
}
fn draw(buf: &str, cur: &Cursor) -> String {
let mut start = true;
let mut skip_to_end = false;
let mut links = 0;
let mut out = String::with_capacity(buf.len() * 2);
let mut prefix = "";
for (i, c) in buf.chars().enumerate() {
let mut is_link = false;
if start {
match c {
'i' => {
prefix = "\x1B[93m";
is_link = false;
}
'h' => {
prefix = "\x1B[96m";
links += 1;
is_link = true;
}
'0' => {
prefix = "\x1B[94m";
links += 1;
is_link = true;
}
'1' => {
prefix = "\x1B[94m";
links += 1;
is_link = true;
}
'.' => {
if buf.len() > i + 2
&& buf[i..].chars().next().unwrap() == '\r'
&& buf[i + 1..].chars().next().unwrap() == '\n'
{
continue;
}
}
'\r' => continue,
'\n' => continue,
_ => prefix = "",
}
if is_link && cur.link > 0 && cur.link == links {
out.push_str("\x1b[92;1m*\x1b[0m");
} else {
out.push(' ');
}
out.push_str(" ");
if is_link {
out.push_str("\x1B[95m");
if links < 10 {
out.push(' ');
}
out.push_str(&links.to_string());
out.push_str(". \x1B[0m");
} else {
out.push(' ');
out.push_str("\x1B[0m");
out.push_str(" ");
}
out.push_str(prefix);
start = false
} else if skip_to_end {
if c == '\n' {
out.push_str("\r\n\x1B[0m");
start = true;
skip_to_end = false;
}
} else if c == '\t' {
skip_to_end = true;
} else {
out.push(c);
if c == '\n' {
start = true;
}
}
}
out
}

Loading…
Cancel
Save