Merge branch 'log' into 'master'

Unify logging

See merge request Librem5/squeekboard!308
This commit is contained in:
Dorota Czaplejewicz
2020-01-28 11:42:02 +00:00
11 changed files with 311 additions and 152 deletions

View File

@ -21,7 +21,7 @@ use ::keyboard::{
}; };
use ::layout; use ::layout;
use ::layout::ArrangementKind; use ::layout::ArrangementKind;
use ::logging::PrintWarnings; use ::logging;
use ::resources; use ::resources;
use ::util::c::as_str; use ::util::c::as_str;
use ::util::hash_map_map; use ::util::hash_map_map;
@ -31,7 +31,7 @@ use ::xdg;
use serde::Deserialize; use serde::Deserialize;
use std::io::BufReader; use std::io::BufReader;
use std::iter::FromIterator; use std::iter::FromIterator;
use ::logging::WarningHandler; use ::logging::Warn;
/// Gathers stuff defined in C or called by C /// Gathers stuff defined in C or called by C
pub mod c { pub mod c {
@ -157,7 +157,7 @@ fn list_layout_sources(
fn load_layout_data(source: DataSource) fn load_layout_data(source: DataSource)
-> Result<::layout::LayoutData, LoadError> -> Result<::layout::LayoutData, LoadError>
{ {
let handler = PrintWarnings{}; let handler = logging::Print {};
match source { match source {
DataSource::File(path) => { DataSource::File(path) => {
Layout::from_file(path.clone()) Layout::from_file(path.clone())
@ -190,11 +190,13 @@ fn load_layout_data_with_fallback(
( (
LoadError::BadData(Error::Missing(e)), LoadError::BadData(Error::Missing(e)),
DataSource::File(file) DataSource::File(file)
) => eprintln!( // TODO: print in debug logging level ) => log_print!(
logging::Level::Debug,
"Tried file {:?}, but it's missing: {}", "Tried file {:?}, but it's missing: {}",
file, e file, e
), ),
(e, source) => eprintln!( (e, source) => log_print!(
logging::Level::Warning,
"Failed to load layout from {}: {}, skipping", "Failed to load layout from {}: {}, skipping",
source, e source, e
), ),
@ -330,7 +332,7 @@ impl Layout {
serde_yaml::from_reader(infile).map_err(Error::Yaml) 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) -> (Result<::layout::LayoutData, FormattingError>, H)
{ {
let button_names = self.views.values() let button_names = self.views.values()
@ -464,7 +466,7 @@ impl Layout {
} }
} }
fn create_action<H: WarningHandler>( fn create_action<H: logging::Handler>(
button_info: &HashMap<String, ButtonMeta>, button_info: &HashMap<String, ButtonMeta>,
name: &str, name: &str,
view_names: Vec<&String>, view_names: Vec<&String>,
@ -494,15 +496,18 @@ fn create_action<H: WarningHandler>(
(None, None, Some(text)) => SubmitData::Text(text.clone()), (None, None, Some(text)) => SubmitData::Text(text.clone()),
(None, None, None) => SubmitData::Text(name.into()), (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)", "Button {} has more than one of (action, keysym, text)",
name name,
)); ),
);
SubmitData::Text("".into()) SubmitData::Text("".into())
}, },
}; };
fn filter_view_name<H: WarningHandler>( fn filter_view_name<H: logging::Handler>(
button_name: &str, button_name: &str,
view_name: String, view_name: String,
view_names: &Vec<&String>, view_names: &Vec<&String>,
@ -511,10 +516,13 @@ fn create_action<H: WarningHandler>(
if view_names.contains(&&view_name) { if view_names.contains(&&view_name) {
view_name view_name
} else { } else {
warning_handler.handle(&format!("Button {} switches to missing view {}", warning_handler.handle(
logging::Level::Warning,
&format!("Button {} switches to missing view {}",
button_name, button_name,
view_name, view_name,
)); ),
);
"base".into() "base".into()
} }
} }
@ -553,27 +561,24 @@ fn create_action<H: WarningHandler>(
match keysym_valid(keysym.as_str()) { match keysym_valid(keysym.as_str()) {
true => keysym.clone(), true => keysym.clone(),
false => { false => {
warning_handler.handle(&format!( warning_handler.handle(
logging::Level::Warning,
&format!(
"Keysym name invalid: {}", "Keysym name invalid: {}",
keysym, keysym,
)); ),
);
"space".into() // placeholder "space".into() // placeholder
}, },
} }
)), )),
}, },
SubmitData::Text(text) => ::action::Action::Submit { SubmitData::Text(text) => ::action::Action::Submit {
text: { text: CString::new(text.clone()).or_warn(
CString::new(text.clone()) warning_handler,
.map_err(|e| { logging::Problem::Warning,
warning_handler.handle(&format!( &format!("Text {} contains problems", text),
"Text {} contains problems: {:?}", ),
text,
e
));
e
}).ok()
},
keys: text.chars().map(|codepoint| { keys: text.chars().map(|codepoint| {
let codepoint_string = codepoint.to_string(); let codepoint_string = codepoint.to_string();
::action::KeySym(match keysym_valid(codepoint_string.as_str()) { ::action::KeySym(match keysym_valid(codepoint_string.as_str()) {
@ -587,7 +592,7 @@ fn create_action<H: WarningHandler>(
/// TODO: Since this will receive user-provided data, /// TODO: Since this will receive user-provided data,
/// all .expect() on them should be turned into soft fails /// 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>, button_info: &HashMap<String, ButtonMeta>,
outlines: &HashMap<String, Outline>, outlines: &HashMap<String, Outline>,
name: &str, name: &str,
@ -611,14 +616,11 @@ fn create_button<H: WarningHandler>(
} else if let Some(text) = &button_meta.text { } else if let Some(text) = &button_meta.text {
::layout::Label::Text( ::layout::Label::Text(
CString::new(text.as_str()) CString::new(text.as_str())
.unwrap_or_else(|e| { .or_warn(
warning_handler.handle(&format!( warning_handler,
"Text {} is invalid: {}", logging::Problem::Warning,
text, &format!("Text {} is invalid", text),
e, ).unwrap_or_else(|| CString::new("").unwrap())
));
CString::new("").unwrap()
})
) )
} else { } else {
::layout::Label::Text(cname.clone()) ::layout::Label::Text(cname.clone())
@ -629,7 +631,10 @@ fn create_button<H: WarningHandler>(
if outlines.contains_key(outline) { if outlines.contains_key(outline) {
outline.clone() outline.clone()
} else { } 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() "default".into()
} }
} }
@ -638,12 +643,11 @@ fn create_button<H: WarningHandler>(
let outline = outlines.get(&outline_name) let outline = outlines.get(&outline_name)
.map(|outline| (*outline).clone()) .map(|outline| (*outline).clone())
.unwrap_or_else(|| { .or_warn(
warning_handler.handle( warning_handler,
&format!("No default outline defined! Using 1x1!") logging::Problem::Warning,
); "No default outline defined! Using 1x1!",
Outline { width: 1f64, height: 1f64 } ).unwrap_or(Outline { width: 1f64, height: 1f64 });
});
layout::Button { layout::Button {
name: cname, name: cname,
@ -663,7 +667,7 @@ mod tests {
use super::*; use super::*;
use std::error::Error as ErrorTrait; use std::error::Error as ErrorTrait;
use ::logging::PanicWarn; use ::logging::ProblemPanic;
#[test] #[test]
fn test_parse_path() { fn test_parse_path() {
@ -733,7 +737,7 @@ mod tests {
fn test_layout_punctuation() { fn test_layout_punctuation() {
let out = Layout::from_file(PathBuf::from("tests/layout_key1.yaml")) let out = Layout::from_file(PathBuf::from("tests/layout_key1.yaml"))
.unwrap() .unwrap()
.build(PanicWarn).0 .build(ProblemPanic).0
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
out.views["base"] out.views["base"]
@ -748,7 +752,7 @@ mod tests {
fn test_layout_unicode() { fn test_layout_unicode() {
let out = Layout::from_file(PathBuf::from("tests/layout_key2.yaml")) let out = Layout::from_file(PathBuf::from("tests/layout_key2.yaml"))
.unwrap() .unwrap()
.build(PanicWarn).0 .build(ProblemPanic).0
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
out.views["base"] out.views["base"]
@ -764,7 +768,7 @@ mod tests {
fn test_layout_unicode_multi() { fn test_layout_unicode_multi() {
let out = Layout::from_file(PathBuf::from("tests/layout_key3.yaml")) let out = Layout::from_file(PathBuf::from("tests/layout_key3.yaml"))
.unwrap() .unwrap()
.build(PanicWarn).0 .build(ProblemPanic).0
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
out.views["base"] out.views["base"]
@ -779,7 +783,7 @@ mod tests {
#[test] #[test]
fn parsing_fallback() { fn parsing_fallback() {
assert!(Layout::from_resource(FALLBACK_LAYOUT_NAME) assert!(Layout::from_resource(FALLBACK_LAYOUT_NAME)
.map(|layout| layout.build(PanicWarn).0.unwrap()) .map(|layout| layout.build(ProblemPanic).0.unwrap())
.is_ok() .is_ok()
); );
} }
@ -827,7 +831,7 @@ mod tests {
}, },
".", ".",
Vec::new(), Vec::new(),
&mut PanicWarn, &mut ProblemPanic,
), ),
::action::Action::Submit { ::action::Action::Submit {
text: Some(CString::new(".").unwrap()), text: Some(CString::new(".").unwrap()),
@ -840,7 +844,7 @@ mod tests {
fn test_layout_margins() { fn test_layout_margins() {
let out = Layout::from_file(PathBuf::from("tests/layout_margins.yaml")) let out = Layout::from_file(PathBuf::from("tests/layout_margins.yaml"))
.unwrap() .unwrap()
.build(PanicWarn).0 .build(ProblemPanic).0
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
out.margins, out.margins,

View File

@ -1,12 +1,15 @@
use std::boxed::Box; use std::boxed::Box;
use std::ffi::CString; use std::ffi::CString;
use std::fmt;
use std::num::Wrapping; use std::num::Wrapping;
use std::string::String; use std::string::String;
use ::logging;
use ::util::c::into_cstring; use ::util::c::into_cstring;
// Traits // Traits
use std::convert::TryFrom; use std::convert::TryFrom;
use ::logging::Warn;
/// Gathers stuff defined in C or called by C /// Gathers stuff defined in C or called by C
@ -87,16 +90,20 @@ pub mod c {
let imservice = check_imservice(imservice, im).unwrap(); let imservice = check_imservice(imservice, im).unwrap();
imservice.pending = IMProtocolState { imservice.pending = IMProtocolState {
content_hint: { content_hint: {
ContentHint::from_bits(hint).unwrap_or_else(|| { ContentHint::from_bits(hint)
eprintln!("Warning: received invalid hint flags"); .or_print(
ContentHint::NONE logging::Problem::Warning,
}) "Received invalid hint flags",
)
.unwrap_or(ContentHint::NONE)
}, },
content_purpose: { content_purpose: {
ContentPurpose::try_from(purpose).unwrap_or_else(|_e| { ContentPurpose::try_from(purpose)
eprintln!("Warning: Received invalid purpose value"); .or_print(
ContentPurpose::Normal logging::Problem::Warning,
}) "Received invalid purpose value",
)
.unwrap_or(ContentPurpose::Normal)
}, },
..imservice.pending.clone() ..imservice.pending.clone()
}; };
@ -111,10 +118,12 @@ pub mod c {
let imservice = check_imservice(imservice, im).unwrap(); let imservice = check_imservice(imservice, im).unwrap();
imservice.pending = IMProtocolState { imservice.pending = IMProtocolState {
text_change_cause: { text_change_cause: {
ChangeCause::try_from(cause).unwrap_or_else(|_e| { ChangeCause::try_from(cause)
eprintln!("Warning: received invalid cause value"); .or_print(
ChangeCause::InputMethod logging::Problem::Warning,
}) "Received invalid cause value",
)
.unwrap_or(ChangeCause::InputMethod)
}, },
..imservice.pending.clone() ..imservice.pending.clone()
}; };
@ -242,10 +251,17 @@ pub enum ContentPurpose {
Terminal = 13, Terminal = 13,
} }
// Utilities from ::logging need a printable error type
pub struct UnrecognizedValue;
impl fmt::Display for UnrecognizedValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Unrecognized value")
}
}
impl TryFrom<u32> for ContentPurpose { impl TryFrom<u32> for ContentPurpose {
// There's only one way to fail: number not in protocol, type Error = UnrecognizedValue;
// so no special error type is needed
type Error = ();
fn try_from(num: u32) -> Result<Self, Self::Error> { fn try_from(num: u32) -> Result<Self, Self::Error> {
use self::ContentPurpose::*; use self::ContentPurpose::*;
match num { match num {
@ -263,7 +279,7 @@ impl TryFrom<u32> for ContentPurpose {
11 => Ok(Time), 11 => Ok(Time),
12 => Ok(Datetime), 12 => Ok(Datetime),
13 => Ok(Terminal), 13 => Ok(Terminal),
_ => Err(()), _ => Err(UnrecognizedValue),
} }
} }
} }
@ -276,14 +292,12 @@ pub enum ChangeCause {
} }
impl TryFrom<u32> for ChangeCause { impl TryFrom<u32> for ChangeCause {
// There's only one way to fail: number not in protocol, type Error = UnrecognizedValue;
// so no special error type is needed
type Error = ();
fn try_from(num: u32) -> Result<Self, Self::Error> { fn try_from(num: u32) -> Result<Self, Self::Error> {
match num { match num {
0 => Ok(ChangeCause::InputMethod), 0 => Ok(ChangeCause::InputMethod),
1 => Ok(ChangeCause::Other), 1 => Ok(ChangeCause::Other),
_ => Err(()) _ => Err(UnrecognizedValue)
} }
} }
} }

View File

@ -7,6 +7,7 @@ use std::io;
use std::string::FromUtf8Error; use std::string::FromUtf8Error;
use ::action::Action; use ::action::Action;
use ::logging;
use std::io::Write; use std::io::Write;
use std::iter::{ FromIterator, IntoIterator }; use std::iter::{ FromIterator, IntoIterator };
@ -110,7 +111,12 @@ pub fn generate_keymap(
for (name, state) in keystates.iter() { for (name, state) in keystates.iter() {
if let Action::Submit { text: _, keys } = &state.action { if let Action::Submit { text: _, keys } = &state.action {
if let 0 = keys.len() { eprintln!("Key {} has no keysyms", name); }; if let 0 = keys.len() {
log_print!(
logging::Level::Warning,
"Key {} has no keysyms", name,
);
};
for (named_keysym, keycode) in keys.iter().zip(&state.keycodes) { for (named_keysym, keycode) in keys.iter().zip(&state.keycodes) {
write!( write!(
buf, buf,

View File

@ -20,17 +20,21 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::{ HashMap, HashSet }; use std::collections::{ HashMap, HashSet };
use std::ffi::CString; use std::ffi::CString;
use std::fmt;
use std::rc::Rc; use std::rc::Rc;
use std::vec::Vec; use std::vec::Vec;
use ::action::Action; use ::action::Action;
use ::drawing; use ::drawing;
use ::keyboard::{ KeyState, PressType }; use ::keyboard::{ KeyState, PressType };
use ::logging;
use ::manager; use ::manager;
use ::submission::{ Submission, Timestamp }; use ::submission::{ Submission, Timestamp };
use ::util::find_max_double; use ::util::find_max_double;
// Traits
use std::borrow::Borrow; use std::borrow::Borrow;
use ::logging::Warn;
/// Gathers stuff defined in C or called by C /// Gathers stuff defined in C or called by C
pub mod c { pub mod c {
@ -628,6 +632,12 @@ pub struct LayoutData {
#[derive(Debug)] #[derive(Debug)]
struct NoSuchView; struct NoSuchView;
impl fmt::Display for NoSuchView {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "No such view")
}
}
// Unfortunately, changes are not atomic due to mutability :( // Unfortunately, changes are not atomic due to mutability :(
// An error will not be recoverable // An error will not be recoverable
// The usage of &mut on Rc<RefCell<KeyState>> doesn't mean anything special. // The usage of &mut on Rc<RefCell<KeyState>> doesn't mean anything special.
@ -793,9 +803,10 @@ mod seat {
fn try_set_view(layout: &mut Layout, view_name: String) { fn try_set_view(layout: &mut Layout, view_name: String) {
layout.set_view(view_name.clone()) layout.set_view(view_name.clone())
.map_err(|e| .or_print(
eprintln!("Bad view {} ({:?}), ignoring", view_name, e) logging::Problem::Bug,
).ok(); &format!("Bad view {}, ignoring", view_name),
);
} }
/// A vessel holding an obligation to switch view. /// A vessel holding an obligation to switch view.
@ -837,9 +848,10 @@ mod seat {
Action::LockView { lock: _, unlock: view } => { Action::LockView { lock: _, unlock: view } => {
new_view = Some(view.clone()); new_view = Some(view.clone());
}, },
a => eprintln!( a => log_print!(
"BUG: action {:?} was found inside locked keys", logging::Level::Bug,
a "Non-locking action {:?} was found inside locked keys",
a,
), ),
}; };
key.locked = false; key.locked = false;
@ -858,7 +870,10 @@ mod seat {
rckey: &Rc<RefCell<KeyState>>, rckey: &Rc<RefCell<KeyState>>,
) { ) {
if !layout.pressed_keys.insert(::util::Pointer(rckey.clone())) { if !layout.pressed_keys.insert(::util::Pointer(rckey.clone())) {
eprintln!("Warning: key {:?} was already pressed", rckey); log_print!(
logging::Level::Bug,
"Key {:?} was already pressed", rckey,
);
} }
let mut key = rckey.borrow_mut(); let mut key = rckey.borrow_mut();
submission.virtual_keyboard.switch( submission.virtual_keyboard.switch(
@ -942,7 +957,10 @@ mod seat {
} }
} }
}, },
Action::SetModifier(_) => eprintln!("Modifiers unsupported"), Action::SetModifier(_) => log_print!(
logging::Level::Bug,
"Modifiers unsupported",
),
}; };
let pointer = ::util::Pointer(rckey.clone()); let pointer = ::util::Pointer(rckey.clone());

View File

@ -15,6 +15,9 @@ extern crate regex;
extern crate serde; extern crate serde;
extern crate xkbcommon; extern crate xkbcommon;
#[macro_use]
mod logging;
mod action; mod action;
pub mod data; pub mod data;
mod drawing; mod drawing;
@ -24,7 +27,6 @@ mod keyboard;
mod layout; mod layout;
mod locale; mod locale;
mod locale_config; mod locale_config;
mod logging;
mod manager; mod manager;
mod outputs; mod outputs;
mod popover; mod popover;

View File

@ -8,6 +8,7 @@
use std::cmp; use std::cmp;
use std::ffi::{ CStr, CString }; use std::ffi::{ CStr, CString };
use std::fmt;
use std::os::raw::c_char; use std::os::raw::c_char;
use std::ptr; use std::ptr;
use std::str::Utf8Error; use std::str::Utf8Error;
@ -47,6 +48,12 @@ pub enum Error {
NoInfo, NoInfo,
} }
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self, f)
}
}
pub struct XkbInfo(c::GnomeXkbInfo); pub struct XkbInfo(c::GnomeXkbInfo);
impl XkbInfo { impl XkbInfo {

View File

@ -26,13 +26,15 @@
* 4. logging to an immutable destination type * 4. logging to an immutable destination type
* *
* Same as above, except it can be parallelized. * 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, * It seems more difficult to pass the logger around,
* but this may be a solved problem from the area of functional programming. * but this may be a solved problem from the area of functional programming.
* *
* This library generally aims at the approach in 3. * This library generally aims at the approach in 3.
* */ * */
use std::error::Error; use std::fmt::Display;
/// Levels are not in order. /// Levels are not in order.
pub enum Level { pub enum Level {
@ -66,18 +68,84 @@ pub enum Level {
Debug, Debug,
} }
/// Sugar for logging errors in results. impl Level {
/// Approach 2. fn as_str(&self) -> &'static str {
pub trait Warn { match self {
type Value; Level::Panic => "Panic",
fn or_warn(self, msg: &str) -> Option<Self::Value>; 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 approach 2
// TODO: avoid, deprecate.
// Handler instances should be long lived, not one per call.
macro_rules! log_print {
($level:expr, $($arg:tt)*) => (::logging::print($level, &format!($($arg)*)))
}
/// Approach 2
pub fn print(level: Level, message: &str) {
Print{}.handle(level, message)
}
/// 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; 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| { self.map_err(|e| {
eprintln!("{}: {}", msg, e); handler.handle(level.into(), &format!("{}: {}", message, e));
e e
}).ok() }).ok()
} }
@ -85,9 +153,14 @@ impl<T, E: Error> Warn for Result<T, E> {
impl<T> Warn for Option<T> { impl<T> Warn for Option<T> {
type Value = 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(|| { self.or_else(|| {
eprintln!("{}", msg); handler.handle(level.into(), message);
None None
}) })
} }
@ -95,26 +168,34 @@ impl<T> Warn for Option<T> {
/// A mutable handler for text warnings. /// A mutable handler for text warnings.
/// Approach 3. /// Approach 3.
pub trait WarningHandler { pub trait Handler {
/// Handle a warning /// Handle a log message
fn handle(&mut self, warning: &str); fn handle(&mut self, level: Level, message: &str);
} }
/// Prints warnings to stderr /// Prints info to stdout, everything else to stderr
pub struct PrintWarnings; pub struct Print;
impl WarningHandler for PrintWarnings { impl Handler for Print {
fn handle(&mut self, warning: &str) { fn handle(&mut self, level: Level, message: &str) {
eprintln!("{}", warning); 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 /// Don't use except in tests
pub struct PanicWarn; pub struct ProblemPanic;
impl WarningHandler for PanicWarn { impl Handler for ProblemPanic {
fn handle(&mut self, warning: &str) { fn handle(&mut self, level: Level, message: &str) {
panic!("{}", warning); use self::Level::*;
match level {
Panic | Bug | Error | Warning | Surprise => panic!("{}", message),
l => Print{}.handle(l, message),
}
} }
} }

View File

@ -1,7 +1,10 @@
/*! Managing Wayland outputs */ /*! Managing Wayland outputs */
use std::vec::Vec; use std::vec::Vec;
use ::logging;
// traits
use ::logging::Warn;
/// Gathers stuff defined in C or called by C /// Gathers stuff defined in C or called by C
pub mod c { pub mod c {
@ -113,14 +116,11 @@ pub mod c {
_make: *const c_char, _model: *const c_char, _make: *const c_char, _model: *const c_char,
transform: i32, transform: i32,
) { ) {
let transform = Transform::from_u32(transform as u32).unwrap_or_else( let transform = Transform::from_u32(transform as u32)
|| { .or_print(
eprintln!( logging::Problem::Warning,
"Warning: received invalid wl_output.transform value" "Received invalid wl_output.transform value",
); ).unwrap_or(Transform::Normal);
Transform::Normal
}
);
let outputs = outputs.clone_ref(); let outputs = outputs.clone_ref();
let mut collection = outputs.borrow_mut(); let mut collection = outputs.borrow_mut();
@ -129,7 +129,10 @@ pub mod c {
.map(|o| &mut o.pending); .map(|o| &mut o.pending);
match output_state { match output_state {
Some(state) => { state.transform = Some(transform) }, Some(state) => { state.transform = Some(transform) },
None => eprintln!("Wayland error: Got mode on unknown output"), None => log_print!(
logging::Level::Warning,
"Got geometry on unknown output",
),
}; };
} }
@ -141,10 +144,12 @@ pub mod c {
height: i32, height: i32,
_refresh: i32, _refresh: i32,
) { ) {
let flags = Mode::from_bits(flags).unwrap_or_else(|| { let flags = Mode::from_bits(flags)
eprintln!("Warning: received invalid wl_output.mode flags"); .or_print(
Mode::NONE logging::Problem::Warning,
}); "Received invalid wl_output.mode flags",
).unwrap_or(Mode::NONE);
let outputs = outputs.clone_ref(); let outputs = outputs.clone_ref();
let mut collection = outputs.borrow_mut(); let mut collection = outputs.borrow_mut();
let output_state: Option<&mut OutputState> let output_state: Option<&mut OutputState>
@ -156,7 +161,10 @@ pub mod c {
state.current_mode = Some(super::Mode { width, height}); state.current_mode = Some(super::Mode { width, height});
} }
}, },
None => eprintln!("Wayland error: Got mode on unknown output"), None => log_print!(
logging::Level::Warning,
"Got mode on unknown output",
),
}; };
} }
@ -169,7 +177,10 @@ pub mod c {
let output = find_output_mut(&mut collection, wl_output); let output = find_output_mut(&mut collection, wl_output);
match output { match output {
Some(output) => { output.current = output.pending.clone(); } Some(output) => { output.current = output.pending.clone(); }
None => eprintln!("Wayland error: Got done on unknown output"), None => log_print!(
logging::Level::Warning,
"Got done on unknown output",
),
}; };
} }
@ -185,7 +196,10 @@ pub mod c {
.map(|o| &mut o.pending); .map(|o| &mut o.pending);
match output_state { match output_state {
Some(state) => { state.scale = factor; } Some(state) => { state.scale = factor; }
None => eprintln!("Wayland error: Got done on unknown output"), None => log_print!(
logging::Level::Warning,
"Got scale on unknown output",
),
}; };
} }
@ -258,7 +272,10 @@ pub mod c {
} }
}, },
_ => { _ => {
eprintln!("Not enough info registered on output"); log_print!(
logging::Level::Surprise,
"Not enough info received on output",
);
0 0
}, },
} }

View File

@ -7,6 +7,7 @@ use ::layout::c::{ Bounds, EekGtkKeyboard };
use ::locale; use ::locale;
use ::locale::{ OwnedTranslation, Translation, compare_current_locale }; use ::locale::{ OwnedTranslation, Translation, compare_current_locale };
use ::locale_config::system_locale; use ::locale_config::system_locale;
use ::logging;
use ::manager; use ::manager;
use ::resources; use ::resources;
@ -221,14 +222,10 @@ fn translate_layout_names(layouts: &Vec<LayoutId>) -> Vec<OwnedTranslation> {
LayoutId::System { name, kind: _ } => { LayoutId::System { name, kind: _ } => {
xkb_translator.get_display_name(name) xkb_translator.get_display_name(name)
.map(|s| Status::Translated(OwnedTranslation(s))) .map(|s| Status::Translated(OwnedTranslation(s)))
.unwrap_or_else(|e| { .or_print(
eprintln!( logging::Problem::Surprise,
"No display name for xkb layout {}: {:?}", &format!("No display name for xkb layout {}", name),
name, ).unwrap_or_else(|| Status::Remaining(name.clone()))
e,
);
Status::Remaining(name.clone())
})
}, },
LayoutId::Local(name) => Status::Remaining(name.clone()), LayoutId::Local(name) => Status::Remaining(name.clone()),
}); });
@ -242,10 +239,13 @@ fn translate_layout_names(layouts: &Vec<LayoutId>) -> Vec<OwnedTranslation> {
.as_ref() .as_ref()
.to_owned() .to_owned()
) )
.or_warn("No locale detected") .or_print(logging::Problem::Surprise, "No locale detected")
.and_then(|lang| { .and_then(|lang| {
resources::get_layout_names(lang.as_str()) 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 { match builtin_translations {
@ -361,10 +361,10 @@ pub fn show(
match state { match state {
Some(v) => { Some(v) => {
v.get::<String>() v.get::<String>()
.or_else(|| { .or_print(
eprintln!("Variant is not string: {:?}", v); logging::Problem::Bug,
None &format!("Variant is not string: {:?}", v)
}) )
.map(|state| { .map(|state| {
let (_id, layout) = choices.iter() let (_id, layout) = choices.iter()
.find( .find(
@ -376,7 +376,10 @@ pub fn show(
) )
}); });
}, },
None => eprintln!("No variant selected"), None => log_print!(
logging::Level::Debug,
"No variant selected",
),
}; };
menu_inner.popdown(); menu_inner.popdown();
}); });

View File

@ -19,6 +19,7 @@
/*! CSS data loading. */ /*! CSS data loading. */
use std::env; use std::env;
use ::logging;
use glib::object::ObjectExt; use glib::object::ObjectExt;
use logging::Warn; use logging::Warn;
@ -84,7 +85,10 @@ fn get_theme_name(settings: &gtk::Settings) -> GtkTheme {
match &e { match &e {
env::VarError::NotPresent => {}, env::VarError::NotPresent => {},
// maybe TODO: forward this warning? // maybe TODO: forward this warning?
e => eprintln!("GTK_THEME variable invalid: {}", e), e => log_print!(
logging::Level::Surprise,
"GTK_THEME variable invalid: {}", e,
),
}; };
e e
}).ok(); }).ok();
@ -94,15 +98,13 @@ fn get_theme_name(settings: &gtk::Settings) -> GtkTheme {
None => GtkTheme { None => GtkTheme {
name: { name: {
settings.get_property("gtk-theme-name") settings.get_property("gtk-theme-name")
// maybe TODO: is this worth a warning? .or_print(logging::Problem::Surprise, "No theme name")
.or_warn("No theme name")
.and_then(|value| value.get::<String>()) .and_then(|value| value.get::<String>())
.unwrap_or(DEFAULT_THEME_NAME.into()) .unwrap_or(DEFAULT_THEME_NAME.into())
}, },
variant: { variant: {
settings.get_property("gtk-application-prefer-dark-theme") settings.get_property("gtk-application-prefer-dark-theme")
// maybe TODO: is this worth a warning? .or_print(logging::Problem::Surprise, "No settings key")
.or_warn("No settings key")
.and_then(|value| value.get::<bool>()) .and_then(|value| value.get::<bool>())
.and_then(|dark_preferred| match dark_preferred { .and_then(|dark_preferred| match dark_preferred {
true => Some("dark".into()), true => Some("dark".into()),

View File

@ -1,17 +1,22 @@
/*! Testing functionality */ /*! Testing functionality */
use ::data::Layout; use ::data::Layout;
use ::logging;
use xkbcommon::xkb; use xkbcommon::xkb;
use ::logging::WarningHandler;
pub struct CountAndPrint(u32); pub struct CountAndPrint(u32);
impl WarningHandler for CountAndPrint { impl logging::Handler for CountAndPrint {
fn handle(&mut self, warning: &str) { fn handle(&mut self, level: logging::Level, warning: &str) {
self.0 = self.0 + 1; use logging::Level::*;
println!("{}", warning); 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); let (layout, handler) = layout.build(handler);
if handler.0 > 0 { if handler.0 > 0 {
println!("{} mistakes in layout", handler.0) println!("{} problems while parsing layout", handler.0)
} }
let layout = layout.expect("layout broken"); let layout = layout.expect("layout broken");