Merge branch 'fallbacks' into 'master'

layout: Fallback to builtin before switching layouts

See merge request Librem5/squeekboard!186
This commit is contained in:
David Boddie
2019-09-29 16:29:47 +00:00

View File

@ -76,6 +76,7 @@ pub fn load_layout_from_resource(
.map_err(|e| LoadError::BadResource(e)) .map_err(|e| LoadError::BadResource(e))
} }
#[derive(Debug, PartialEq)]
enum DataSource { enum DataSource {
File(PathBuf), File(PathBuf),
Resource(String), Resource(String),
@ -93,62 +94,79 @@ impl fmt::Display for DataSource {
/// Tries to load the layout from the first place where it's present. /// Tries to load the layout from the first place where it's present.
/// If the layout exists, but is broken, fallback is activated. /// If the layout exists, but is broken, fallback is activated.
fn load_layout( fn load_layout(
name: &str name: &str,
) -> (Result<::layout::Layout, LoadError>, DataSource) { keyboards_path: Option<PathBuf>,
let path = env::var_os("SQUEEKBOARD_KEYBOARDSDIR") ) -> (
.map(PathBuf::from) Result<::layout::Layout, LoadError>, // last attempted
.or_else(|| xdg::data_path("squeekboard/keyboards")) DataSource, // last attempt source
.map(|path| path.join(name).with_extension("yaml")); Option<(LoadError, DataSource)>, // first attempt source
) {
let path = keyboards_path.map(|path| path.join(name).with_extension("yaml"));
let (layout, source) = match path { let layout = match path {
Some(path) => {( Some(path) => Some((
Layout::from_yaml_stream(path.clone()) Layout::from_yaml_stream(path.clone())
.map_err(|e| LoadError::BadData(e)), .map_err(LoadError::BadData)
DataSource::File(path) .and_then(|layout|
)}, layout.build().map_err(LoadError::BadKeyMap)
None => {( ),
load_layout_from_resource(name), DataSource::File(path),
DataSource::Resource(name.into()) )),
)}, None => None, // No env var, not an error
}; };
let layout = layout.and_then( let (failed_attempt, layout) = match layout {
|layout| layout.build().map_err(LoadError::BadKeyMap) Some((Ok(layout), path)) => (None, Some((layout, path))),
); Some((Err(e), path)) => (Some((e, path)), None),
None => (None, None),
};
(layout, source) let (layout, source) = match layout {
Some((layout, path)) => (Ok(layout), path),
None => (
load_layout_from_resource(name)
.and_then(|layout|
layout.build().map_err(LoadError::BadKeyMap)
),
DataSource::Resource(name.into()),
),
};
(layout, source, failed_attempt)
} }
fn load_layout_with_fallback( fn load_layout_with_fallback(
name: &str name: &str
) -> ::layout::Layout { ) -> ::layout::Layout {
let (layout, source) = load_layout(name); let path = env::var_os("SQUEEKBOARD_KEYBOARDSDIR")
let (layout, source) = match (layout, source) { .map(PathBuf::from)
.or_else(|| xdg::data_path("squeekboard/keyboards"));
let (layout, source, attempt) = load_layout(name, path.clone());
if let Some((e, source)) = attempt {
eprintln!(
"Failed to load layout from {}: {}, trying builtin",
source, e
);
};
let (layout, source, attempt) = match (layout, source) {
(Err(e), source) => { (Err(e), source) => {
eprintln!( eprintln!(
"Failed to load layout from {}: {}, using fallback", "Failed to load layout from {}: {}, using fallback",
source, e source, e
); );
load_layout(FALLBACK_LAYOUT_NAME) load_layout(FALLBACK_LAYOUT_NAME, path)
}, },
res => res, (res, source) => (res, source, None),
}; };
let (layout, source) = match (layout, source) { if let Some((e, source)) = attempt {
(Err(e), source) => { eprintln!(
eprintln!( "Failed to load layout from {}: {}, trying builtin",
"Failed to load fallback layout from {}: {}, using hardcoded", source, e
source, e );
);
(
load_layout_from_resource(FALLBACK_LAYOUT_NAME)
.and_then(
|layout| layout.build().map_err(LoadError::BadKeyMap)
),
DataSource::Resource(FALLBACK_LAYOUT_NAME.into()),
)
},
res => res,
}; };
match (layout, source) { match (layout, source) {
@ -608,6 +626,20 @@ mod tests {
); );
} }
/// First fallback should be to builtin, not to FALLBACK_LAYOUT_NAME
#[test]
fn fallbacks_order() {
let (layout, source, _failure) = load_layout(
"nb",
Some(PathBuf::from("tests"))
);
assert_eq!(
source,
load_layout("nb", None).1
);
}
#[test] #[test]
fn unicode_keysym() { fn unicode_keysym() {
let keysym = xkb::keysym_from_name( let keysym = xkb::keysym_from_name(