share config so we can modify it in views

pull/22/head
chris west 4 years ago
parent c07656509f
commit cf9e16650e

@ -43,7 +43,7 @@ impl Error for ArgError {
pub fn parse<T: AsRef<str>>(args: &[T]) -> Result<Config, ArgError> { pub fn parse<T: AsRef<str>>(args: &[T]) -> Result<Config, ArgError> {
let mut set_nocfg = false; let mut set_nocfg = false;
let mut set_cfg = false; let mut set_cfg = false;
let mut cfg = config::default(); let mut cfg = Config::default();
// check for config to load / not load first // check for config to load / not load first
let mut iter = args.iter(); let mut iter = args.iter();
@ -61,12 +61,8 @@ pub fn parse<T: AsRef<str>>(args: &[T]) -> Result<Config, ArgError> {
} }
set_cfg = true; set_cfg = true;
if let Some(arg) = iter.next() { if let Some(arg) = iter.next() {
cfg = match config::load_file(arg.as_ref()) { cfg = config::load_file(arg.as_ref())
Ok(c) => c, .map_err(|e| ArgError::new(format!("error loading config: {}", e)))?;
Err(e) => {
return Err(ArgError::new(format!("error loading config: {}", e)));
}
};
} else { } else {
return Err(ArgError::new("need a config file")); return Err(ArgError::new("need a config file"));
} }

@ -9,9 +9,13 @@ use {
collections::HashMap, collections::HashMap,
fs::OpenOptions, fs::OpenOptions,
io::{Read, Result}, io::{Read, Result},
sync::{Arc, RwLock},
}, },
}; };
/// Global, shared config.
pub type SharedConfig = Arc<RwLock<Config>>;
/// phetch will look for this file on load. /// phetch will look for this file on load.
const CONFIG_FILE: &str = "phetch.conf"; const CONFIG_FILE: &str = "phetch.conf";
@ -113,8 +117,8 @@ pub fn exists() -> bool {
} }
/// Parses a phetch config file into a Config struct. /// Parses a phetch config file into a Config struct.
pub fn parse(text: &str) -> Result<Config> { fn parse(text: &str) -> Result<Config> {
let mut cfg = default(); let mut cfg = Config::default();
let mut keys: HashMap<&str, bool> = HashMap::new(); let mut keys: HashMap<&str, bool> = HashMap::new();
for (mut linenum, line) in text.split_terminator('\n').enumerate() { for (mut linenum, line) in text.split_terminator('\n').enumerate() {
@ -154,9 +158,8 @@ pub fn parse(text: &str) -> Result<Config> {
} }
} }
"encoding" => { "encoding" => {
cfg.encoding = Encoding::from_str(val).map_err(|e|{ cfg.encoding = Encoding::from_str(val)
error!("{} on line {}: {:?}",e, linenum, line) .map_err(|e| error!("{} on line {}: {:?}", e, linenum, line))?;
})?;
} }
_ => return Err(error!("Unknown key on line {}: {}", linenum, key)), _ => return Err(error!("Unknown key on line {}: {}", linenum, key)),
} }

