logging: Try to improve common operations
This adds sugar for logging `Result`s with a handler, makes names evoke something closer to "logging" than "warning", tries to remove any redundant `Logging` where the module name will do, and introduces a type strictly for bad things happening.
This commit is contained in:
		
							
								
								
									
										96
									
								
								src/data.rs
									
									
									
									
									
								
							
							
						
						
									
										96
									
								
								src/data.rs
									
									
									
									
									
								
							@ -21,7 +21,7 @@ use ::keyboard::{
 | 
			
		||||
};
 | 
			
		||||
use ::layout;
 | 
			
		||||
use ::layout::ArrangementKind;
 | 
			
		||||
use ::logging::PrintWarnings;
 | 
			
		||||
use ::logging;
 | 
			
		||||
use ::resources;
 | 
			
		||||
use ::util::c::as_str;
 | 
			
		||||
use ::util::hash_map_map;
 | 
			
		||||
@ -31,7 +31,7 @@ use ::xdg;
 | 
			
		||||
use serde::Deserialize;
 | 
			
		||||
use std::io::BufReader;
 | 
			
		||||
use std::iter::FromIterator;
 | 
			
		||||
use ::logging::WarningHandler;
 | 
			
		||||
use ::logging::Warn;
 | 
			
		||||
 | 
			
		||||
/// Gathers stuff defined in C or called by C
 | 
			
		||||
pub mod c {
 | 
			
