Mike Burns: 14 Read in start_url once Read background_color once Refactor: pass the Settings struct to draw funcs Move get_gemini_text_font_family into method Move max_width into method Move Pango markup span rendering into Settings Pango markup span rendering for LineType::Quote Pango markup span rendering for LineType::ListItem Pango markup for LineType::H3 Pango markup for LineType::H2 Pango markup for LineType::H1 Pango markup for LineType::Preformatted Pango markup for LineType::Gopher and Finger Cleanup 29 files changed, 662 insertions(+), 708 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~julienxx/castor/patches/19437/mbox | git am -3Learn more about email & git
Read in the settings when the program launches, then use that setting to pull out the `start_url`. This lead to a few changes: - Move `start_url()` into a method instead of function. We will be passing the `Setting` struct around and this makes the syntax a little easier to work with. - Make the `Setting` struct public so we can pass it around. - Pass around a `&str` instead of `String`. This cuts down on the amount of data we have to copy and allows us to use existing `&str`-expecting functions, and everything else explained in [the Rust Design Patterns chapter on this]. - The `route_url` function now takes a `&str`, so propagate that through using `as_ref()` and `as_deref()` as appropriate. [the Rust Design Patterns chapter on this]: https://rust-unofficial.github.io/patterns/idioms/coercion-arguments.html This is step one of a longer refactoring with the goal of reducing the number of times we read the config file. --- src/main.rs | 23 +++++++++++++---------- src/settings.rs | 21 ++++++++++++--------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/main.rs b/src/main.rs index bcbc7c3..adc1842 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,6 +32,9 @@ mod status; use status::Status; fn main() { + // Read in settings + let config = settings::read(); + // Start up the GTK3 subsystem. gtk::init().expect("Unable to start GTK3. Error"); @@ -102,8 +105,8 @@ fn main() { let gui_clone = gui.clone(); let url_bar = gui.url_bar(); url_bar.connect_activate(move |b| { - let url = b.get_text().expect("get_text failed").to_string(); - route_url(&gui_clone, url) + let url = b.get_text().expect("get_text failed"); + route_url(&gui_clone, url.as_str()) }); } @@ -124,26 +127,26 @@ fn main() { match args.len() { // no argument passed, check settings 1 => { - if let Some(url) = settings::start_url() { + if let Some(url) = config.start_url() { route_url(&gui, url) } } // Use argument as initial URL - _ => route_url(&gui, args[1].to_string()), + _ => route_url(&gui, &args[1]), } gui.start(); gtk::main(); } -fn route_url(gui: &Arc<Gui>, url: String) { +fn route_url(gui: &Arc<Gui>, url: &str) { if url == "" { } else if url.starts_with("gemini://") { - visit_url(&gui, Gemini { source: url }) + visit_url(&gui, Gemini { source: url.to_string() }) } else if url.starts_with("gopher://") { - visit_url(&gui, Gopher { source: url }) + visit_url(&gui, Gopher { source: url.to_string() }) } else if url.starts_with("finger://") { - visit_url(&gui, Finger { source: url }) + visit_url(&gui, Finger { source: url.to_string() }) } else { visit_url( &gui, @@ -192,8 +195,8 @@ fn visit(gui: &Arc<Gui>, url: &Url) { fn refresh(gui: &Arc<Gui>) { let url_bar = gui.url_bar(); - let url = url_bar.get_text().expect("get_text failed").to_string(); - route_url(&gui, url) + let url = url_bar.get_text().expect("get_text failed"); + route_url(&gui, url.as_str()) } fn update_url_field(gui: &Arc<Gui>, url: &str) { diff --git a/src/settings.rs b/src/settings.rs index ee226e3..c80aa55 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -8,13 +8,22 @@ use std::io::Read; use serde_derive::Deserialize; #[derive(Deserialize)] -struct Settings { +pub struct Settings { general: Option<General>, colors: Option<Color>, characters: Option<Character>, fonts: Option<Font>, } +impl Settings { + pub fn start_url(&self) -> Option<&str> { + match &self.general { + Some(general) => general.start_url.as_deref(), + None => None, + } + } +} + #[derive(Deserialize)] struct General { start_url: Option<String>, @@ -70,13 +79,6 @@ struct QuoteColor { background: Option<String>, } -pub fn start_url() -> Option<String> { - match read().general { - Some(general) => general.start_url, - None => None, - } -} - pub fn max_width() -> Option<usize> { match read().general { Some(general) => general.max_width, @@ -449,9 +451,10 @@ pub fn get_list_character() -> String { } } -fn read() -> Settings { +pub fn read() -> Settings { let mut file = settings_file(); let mut content = String::new(); + println!("reading from config"); file.read_to_string(&mut content) .expect("Unable to read file"); -- 2.20.1
Since we are already reading the settings on app launch for `start_url()`, reuse that existing `Settings` struct for the `background_color()`. Like for the `start_url()`, change the value to be a `&str`. This means we now read the config file once at program launch. --- src/main.rs | 2 +- src/settings.rs | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index adc1842..9a6bc07 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,7 +42,7 @@ fn main() { let gui = Arc::new(Gui::new()); // Set background color - if let Some(color) = settings::background_color() { + if let Some(color) = config.background_color() { let provider = gtk::CssProvider::new(); provider .load_from_data(format!("textview text {{ background-color: {}; }}", color).as_bytes()) diff --git a/src/settings.rs b/src/settings.rs index c80aa55..0caec8c 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -22,6 +22,13 @@ impl Settings { None => None, } } + + pub fn background_color(&self) -> Option<&str> { + match &self.colors { + Some(colors) => colors.background.as_deref(), + None => None, + } + } } #[derive(Deserialize)] @@ -403,10 +410,6 @@ pub fn get_text_color() -> String { } } -pub fn background_color() -> Option<String> { - read().colors?.background -} - fn h1_character() -> Option<String> { read().characters?.h1 } -- 2.20.1
This is a step with the goal of reducing the number of times we read the config file. --- src/dialog.rs | 4 +-- src/draw.rs | 43 +++++++++++++++++-------------- src/main.rs | 70 +++++++++++++++++++++++++++++---------------------- 3 files changed, 66 insertions(+), 51 deletions(-) diff --git a/src/dialog.rs b/src/dialog.rs index 485a5ec..3587229 100644 --- a/src/dialog.rs +++ b/src/dialog.rs @@ -41,7 +41,7 @@ pub fn error(gui: &Arc<Gui>, message: &str) { dialog.show_all(); } -pub fn input(gui: &Arc<Gui>, url: Url, message: &str) { +pub fn input(gui: &Arc<Gui>, config: &Arc<crate::settings::Settings>, url: Url, message: &str) { let dialog = gtk::Dialog::new_with_buttons( Some(message), Some(gui.window()), @@ -63,7 +63,7 @@ pub fn input(gui: &Arc<Gui>, url: Url, message: &str) { let cleaned: &str = &url[..Position::AfterPath]; let full_url = format!("{}?{}", cleaned.to_string(), response); - crate::visit_url(&gui, Gemini { source: full_url }); + crate::visit_url(&gui, &config, Gemini { source: full_url }); } dialog.destroy(); diff --git a/src/draw.rs b/src/draw.rs index 451adef..a05c05c 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -15,10 +15,12 @@ use crate::gemini::link::Link as GeminiLink; use crate::gopher::link::Link as GopherLink; use crate::gui::Gui; use crate::protocols::{Finger, Gemini, Gopher}; +use crate::settings; pub fn gemini_content( gui: &Arc<Gui>, + config: &Arc<settings::Settings>, content: Vec<Result<crate::gemini::parser::TextElement, crate::gemini::parser::ParseError>>, ) -> TextBuffer { let content_view = gui.content_view(); @@ -149,7 +151,7 @@ pub fn gemini_content( let mut end_iter = buffer.get_end_iter(); buffer.insert_markup(&mut end_iter, &mono_span(escape_text(&link_item))); } else { - gemini_link(&gui, link_item); + gemini_link(&gui, &config, link_item); } } Err(_) => println!("Something failed."), @@ -158,7 +160,7 @@ pub fn gemini_content( buffer } -pub fn gemini_text_content(gui: &Arc<Gui>, content: std::str::Lines) -> TextBuffer { +pub fn gemini_text_content(gui: &Arc<Gui>, config: &Arc<settings::Settings>, content: std::str::Lines) -> TextBuffer { let content_view = gui.content_view(); let buffer = content_view.get_buffer().unwrap(); @@ -178,6 +180,7 @@ pub fn gemini_text_content(gui: &Arc<Gui>, content: std::str::Lines) -> TextBuff pub fn gopher_content( gui: &Arc<Gui>, + config: &Arc<settings::Settings>, content: Vec<Result<crate::gopher::parser::TextElement, crate::gopher::parser::ParseError>>, ) -> TextBuffer { let content_view = gui.content_view(); @@ -201,16 +204,16 @@ pub fn gopher_content( ); } Ok(crate::gopher::parser::TextElement::LinkItem(link_item)) => { - gopher_link(&gui, colors::cleanup(&link_item)); + gopher_link(&gui, &config, colors::cleanup(&link_item)); } Ok(crate::gopher::parser::TextElement::ExternalLinkItem(link_item)) => { - gopher_link(&gui, colors::cleanup(&link_item)); + gopher_link(&gui, &config, colors::cleanup(&link_item)); } Ok(crate::gopher::parser::TextElement::Image(link_item)) => { - gopher_link(&gui, link_item); + gopher_link(&gui, &config, link_item); } Ok(crate::gopher::parser::TextElement::Binary(link_item)) => { - gopher_link(&gui, link_item); + gopher_link(&gui, &config, link_item); } Err(_) => println!("Something failed."), } @@ -220,6 +223,7 @@ pub fn gopher_content( pub fn finger_content( gui: &Arc<Gui>, + config: &Arc<settings::Settings>, content: Vec<Result<crate::finger::parser::TextElement, crate::finger::parser::ParseError>>, ) -> TextBuffer { let content_view = gui.content_view(); @@ -247,7 +251,7 @@ pub fn finger_content( buffer } -pub fn gemini_link(gui: &Arc<Gui>, link_item: String) { +pub fn gemini_link(gui: &Arc<Gui>, config: &Arc<settings::Settings>, link_item: String) { match GeminiLink::from_str(&link_item) { Ok(GeminiLink::Finger(url, label)) => { let button_label = if label.is_empty() { @@ -256,10 +260,10 @@ pub fn gemini_link(gui: &Arc<Gui>, link_item: String) { label }; let finger_label = format!("{} [Finger]", button_label); - insert_button(&gui, url, finger_label); + insert_button(&gui, &config, url, finger_label); } Ok(GeminiLink::Gemini(url, label)) => { - insert_button(&gui, url, label); + insert_button(&gui, &config, url, label); } Ok(GeminiLink::Gopher(url, label)) => { let button_label = if label.is_empty() { @@ -268,7 +272,7 @@ pub fn gemini_link(gui: &Arc<Gui>, link_item: String) { label }; let gopher_label = format!("{} [Gopher]", button_label); - insert_button(&gui, url, gopher_label); + insert_button(&gui, &config, url, gopher_label); } Ok(GeminiLink::Http(url, label)) => { let button_label = if label.is_empty() { @@ -312,14 +316,14 @@ pub fn gemini_link(gui: &Arc<Gui>, link_item: String) { } Ok(GeminiLink::Relative(url, label)) => { let new_url = Gemini { source: url }.to_absolute_url().unwrap(); - insert_button(&gui, new_url, label); + insert_button(&gui, &config, new_url, label); } Ok(GeminiLink::Unknown(_, _)) => (), Err(_) => (), } } -pub fn gopher_link(gui: &Arc<Gui>, link_item: String) { +pub fn gopher_link(gui: &Arc<Gui>, config: &Arc<settings::Settings>, link_item: String) { match GopherLink::from_str(&link_item) { Ok(GopherLink::Http(url, label)) => { let button_label = if label.is_empty() { @@ -338,7 +342,7 @@ pub fn gopher_link(gui: &Arc<Gui>, link_item: String) { label }; let gopher_label = format!("{} [Gopher]", button_label); - insert_button(&gui, url, gopher_label); + insert_button(&gui, &config, url, gopher_label); } Ok(GopherLink::Image(url, label)) => { let button_label = if label.is_empty() { @@ -359,11 +363,11 @@ pub fn gopher_link(gui: &Arc<Gui>, link_item: String) { insert_gopher_file_button(&gui, url, file_label); } Ok(GopherLink::Gemini(url, label)) => { - insert_button(&gui, url, label); + insert_button(&gui, &config, url, label); } Ok(GopherLink::Relative(url, label)) => { let new_url = Gopher { source: url }.to_absolute_url().unwrap(); - insert_button(&gui, new_url, label); + insert_button(&gui, &config, new_url, label); } Ok(GopherLink::Ftp(url, label)) => { let button_label = if label.is_empty() { @@ -390,7 +394,7 @@ pub fn gopher_link(gui: &Arc<Gui>, link_item: String) { } } -pub fn insert_button(gui: &Arc<Gui>, url: Url, label: String) { +fn insert_button(gui: &Arc<Gui>, config: &Arc<settings::Settings>, url: Url, label: String) { let content_view = gui.content_view(); let buffer = content_view.get_buffer().unwrap(); @@ -403,11 +407,12 @@ pub fn insert_button(gui: &Arc<Gui>, url: Url, label: String) { let button = gtk::Button::new_with_label(&button_label); button.set_tooltip_text(Some(&url.to_string())); + let config = config.clone(); button.connect_clicked(clone!(@weak gui => move |_| { match url.scheme() { - "finger" => crate::visit_url(&gui, Finger { source: url.to_string() }), - "gemini" => crate::visit_url(&gui, Gemini { source: url.to_string() }), - "gopher" => crate::visit_url(&gui, Gopher { source: url.to_string() }), + "finger" => crate::visit_url(&gui, &config, Finger { source: url.to_string() }), + "gemini" => crate::visit_url(&gui, &config, Gemini { source: url.to_string() }), + "gopher" => crate::visit_url(&gui, &config, Gopher { source: url.to_string() }), _ => () } })); diff --git a/src/main.rs b/src/main.rs index 9a6bc07..1a22ad9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,7 +33,7 @@ use status::Status; fn main() { // Read in settings - let config = settings::read(); + let config = Arc::new(settings::read()); // Start up the GTK3 subsystem. gtk::init().expect("Unable to start GTK3. Error"); @@ -59,8 +59,9 @@ fn main() { { let button = gui.back_button(); let gui = gui.clone(); + let config = config.clone(); button.connect_clicked(move |_| { - go_back(&gui); + go_back(&gui, &config); }); } @@ -68,17 +69,19 @@ fn main() { { let button = gui.forward_button(); let gui = gui.clone(); + let config = config.clone(); button.connect_clicked(move |_| { - go_forward(&gui); + go_forward(&gui, &config); }); } // Bind refresh button { let button = gui.refresh_button(); + let config = config.clone(); let gui = gui.clone(); button.connect_clicked(move |_| { - refresh(&gui); + refresh(&gui, &config); }); } @@ -95,28 +98,31 @@ fn main() { { let button = gui.show_bookmarks_button(); let gui = gui.clone(); + let config = config.clone(); button.connect_clicked(move |_| { - show_bookmarks(&gui); + show_bookmarks(&gui, &config); }); } // Bind URL bar { let gui_clone = gui.clone(); + let config = config.clone(); let url_bar = gui.url_bar(); url_bar.connect_activate(move |b| { let url = b.get_text().expect("get_text failed"); - route_url(&gui_clone, url.as_str()) + route_url(&gui_clone, &config, url.as_str()) }); } // Bind Mouse-Back { let gui_clone = gui.clone(); + let config = config.clone(); let content_view = gui.content_view(); content_view.connect_button_press_event(move |_, event| { if event.get_button() == 8 { - go_back(&gui_clone); + go_back(&gui_clone, &config); } Inhibit(false) }); @@ -128,28 +134,29 @@ fn main() { // no argument passed, check settings 1 => { if let Some(url) = config.start_url() { - route_url(&gui, url) + route_url(&gui, &config, url) } } // Use argument as initial URL - _ => route_url(&gui, &args[1]), + _ => route_url(&gui, &config, &args[1]), } gui.start(); gtk::main(); } -fn route_url(gui: &Arc<Gui>, url: &str) { +fn route_url(gui: &Arc<Gui>, config: &Arc<settings::Settings>, url: &str) { if url == "" { } else if url.starts_with("gemini://") { - visit_url(&gui, Gemini { source: url.to_string() }) + visit_url(&gui, &config, Gemini { source: url.to_string() }) } else if url.starts_with("gopher://") { - visit_url(&gui, Gopher { source: url.to_string() }) + visit_url(&gui, &config, Gopher { source: url.to_string() }) } else if url.starts_with("finger://") { - visit_url(&gui, Finger { source: url.to_string() }) + visit_url(&gui, &config, Finger { source: url.to_string() }) } else { visit_url( &gui, + &config, Gemini { source: format!("gemini://{}", url), }, @@ -157,34 +164,37 @@ fn route_url(gui: &Arc<Gui>, url: &str) { }; } -fn go_back(gui: &Arc<Gui>) { +fn go_back(gui: &Arc<Gui>, config: &Arc<settings::Settings>) { if let Some(prev) = history::get_previous_url() { - visit(gui, &prev); + visit(gui, &config, &prev); } } -fn go_forward(gui: &Arc<Gui>) { +fn go_forward(gui: &Arc<Gui>, config: &Arc<settings::Settings>) { if let Some(next) = history::get_next_url() { - visit(gui, &next); + visit(gui, &config, &next); } } -fn visit(gui: &Arc<Gui>, url: &Url) { +fn visit(gui: &Arc<Gui>, config: &Arc<settings::Settings>, url: &Url) { match url.scheme() { "finger" => visit_url( gui, + &config, Finger { source: url.to_string(), }, ), "gemini" => visit_url( gui, + &config, Gemini { source: url.to_string(), }, ), "gopher" => visit_url( gui, + &config, Gopher { source: url.to_string(), }, @@ -193,10 +203,10 @@ fn visit(gui: &Arc<Gui>, url: &Url) { } } -fn refresh(gui: &Arc<Gui>) { +fn refresh(gui: &Arc<Gui>, config: &Arc<settings::Settings>) { let url_bar = gui.url_bar(); let url = url_bar.get_text().expect("get_text failed"); - route_url(&gui, url.as_str()) + route_url(&gui, &config, url.as_str()) } fn update_url_field(gui: &Arc<Gui>, url: &str) { @@ -218,23 +228,23 @@ fn add_bookmark(gui: &Arc<Gui>) { } } -fn show_bookmarks(gui: &Arc<Gui>) { +fn show_bookmarks(gui: &Arc<Gui>, config: &Arc<settings::Settings>) { let content_view = gui.content_view(); let bookmarks_list = format!("# Bookmarks\n\n{}", bookmarks::content()); let parsed_content = gemini::parser::parse(bookmarks_list); clear_buffer(&content_view); - draw::gemini_content(&gui, parsed_content); + draw::gemini_content(&gui, &config, parsed_content); update_url_field(&gui, "::bookmarks"); content_view.show_all(); } -pub fn visit_url<T: AbsoluteUrl + Protocol>(gui: &Arc<Gui>, url: T) { +pub fn visit_url<T: AbsoluteUrl + Protocol>(gui: &Arc<Gui>, config: &Arc<settings::Settings>, url: T) { if url.get_source_str() == "gemini://::bookmarks" { - show_bookmarks(&gui); + show_bookmarks(&gui, &config); return; } @@ -264,10 +274,10 @@ pub fn visit_url<T: AbsoluteUrl + Protocol>(gui: &Arc<Gui>, url: T) { clear_buffer(&content_view); if meta.starts_with("text/gemini") { let parsed_content = gemini::parser::parse(content_str); - draw::gemini_content(&gui, parsed_content); + draw::gemini_content(&gui, &config, parsed_content); } else { // just a text file - draw::gemini_text_content(&gui, content_str.lines()); + draw::gemini_text_content(&gui, &config, content_str.lines()); } content_view.show_all(); @@ -282,7 +292,7 @@ pub fn visit_url<T: AbsoluteUrl + Protocol>(gui: &Arc<Gui>, url: T) { Status::RedirectTemporary(new_url) | Status::RedirectPermanent(new_url) => { history::append(absolute_url.as_str()); - visit_url(&gui, Gemini { source: new_url }); + visit_url(&gui, &config, Gemini { source: new_url }); } Status::TransientCertificateRequired(_meta) | Status::AuthorisedCertificatedRequired(_meta) => { @@ -292,7 +302,7 @@ pub fn visit_url<T: AbsoluteUrl + Protocol>(gui: &Arc<Gui>, url: T) { ); } Status::Input(message) => { - dialog::input(&gui, absolute_url, &message); + dialog::input(&gui, &config, absolute_url, &message); } _ => (), } @@ -318,7 +328,7 @@ pub fn visit_url<T: AbsoluteUrl + Protocol>(gui: &Arc<Gui>, url: T) { let parsed_content = gopher::parser::parse(content_str); clear_buffer(&content_view); - draw::gopher_content(&gui, parsed_content); + draw::gopher_content(&gui, &config, parsed_content); content_view.show_all(); } @@ -342,7 +352,7 @@ pub fn visit_url<T: AbsoluteUrl + Protocol>(gui: &Arc<Gui>, url: T) { let parsed_content = finger::parser::parse(content_str); clear_buffer(&content_view); - draw::finger_content(&gui, parsed_content); + draw::finger_content(&gui, &config, parsed_content); content_view.show_all(); } -- 2.20.1
Move the `get_gemini_text_font_family()` function into a method on the `Settings` struct. This allows us to use the existing `Settings` struct that we read at the start of `main`. This reduces the number of times we read the config file while rendering a document. --- src/draw.rs | 3 +-- src/settings.rs | 19 ++++++++----------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/draw.rs b/src/draw.rs index a05c05c..8f85c95 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -27,7 +27,6 @@ pub fn gemini_content( let buffer = content_view.get_buffer().unwrap(); let mut mono_toggle = false; - let font_family = crate::settings::get_gemini_text_font_family(); for el in content { match el { @@ -139,7 +138,7 @@ pub fn gemini_content( &format!( "<span foreground=\"{}\" font_family=\"{}\" size=\"{}\">{}</span>\n", crate::settings::get_text_color(), - font_family, + config.get_gemini_text_font_family(), crate::settings::get_gemini_text_font_size(), wrap_text(&text, &gui) ), diff --git a/src/settings.rs b/src/settings.rs index 0caec8c..5e9f568 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -29,6 +29,14 @@ impl Settings { None => None, } } + + pub fn get_gemini_text_font_family(&self) -> &str { + self.gemini_text_font_family().unwrap_or(DEFAULT_FONT) + } + + fn gemini_text_font_family(&self) -> Option<&str> { + self.fonts.as_ref()?.gemini.as_ref()?.text.as_ref()?.family.as_deref() + } } #[derive(Deserialize)] @@ -122,17 +130,6 @@ pub fn get_finger_font_size() -> i32 { } } -fn gemini_text_font_family() -> Option<String> { - read().fonts?.gemini?.text?.family -} - -pub fn get_gemini_text_font_family() -> String { - match gemini_text_font_family() { - Some(family) => family, - None => String::from(DEFAULT_FONT), - } -} - fn gemini_text_font_size() -> Option<i32> { read().fonts?.gemini?.text?.size } -- 2.20.1
Moving the `max_width` function into a method on the `Settings` struct means we don't have the read the config file every time we calculate the maximum width of some text. This was happening on every line rendered; doing this reduces the number of reads by that much. --- src/draw.rs | 14 +++++++------- src/settings.rs | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/draw.rs b/src/draw.rs index 8f85c95..dc814f0 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -104,7 +104,7 @@ pub fn gemini_content( crate::settings::get_gemini_list_font_family(), crate::settings::get_gemini_list_font_style(), crate::settings::get_list_character(), - wrap_text(&item, &gui) + wrap_text(&item, &gui, &config) ), ); } @@ -123,7 +123,7 @@ pub fn gemini_content( crate::settings::get_gemini_quote_font_family(), crate::settings::get_gemini_quote_font_size(), crate::settings::get_gemini_quote_font_style(), - wrap_text(&text, &gui) + wrap_text(&text, &gui, &config) ), ); } @@ -140,7 +140,7 @@ pub fn gemini_content( crate::settings::get_text_color(), config.get_gemini_text_font_family(), crate::settings::get_gemini_text_font_size(), - wrap_text(&text, &gui) + wrap_text(&text, &gui, &config) ), ); } @@ -469,8 +469,8 @@ pub fn insert_external_button(gui: &Arc<Gui>, url: Url, label: &str) { buffer.insert(&mut end_iter, "\n"); } -fn wrap_text(str: &str, gui: &Arc<Gui>) -> String { - fill(&escape_text(str), width(&gui)) +fn wrap_text(str: &str, gui: &Arc<Gui>, config: &Arc<settings::Settings>) -> String { + fill(&escape_text(str), width(&gui, &config)) } fn escape_text(str: &str) -> String { @@ -486,8 +486,8 @@ fn mono_span(text: String) -> String { ) } -fn width(gui: &Arc<Gui>) -> usize { +fn width(gui: &Arc<Gui>, config: &Arc<settings::Settings>) -> usize { let (win_width, _) = gtk::ApplicationWindow::get_size(gui.window()); let calculated_width = (win_width / 10).try_into().unwrap(); - std::cmp::min(calculated_width, crate::settings::max_width().unwrap_or(std::usize::MAX)) + std::cmp::min(calculated_width, config.max_width().unwrap_or(std::usize::MAX)) } diff --git a/src/settings.rs b/src/settings.rs index 5e9f568..3a52ea7 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -34,6 +34,13 @@ impl Settings { self.gemini_text_font_family().unwrap_or(DEFAULT_FONT) } + pub fn max_width(&self) -> Option<usize> { + match &self.general { + Some(general) => general.max_width, + None => None, + } + } + fn gemini_text_font_family(&self) -> Option<&str> { self.fonts.as_ref()?.gemini.as_ref()?.text.as_ref()?.family.as_deref() } @@ -94,13 +101,6 @@ struct QuoteColor { background: Option<String>, } -pub fn max_width() -> Option<usize> { - match read().general { - Some(general) => general.max_width, - None => None, - } -} - const DEFAULT_FONT: &str = "serif"; const DEFAULT_FONT_STYLE: &str = "normal"; const DEFAULT_FONT_SIZE: i32 = 11 * pango_sys::PANGO_SCALE; -- 2.20.1
Put the `Settings` struct in charge of the Pango markup for a given line type. It knows all about the configuration data and how it maps to a line type. This introduces a new enum, `LineType`, for describing what kind of line we're operating on. It only knows about `Text` so far. This reduces the number of reads of the config file while rendering normal text. This also sets us up for a potential future refactoring where a helper method renders the `span` with knowledge about the line type's settings and defaults. --- src/draw.rs | 12 ++---------- src/settings.rs | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/draw.rs b/src/draw.rs index dc814f0..8128ca4 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -133,16 +133,8 @@ pub fn gemini_content( if mono_toggle { buffer.insert_markup(&mut end_iter, &mono_span(colors::colorize(&text))); } else { - buffer.insert_markup( - &mut end_iter, - &format!( - "<span foreground=\"{}\" font_family=\"{}\" size=\"{}\">{}</span>\n", - crate::settings::get_text_color(), - config.get_gemini_text_font_family(), - crate::settings::get_gemini_text_font_size(), - wrap_text(&text, &gui, &config) - ), - ); + let markup = config.format_markup(settings::LineType::Text, &wrap_text(&text, &gui, &config)); + buffer.insert_markup(&mut end_iter, &markup); } } Ok(crate::gemini::parser::TextElement::LinkItem(link_item)) => { diff --git a/src/settings.rs b/src/settings.rs index 3a52ea7..fd4199a 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -7,6 +7,10 @@ use std::io::Read; use serde_derive::Deserialize; +pub enum LineType { + Text, +} + #[derive(Deserialize)] pub struct Settings { general: Option<General>, @@ -30,6 +34,20 @@ impl Settings { } } + pub fn format_markup(&self, line_type: LineType, text: &str) -> String { + match line_type { + LineType::Text => { + format!( + "<span foreground=\"{}\" font_family=\"{}\" size=\"{}\">{}</span>\n", + self.get_text_color(), + self.get_gemini_text_font_family(), + self.get_gemini_text_font_size(), + text, + ) + } + } + } + pub fn get_gemini_text_font_family(&self) -> &str { self.gemini_text_font_family().unwrap_or(DEFAULT_FONT) } @@ -44,6 +62,25 @@ impl Settings { fn gemini_text_font_family(&self) -> Option<&str> { self.fonts.as_ref()?.gemini.as_ref()?.text.as_ref()?.family.as_deref() } + + fn get_text_color(&self) -> &str { + self.text_color().unwrap_or("black") + } + + fn text_color(&self) -> Option<&str> { + self.colors.as_ref()?.text.as_deref() + } + + pub fn get_gemini_text_font_size(&self) -> i32 { + match &self.gemini_text_font_size() { + Some(size) => size * pango_sys::PANGO_SCALE, + None => DEFAULT_FONT_SIZE, + } + } + + fn gemini_text_font_size(&self) -> Option<i32> { + self.fonts.as_ref()?.gemini.as_ref()?.text.as_ref()?.size + } } #[derive(Deserialize)] -- 2.20.1
This currently looks like it is shuffling clutter around, and that is what is happening. We need to expand before we can do the next refactoring. --- src/draw.rs | 14 +----- src/settings.rs | 123 +++++++++++++++++++++++------------------------- 2 files changed, 62 insertions(+), 75 deletions(-) diff --git a/src/draw.rs b/src/draw.rs index 8128ca4..608ba22 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -114,18 +114,8 @@ pub fn gemini_content( if mono_toggle { buffer.insert_markup(&mut end_iter, &mono_span(text)); } else { - buffer.insert_markup( - &mut end_iter, - &format!( - "<span foreground=\"{}\" background=\"{}\" font_family=\"{}\" size=\"{}\" style=\"{}\">{}</span>\n", - crate::settings::get_gemini_quote_foreground_color(), - crate::settings::get_gemini_quote_background_color(), - crate::settings::get_gemini_quote_font_family(), - crate::settings::get_gemini_quote_font_size(), - crate::settings::get_gemini_quote_font_style(), - wrap_text(&text, &gui, &config) - ), - ); + let markup = config.format_markup(settings::LineType::Quote, &wrap_text(&text, &gui, &config)); + buffer.insert_markup(&mut end_iter, &markup); } } Ok(crate::gemini::parser::TextElement::Text(text)) => { diff --git a/src/settings.rs b/src/settings.rs index fd4199a..b1993df 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -9,6 +9,7 @@ use serde_derive::Deserialize; pub enum LineType { Text, + Quote, } #[derive(Deserialize)] @@ -44,14 +45,21 @@ impl Settings { self.get_gemini_text_font_size(), text, ) - } + }, + LineType::Quote => { + format!( + "<span foreground=\"{}\" background=\"{}\" font_family=\"{}\" size=\"{}\" style=\"{}\">{}</span>\n", + self.get_gemini_quote_foreground_color(), + self.get_gemini_quote_background_color(), + self.get_gemini_quote_font_family(), + self.get_gemini_quote_font_size(), + self.get_gemini_quote_font_style(), + text, + ) + }, } } - pub fn get_gemini_text_font_family(&self) -> &str { - self.gemini_text_font_family().unwrap_or(DEFAULT_FONT) - } - pub fn max_width(&self) -> Option<usize> { match &self.general { Some(general) => general.max_width, @@ -59,10 +67,22 @@ impl Settings { } } + fn get_gemini_text_font_family(&self) -> &str { + self.gemini_text_font_family().unwrap_or(DEFAULT_FONT) + } + fn gemini_text_font_family(&self) -> Option<&str> { self.fonts.as_ref()?.gemini.as_ref()?.text.as_ref()?.family.as_deref() } + fn get_gemini_quote_font_family(&self) -> &str { + self.gemini_quote_font_family().unwrap_or(DEFAULT_FONT) + } + + fn gemini_quote_font_family(&self) -> Option<&str> { + self.fonts.as_ref()?.gemini.as_ref()?.quote.as_ref()?.family.as_deref() + } + fn get_text_color(&self) -> &str { self.text_color().unwrap_or("black") } @@ -71,7 +91,7 @@ impl Settings { self.colors.as_ref()?.text.as_deref() } - pub fn get_gemini_text_font_size(&self) -> i32 { + fn get_gemini_text_font_size(&self) -> i32 { match &self.gemini_text_font_size() { Some(size) => size * pango_sys::PANGO_SCALE, None => DEFAULT_FONT_SIZE, @@ -81,6 +101,40 @@ impl Settings { fn gemini_text_font_size(&self) -> Option<i32> { self.fonts.as_ref()?.gemini.as_ref()?.text.as_ref()?.size } + + fn get_gemini_quote_font_size(&self) -> i32 { + match &self.gemini_quote_font_size() { + Some(size) => size * pango_sys::PANGO_SCALE, + None => DEFAULT_FONT_SIZE, + } + } + + fn gemini_quote_font_size(&self) -> Option<i32> { + self.fonts.as_ref()?.gemini.as_ref()?.quote.as_ref()?.size + } + + fn get_gemini_quote_foreground_color(&self) -> &str { + self.quote_color().and_then(|color| color.foreground.as_deref()).unwrap_or("#e4e4e4") + } + + fn get_gemini_quote_background_color(&self) -> &str { + self.quote_color().and_then(|color| color.background.as_deref()).unwrap_or("gray") + } + + fn quote_color(&self) -> Option<&QuoteColor> { + self.colors.as_ref()?.quote.as_ref() + } + + fn get_gemini_quote_font_style(&self) -> &str { + match self.gemini_quote_font_style() { + Some(style) => style, + None => "italic", + } + } + + fn gemini_quote_font_style(&self) -> Option<&str> { + self.fonts.as_ref()?.gemini.as_ref()?.quote.as_ref()?.style.as_deref() + } } #[derive(Deserialize)] @@ -289,18 +343,6 @@ fn gemini_list_font_style() -> Option<String> { read().fonts?.gemini?.list?.style } -fn gemini_quote_font_family() -> Option<String> { - read().fonts?.gemini?.quote?.family -} - -fn gemini_quote_font_size() -> Option<i32> { - read().fonts?.gemini?.quote?.size -} - -fn gemini_quote_font_style() -> Option<String> { - read().fonts?.gemini?.quote?.style -} - pub fn get_gemini_list_font_size() -> i32 { match gemini_list_font_size() { Some(size) => size * pango_sys::PANGO_SCALE, @@ -322,27 +364,6 @@ pub fn get_gemini_list_font_style() -> String { } } -pub fn get_gemini_quote_font_size() -> i32 { - match gemini_quote_font_size() { - Some(size) => size * pango_sys::PANGO_SCALE, - None => DEFAULT_FONT_SIZE, - } -} - -pub fn get_gemini_quote_font_family() -> String { - match gemini_quote_font_family() { - Some(family) => family, - None => String::from(DEFAULT_FONT), - } -} - -pub fn get_gemini_quote_font_style() -> String { - match gemini_quote_font_style() { - Some(style) => style, - None => String::from("italic"), - } -} - fn gopher_font_family() -> Option<String> { read().fonts?.gopher?.family } @@ -409,30 +430,6 @@ pub fn get_list_color() -> String { } } -fn quote_color() -> Option<QuoteColor> { - read().colors?.quote -} - -pub fn get_gemini_quote_foreground_color() -> String { - match quote_color() { - Some(color) => match color.foreground { - Some(color) => color, - None => String::from("#e4e4e4"), - }, - None => String::from("#e4e4e4"), - } -} - -pub fn get_gemini_quote_background_color() -> String { - match quote_color() { - Some(color) => match color.background { - Some(color) => color, - None => String::from("grey"), - }, - None => String::from("grey"), - } -} - fn text_color() -> Option<String> { read().colors?.text } -- 2.20.1
--- src/draw.rs | 14 +----- src/settings.rs | 110 ++++++++++++++++++++++++------------------------ 2 files changed, 57 insertions(+), 67 deletions(-) diff --git a/src/draw.rs b/src/draw.rs index 608ba22..9646d00 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -95,18 +95,8 @@ pub fn gemini_content( if mono_toggle { buffer.insert_markup(&mut end_iter, &mono_span(item)); } else { - buffer.insert_markup( - &mut end_iter, - &format!( - "<span foreground=\"{}\" size=\"{}\" font_family=\"{}\" style=\"{}\">{}{}</span>\n", - crate::settings::get_list_color(), - crate::settings::get_gemini_list_font_size(), - crate::settings::get_gemini_list_font_family(), - crate::settings::get_gemini_list_font_style(), - crate::settings::get_list_character(), - wrap_text(&item, &gui, &config) - ), - ); + let markup = config.format_markup(settings::LineType::ListItem, &wrap_text(&item, &gui, &config)); + buffer.insert_markup(&mut end_iter, &markup); } } Ok(crate::gemini::parser::TextElement::Quote(text)) => { diff --git a/src/settings.rs b/src/settings.rs index b1993df..a210dd1 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -10,6 +10,7 @@ use serde_derive::Deserialize; pub enum LineType { Text, Quote, + ListItem, } #[derive(Deserialize)] @@ -57,6 +58,17 @@ impl Settings { text, ) }, + LineType::ListItem => { + format!( + "<span foreground=\"{}\" size=\"{}\" font_family=\"{}\" style=\"{}\">{}{}</span>\n", + self.get_list_color(), + self.get_gemini_list_font_size(), + self.get_gemini_list_font_family(), + self.get_gemini_list_font_style(), + self.get_list_character(), + text, + ) + } } } @@ -135,6 +147,49 @@ impl Settings { fn gemini_quote_font_style(&self) -> Option<&str> { self.fonts.as_ref()?.gemini.as_ref()?.quote.as_ref()?.style.as_deref() } + + fn get_list_color(&self) -> &str { + self.list_color().unwrap_or("green") + } + + fn list_color(&self) -> Option<&str> { + self.colors.as_ref()?.list.as_deref() + } + + fn get_gemini_list_font_size(&self) -> i32 { + match self.gemini_list_font_size() { + Some(size) => size * pango_sys::PANGO_SCALE, + None => DEFAULT_FONT_SIZE, + } + } + + fn get_gemini_list_font_family(&self) -> &str { + self.gemini_list_font_family().unwrap_or(DEFAULT_FONT) + } + + fn get_gemini_list_font_style(&self) -> &str { + self.gemini_list_font_style().unwrap_or(DEFAULT_FONT_STYLE) + } + + fn gemini_list_font_family(&self) -> Option<&str> { + self.fonts.as_ref()?.gemini.as_ref()?.list.as_ref()?.family.as_deref() + } + + fn gemini_list_font_size(&self) -> Option<i32> { + self.fonts.as_ref()?.gemini.as_ref()?.list.as_ref()?.size + } + + fn gemini_list_font_style(&self) -> Option<&str> { + self.fonts.as_ref()?.gemini.as_ref()?.list.as_ref()?.style.as_deref() + } + + fn get_list_character(&self) -> &str { + self.list_character().unwrap_or("â– ") + } + + fn list_character(&self) -> Option<&str> { + self.characters.as_ref()?.list.as_deref() + } } #[derive(Deserialize)] @@ -331,39 +386,6 @@ pub fn get_gemini_h3_font_style() -> String { } } -fn gemini_list_font_family() -> Option<String> { - read().fonts?.gemini?.list?.family -} - -fn gemini_list_font_size() -> Option<i32> { - read().fonts?.gemini?.list?.size -} - -fn gemini_list_font_style() -> Option<String> { - read().fonts?.gemini?.list?.style -} - -pub fn get_gemini_list_font_size() -> i32 { - match gemini_list_font_size() { - Some(size) => size * pango_sys::PANGO_SCALE, - None => DEFAULT_FONT_SIZE, - } -} - -pub fn get_gemini_list_font_family() -> String { - match gemini_list_font_family() { - Some(family) => family, - None => String::from(DEFAULT_FONT), - } -} - -pub fn get_gemini_list_font_style() -> String { - match gemini_list_font_style() { - Some(style) => style, - None => String::from(DEFAULT_FONT_STYLE), - } -} - fn gopher_font_family() -> Option<String> { read().fonts?.gopher?.family } @@ -419,17 +441,6 @@ pub fn get_h3_color() -> String { } } -fn list_color() -> Option<String> { - read().colors?.list -} - -pub fn get_list_color() -> String { - match list_color() { - Some(color) => color, - None => String::from("green"), - } -} - fn text_color() -> Option<String> { read().colors?.text } @@ -474,17 +485,6 @@ pub fn get_h3_character() -> String { } } -fn list_character() -> Option<String> { - read().characters?.list -} - -pub fn get_list_character() -> String { - match list_character() { - Some(char) => char, - None => String::from("â– "), - } -} - pub fn read() -> Settings { let mut file = settings_file(); let mut content = String::new(); -- 2.20.1
--- src/draw.rs | 14 +----- src/settings.rs | 110 ++++++++++++++++++++++++------------------------ 2 files changed, 57 insertions(+), 67 deletions(-) diff --git a/src/draw.rs b/src/draw.rs index 9646d00..277f8e2 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -76,18 +76,8 @@ pub fn gemini_content( if mono_toggle { buffer.insert_markup(&mut end_iter, &mono_span(escape_text(&header))); } else { - buffer.insert_markup( - &mut end_iter, - &format!( - "<span foreground=\"{}\" size=\"{}\" font_family=\"{}\" style=\"{}\">{}{}</span>\n", - crate::settings::get_h3_color(), - crate::settings::get_gemini_h3_font_size(), - crate::settings::get_gemini_h3_font_family(), - crate::settings::get_gemini_h3_font_style(), - crate::settings::get_h3_character(), - escape_text(&header) - ), - ); + let markup = config.format_markup(settings::LineType::H3, &escape_text(&header)); + buffer.insert_markup(&mut end_iter, &markup); } } Ok(crate::gemini::parser::TextElement::ListItem(item)) => { diff --git a/src/settings.rs b/src/settings.rs index a210dd1..df5880a 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -11,6 +11,7 @@ pub enum LineType { Text, Quote, ListItem, + H3, } #[derive(Deserialize)] @@ -68,6 +69,17 @@ impl Settings { self.get_list_character(), text, ) + }, + LineType::H3 => { + format!( + "<span foreground=\"{}\" size=\"{}\" font_family=\"{}\" style=\"{}\">{}{}</span>\n", + self.get_h3_color(), + self.get_gemini_h3_font_size(), + self.get_gemini_h3_font_family(), + self.get_gemini_h3_font_style(), + self.get_h3_character(), + text + ) } } } @@ -190,6 +202,49 @@ impl Settings { fn list_character(&self) -> Option<&str> { self.characters.as_ref()?.list.as_deref() } + + fn get_h3_color(&self) -> &str { + self.h3_color().unwrap_or("#87CEFA") + } + + fn h3_color(&self) -> Option<&str> { + self.colors.as_ref()?.h3.as_deref() + } + + fn get_gemini_h3_font_size(&self) -> i32 { + match self.gemini_h3_font_size() { + Some(size) => size * pango_sys::PANGO_SCALE, + None => DEFAULT_H3_FONT_SIZE, + } + } + + fn get_gemini_h3_font_family(&self) -> &str { + self.gemini_h3_font_family().unwrap_or(DEFAULT_FONT) + } + + fn get_gemini_h3_font_style(&self) -> &str { + self.gemini_h3_font_style().unwrap_or(DEFAULT_FONT_STYLE) + } + + fn gemini_h3_font_family(&self) -> Option<&str> { + self.fonts.as_ref()?.gemini.as_ref()?.h3.as_ref()?.family.as_deref() + } + + fn gemini_h3_font_size(&self) -> Option<i32> { + self.fonts.as_ref()?.gemini.as_ref()?.h3.as_ref()?.size + } + + fn gemini_h3_font_style(&self) -> Option<&str> { + self.fonts.as_ref()?.gemini.as_ref()?.h3.as_ref()?.style.as_deref() + } + + fn get_h3_character(&self) -> &str { + self.h3_character().unwrap_or("") + } + + fn h3_character(&self) -> Option<&str> { + self.characters.as_ref()?.h3.as_deref() + } } #[derive(Deserialize)] @@ -353,39 +408,6 @@ pub fn get_gemini_h2_font_style() -> String { } } -fn gemini_h3_font_family() -> Option<String> { - read().fonts?.gemini?.h3?.family -} - -fn gemini_h3_font_size() -> Option<i32> { - read().fonts?.gemini?.h3?.size -} - -fn gemini_h3_font_style() -> Option<String> { - read().fonts?.gemini?.h3?.style -} - -pub fn get_gemini_h3_font_size() -> i32 { - match gemini_h3_font_size() { - Some(size) => size * pango_sys::PANGO_SCALE, - None => DEFAULT_H3_FONT_SIZE, - } -} - -pub fn get_gemini_h3_font_family() -> String { - match gemini_h3_font_family() { - Some(family) => family, - None => String::from(DEFAULT_FONT), - } -} - -pub fn get_gemini_h3_font_style() -> String { - match gemini_h3_font_style() { - Some(style) => style, - None => String::from(DEFAULT_FONT_STYLE), - } -} - fn gopher_font_family() -> Option<String> { read().fonts?.gopher?.family } @@ -430,17 +452,6 @@ pub fn get_h2_color() -> String { } } -fn h3_color() -> Option<String> { - read().colors?.h3 -} - -pub fn get_h3_color() -> String { - match h3_color() { - Some(color) => color, - None => String::from("#87CEFA"), - } -} - fn text_color() -> Option<String> { read().colors?.text } @@ -474,17 +485,6 @@ pub fn get_h2_character() -> String { } } -fn h3_character() -> Option<String> { - read().characters?.h3 -} - -pub fn get_h3_character() -> String { - match h3_character() { - Some(char) => char, - None => String::new(), - } -} - pub fn read() -> Settings { let mut file = settings_file(); let mut content = String::new(); -- 2.20.1
--- src/draw.rs | 14 +----- src/settings.rs | 112 ++++++++++++++++++++++++------------------------ 2 files changed, 58 insertions(+), 68 deletions(-) diff --git a/src/draw.rs b/src/draw.rs index 277f8e2..0a14ba2 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -57,18 +57,8 @@ pub fn gemini_content( if mono_toggle { buffer.insert_markup(&mut end_iter, &mono_span(escape_text(&header))); } else { - buffer.insert_markup( - &mut end_iter, - &format!( - "<span foreground=\"{}\" size=\"{}\" font_family=\"{}\" style=\"{}\">{}{}</span>\n", - crate::settings::get_h2_color(), - crate::settings::get_gemini_h2_font_size(), - crate::settings::get_gemini_h2_font_family(), - crate::settings::get_gemini_h2_font_style(), - crate::settings::get_h2_character(), - escape_text(&header) - ), - ); + let markup = config.format_markup(settings::LineType::H2, &escape_text(&header)); + buffer.insert_markup(&mut end_iter, &markup); } } Ok(crate::gemini::parser::TextElement::H3(header)) => { diff --git a/src/settings.rs b/src/settings.rs index df5880a..d11d0a0 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -12,6 +12,7 @@ pub enum LineType { Quote, ListItem, H3, + H2, } #[derive(Deserialize)] @@ -80,7 +81,18 @@ impl Settings { self.get_h3_character(), text ) - } + }, + LineType::H2 => { + format!( + "<span foreground=\"{}\" size=\"{}\" font_family=\"{}\" style=\"{}\">{}{}</span>\n", + self.get_h2_color(), + self.get_gemini_h2_font_size(), + self.get_gemini_h2_font_family(), + self.get_gemini_h2_font_style(), + self.get_h2_character(), + text, + ) + }, } } @@ -245,6 +257,49 @@ impl Settings { fn h3_character(&self) -> Option<&str> { self.characters.as_ref()?.h3.as_deref() } + + fn get_h2_color(&self) -> &str { + self.h2_color().unwrap_or("#FF1493") + } + + fn h2_color(&self) -> Option<&str> { + self.colors.as_ref()?.h2.as_deref() + } + + fn get_gemini_h2_font_size(&self) -> i32 { + match self.gemini_h2_font_size() { + Some(size) => size * pango_sys::PANGO_SCALE, + None => DEFAULT_H2_FONT_SIZE, + } + } + + fn get_gemini_h2_font_family(&self) -> &str { + self.gemini_h2_font_family().unwrap_or(DEFAULT_FONT) + } + + fn get_gemini_h2_font_style(&self) -> &str { + self.gemini_h2_font_style().unwrap_or(DEFAULT_FONT_STYLE) + } + + fn gemini_h2_font_family(&self) -> Option<&str> { + self.fonts.as_ref()?.gemini.as_ref()?.h2.as_ref()?.family.as_deref() + } + + fn gemini_h2_font_size(&self) -> Option<i32> { + self.fonts.as_ref()?.gemini.as_ref()?.h2.as_ref()?.size + } + + fn gemini_h2_font_style(&self) -> Option<&str> { + self.fonts.as_ref()?.gemini.as_ref()?.h2.as_ref()?.style.as_deref() + } + + fn get_h2_character(&self) -> &str { + self.h2_character().unwrap_or("") + } + + fn h2_character(&self) -> Option<&str> { + self.characters.as_ref()?.h2.as_deref() + } } #[derive(Deserialize)] @@ -375,39 +430,6 @@ pub fn get_gemini_h1_font_style() -> String { } } -fn gemini_h2_font_family() -> Option<String> { - read().fonts?.gemini?.h2?.family -} - -fn gemini_h2_font_size() -> Option<i32> { - read().fonts?.gemini?.h2?.size -} - -fn gemini_h2_font_style() -> Option<String> { - read().fonts?.gemini?.h2?.style -} - -pub fn get_gemini_h2_font_size() -> i32 { - match gemini_h2_font_size() { - Some(size) => size * pango_sys::PANGO_SCALE, - None => DEFAULT_H2_FONT_SIZE, - } -} - -pub fn get_gemini_h2_font_family() -> String { - match gemini_h2_font_family() { - Some(family) => family, - None => String::from(DEFAULT_FONT), - } -} - -pub fn get_gemini_h2_font_style() -> String { - match gemini_h2_font_style() { - Some(style) => style, - None => String::from(DEFAULT_FONT_STYLE), - } -} - fn gopher_font_family() -> Option<String> { read().fonts?.gopher?.family } @@ -441,17 +463,6 @@ pub fn get_h1_color() -> String { } } -fn h2_color() -> Option<String> { - read().colors?.h2 -} - -pub fn get_h2_color() -> String { - match h2_color() { - Some(color) => color, - None => String::from("#FF1493"), - } -} - fn text_color() -> Option<String> { read().colors?.text } @@ -474,17 +485,6 @@ pub fn get_h1_character() -> String { } } -fn h2_character() -> Option<String> { - read().characters?.h2 -} - -pub fn get_h2_character() -> String { - match h2_character() { - Some(char) => char, - None => String::new(), - } -} - pub fn read() -> Settings { let mut file = settings_file(); let mut content = String::new(); -- 2.20.1
--- src/draw.rs | 14 +----- src/settings.rs | 110 ++++++++++++++++++++++++------------------------ 2 files changed, 57 insertions(+), 67 deletions(-) diff --git a/src/draw.rs b/src/draw.rs index 0a14ba2..4c800db 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -38,18 +38,8 @@ pub fn gemini_content( if mono_toggle { buffer.insert_markup(&mut end_iter, &mono_span(escape_text(&header))); } else { - buffer.insert_markup( - &mut end_iter, - &format!( - "<span foreground=\"{}\" size=\"{}\" font_family=\"{}\" style=\"{}\">{}{}</span>\n", - crate::settings::get_h1_color(), - crate::settings::get_gemini_h1_font_size(), - crate::settings::get_gemini_h1_font_family(), - crate::settings::get_gemini_h1_font_style(), - crate::settings::get_h1_character(), - escape_text(&header) - ), - ); + let markup = config.format_markup(settings::LineType::H1, &escape_text(&header)); + buffer.insert_markup(&mut end_iter, &markup); } } Ok(crate::gemini::parser::TextElement::H2(header)) => { diff --git a/src/settings.rs b/src/settings.rs index d11d0a0..e97e667 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -13,6 +13,7 @@ pub enum LineType { ListItem, H3, H2, + H1, } #[derive(Deserialize)] @@ -93,6 +94,17 @@ impl Settings { text, ) }, + LineType::H1 => { + format!( + "<span foreground=\"{}\" size=\"{}\" font_family=\"{}\" style=\"{}\">{}{}</span>\n", + self.get_h1_color(), + self.get_gemini_h1_font_size(), + self.get_gemini_h1_font_family(), + self.get_gemini_h1_font_style(), + self.get_h1_character(), + text, + ) + } } } @@ -300,6 +312,49 @@ impl Settings { fn h2_character(&self) -> Option<&str> { self.characters.as_ref()?.h2.as_deref() } + + fn get_h1_color(&self) -> &str { + self.h1_color().unwrap_or("#9932CC") + } + + fn h1_color(&self) -> Option<&str> { + self.colors.as_ref()?.h1.as_deref() + } + + fn get_gemini_h1_font_size(&self) -> i32 { + match self.gemini_h1_font_size() { + Some(size) => size * pango_sys::PANGO_SCALE, + None => DEFAULT_H1_FONT_SIZE, + } + } + + fn get_gemini_h1_font_family(&self) -> &str { + self.gemini_h1_font_family().unwrap_or(DEFAULT_FONT) + } + + fn get_gemini_h1_font_style(&self) -> &str { + self.gemini_h1_font_style().unwrap_or(DEFAULT_FONT_STYLE) + } + + fn gemini_h1_font_family(&self) -> Option<&str> { + self.fonts.as_ref()?.gemini.as_ref()?.h1.as_ref()?.family.as_deref() + } + + fn gemini_h1_font_size(&self) -> Option<i32> { + self.fonts.as_ref()?.gemini.as_ref()?.h1.as_ref()?.size + } + + fn gemini_h1_font_style(&self) -> Option<&str> { + self.fonts.as_ref()?.gemini.as_ref()?.h1.as_ref()?.style.as_deref() + } + + fn get_h1_character(&self) -> &str { + self.h1_character().unwrap_or("") + } + + fn h1_character(&self) -> Option<&str> { + self.characters.as_ref()?.h1.as_deref() + } } #[derive(Deserialize)] @@ -397,39 +452,6 @@ pub fn get_gemini_text_font_size() -> i32 { } } -fn gemini_h1_font_family() -> Option<String> { - read().fonts?.gemini?.h1?.family -} - -fn gemini_h1_font_size() -> Option<i32> { - read().fonts?.gemini?.h1?.size -} - -fn gemini_h1_font_style() -> Option<String> { - read().fonts?.gemini?.h1?.style -} - -pub fn get_gemini_h1_font_size() -> i32 { - match gemini_h1_font_size() { - Some(size) => size * pango_sys::PANGO_SCALE, - None => DEFAULT_H1_FONT_SIZE, - } -} - -pub fn get_gemini_h1_font_family() -> String { - match gemini_h1_font_family() { - Some(family) => family, - None => String::from(DEFAULT_FONT), - } -} - -pub fn get_gemini_h1_font_style() -> String { - match gemini_h1_font_style() { - Some(style) => style, - None => String::from(DEFAULT_FONT_STYLE), - } -} - fn gopher_font_family() -> Option<String> { read().fonts?.gopher?.family } @@ -452,17 +474,6 @@ pub fn get_gopher_font_size() -> i32 { } } -fn h1_color() -> Option<String> { - read().colors?.h1 -} - -pub fn get_h1_color() -> String { - match h1_color() { - Some(color) => color, - None => String::from("#9932CC"), - } -} - fn text_color() -> Option<String> { read().colors?.text } @@ -474,17 +485,6 @@ pub fn get_text_color() -> String { } } -fn h1_character() -> Option<String> { - read().characters?.h1 -} - -pub fn get_h1_character() -> String { - match h1_character() { - Some(char) => char, - None => String::new(), - } -} - pub fn read() -> Settings { let mut file = settings_file(); let mut content = String::new(); -- 2.20.1
This fills in the "monospace" spans. One of them specified the size and the other used the default. Collapse them to both specify the size so the user can configure all monospace text at once. --- src/draw.rs | 46 +++++++++++++++++++--------------------------- src/settings.rs | 22 ++++++++++------------ 2 files changed, 29 insertions(+), 39 deletions(-) diff --git a/src/draw.rs b/src/draw.rs index 4c800db..0b8292a 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -36,7 +36,8 @@ pub fn gemini_content( Ok(crate::gemini::parser::TextElement::H1(header)) => { let mut end_iter = buffer.get_end_iter(); if mono_toggle { - buffer.insert_markup(&mut end_iter, &mono_span(escape_text(&header))); + let markup = config.format_markup(settings::LineType::Preformatted, &escape_text(&header)); + buffer.insert_markup(&mut end_iter, &markup); } else { let markup = config.format_markup(settings::LineType::H1, &escape_text(&header)); buffer.insert_markup(&mut end_iter, &markup); @@ -45,16 +46,18 @@ pub fn gemini_content( Ok(crate::gemini::parser::TextElement::H2(header)) => { let mut end_iter = buffer.get_end_iter(); if mono_toggle { - buffer.insert_markup(&mut end_iter, &mono_span(escape_text(&header))); - } else { - let markup = config.format_markup(settings::LineType::H2, &escape_text(&header)); - buffer.insert_markup(&mut end_iter, &markup); + let markup = config.format_markup(settings::LineType::Preformatted, &escape_text(&header)); + buffer.insert_markup(&mut end_iter, &markup); + } else { + let markup = config.format_markup(settings::LineType::H2, &escape_text(&header)); + buffer.insert_markup(&mut end_iter, &markup); } } Ok(crate::gemini::parser::TextElement::H3(header)) => { let mut end_iter = buffer.get_end_iter(); if mono_toggle { - buffer.insert_markup(&mut end_iter, &mono_span(escape_text(&header))); + let markup = config.format_markup(settings::LineType::Preformatted, &escape_text(&header)); + buffer.insert_markup(&mut end_iter, &markup); } else { let markup = config.format_markup(settings::LineType::H3, &escape_text(&header)); buffer.insert_markup(&mut end_iter, &markup); @@ -63,7 +66,8 @@ pub fn gemini_content( Ok(crate::gemini::parser::TextElement::ListItem(item)) => { let mut end_iter = buffer.get_end_iter(); if mono_toggle { - buffer.insert_markup(&mut end_iter, &mono_span(item)); + let markup = config.format_markup(settings::LineType::Preformatted, &item); + buffer.insert_markup(&mut end_iter, &markup); } else { let markup = config.format_markup(settings::LineType::ListItem, &wrap_text(&item, &gui, &config)); buffer.insert_markup(&mut end_iter, &markup); @@ -72,7 +76,8 @@ pub fn gemini_content( Ok(crate::gemini::parser::TextElement::Quote(text)) => { let mut end_iter = buffer.get_end_iter(); if mono_toggle { - buffer.insert_markup(&mut end_iter, &mono_span(text)); + let markup = config.format_markup(settings::LineType::Preformatted, &text); + buffer.insert_markup(&mut end_iter, &markup); } else { let markup = config.format_markup(settings::LineType::Quote, &wrap_text(&text, &gui, &config)); buffer.insert_markup(&mut end_iter, &markup); @@ -81,7 +86,8 @@ pub fn gemini_content( Ok(crate::gemini::parser::TextElement::Text(text)) => { let mut end_iter = buffer.get_end_iter(); if mono_toggle { - buffer.insert_markup(&mut end_iter, &mono_span(colors::colorize(&text))); + let markup = config.format_markup(settings::LineType::Preformatted, &colors::colorize(&text)); + buffer.insert_markup(&mut end_iter, &markup); } else { let markup = config.format_markup(settings::LineType::Text, &wrap_text(&text, &gui, &config)); buffer.insert_markup(&mut end_iter, &markup); @@ -90,7 +96,8 @@ pub fn gemini_content( Ok(crate::gemini::parser::TextElement::LinkItem(link_item)) => { if mono_toggle { let mut end_iter = buffer.get_end_iter(); - buffer.insert_markup(&mut end_iter, &mono_span(escape_text(&link_item))); + let markup = config.format_markup(settings::LineType::Preformatted, &escape_text(&link_item)); + buffer.insert_markup(&mut end_iter, &markup); } else { gemini_link(&gui, &config, link_item); } @@ -107,14 +114,8 @@ pub fn gemini_text_content(gui: &Arc<Gui>, config: &Arc<settings::Settings>, con for line in content { let mut end_iter = buffer.get_end_iter(); - buffer.insert_markup( - &mut end_iter, - &format!( - "<span foreground=\"{}\" font_family=\"monospace\">{}</span>\n", - crate::settings::get_text_color(), - colors::colorize(&line) - ), - ); + let markup = config.format_markup(settings::LineType::Preformatted, &colors::colorize(&line)); + buffer.insert_markup(&mut end_iter, &markup); } buffer } @@ -419,15 +420,6 @@ fn escape_text(str: &str) -> String { String::from(glib::markup_escape_text(&str).as_str()) } -fn mono_span(text: String) -> String { - format!( - "<span foreground=\"{}\" font_family=\"monospace\" size=\"{}\">{}</span>\n", - crate::settings::get_text_color(), - crate::settings::get_gemini_text_font_size(), - text - ) -} - fn width(gui: &Arc<Gui>, config: &Arc<settings::Settings>) -> usize { let (win_width, _) = gtk::ApplicationWindow::get_size(gui.window()); let calculated_width = (win_width / 10).try_into().unwrap(); diff --git a/src/settings.rs b/src/settings.rs index e97e667..18c99d7 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -14,6 +14,7 @@ pub enum LineType { H3, H2, H1, + Preformatted, } #[derive(Deserialize)] @@ -104,7 +105,15 @@ impl Settings { self.get_h1_character(), text, ) - } + }, + LineType::Preformatted => { + format!( + "<span foreground=\"{}\" font_family=\"monospace\" size=\"{}\">{}</span>\n", + self.get_text_color(), + self.get_gemini_text_font_size(), + text, + ) + }, } } @@ -441,17 +450,6 @@ pub fn get_finger_font_size() -> i32 { } } -fn gemini_text_font_size() -> Option<i32> { - read().fonts?.gemini?.text?.size -} - -pub fn get_gemini_text_font_size() -> i32 { - match gemini_text_font_size() { - Some(size) => size * pango_sys::PANGO_SCALE, - None => DEFAULT_FONT_SIZE, - } -} - fn gopher_font_family() -> Option<String> { read().fonts?.gopher?.family } -- 2.20.1
--- src/draw.rs | 24 ++-------- src/settings.rs | 113 +++++++++++++++++++++++++----------------------- 2 files changed, 62 insertions(+), 75 deletions(-) diff --git a/src/draw.rs b/src/draw.rs index 0b8292a..c543fb6 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -133,17 +133,9 @@ pub fn gopher_content( Ok(crate::gopher::parser::TextElement::Text(text)) => { let mut end_iter = buffer.get_end_iter(); let text = colors::colorize(&text); + let markup = config.format_markup(settings::LineType::Gopher, &text); - buffer.insert_markup( - &mut end_iter, - &format!( - "<span foreground=\"{}\" font_family=\"{}\" size=\"{}\">{}</span>\n", - crate::settings::get_text_color(), - crate::settings::get_gopher_font_family(), - crate::settings::get_gopher_font_size(), - text - ), - ); + buffer.insert_markup(&mut end_iter, &markup); } Ok(crate::gopher::parser::TextElement::LinkItem(link_item)) => { gopher_link(&gui, &config, colors::cleanup(&link_item)); @@ -175,17 +167,9 @@ pub fn finger_content( match el { Ok(crate::finger::parser::TextElement::Text(text)) => { let mut end_iter = buffer.get_end_iter(); + let markup = config.format_markup(settings::LineType::Finger, &escape_text(&text)); - buffer.insert_markup( - &mut end_iter, - &format!( - "<span foreground=\"{}\" font_family=\"{}\" size=\"{}\">{}</span>\n", - crate::settings::get_text_color(), - crate::settings::get_finger_font_family(), - crate::settings::get_finger_font_size(), - escape_text(&text) - ), - ); + buffer.insert_markup(&mut end_iter, &markup); } Err(_) => println!("Something failed."), } diff --git a/src/settings.rs b/src/settings.rs index 18c99d7..d785324 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -15,6 +15,8 @@ pub enum LineType { H2, H1, Preformatted, + Gopher, + Finger, } #[derive(Deserialize)] @@ -114,6 +116,24 @@ impl Settings { text, ) }, + LineType::Gopher => { + format!( + "<span foreground=\"{}\" font_family=\"{}\" size=\"{}\">{}</span>\n", + self.get_text_color(), + self.get_gopher_font_family(), + self.get_gopher_font_size(), + text + ) + }, + LineType::Finger => { + format!( + "<span foreground=\"{}\" font_family=\"{}\" size=\"{}\">{}</span>\n", + self.get_text_color(), + self.get_finger_font_family(), + self.get_finger_font_size(), + text, + ) + }, } } @@ -364,6 +384,44 @@ impl Settings { fn h1_character(&self) -> Option<&str> { self.characters.as_ref()?.h1.as_deref() } + + fn get_gopher_font_family(&self) -> &str { + self.gopher_font_family().unwrap_or(DEFAULT_FONT) + } + + fn get_gopher_font_size(&self) -> i32 { + match self.gopher_font_size() { + Some(size) => size * pango_sys::PANGO_SCALE, + None => DEFAULT_FONT_SIZE, + } + } + + fn gopher_font_family(&self) -> Option<&str> { + self.fonts.as_ref()?.gopher.as_ref()?.family.as_deref() + } + + fn gopher_font_size(&self) -> Option<i32> { + self.fonts.as_ref()?.gopher.as_ref()?.size + } + + fn get_finger_font_family(&self) -> &str { + self.finger_font_family().unwrap_or(DEFAULT_FONT) + } + + fn get_finger_font_size(&self) -> i32 { + match self.finger_font_size() { + Some(size) => size * pango_sys::PANGO_SCALE, + None => DEFAULT_FONT_SIZE, + } + } + + fn finger_font_family(&self) -> Option<&str> { + self.fonts.as_ref()?.finger.as_ref()?.family.as_deref() + } + + fn finger_font_size(&self) -> Option<i32> { + self.fonts.as_ref()?.finger.as_ref()?.size + } } #[derive(Deserialize)] @@ -428,61 +486,6 @@ const DEFAULT_H1_FONT_SIZE: i32 = 16 * pango_sys::PANGO_SCALE; const DEFAULT_H2_FONT_SIZE: i32 = 13 * pango_sys::PANGO_SCALE; const DEFAULT_H3_FONT_SIZE: i32 = 12 * pango_sys::PANGO_SCALE; -fn finger_font_family() -> Option<String> { - read().fonts?.finger?.family -} - -fn finger_font_size() -> Option<i32> { - read().fonts?.finger?.size.or(Some(DEFAULT_FONT_SIZE)) -} - -pub fn get_finger_font_family() -> String { - match finger_font_family() { - Some(family) => family, - None => String::from(DEFAULT_FONT), - } -} - -pub fn get_finger_font_size() -> i32 { - match finger_font_size() { - Some(size) => size * pango_sys::PANGO_SCALE, - None => DEFAULT_FONT_SIZE, - } -} - -fn gopher_font_family() -> Option<String> { - read().fonts?.gopher?.family -} - -fn gopher_font_size() -> Option<i32> { - read().fonts?.gopher?.size -} - -pub fn get_gopher_font_family() -> String { - match gopher_font_family() { - Some(family) => family, - None => String::from(DEFAULT_FONT), - } -} - -pub fn get_gopher_font_size() -> i32 { - match gopher_font_size() { - Some(size) => size * pango_sys::PANGO_SCALE, - None => DEFAULT_FONT_SIZE, - } -} - -fn text_color() -> Option<String> { - read().colors?.text -} - -pub fn get_text_color() -> String { - match text_color() { - Some(color) => color, - None => String::from("black"), - } -} - pub fn read() -> Settings { let mut file = settings_file(); let mut content = String::new(); -- 2.20.1
The boring part is that I moved some lines up (or down, depending on your perspective). More interestingly, use `Option` methods to simplify the match statements. Most interestingly, make `settings::read()` return a `std::io::Result<Settings>`, use `?` in it and in `settings_file`, and have `main` return a `std::io::Result<()>`. --- src/main.rs | 6 +- src/settings.rs | 251 ++++++++++++++++++++++-------------------------- 2 files changed, 119 insertions(+), 138 deletions(-) diff --git a/src/main.rs b/src/main.rs index 1a22ad9..c2dd7b2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,9 +31,9 @@ mod settings; mod status; use status::Status; -fn main() { +fn main() -> std::io::Result<()> { // Read in settings - let config = Arc::new(settings::read()); + let config = Arc::new(settings::read()?); // Start up the GTK3 subsystem. gtk::init().expect("Unable to start GTK3. Error"); @@ -143,6 +143,8 @@ fn main() { gui.start(); gtk::main(); + + Ok(()) } fn route_url(gui: &Arc<Gui>, config: &Arc<settings::Settings>, url: &str) { diff --git a/src/settings.rs b/src/settings.rs index d785324..ca06308 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -27,19 +27,100 @@ pub struct Settings { fonts: Option<Font>, } +#[derive(Deserialize)] +struct General { + start_url: Option<String>, + max_width: Option<usize>, +} + +#[derive(Deserialize)] +struct Color { + h1: Option<String>, + h2: Option<String>, + h3: Option<String>, + list: Option<String>, + text: Option<String>, + background: Option<String>, + quote: Option<QuoteColor>, +} + +#[derive(Deserialize)] +struct Character { + h1: Option<String>, + h2: Option<String>, + h3: Option<String>, + list: Option<String>, +} + +#[derive(Debug, Deserialize)] +struct Font { + finger: Option<FontAttr>, + gemini: Option<GeminiFontAttr>, + gopher: Option<FontAttr>, +} + +#[derive(Debug, Deserialize)] +struct FontAttr { + family: Option<String>, + style: Option<String>, + size: Option<i32>, +} + +#[derive(Debug, Deserialize)] +struct GeminiFontAttr { + text: Option<FontAttr>, + h1: Option<FontAttr>, + h2: Option<FontAttr>, + h3: Option<FontAttr>, + list: Option<FontAttr>, + quote: Option<FontAttr>, +} + +#[derive(Debug, Deserialize)] +struct QuoteColor { + foreground: Option<String>, + background: Option<String>, +} + +const DEFAULT_FONT: &str = "serif"; +const DEFAULT_FONT_STYLE: &str = "normal"; +const DEFAULT_FONT_SIZE: i32 = 11 * pango_sys::PANGO_SCALE; +const DEFAULT_H1_FONT_SIZE: i32 = 16 * pango_sys::PANGO_SCALE; +const DEFAULT_H2_FONT_SIZE: i32 = 13 * pango_sys::PANGO_SCALE; +const DEFAULT_H3_FONT_SIZE: i32 = 12 * pango_sys::PANGO_SCALE; + +pub fn read() -> std::io::Result<Settings> { + let mut file = settings_file()?; + let mut content = String::new(); + file.read_to_string(&mut content)?; + + let settings: Settings = toml::from_str(&content)?; + Ok(settings) +} + +fn settings_file() -> std::io::Result<File> { + let mut settings = dirs::config_dir() + .ok_or(std::io::Error::new(std::io::ErrorKind::NotFound, "no XDG config dir"))?; + settings.push("castor"); + fs::create_dir_all(&settings)?; + settings.push("settings.toml"); + let file_path = settings.into_os_string(); + let file = OpenOptions::new() + .create(true) + .append(true) + .read(true) + .open(file_path)?; + + Ok(file) +} + impl Settings { pub fn start_url(&self) -> Option<&str> { - match &self.general { - Some(general) => general.start_url.as_deref(), - None => None, - } + self.general.as_ref().and_then(|general| general.start_url.as_deref()) } pub fn background_color(&self) -> Option<&str> { - match &self.colors { - Some(colors) => colors.background.as_deref(), - None => None, - } + self.colors.as_ref().and_then(|colors| colors.background.as_deref()) } pub fn format_markup(&self, line_type: LineType, text: &str) -> String { @@ -138,10 +219,7 @@ impl Settings { } pub fn max_width(&self) -> Option<usize> { - match &self.general { - Some(general) => general.max_width, - None => None, - } + self.general.as_ref().and_then(|general| general.max_width) } fn get_gemini_text_font_family(&self) -> &str { @@ -169,10 +247,9 @@ impl Settings { } fn get_gemini_text_font_size(&self) -> i32 { - match &self.gemini_text_font_size() { - Some(size) => size * pango_sys::PANGO_SCALE, - None => DEFAULT_FONT_SIZE, - } + self.gemini_text_font_size(). + map(|size| size * pango_sys::PANGO_SCALE). + unwrap_or(DEFAULT_FONT_SIZE) } fn gemini_text_font_size(&self) -> Option<i32> { @@ -180,10 +257,9 @@ impl Settings { } fn get_gemini_quote_font_size(&self) -> i32 { - match &self.gemini_quote_font_size() { - Some(size) => size * pango_sys::PANGO_SCALE, - None => DEFAULT_FONT_SIZE, - } + self.gemini_quote_font_size(). + map(|size| size * pango_sys::PANGO_SCALE). + unwrap_or(DEFAULT_FONT_SIZE) } fn gemini_quote_font_size(&self) -> Option<i32> { @@ -203,10 +279,7 @@ impl Settings { } fn get_gemini_quote_font_style(&self) -> &str { - match self.gemini_quote_font_style() { - Some(style) => style, - None => "italic", - } + self.gemini_quote_font_style().unwrap_or("italic") } fn gemini_quote_font_style(&self) -> Option<&str> { @@ -222,10 +295,9 @@ impl Settings { } fn get_gemini_list_font_size(&self) -> i32 { - match self.gemini_list_font_size() { - Some(size) => size * pango_sys::PANGO_SCALE, - None => DEFAULT_FONT_SIZE, - } + self.gemini_list_font_size(). + map(|size| size * pango_sys::PANGO_SCALE). + unwrap_or(DEFAULT_FONT_SIZE) } fn get_gemini_list_font_family(&self) -> &str { @@ -265,10 +337,9 @@ impl Settings { } fn get_gemini_h3_font_size(&self) -> i32 { - match self.gemini_h3_font_size() { - Some(size) => size * pango_sys::PANGO_SCALE, - None => DEFAULT_H3_FONT_SIZE, - } + self.gemini_h3_font_size(). + map(|size| size * pango_sys::PANGO_SCALE). + unwrap_or(DEFAULT_H3_FONT_SIZE) } fn get_gemini_h3_font_family(&self) -> &str { @@ -308,10 +379,9 @@ impl Settings { } fn get_gemini_h2_font_size(&self) -> i32 { - match self.gemini_h2_font_size() { - Some(size) => size * pango_sys::PANGO_SCALE, - None => DEFAULT_H2_FONT_SIZE, - } + self.gemini_h2_font_size(). + map(|size| size * pango_sys::PANGO_SCALE). + unwrap_or(DEFAULT_H2_FONT_SIZE) } fn get_gemini_h2_font_family(&self) -> &str { @@ -351,10 +421,9 @@ impl Settings { } fn get_gemini_h1_font_size(&self) -> i32 { - match self.gemini_h1_font_size() { - Some(size) => size * pango_sys::PANGO_SCALE, - None => DEFAULT_H1_FONT_SIZE, - } + self.gemini_h1_font_size(). + map(|size| size * pango_sys::PANGO_SCALE). + unwrap_or(DEFAULT_H1_FONT_SIZE) } fn get_gemini_h1_font_family(&self) -> &str { @@ -390,10 +459,9 @@ impl Settings { } fn get_gopher_font_size(&self) -> i32 { - match self.gopher_font_size() { - Some(size) => size * pango_sys::PANGO_SCALE, - None => DEFAULT_FONT_SIZE, - } + self.gopher_font_size(). + map(|size| size * pango_sys::PANGO_SCALE). + unwrap_or(DEFAULT_FONT_SIZE) } fn gopher_font_family(&self) -> Option<&str> { @@ -409,10 +477,9 @@ impl Settings { } fn get_finger_font_size(&self) -> i32 { - match self.finger_font_size() { - Some(size) => size * pango_sys::PANGO_SCALE, - None => DEFAULT_FONT_SIZE, - } + self.finger_font_size(). + map(|size| size * pango_sys::PANGO_SCALE). + unwrap_or(DEFAULT_FONT_SIZE) } fn finger_font_family(&self) -> Option<&str> { @@ -423,91 +490,3 @@ impl Settings { self.fonts.as_ref()?.finger.as_ref()?.size } } - -#[derive(Deserialize)] -struct General { - start_url: Option<String>, - max_width: Option<usize>, -} - -#[derive(Deserialize)] -struct Color { - h1: Option<String>, - h2: Option<String>, - h3: Option<String>, - list: Option<String>, - text: Option<String>, - background: Option<String>, - quote: Option<QuoteColor>, -} - -#[derive(Deserialize)] -struct Character { - h1: Option<String>, - h2: Option<String>, - h3: Option<String>, - list: Option<String>, -} - -#[derive(Debug, Deserialize)] -struct Font { - finger: Option<FontAttr>, - gemini: Option<GeminiFontAttr>, - gopher: Option<FontAttr>, -} - -#[derive(Debug, Deserialize)] -struct FontAttr { - family: Option<String>, - style: Option<String>, - size: Option<i32>, -} - -#[derive(Debug, Deserialize)] -struct GeminiFontAttr { - text: Option<FontAttr>, - h1: Option<FontAttr>, - h2: Option<FontAttr>, - h3: Option<FontAttr>, - list: Option<FontAttr>, - quote: Option<FontAttr>, -} - -#[derive(Debug, Deserialize)] -struct QuoteColor { - foreground: Option<String>, - background: Option<String>, -} - -const DEFAULT_FONT: &str = "serif"; -const DEFAULT_FONT_STYLE: &str = "normal"; -const DEFAULT_FONT_SIZE: i32 = 11 * pango_sys::PANGO_SCALE; -const DEFAULT_H1_FONT_SIZE: i32 = 16 * pango_sys::PANGO_SCALE; -const DEFAULT_H2_FONT_SIZE: i32 = 13 * pango_sys::PANGO_SCALE; -const DEFAULT_H3_FONT_SIZE: i32 = 12 * pango_sys::PANGO_SCALE; - -pub fn read() -> Settings { - let mut file = settings_file(); - let mut content = String::new(); - println!("reading from config"); - file.read_to_string(&mut content) - .expect("Unable to read file"); - - let settings: Settings = toml::from_str(&content).unwrap(); - settings -} - -fn settings_file() -> File { - let mut settings = dirs::config_dir().unwrap(); - settings.push("castor"); - fs::create_dir_all(&settings).unwrap(); - settings.push("settings.toml"); - let file_path = settings.into_os_string(); - - OpenOptions::new() - .create(true) - .append(true) - .read(true) - .open(file_path) - .expect("file not found") -} -- 2.20.1