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

187 lines
5.0 KiB
Rust

4 years ago
//! A View representing a Gopher text entry.
//! Responds to user input by producing an Action which is then handed
//! to the main UI to perform.
use crate::{
config::Config,
ui::{self, Action, Key, View, MAX_COLS, SCROLL_LINES},
};
5 years ago
use std::fmt;
use termion::clear;
5 years ago
4 years ago
/// The Text View holds the raw Gopher response as well as information
/// about which lines should currently be displayed on screen.
5 years ago
pub struct Text {
5 years ago
url: String,
5 years ago
raw_response: String,
scroll: usize, // offset
lines: usize, // # of lines
longest: usize, // longest line
size: (usize, usize), // cols, rows
pub tls: bool, // retrieved via tls?
4 years ago
pub tor: bool, // retrieved via tor?
pub wide: bool, // in wide mode? turns off margins
5 years ago
}
5 years ago
impl fmt::Display for Text {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.url())
}
}
5 years ago
impl View for Text {
fn is_tls(&self) -> bool {
self.tls
}
4 years ago
fn is_tor(&self) -> bool {
self.tor
}
5 years ago
fn url(&self) -> String {
self.url.to_string()
}
5 years ago
fn raw(&self) -> String {
self.raw_response.to_string()
}
5 years ago
fn term_size(&mut self, cols: usize, rows: usize) {
self.size = (cols, rows);
}
5 years ago
fn respond(&mut self, c: Key) -> Action {
match c {
4 years ago
Key::Home => {
5 years ago
self.scroll = 0;
Action::Redraw
}
4 years ago
Key::End => {
4 years ago
self.scroll = self.final_scroll();
Action::Redraw
5 years ago
}
4 years ago
Key::Down | Key::Ctrl('n') | Key::Char('n') | Key::Ctrl('j') | Key::Char('j') => {
4 years ago
if self.scroll < self.final_scroll() {
self.scroll += 1;
Action::Redraw
} else {
Action::None
}
}
4 years ago
Key::Up | Key::Ctrl('p') | Key::Char('p') | Key::Ctrl('k') | Key::Char('k') => {
if self.scroll > 0 {
self.scroll -= 1;
Action::Redraw
} else {
Action::None
}
}
Key::PageUp | Key::Char('-') => {
if self.scroll > 0 {
if self.scroll >= SCROLL_LINES {
self.scroll -= SCROLL_LINES;
} else {
self.scroll = 0;
}
Action::Redraw
} else {
Action::None
}
}
Key::PageDown | Key::Char(' ') => {
4 years ago
self.scroll += SCROLL_LINES;
if self.scroll > self.final_scroll() {
self.scroll = self.final_scroll();
}
4 years ago
Action::Redraw
}
_ => Action::Keypress(c),
}
5 years ago
}
fn render(&mut self, cfg: &Config) -> String {
self.wide = cfg.wide;
let (cols, rows) = self.size;
5 years ago
let mut out = String::new();
5 years ago
let longest = if self.longest > MAX_COLS {
MAX_COLS
} else {
self.longest
};
let indent = if cols >= longest && cols - longest <= 6 {
String::from("")
} else if cols >= longest {
" ".repeat((cols - longest) / 2)
} else {
String::from("")
};
let limit = if cfg.mode == ui::Mode::Run {
rows - 1
} else {
self.lines
};
let iter = self
5 years ago
.raw_response
.split_terminator('\n')
5 years ago
.skip(self.scroll)
.take(limit);
for line in iter {
4 years ago
// Check for Gopher's weird "end of response" line.
if line == ".\r" || line == "." {
continue;
}
5 years ago
if !self.wide {
out.push_str(&indent);
}
let line = line.trim_end_matches('\r').replace('\t', " ");
out.push_str(&line);
// clear rest of line
out.push_str(&format!("{}", clear::UntilNewline));
out.push_str("\r\n");
5 years ago
}
// clear remainder of screen
out.push_str(&format!("{}", clear::AfterCursor));
5 years ago
out
5 years ago
}
}
5 years ago
impl Text {
4 years ago
pub fn from(url: String, response: String, tls: bool, tor: bool) -> Text {
let mut lines = 0;
let mut longest = 0;
for line in response.split_terminator('\n') {
lines += 1;
if line.len() > longest {
longest = line.len();
}
}
5 years ago
Text {
url,
5 years ago
raw_response: response,
scroll: 0,
5 years ago
lines,
longest,
size: (0, 0),
tls,
4 years ago
tor,
5 years ago
wide: false,
}
5 years ago
}
5 years ago
4 years ago
/// Final `self.scroll` value.
fn final_scroll(&self) -> usize {
4 years ago
let padding = (self.size.1 as f64 * 0.9) as usize;
5 years ago
if self.lines > padding {
self.lines - padding
} else {
0
}
}
5 years ago
}