From dd4e47dc8e2e584af165d090bdc8ff3b2046478c Mon Sep 17 00:00:00 2001 From: chris west Date: Sat, 11 Jan 2020 19:34:27 -0800 Subject: [PATCH] some notes --- src/args.rs | 3 +++ src/bookmarks.rs | 4 ++++ src/color.rs | 4 ++++ src/config.rs | 5 +++++ src/gopher.rs | 16 +++++++++++----- src/gopher/type.rs | 39 ++++++++++++++++++++------------------- src/help.rs | 3 +++ src/history.rs | 4 ++++ src/main.rs | 4 ++-- src/menu.rs | 11 +++++++++++ src/phetchdir.rs | 8 ++++++++ src/text.rs | 4 ++++ src/ui.rs | 30 ++++++++++++++++++++++++++++++ src/ui/action.rs | 2 ++ src/ui/view.rs | 1 + src/utils.rs | 3 +++ 16 files changed, 115 insertions(+), 26 deletions(-) diff --git a/src/args.rs b/src/args.rs index edb08c6..24d7234 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,3 +1,6 @@ +//! args::parse() is used to parse command line arguments into a +//! Config structure. + use crate::{ config::{self, Config}, ui::Mode, diff --git a/src/bookmarks.rs b/src/bookmarks.rs index 7cd2ce0..90db679 100644 --- a/src/bookmarks.rs +++ b/src/bookmarks.rs @@ -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}; diff --git a/src/color.rs b/src/color.rs index cc7feab..d541566 100644 --- a/src/color.rs +++ b/src/color.rs @@ -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. diff --git a/src/config.rs b/src/config.rs index 4fc89b4..48e04a9 100644 --- a/src/config.rs +++ b/src/config.rs @@ -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, diff --git a/src/gopher.rs b/src/gopher.rs index 6ceb6f5..bdef0a0 100644 --- a/src/gopher.rs +++ b/src/gopher.rs @@ -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 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)> { diff --git a/src/gopher/type.rs b/src/gopher/type.rs index bc8dab2..ae76c76 100644 --- a/src/gopher/type.rs +++ b/src/gopher/type.rs @@ -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 { diff --git a/src/help.rs b/src/help.rs index 4fec4bd..3265272 100644 --- a/src/help.rs +++ b/src/help.rs @@ -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. diff --git a/src/history.rs b/src/history.rs index de7ffef..09ce33f 100644 --- a/src/history.rs +++ b/src/history.rs @@ -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}; diff --git a/src/main.rs b/src/main.rs index a89ff34..b9d2b82 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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. diff --git a/src/menu.rs b/src/menu.rs index 0034afa..d7bfeee 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -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, diff --git a/src/phetchdir.rs b/src/phetchdir.rs index 68786d5..3239694 100644 --- a/src/phetchdir.rs +++ b/src/phetchdir.rs @@ -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}, diff --git a/src/text.rs b/src/text.rs index 4b45445..72ffe17 100644 --- a/src/text.rs +++ b/src/text.rs @@ -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}, diff --git a/src/ui.rs b/src/ui.rs index 6b92761..2f9c8db 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -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 { // 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 { // 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 { 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) => { diff --git a/src/ui/action.rs b/src/ui/action.rs index 862c486..099984c 100644 --- a/src/ui/action.rs +++ b/src/ui/action.rs @@ -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) diff --git a/src/ui/view.rs b/src/ui/view.rs index b276b87..a7c6824 100644 --- a/src/ui/view.rs +++ b/src/ui/view.rs @@ -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; diff --git a/src/utils.rs b/src/utils.rs index f23ee69..c157aa9 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -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) => {