@ -7,7 +7,7 @@
//! it returns an Action to the UI representing its intent. //! it returns an Action to the UI representing its intent.
use crate::{ use crate::{
config::Config, config::SharedConfig as Config,
gopher::{self, Type}, gopher::{self, Type},
terminal, terminal,
ui::{self, Action, Key, View, MAX_COLS, SCROLL_LINES}, ui::{self, Action, Key, View, MAX_COLS, SCROLL_LINES},
@ -249,12 +249,12 @@ impl View for Menu {
impl Menu { impl Menu {
/// Create a representation of a Gopher Menu from a raw Gopher /// Create a representation of a Gopher Menu from a raw Gopher
/// response and a few options. /// 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 { Menu {
tls, tls,
tor: config.tor, tor: config.read().unwrap().tor,
wide: config.wide, wide: config.read().unwrap().wide,
mode: config.mode, mode: config.read().unwrap().mode,
..parse(url, response) ..parse(url, response)
} }
} }

@ -178,7 +178,7 @@ impl View for Text {
impl Text { impl Text {
/// Create a Text View from a raw Gopher response and a few options. /// Create a Text View from a raw Gopher response and a few options.
pub fn from(url: &str, response: Vec<u8>, config: &Config, tls: bool) -> Text { pub fn from(url: &str, response: Vec<u8>, config: Config, tls: bool) -> Text {
let mut lines = 0; let mut lines = 0;
let mut longest = 0; let mut longest = 0;
let mut line_len = 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 { Text {
config,
url: url.into(), url: url.into(),
raw_response: response, raw_response: response,
scroll: 0, scroll: 0,
lines, lines,
longest, longest,
size: (0, 0), size: (0, 0),
mode: config.mode, mode,
tls, tls,
tor: config.tor, tor,
encoding: config.encoding, encoding,
wide: config.wide, wide,
} }
} }
@ -250,7 +256,7 @@ mod test {
#[test] #[test]
fn test_cp437() { fn test_cp437() {
let body = include_bytes!("../tests/CP437.txt"); 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; text.mode = ui::Mode::Print;
let res = text.render(); let res = text.render();

@ -18,7 +18,7 @@ pub use self::{action::Action, mode::Mode, view::View};
use crate::{ use crate::{
bookmarks, color, bookmarks, color,
config::Config, config::{Config, SharedConfig},
encoding::Encoding, encoding::Encoding,
gopher::{self, Type}, gopher::{self, Type},
help, history, help, history,
@ -32,7 +32,7 @@ use std::{
process::{self, Stdio}, process::{self, Stdio},
sync::{ sync::{
mpsc::{channel, Receiver, Sender}, mpsc::{channel, Receiver, Sender},
Arc, Mutex, Arc, Mutex, RwLock,
}, },
thread, thread,
time::Duration, time::Duration,
@ -92,7 +92,7 @@ pub struct UI {
/// Status message to display on screen, if any /// Status message to display on screen, if any
status: String, status: String,
/// User config. Command line options + phetch.conf /// User config. Command line options + phetch.conf
config: Config, config: SharedConfig,
/// Channel where UI events are sent. /// Channel where UI events are sent.
keys: KeyReceiver, keys: KeyReceiver,
} }
@ -111,7 +111,7 @@ impl UI {
dirty: true, dirty: true,
running: true, running: true,
size, size,
config, config: Arc::new(RwLock::new(config)),
status: String::new(), status: String::new(),
keys: Self::spawn_keyboard_listener(), keys: Self::spawn_keyboard_listener(),
} }
@ -204,10 +204,10 @@ impl UI {
// binary downloads // binary downloads
let typ = gopher::type_for_url(url); 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; self.dirty = true;
return if self.confirm(&format!("Open in media player? {}", url)) { 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 { } else {
Ok(()) Ok(())
}; };
@ -230,7 +230,10 @@ impl UI {
/// Download a binary file. Used by `open()` internally. /// Download a binary file. Used by `open()` internally.
fn download(&mut self, url: &str) -> Result<()> { fn download(&mut self, url: &str) -> Result<()> {
let url = url.to_string(); 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(); let chan = self.keys.clone();
self.spinner(&format!("Downloading {}", url), move || { self.spinner(&format!("Downloading {}", url), move || {
gopher::download_url(&url, tls, tor, chan) gopher::download_url(&url, tls, tor, chan)
@ -260,7 +263,10 @@ impl UI {
thread::spawn(move || history::save(&hname, &hurl)); thread::spawn(move || history::save(&hname, &hurl));
// request thread // request thread
let thread_url = url.to_string(); 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 // don't spin on first ever request
let (tls, res) = if self.views.is_empty() { let (tls, res) = if self.views.is_empty() {
gopher::fetch_url(&thread_url, tls, tor)? gopher::fetch_url(&thread_url, tls, tor)?
@ -272,10 +278,10 @@ impl UI {
Type::Menu | Type::Search => Ok(Box::new(Menu::from( Type::Menu | Type::Search => Ok(Box::new(Menu::from(
url, url,
gopher::response_to_string(&res), gopher::response_to_string(&res),
&self.config, self.config.clone(),
tls, 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)), _ => Err(error!("Unsupported Gopher Response: {:?}", typ)),
} }
} }
@ -286,7 +292,12 @@ impl UI {
&url.trim_start_matches("gopher://phetch/") &url.trim_start_matches("gopher://phetch/")
.trim_start_matches("1/"), .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 { } else {
Err(error!("phetch URL not found: {}", url)) Err(error!("phetch URL not found: {}", url))
} }
@ -383,13 +394,13 @@ impl UI {
} }
if view.is_tls() { if view.is_tls() {
if self.config.emoji { if self.config.read().unwrap().emoji {
status.push("🔐"); status.push("🔐");
} else { } else {
status.push("TLS"); status.push("TLS");
} }
} else if view.is_tor() { } else if view.is_tor() {
if self.config.emoji { if self.config.read().unwrap().emoji {
status.push("🧅"); status.push("🧅");
} else { } else {
status.push("TOR"); status.push("TOR");
@ -653,7 +664,7 @@ impl UI {
if let Some(view) = self.views.get(self.focused) { if let Some(view) = self.views.get(self.focused) {
let url = view.url(); let url = view.url();
let mut text = 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; text.wide = true;
self.add_view(Box::new(text)); self.add_view(Box::new(text));
} }
@ -687,7 +698,8 @@ impl UI {
} }
} }
'w' => { '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) { if let Some(view) = self.views.get_mut(self.focused) {
let w = view.wide(); let w = view.wide();
view.set_wide(!w); view.set_wide(!w);

Loading…
Cancel
Save