		||||
@ -157,7 +157,7 @@ fn list_layout_sources(
 | 
			
		||||
fn load_layout_data(source: DataSource)
 | 
			
		||||
    -> Result<::layout::LayoutData, LoadError>
 | 
			
		||||
{
 | 
			
		||||
    let handler = PrintWarnings{};
 | 
			
		||||
    let handler = logging::Print {};
 | 
			
		||||
    match source {
 | 
			
		||||
        DataSource::File(path) => {
 | 
			
		||||
            Layout::from_file(path.clone())
 | 
			
		||||
@ -330,7 +330,7 @@ impl Layout {
 | 
			
		||||
        serde_yaml::from_reader(infile).map_err(Error::Yaml)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn build<H: WarningHandler>(self, mut warning_handler: H)
 | 
			
		||||
    pub fn build<H: logging::Handler>(self, mut warning_handler: H)
 | 
			
		||||
        -> (Result<::layout::LayoutData, FormattingError>, H)
 | 
			
		||||
    {
 | 
			
		||||
        let button_names = self.views.values()
 | 
			
		||||
@ -464,7 +464,7 @@ impl Layout {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn create_action<H: WarningHandler>(
 | 
			
		||||
fn create_action<H: logging::Handler>(
 | 
			
		||||
    button_info: &HashMap<String, ButtonMeta>,
 | 
			
		||||
    name: &str,
 | 
			
		||||
    view_names: Vec<&String>,
 | 
			
		||||
@ -494,15 +494,18 @@ fn create_action<H: WarningHandler>(
 | 
			
		||||
        (None, None, Some(text)) => SubmitData::Text(text.clone()),
 | 
			
		||||
        (None, None, None) => SubmitData::Text(name.into()),
 | 
			
		||||
        _ => {
 | 
			
		||||
            warning_handler.handle(&format!(
 | 
			
		||||
            warning_handler.handle(
 | 
			
		||||
                logging::Level::Warning,
 | 
			
		||||
                &format!(
 | 
			
		||||
                    "Button {} has more than one of (action, keysym, text)",
 | 
			
		||||
                name
 | 
			
		||||
            ));
 | 
			
		||||
                    name,
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
            SubmitData::Text("".into())
 | 
			
		||||
        },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    fn filter_view_name<H: WarningHandler>(
 | 
			
		||||
    fn filter_view_name<H: logging::Handler>(
 | 
			
		||||
        button_name: &str,
 | 
			
		||||
        view_name: String,
 | 
			
		||||
        view_names: &Vec<&String>,
 | 
			
		||||
@ -511,10 +514,13 @@ fn create_action<H: WarningHandler>(
 | 
			
		||||
        if view_names.contains(&&view_name) {
 | 
			
		||||
            view_name
 | 
			
		||||
        } else {
 | 
			
		||||
            warning_handler.handle(&format!("Button {} switches to missing view {}",
 | 
			
		||||
            warning_handler.handle(
 | 
			
		||||
                logging::Level::Warning,
 | 
			
		||||
                &format!("Button {} switches to missing view {}",
 | 
			
		||||
                    button_name,
 | 
			
		||||
                    view_name,
 | 
			
		||||
            ));
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
            "base".into()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -553,27 +559,24 @@ fn create_action<H: WarningHandler>(
 | 
			
		||||
                match keysym_valid(keysym.as_str()) {
 | 
			
		||||
                    true => keysym.clone(),
 | 
			
		||||
                    false => {
 | 
			
		||||
                        warning_handler.handle(&format!(
 | 
			
		||||
                        warning_handler.handle(
 | 
			
		||||
                            logging::Level::Warning,
 | 
			
		||||
                            &format!(
 | 
			
		||||
                                "Keysym name invalid: {}",
 | 
			
		||||
                                keysym,
 | 
			
		||||
                        ));
 | 
			
		||||
                            ),
 | 
			
		||||
                        );
 | 
			
		||||
                        "space".into() // placeholder
 | 
			
		||||
                    },
 | 
			
		||||
                }
 | 
			
		||||
            )),
 | 
			
		||||
        },
 | 
			
		||||
        SubmitData::Text(text) => ::action::Action::Submit {
 | 
			
		||||
            text: {
 | 
			
		||||
                CString::new(text.clone())
 | 
			
		||||
                    .map_err(|e| {
 | 
			
		||||
                        warning_handler.handle(&format!(
 | 
			
		||||
                            "Text {} contains problems: {:?}",
 | 
			
		||||
                            text,
 | 
			
		||||
                            e
 | 
			
		||||
                        ));
 | 
			
		||||
                        e
 | 
			
		||||
                    }).ok()
 | 
			
		||||
            },
 | 
			
		||||
            text: CString::new(text.clone()).or_warn(
 | 
			
		||||
                warning_handler,
 | 
			
		||||
                logging::Problem::Warning,
 | 
			
		||||
                &format!("Text {} contains problems", text),
 | 
			
		||||
            ),
 | 
			
		||||
            keys: text.chars().map(|codepoint| {
 | 
			
		||||
                let codepoint_string = codepoint.to_string();
 | 
			
		||||
                ::action::KeySym(match keysym_valid(codepoint_string.as_str()) {
 | 
			
		||||
@ -587,7 +590,7 @@ fn create_action<H: WarningHandler>(
 | 
			
		||||
 | 
			
		||||
/// TODO: Since this will receive user-provided data,
 | 
			
		||||
/// all .expect() on them should be turned into soft fails
 | 
			
		||||
fn create_button<H: WarningHandler>(
 | 
			
		||||
fn create_button<H: logging::Handler>(
 | 
			
		||||
    button_info: &HashMap<String, ButtonMeta>,
 | 
			
		||||
    outlines: &HashMap<String, Outline>,
 | 
			
		||||
    name: &str,
 | 
			
		||||
@ -611,14 +614,11 @@ fn create_button<H: WarningHandler>(
 | 
			
		||||
    } else if let Some(text) = &button_meta.text {
 | 
			
		||||
        ::layout::Label::Text(
 | 
			
		||||
            CString::new(text.as_str())
 | 
			
		||||
                .unwrap_or_else(|e| {
 | 
			
		||||
                    warning_handler.handle(&format!(
 | 
			
		||||
                        "Text {} is invalid: {}",
 | 
			
		||||
                        text,
 | 
			
		||||
                        e,
 | 
			
		||||
                    ));
 | 
			
		||||
                    CString::new("").unwrap()
 | 
			
		||||
                })
 | 
			
		||||
                .or_warn(
 | 
			
		||||
                    warning_handler,
 | 
			
		||||
                    logging::Problem::Warning,
 | 
			
		||||
                    &format!("Text {} is invalid", text),
 | 
			
		||||
                ).unwrap_or_else(|| CString::new("").unwrap())
 | 
			
		||||
        )
 | 
			
		||||
    } else {
 | 
			
		||||
        ::layout::Label::Text(cname.clone())
 | 
			
		||||
@ -629,7 +629,10 @@ fn create_button<H: WarningHandler>(
 | 
			
		||||
            if outlines.contains_key(outline) {
 | 
			
		||||
                outline.clone()
 | 
			
		||||
            } else {
 | 
			
		||||
                warning_handler.handle(&format!("Outline named {} does not exist! Using default for button {}", outline, name));
 | 
			
		||||
                warning_handler.handle(
 | 
			
		||||
                    logging::Level::Warning,
 | 
			
		||||
                    &format!("Outline named {} does not exist! Using default for button {}", outline, name)
 | 
			
		||||
                );
 | 
			
		||||
                "default".into()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -638,12 +641,11 @@ fn create_button<H: WarningHandler>(
 | 
			
		||||
 | 
			
		||||
    let outline = outlines.get(&outline_name)
 | 
			
		||||
        .map(|outline| (*outline).clone())
 | 
			
		||||
        .unwrap_or_else(|| {
 | 
			
		||||
            warning_handler.handle(
 | 
			
		||||
                &format!("No default outline defined! Using 1x1!")
 | 
			
		||||
            );
 | 
			
		||||
            Outline { width: 1f64, height: 1f64 }
 | 
			
		||||
        });
 | 
			
		||||
        .or_warn(
 | 
			
		||||
            warning_handler,
 | 
			
		||||
            logging::Problem::Warning,
 | 
			
		||||
            "No default outline defined! Using 1x1!",
 | 
			
		||||
        ).unwrap_or(Outline { width: 1f64, height: 1f64 });
 | 
			
		||||
 | 
			
		||||
    layout::Button {
 | 
			
		||||
        name: cname,
 | 
			
		||||
@ -663,7 +665,7 @@ mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    
 | 
			
		||||
    use std::error::Error as ErrorTrait;
 | 
			
		||||
    use ::logging::PanicWarn;
 | 
			
		||||
    use ::logging::ProblemPanic;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_parse_path() {
 | 
			
		||||
@ -733,7 +735,7 @@ mod tests {
 | 
			
		||||
    fn test_layout_punctuation() {
 | 
			
		||||
        let out = Layout::from_file(PathBuf::from("tests/layout_key1.yaml"))
 | 
			
		||||
            .unwrap()
 | 
			
		||||
            .build(PanicWarn).0
 | 
			
		||||
            .build(ProblemPanic).0
 | 
			
		||||
            .unwrap();
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            out.views["base"]
 | 
			
		||||
@ -748,7 +750,7 @@ mod tests {
 | 
			
		||||
    fn test_layout_unicode() {
 | 
			
		||||
        let out = Layout::from_file(PathBuf::from("tests/layout_key2.yaml"))
 | 
			
		||||
            .unwrap()
 | 
			
		||||
            .build(PanicWarn).0
 | 
			
		||||
            .build(ProblemPanic).0
 | 
			
		||||
            .unwrap();
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            out.views["base"]
 | 
			
		||||
@ -764,7 +766,7 @@ mod tests {
 | 
			
		||||
    fn test_layout_unicode_multi() {
 | 
			
		||||
        let out = Layout::from_file(PathBuf::from("tests/layout_key3.yaml"))
 | 
			
		||||
            .unwrap()
 | 
			
		||||
            .build(PanicWarn).0
 | 
			
		||||
            .build(ProblemPanic).0
 | 
			
		||||
            .unwrap();
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            out.views["base"]
 | 
			
		||||
@ -779,7 +781,7 @@ mod tests {
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn parsing_fallback() {
 | 
			
		||||
        assert!(Layout::from_resource(FALLBACK_LAYOUT_NAME)
 | 
			
		||||
            .map(|layout| layout.build(PanicWarn).0.unwrap())
 | 
			
		||||
            .map(|layout| layout.build(ProblemPanic).0.unwrap())
 | 
			
		||||
            .is_ok()
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
@ -827,7 +829,7 @@ mod tests {
 | 
			
		||||
                },
 | 
			
		||||
                ".",
 | 
			
		||||
                Vec::new(),
 | 
			
		||||
                &mut PanicWarn,
 | 
			
		||||
                &mut ProblemPanic,
 | 
			
		||||
            ),
 | 
			
		||||
            ::action::Action::Submit {
 | 
			
		||||
                text: Some(CString::new(".").unwrap()),
 | 
			
		||||
@ -840,7 +842,7 @@ mod tests {
 | 
			
		||||
    fn test_layout_margins() {
 | 
			
		||||
        let out = Layout::from_file(PathBuf::from("tests/layout_margins.yaml"))
 | 
			
		||||
            .unwrap()
 | 
			
		||||
            .build(PanicWarn).0
 | 
			
		||||
            .build(ProblemPanic).0
 | 
			
		||||
            .unwrap();
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            out.margins,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										117
									
								
								src/logging.rs
									
									
									
									
									
								
							
							
						
						
									
										117
									
								
								src/logging.rs
									
									
									
									
									
								
							@ -26,13 +26,15 @@
 | 
			
		||||
 * 4. logging to an immutable destination type
 | 
			
		||||
 * 
 | 
			
		||||
 *   Same as above, except it can be parallelized.
 | 
			
		||||
 *   Logs being outputs, they get returned
 | 
			
		||||
 *   instead of being misleadingly passed back through arguments.
 | 
			
		||||
 *   It seems more difficult to pass the logger around,
 | 
			
		||||
 *   but this may be a solved problem from the area of functional programming.
 | 
			
		||||
 * 
 | 
			
		||||
 * This library generally aims at the approach in 3.
 | 
			
		||||
 * */
 | 
			
		||||
 | 
			
		||||
use std::error::Error;
 | 
			
		||||
use std::fmt::Display;
 | 
			
		||||
 | 
			
		||||
/// Levels are not in order.
 | 
			
		||||
pub enum Level {
 | 
			
		||||
@ -66,18 +68,72 @@ pub enum Level {
 | 
			
		||||
    Debug,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Sugar for logging errors in results.
 | 
			
		||||
/// Approach 2.
 | 
			
		||||
pub trait Warn {
 | 
			
		||||
    type Value;
 | 
			
		||||
    fn or_warn(self, msg: &str) -> Option<Self::Value>;
 | 
			
		||||
impl Level {
 | 
			
		||||
    fn as_str(&self) -> &'static str {
 | 
			
		||||
        match self {
 | 
			
		||||
            Level::Panic => "Panic",
 | 
			
		||||
            Level::Bug => "Bug",
 | 
			
		||||
            Level::Error => "Error",
 | 
			
		||||
            Level::Warning => "Warning",
 | 
			
		||||
            Level::Surprise => "Surprise",
 | 
			
		||||
            Level::Info => "Info",
 | 
			
		||||
            Level::Debug => "Debug",
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T, E: Error> Warn for Result<T, E> {
 | 
			
		||||
impl From<Problem> for Level {
 | 
			
		||||
    fn from(problem: Problem) -> Level {
 | 
			
		||||
        use self::Level::*;
 | 
			
		||||
        match problem {
 | 
			
		||||
            Problem::Panic => Panic,
 | 
			
		||||
            Problem::Bug => Bug,
 | 
			
		||||
            Problem::Error => Error,
 | 
			
		||||
            Problem::Warning => Warning,
 | 
			
		||||
            Problem::Surprise => Surprise,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Only levels which indicate problems
 | 
			
		||||
/// To use with `Result::Err` handlers,
 | 
			
		||||
/// which are needed only when something went off the optimal path.
 | 
			
		||||
/// A separate type ensures that `Err`
 | 
			
		||||
/// can't end up misclassified as a benign event like `Info`.
 | 
			
		||||
pub enum Problem {
 | 
			
		||||
    Panic,
 | 
			
		||||
    Bug,
 | 
			
		||||
    Error,
 | 
			
		||||
    Warning,
 | 
			
		||||
    Surprise,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Sugar for logging errors in results.
 | 
			
		||||
pub trait Warn where Self: Sized{
 | 
			
		||||
    type Value;
 | 
			
		||||
    /// Approach 2.
 | 
			
		||||
    fn or_print(self, level: Problem, message: &str) -> Option<Self::Value> {
 | 
			
		||||
        self.or_warn(&mut Print {}, level.into(), message)
 | 
			
		||||
    }
 | 
			
		||||
    /// Approach 3.
 | 
			
		||||
    fn or_warn<H: Handler>(
 | 
			
		||||
        self,
 | 
			
		||||
        handler: &mut H,
 | 
			
		||||
        level: Problem,
 | 
			
		||||
        message: &str,
 | 
			
		||||
    ) -> Option<Self::Value>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T, E: Display> Warn for Result<T, E> {
 | 
			
		||||
    type Value = T;
 | 
			
		||||
    fn or_warn(self, msg: &str) -> Option<T> {
 | 
			
		||||
    fn or_warn<H: Handler>(
 | 
			
		||||
        self,
 | 
			
		||||
        handler: &mut H,
 | 
			
		||||
        level: Problem,
 | 
			
		||||
        message: &str,
 | 
			
		||||
    ) -> Option<T> {
 | 
			
		||||
        self.map_err(|e| {
 | 
			
		||||
            eprintln!("{}: {}", msg, e);
 | 
			
		||||
            handler.handle(level.into(), &format!("{}: {}", message, e));
 | 
			
		||||
            e
 | 
			
		||||
        }).ok()
 | 
			
		||||
    }
 | 
			
		||||
@ -85,9 +141,14 @@ impl<T, E: Error> Warn for Result<T, E> {
 | 
			
		||||
 | 
			
		||||
impl<T> Warn for Option<T> {
 | 
			
		||||
    type Value = T;
 | 
			
		||||
    fn or_warn(self, msg: &str) -> Option<T> {
 | 
			
		||||
    fn or_warn<H: Handler>(
 | 
			
		||||
        self,
 | 
			
		||||
        handler: &mut H,
 | 
			
		||||
        level: Problem,
 | 
			
		||||
        message: &str,
 | 
			
		||||
    ) -> Option<T> {
 | 
			
		||||
        self.or_else(|| {
 | 
			
		||||
            eprintln!("{}", msg);
 | 
			
		||||
            handler.handle(level.into(), message);
 | 
			
		||||
            None
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
@ -95,26 +156,34 @@ impl<T> Warn for Option<T> {
 | 
			
		||||
 | 
			
		||||
/// A mutable handler for text warnings.
 | 
			
		||||
/// Approach 3.
 | 
			
		||||
pub trait WarningHandler {
 | 
			
		||||
    /// Handle a warning
 | 
			
		||||
    fn handle(&mut self, warning: &str);
 | 
			
		||||
pub trait Handler {
 | 
			
		||||
    /// Handle a log message
 | 
			
		||||
    fn handle(&mut self, level: Level, message: &str);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Prints warnings to stderr
 | 
			
		||||
pub struct PrintWarnings;
 | 
			
		||||
/// Prints info to stdout, everything else to stderr
 | 
			
		||||
pub struct Print;
 | 
			
		||||
 | 
			
		||||
impl WarningHandler for PrintWarnings {
 | 
			
		||||
    fn handle(&mut self, warning: &str) {
 | 
			
		||||
        eprintln!("{}", warning);
 | 
			
		||||
impl Handler for Print {
 | 
			
		||||
    fn handle(&mut self, level: Level, message: &str) {
 | 
			
		||||
        match level {
 | 
			
		||||
            Level::Info => println!("Info: {}", message),
 | 
			
		||||
            l => eprintln!("{}: {}", l.as_str(), message),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Warning handler that will panic at any warning.
 | 
			
		||||
/// Warning handler that will panic
 | 
			
		||||
/// at any warning, error, surprise, bug, or panic.
 | 
			
		||||
/// Don't use except in tests
 | 
			
		||||
pub struct PanicWarn;
 | 
			
		||||
pub struct ProblemPanic;
 | 
			
		||||
 | 
			
		||||
impl WarningHandler for PanicWarn {
 | 
			
		||||
    fn handle(&mut self, warning: &str) {
 | 
			
		||||
        panic!("{}", warning);
 | 
			
		||||
impl Handler for ProblemPanic {
 | 
			
		||||
    fn handle(&mut self, level: Level, message: &str) {
 | 
			
		||||
        use self::Level::*;
 | 
			
		||||
        match level {
 | 
			
		||||
            Panic | Bug | Error | Warning | Surprise => panic!("{}", message),
 | 
			
		||||
            l => Print{}.handle(l, message),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@ use ::layout::c::{ Bounds, EekGtkKeyboard };
 | 
			
		||||
use ::locale;
 | 
			
		||||
use ::locale::{ OwnedTranslation, Translation, compare_current_locale };
 | 
			
		||||
use ::locale_config::system_locale;
 | 
			
		||||
use ::logging;
 | 
			
		||||
use ::manager;
 | 
			
		||||
use ::resources;
 | 
			
		||||
 | 
			
		||||
@ -242,10 +243,13 @@ fn translate_layout_names(layouts: &Vec<LayoutId>) -> Vec<OwnedTranslation> {
 | 
			
		||||
                .as_ref()
 | 
			
		||||
                .to_owned()
 | 
			
		||||
        )
 | 
			
		||||
        .or_warn("No locale detected")
 | 
			
		||||
        .or_print(logging::Problem::Surprise, "No locale detected")
 | 
			
		||||
        .and_then(|lang| {
 | 
			
		||||
            resources::get_layout_names(lang.as_str())
 | 
			
		||||
                .or_warn(&format!("No translations for locale {}", lang))
 | 
			
		||||
                .or_print(
 | 
			
		||||
                    logging::Problem::Surprise,
 | 
			
		||||
                    &format!("No translations for locale {}", lang),
 | 
			
		||||
                )
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    match builtin_translations {
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@
 | 
			
		||||
/*! CSS data loading. */
 | 
			
		||||
 | 
			
		||||
use std::env;
 | 
			
		||||
use ::logging;
 | 
			
		||||
 | 
			
		||||
use glib::object::ObjectExt;
 | 
			
		||||
use logging::Warn;
 | 
			
		||||
@ -94,15 +95,13 @@ fn get_theme_name(settings: >k::Settings) -> GtkTheme {
 | 
			
		||||
        None => GtkTheme {
 | 
			
		||||
            name: {
 | 
			
		||||
                settings.get_property("gtk-theme-name")
 | 
			
		||||
                    // maybe TODO: is this worth a warning?
 | 
			
		||||
                    .or_warn("No theme name")
 | 
			
		||||
                    .or_print(logging::Problem::Surprise, "No theme name")
 | 
			
		||||
                    .and_then(|value| value.get::<String>())
 | 
			
		||||
                    .unwrap_or(DEFAULT_THEME_NAME.into())
 | 
			
		||||
            },
 | 
			
		||||
            variant: {
 | 
			
		||||
                settings.get_property("gtk-application-prefer-dark-theme")
 | 
			
		||||
                    // maybe TODO: is this worth a warning?
 | 
			
		||||
                    .or_warn("No settings key")
 | 
			
		||||
                    .or_print(logging::Problem::Surprise, "No settings key")
 | 
			
		||||
                    .and_then(|value| value.get::<bool>())
 | 
			
		||||
                    .and_then(|dark_preferred| match dark_preferred {
 | 
			
		||||
                        true => Some("dark".into()),
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										19
									
								
								src/tests.rs
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								src/tests.rs
									
									
									
									
									
								
							@ -1,17 +1,22 @@
 | 
			
		||||
/*! Testing functionality */
 | 
			
		||||
 | 
			
		||||
use ::data::Layout;
 | 
			
		||||
use ::logging;
 | 
			
		||||
use xkbcommon::xkb;
 | 
			
		||||
 | 
			
		||||
use ::logging::WarningHandler;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
pub struct CountAndPrint(u32);
 | 
			
		||||
 | 
			
		||||
impl WarningHandler for CountAndPrint {
 | 
			
		||||
    fn handle(&mut self, warning: &str) {
 | 
			
		||||
        self.0 = self.0 + 1;
 | 
			
		||||
        println!("{}", warning);
 | 
			
		||||
impl logging::Handler for CountAndPrint {
 | 
			
		||||
    fn handle(&mut self, level: logging::Level, warning: &str) {
 | 
			
		||||
        use logging::Level::*;
 | 
			
		||||
        match level {
 | 
			
		||||
            Panic | Bug | Error | Warning | Surprise => {
 | 
			
		||||
                self.0 += 1;
 | 
			
		||||
            },
 | 
			
		||||
            _ => {}
 | 
			
		||||
        }
 | 
			
		||||
        logging::Print{}.handle(level, warning)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -34,7 +39,7 @@ fn check_layout(layout: Layout) {
 | 
			
		||||
    let (layout, handler) = layout.build(handler);
 | 
			
		||||
 | 
			
		||||
    if handler.0 > 0 {
 | 
			
		||||
        println!("{} mistakes in layout", handler.0)
 | 
			
		||||
        println!("{} problems while parsing layout", handler.0)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let layout = layout.expect("layout broken");
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user