diff --git a/src/data.rs b/src/data.rs index 9aa1fc4b..c515abe1 100644 --- a/src/data.rs +++ b/src/data.rs @@ -21,17 +21,17 @@ use ::keyboard::{ }; use ::layout; use ::layout::ArrangementKind; +use ::logging::PrintWarnings; use ::resources; use ::util::c::as_str; use ::util::hash_map_map; use ::xdg; // traits, derives +use serde::Deserialize; use std::io::BufReader; use std::iter::FromIterator; -use serde::Deserialize; -use util::WarningHandler; - +use ::logging::WarningHandler; /// Gathers stuff defined in C or called by C pub mod c { @@ -154,14 +154,6 @@ fn list_layout_sources( ret } -struct PrintWarnings; - -impl WarningHandler for PrintWarnings { - fn handle(&mut self, warning: &str) { - println!("{}", warning); - } -} - fn load_layout_data(source: DataSource) -> Result<::layout::LayoutData, LoadError> { @@ -671,14 +663,7 @@ mod tests { use super::*; use std::error::Error as ErrorTrait; - - struct PanicWarn; - - impl WarningHandler for PanicWarn { - fn handle(&mut self, warning: &str) { - panic!("{}", warning); - } - } + use ::logging::PanicWarn; #[test] fn test_parse_path() { diff --git a/src/lib.rs b/src/lib.rs index d7bf622d..5679656c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,7 @@ mod keyboard; mod layout; mod locale; mod locale_config; +mod logging; mod outputs; mod popover; mod resources; diff --git a/src/logging.rs b/src/logging.rs new file mode 100644 index 00000000..9848783e --- /dev/null +++ b/src/logging.rs @@ -0,0 +1,110 @@ +/*! Logging library. + * + * This is probably the only part of squeekboard + * that should be doing any direct printing. + * + * There are several approaches to logging, + * in the order of increasing flexibility and/or purity: + * + * 1. `println!` directly + * + * It can't be easily replaced by a different solution + * + * 2. simple `log!` macro + * + * Replacing the destination at runtime other than globally would be awkward, + * so no easy way to suppress errors for things that don't matter, + * but formatting is still easy. + * + * 3. logging to a mutable destination type + * + * Can be easily replaced, but logging `Result` types, + * which should be done by calling a method on the result, + * can't be formatted directly. + * Cannot be parallelized. + * + * 4. logging to an immutable destination type + * + * Same as above, except it can be parallelized. + * 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; + +/// Levels are not in order. +pub enum Level { + // Levels for reporting violated constraints + /// The program violated a self-imposed constraint, + /// ended up in an inconsistent state, and cannot recover. + /// Handlers must not actually panic. (should they?) + Panic, + /// The program violated a self-imposed constraint, + /// ended up in an inconsistent state, but some state can be recovered. + Bug, + /// Invalid data given by an external source, + /// some state of the program must be dropped. + Error, + // Still violated constraints, but harmless + /// Invalid data given by an external source, parts of data are ignored. + /// No previous program state needs to be dropped. + Warning, + /// External source not in an expected state, + /// but not violating any protocols (including no relevant protocol). + Surprise, + // Informational + /// A change in internal state that results in a change of behaviour + /// that a user can observe, and a tinkerer might find useful. + /// E.g. selection of external sources, like loading user's UI files, + /// language switch, overrides. + Info, + /// Information useful for application developer only. + /// Should be limited to information gotten from external sources, + /// and more tricky parts of internal state. + Debug, +} + +/// Sugar for logging errors in results. +/// Approach 2. +pub trait Warn { + type Value; + fn ok_warn(self, msg: &str) -> Option; +} + +impl Warn for Result { + type Value = T; + fn ok_warn(self, msg: &str) -> Option { + self.map_err(|e| { + eprintln!("{}: {}", msg, e); + e + }).ok() + } +} + +/// A mutable handler for text warnings. +/// Approach 3. +pub trait WarningHandler { + /// Handle a warning + fn handle(&mut self, warning: &str); +} + +/// Prints warnings to stderr +pub struct PrintWarnings; + +impl WarningHandler for PrintWarnings { + fn handle(&mut self, warning: &str) { + eprintln!("{}", warning); + } +} + +/// Warning handler that will panic at any warning. +/// Don't use except in tests +pub struct PanicWarn; + +impl WarningHandler for PanicWarn { + fn handle(&mut self, warning: &str) { + panic!("{}", warning); + } +} diff --git a/src/style.rs b/src/style.rs index b8f147a7..b12e756c 100644 --- a/src/style.rs +++ b/src/style.rs @@ -21,7 +21,7 @@ use std::env; use glib::object::ObjectExt; -use util::Warn; +use logging::Warn; /// Gathers stuff defined in C or called by C pub mod c { diff --git a/src/tests.rs b/src/tests.rs index d243eab4..3de54ccf 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -3,7 +3,7 @@ use ::data::Layout; use xkbcommon::xkb; -use ::util::WarningHandler; +use ::logging::WarningHandler; pub struct CountAndPrint(u32); diff --git a/src/util.rs b/src/util.rs index 8bd156cc..1553fd19 100644 --- a/src/util.rs +++ b/src/util.rs @@ -189,27 +189,6 @@ impl Borrow> for Pointer { } } -/// Sugar for logging errors in results -pub trait Warn { - type Value; - fn ok_warn(self, msg: &str) -> Option; -} - -impl Warn for Result { - type Value = T; - fn ok_warn(self, msg: &str) -> Option { - self.map_err(|e| { - eprintln!("{}: {}", msg, e); - e - }).ok() - } -} - -pub trait WarningHandler { - /// Handle a warning - fn handle(&mut self, warning: &str); -} - #[cfg(test)] mod tests { use super::*;