From cf9e16650ec2d0e88ca9ac3bd69acf2b3cf42329 Mon Sep 17 00:00:00 2001 From: chris west Date: Wed, 11 Nov 2020 16:59:03 -0800 Subject: [PATCH] share config so we can modify it in views --- src/args.rs | 10 +++------- src/config.rs | 13 ++++++++----- src/menu.rs | 10 +++++----- src/text.rs | 18 ++++++++++++------ src/ui.rs | 42 +++++++++++++++++++++++++++--------------- 5 files changed, 55 insertions(+), 38 deletions(-) diff --git a/src/args.rs b/src/args.rs index 4f62d18..752310c 100644 --- a/src/args.rs +++ b/src/args.rs @@ -43,7 +43,7 @@ impl Error for ArgError { pub fn parse>(args: &[T]) -> Result { let mut set_nocfg = false; let mut set_cfg = false; - let mut cfg = config::default(); + let mut cfg = Config::default(); // check for config to load / not load first let mut iter = args.iter(); @@ -61,12 +61,8 @@ pub fn parse>(args: &[T]) -> Result { } set_cfg = true; if let Some(arg) = iter.next() { - cfg = match config::load_file(arg.as_ref()) { - Ok(c) => c, - Err(e) => { - return Err(ArgError::new(format!("error loading config: {}", e))); - } - }; + cfg = config::load_file(arg.as_ref()) + .map_err(|e| ArgError::new(format!("error loading config: {}", e)))?; } else { return Err(ArgError::new("need a config file")); } diff --git a/src/config.rs b/src/config.rs index 19abbc9..1222251 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,9 +9,13 @@ use { collections::HashMap, fs::OpenOptions, io::{Read, Result}, + sync::{Arc, RwLock}, }, }; +/// Global, shared config. +pub type SharedConfig = Arc>; + /// phetch will look for this file on load. const CONFIG_FILE: &str = "phetch.conf"; @@ -113,8 +117,8 @@ pub fn exists() -> bool { } /// Parses a phetch config file into a Config struct. -pub fn parse(text: &str) -> Result { - let mut cfg = default(); +fn parse(text: &str) -> Result { + let mut cfg = Config::default(); let mut keys: HashMap<&str, bool> = HashMap::new(); for (mut linenum, line) in text.split_terminator('\n').enumerate() { @@ -154,9 +158,8 @@ pub fn parse(text: &str) -> Result { } } "encoding" => { - cfg.encoding = Encoding::from_str(val).map_err(|e|{ - error!("{} on line {}: {:?}",e, linenum, line) - })?; + cfg.encoding = Encoding::from_str(val) + .map_err(|e| error!("{} on line {}: {:?}", e, linenum, line))?; } _ => return Err(error!("Unknown key on line {}: {}", linenum, key)), } diff --git a/src/menu.rs b/src/menu.rs index ddeadaf..d96cbef 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -7,7 +7,7 @@ //! it returns an Action to the UI representing its intent. use crate::{ - config::Config, + config::SharedConfig as Config, gopher::{self, Type}, terminal, ui::{self, Action, Key, View, MAX_COLS, SCROLL_LINES}, @@ -249,12 +249,12 @@ impl View for Menu { impl Menu { /// Create a representation of a Gopher Menu from a raw Gopher /// response and a few options. - pub fn from(url: &str, response: String, config: &Config, tls: bool) -> Menu { + pub fn from(url: &str, response: String, config: Config, tls: bool) -> Menu { Menu { tls, - tor: config.tor, - wide: config.wide, - mode: config.mode, + tor: config.read().unwrap().tor, + wide: config.read().unwrap().wide, + mode: config.read().unwrap().mode, ..parse(url, response) } } diff --git a/src/text.rs b/src/text.rs index 0045f6e..24a4b52 100644 --- a/src/text.rs +++ b/src/text.rs @@ -178,7 +178,7 @@ impl View for Text { impl Text { /// Create a Text View from a raw Gopher response and a few options. - pub fn from(url: &str, response: Vec, config: &Config, tls: bool) -> Text { + pub fn from(url: &str, response: Vec, config: Config, tls: bool) -> Text { let mut lines = 0; let mut longest = 0; let mut line_len = 0; @@ -194,18 +194,24 @@ impl Text { } } + let mode = config.read().unwrap().mode; + let tor = config.read().unwrap().tor; + let encoding = config.read().unwrap().encoding; + let wide = config.read().unwrap().wide; + Text { + config, url: url.into(), raw_response: response, scroll: 0, lines, longest, size: (0, 0), - mode: config.mode, + mode, tls, - tor: config.tor, - encoding: config.encoding, - wide: config.wide, + tor, + encoding, + wide, } } @@ -250,7 +256,7 @@ mod test { #[test] fn test_cp437() { let body = include_bytes!("../tests/CP437.txt"); - let mut text = Text::from("", body.to_vec(), &Config::default(), false); + let mut text = Text::from("", body.to_vec(), Config::default(), false); text.mode = ui::Mode::Print; let res = text.render(); diff --git a/src/ui.rs b/src/ui.rs index 0ea4a0f..fb2f2db 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -18,7 +18,7 @@ pub use self::{action::Action, mode::Mode, view::View}; use crate::{ bookmarks, color, - config::Config, + config::{Config, SharedConfig}, encoding::Encoding, gopher::{self, Type}, help, history, @@ -32,7 +32,7 @@ use std::{ process::{self, Stdio}, sync::{ mpsc::{channel, Receiver, Sender}, - Arc, Mutex, + Arc, Mutex, RwLock, }, thread, time::Duration, @@ -92,7 +92,7 @@ pub struct UI { /// Status message to display on screen, if any status: String, /// User config. Command line options + phetch.conf - config: Config, + config: SharedConfig, /// Channel where UI events are sent. keys: KeyReceiver, } @@ -111,7 +111,7 @@ impl UI { dirty: true, running: true, size, - config, + config: Arc::new(RwLock::new(config)), status: String::new(), keys: Self::spawn_keyboard_listener(), } @@ -204,10 +204,10 @@ impl UI { // binary downloads let typ = gopher::type_for_url(url); - if typ.is_media() && self.config.media.is_some() { + if typ.is_media() && self.config.read().unwrap().media.is_some() { self.dirty = true; return if self.confirm(&format!("Open in media player? {}", url)) { - utils::open_media(self.config.media.as_ref().unwrap(), url) + utils::open_media(self.config.read().unwrap().media.as_ref().unwrap(), url) } else { Ok(()) }; @@ -230,7 +230,10 @@ 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); + let (tls, tor) = ( + self.config.read().unwrap().tls, + self.config.read().unwrap().tor, + ); let chan = self.keys.clone(); self.spinner(&format!("Downloading {}", url), move || { gopher::download_url(&url, tls, tor, chan) @@ -260,7 +263,10 @@ impl UI { thread::spawn(move || history::save(&hname, &hurl)); // request thread let thread_url = url.to_string(); - let (tls, tor) = (self.config.tls, self.config.tor); + let (tls, tor) = ( + self.config.read().unwrap().tls, + self.config.read().unwrap().tor, + ); // don't spin on first ever request let (tls, res) = if self.views.is_empty() { gopher::fetch_url(&thread_url, tls, tor)? @@ -272,10 +278,10 @@ impl UI { Type::Menu | Type::Search => Ok(Box::new(Menu::from( url, gopher::response_to_string(&res), - &self.config, + self.config.clone(), tls, ))), - Type::Text | Type::HTML => Ok(Box::new(Text::from(url, res, &self.config, tls))), + Type::Text | Type::HTML => Ok(Box::new(Text::from(url, res, self.config.clone(), tls))), _ => Err(error!("Unsupported Gopher Response: {:?}", typ)), } } @@ -286,7 +292,12 @@ impl UI { &url.trim_start_matches("gopher://phetch/") .trim_start_matches("1/"), ) { - Ok(Box::new(Menu::from(url, source, &self.config, false))) + Ok(Box::new(Menu::from( + url, + source, + self.config.clone(), + false, + ))) } else { Err(error!("phetch URL not found: {}", url)) } @@ -383,13 +394,13 @@ impl UI { } if view.is_tls() { - if self.config.emoji { + if self.config.read().unwrap().emoji { status.push("🔐"); } else { status.push("TLS"); } } else if view.is_tor() { - if self.config.emoji { + if self.config.read().unwrap().emoji { status.push("🧅"); } else { status.push("TOR"); @@ -653,7 +664,7 @@ impl UI { if let Some(view) = self.views.get(self.focused) { let url = view.url(); let mut text = - Text::from(url, view.raw().into(), &self.config, view.is_tls()); + Text::from(url, view.raw().into(), self.config.clone(), view.is_tls()); text.wide = true; self.add_view(Box::new(text)); } @@ -687,7 +698,8 @@ impl UI { } } 'w' => { - self.config.wide = !self.config.wide; + let wide = self.config.read().unwrap().wide; + self.config.write().unwrap().wide = !wide; if let Some(view) = self.views.get_mut(self.focused) { let w = view.wide(); view.set_wide(!w);