some notes

pull/14/head
chris west 4 years ago
parent 349b1c6ba6
commit dd4e47dc8e

@ -1,3 +1,6 @@
//! args::parse() is used to parse command line arguments into a
//! Config structure.
use crate::{
config::{self, Config},
ui::Mode,

@ -1,3 +1,7 @@
//! Bookmarks are enabled if you create a ~/.config/phetch/ directory
//! manually. They are stored as a simple Gophermap, `BOOKMARKS_FILE`,
//! in that directory.
use crate::phetchdir;
use std::io::{Read, Result};

@ -1,3 +1,7 @@
//! Terminal colors.
//! Provides a macro to color text as well as sturcts to get their
//! raw ansi codes.
use std::fmt;
/// Shortcut to produce a String colored with one or more colors.

@ -1,3 +1,8 @@
//! phetch will load `~/.config/phetch/phetch.conf` or a file you
//! specify with the `--config` command line option when it starts.
//!
//! An example default config is provided but unused by this module.
use crate::{phetchdir, ui};
use std::{
collections::HashMap,

@ -1,3 +1,9 @@
//! phetch's Gopher library contains a few phetch-specific features:
//! the ability to make requests or downloads over TLS or Tor,
//! cleaning Unicode control characters from Gopher responses, and
//! URL parsing that recognizes different protocols like telnet and
//! IPv6 addresses.
use std::{
env,
io::{Read, Result, Write},
@ -15,6 +21,11 @@ use native_tls::TlsConnector;
mod r#type;
pub use self::r#type::Type;
/// Some Gopher servers can be kind of slow, we may want to up this or
/// make it configurable eventually.
pub const TCP_TIMEOUT_IN_SECS: u64 = 8;
pub const TCP_TIMEOUT_DURATION: Duration = Duration::from_secs(TCP_TIMEOUT_IN_SECS);
trait ReadWrite: Read + Write {}
impl<T: Read + Write> ReadWrite for T {}
@ -46,11 +57,6 @@ impl Write for Stream {
}
}
/// Some Gopher servers can be kind of slow, we may want to up this or
/// make it configurable eventually.
pub const TCP_TIMEOUT_IN_SECS: u64 = 8;
pub const TCP_TIMEOUT_DURATION: Duration = Duration::from_secs(TCP_TIMEOUT_IN_SECS);
/// Fetches a gopher URL and returns a tuple of:
/// (did tls work?, raw Gopher response)
pub fn fetch_url(url: &str, tls: bool, tor: bool) -> Result<(bool, String)> {

@ -1,24 +1,25 @@
/// Gopher types are defined according to RFC 1436.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Type {
Text, // 0 | 96 | cyan
Menu, // 1 | 94 | blue
CSOEntity, // 2 | | white background
Error, // 3 | 91 | red
Binhex, // 4 | 4 | white underline
DOSFile, // 5 | 4 | white underline
UUEncoded, // 6 | 4 | white underline
Search, // 7 | 0 | white
Telnet, // 8 | 90 | gray underline
Binary, // 9 | 4 | white underline
Mirror, // + | | white background
GIF, // g | 4 | white underline
Telnet3270, // T | | white background
HTML, // h | 92 | green
Image, // I | 4 | white underline
PNG, // p | 4 | white underline
Info, // i | 93 | yellow
Sound, // s | 4 | white underline
Document, // d | 4 | white underline
Text, // 0 | cyan
Menu, // 1 | blue
CSOEntity, // 2 | unsupported
Error, // 3 | red
Binhex, // 4 | download
DOSFile, // 5 | download
UUEncoded, // 6 | download
Search, // 7 | white
Telnet, // 8 | gray underline
Binary, // 9 | download
Mirror, // + | unsupported
GIF, // g | download
Telnet3270, // T | unsupported
HTML, // h | green
Image, // I | download
PNG, // p | download
Info, // i | yellow
Sound, // s | download
Document, // d | download
}
impl Type {

@ -1,3 +1,6 @@
//! The `help` module manages all internal Gopher pages, from the help
//! system itself to the Start and "About Phetch" pages.
use crate::{bookmarks, history};
/// Find a help file/page. If found, gives the raw Gophermap.

@ -1,3 +1,7 @@
//! phetch will append every URL visited to a Gophermap if a
//! `HISTORY_FILE` in `~/.config/phetch/` exists. This file must be
//! manually created by the user for history tracking to engage.
use crate::phetchdir;
use std::io::{BufRead, Result};

@ -2,10 +2,10 @@ use phetch::{
args, gopher,
ui::{Mode, UI},
};
use std::{env, process::exit};
use std::{env, process};
fn main() {
exit(run())
process::exit(run())
}
/// Start the app. Returns UNIX exit code.

@ -1,3 +1,11 @@
//! The Menu is a View representing a Gopher menu. It renders the
//! colorful representation, manages the cursor and selection state,
//! and responds to input like the UP and DOWN arrows or other key
//! combinations.
//!
//! The Menu doesn't draw or perform any actions on its own, instead
//! it returns an Action to the UI representing its intent.
use crate::ui::{self, Action, Key, View, MAX_COLS, SCROLL_LINES};
use crate::{
config::Config,
@ -23,6 +31,9 @@ pub struct Menu {
pub wide: bool, // in wide mode?
}
/// The Line represents a single line in a Gopher menu.
/// It must exist in the context of a Menu struct, and its `link`
/// field will point to its index in the Menu's `links` Vec.
pub struct Line {
pub name: String,
pub url: String,

@ -1,3 +1,11 @@
//! The phetchdir is `DIR`, or `~/.config/phetch` by default. There is
//! currently no way to change it. Bookmarks, user history, and the
//! `phetch.conf` all live in this directory in a fully loaded
//! installation of phetch.
//!
//! This module provides helpers for working with the phetchdir:
//! checking its existence, saving to files inside it, and the sort.
use crate::gopher;
use std::{
fs::{File, OpenOptions},

@ -1,3 +1,7 @@
//! 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},

@ -1,3 +1,16 @@
//! The UI is what drives the interactive phetch application: it
//! spawns threads to fetch Gopher pages and download binary files, it
//! manages the opened pages (Views), it asks the focused View to
//! respond to user input, and it performs actions based on what the
//! View returns - like opening a telnet client, or displaying an
//! error on the status line.
//!
//! The UI also directly responds to user input on its own, such as
//! ctrl-q to quit the app or keyboard entry during an input prompt.
//!
//! Finally, the UI is what prints to the screen - each View just
//! renders its content to a String. The UI is what draws it.
mod action;
mod mode;
mod view;
@ -87,6 +100,7 @@ impl UI {
write!(out, "{}", termion::screen::ToMainScreen);
}
/// Main loop.
pub fn run(&mut self) -> Result<()> {
self.startup();
while self.running {
@ -97,6 +111,7 @@ impl UI {
Ok(())
}
/// Print the current view to the screen in rendered form.
pub fn draw(&mut self) -> Result<()> {
let status = self.render_status();
if self.dirty {
@ -120,6 +135,7 @@ impl UI {
Ok(())
}
/// Accept user input and update data.
pub fn update(&mut self) {
let action = self.process_page_input();
if !action.is_none() {
@ -130,6 +146,7 @@ impl UI {
}
}
/// Open a URL - Gopher, internal, telnet, or something else.
pub fn open(&mut self, title: &str, url: &str) -> Result<()> {
// no open loops
if let Some(page) = self.views.get(self.focused) {
@ -170,6 +187,7 @@ impl UI {
})
}
/// Download a binary file. Used by `open()` internally.
fn download(&mut self, url: &str) -> Result<()> {
let url = url.to_string();
let (tls, tor) = (self.config.tls, self.config.tor);
@ -187,6 +205,7 @@ impl UI {
})
}
/// Fetches a URL and returns a View for its content.
fn fetch(&mut self, title: &str, url: &str) -> Result<Page> {
// on-line help
if url.starts_with("gopher://phetch/") {
@ -225,14 +244,17 @@ impl UI {
}
}
/// # of visible columns
fn cols(&self) -> u16 {
self.size.0 as u16
}
/// # of visible row
fn rows(&self) -> u16 {
self.size.1 as u16
}
/// Set the current columns and rows.
fn term_size(&mut self, cols: usize, rows: usize) {
self.size = (cols, rows);
}
@ -275,6 +297,7 @@ impl UI {
result.map_err(|e| error!("Spinner error: {:?}", e))
}
/// Create a rendered String for the current View in its current state.
pub fn render(&mut self) -> Result<String> {
// TODO: only get size on SIGWINCH
if let Ok((cols, rows)) = terminal_size() {
@ -297,10 +320,12 @@ impl UI {
}
}
/// Set the status line's content.
fn set_status(&mut self, status: String) {
self.status = status;
}
/// Render the connection status (TLS or Tor).
fn render_conn_status(&self) -> Option<String> {
let page = self.views.get(self.focused)?;
if page.is_tls() {
@ -321,6 +346,7 @@ impl UI {
None
}
/// Render the status line.
fn render_status(&self) -> String {
format!(
"{}{}{}{}{}{}",
@ -333,6 +359,7 @@ impl UI {
)
}
/// Add a View to the app's currently opened Views.
fn add_page(&mut self, page: Page) {
self.dirty = true;
if !self.views.is_empty() && self.focused < self.views.len() - 1 {
@ -457,6 +484,7 @@ impl UI {
Ok(())
}
/// Asks the current View to process user input and produce an Action.
fn process_page_input(&mut self) -> Action {
if let Some(page) = self.views.get_mut(self.focused) {
if let Ok(key) = stdin()
@ -484,6 +512,8 @@ impl UI {
self.dirty = true;
}
/// Given an Action from a View in response to user input, do the
/// action.
fn process_action(&mut self, action: Action) -> Result<()> {
match action {
Action::List(actions) => {

@ -1,6 +1,8 @@
use crate::ui::Key;
use std::fmt;
/// Views generate Actions in response to user input, which are
/// processed by the UI.
pub enum Action {
None, // do nothing
Open(String, String), // open(title, url)

@ -1,6 +1,7 @@
use crate::{config::Config, ui};
use std::fmt;
/// Views represent what's on screen, a Gopher Menu/Text/etc item.
pub trait View: fmt::Display {
fn respond(&mut self, key: ui::Key) -> ui::Action;
fn render(&mut self, cfg: &Config) -> String;

@ -1,3 +1,5 @@
//! Helper functions and macros.
/// Debug macro that appends a line to `phetch.log`.
/// Useful for printf-style debugging - add your `log!()` calls,
/// and `tail -f phetch.log` while running phetch to peek inside.
@ -22,6 +24,7 @@ macro_rules! log {
}
};
}
/// Creates an Other kind of io::Error.
macro_rules! error {
($e:expr) => {

Loading…
Cancel
Save