From 2b7e8f829ea3f6cbadfce4cf85d7581589eff0a8 Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Mon, 5 Apr 2021 11:03:57 +0000 Subject: [PATCH 1/2] data: Split into loading and parsing --- src/data/loading.rs | 424 ++++++++++++++++++++++++++++ src/data/mod.rs | 65 +++++ src/{data.rs => data/parsing.rs} | 466 +------------------------------ src/tests.rs | 2 +- 4 files changed, 502 insertions(+), 455 deletions(-) create mode 100644 src/data/loading.rs create mode 100644 src/data/mod.rs rename src/{data.rs => data/parsing.rs} (62%) diff --git a/src/data/loading.rs b/src/data/loading.rs new file mode 100644 index 00000000..089e640d --- /dev/null +++ b/src/data/loading.rs @@ -0,0 +1,424 @@ +/* Copyright (C) 2020-2021 Purism SPC + * SPDX-License-Identifier: GPL-3.0+ + */ + +/*! Loading layout files */ + +use std::env; +use std::fmt; +use std::path::PathBuf; +use std::convert::TryFrom; + +use super::{ Error, LoadError }; +use super::parsing; + +use ::layout::ArrangementKind; +use ::logging; +use ::util::c::as_str; +use ::xdg; +use ::imservice::ContentPurpose; + +// traits, derives +use ::logging::Warn; + + +/// Gathers stuff defined in C or called by C +pub mod c { + use super::*; + use std::os::raw::c_char; + + #[no_mangle] + pub extern "C" + fn squeek_load_layout( + name: *const c_char, // name of the keyboard + type_: u32, // type like Wide + variant: u32, // purpose variant like numeric, terminal... + overlay: *const c_char, // the overlay (looking for "terminal") + ) -> *mut ::layout::Layout { + let type_ = match type_ { + 0 => ArrangementKind::Base, + 1 => ArrangementKind::Wide, + _ => panic!("Bad enum value"), + }; + + let name = as_str(&name) + .expect("Bad layout name") + .expect("Empty layout name"); + + let variant = ContentPurpose::try_from(variant) + .or_print( + logging::Problem::Warning, + "Received invalid purpose value", + ) + .unwrap_or(ContentPurpose::Normal); + + let overlay_str = as_str(&overlay) + .expect("Bad overlay name") + .expect("Empty overlay name"); + let overlay_str = match overlay_str { + "" => None, + other => Some(other), + }; + + let (kind, layout) = load_layout_data_with_fallback(&name, type_, variant, overlay_str); + let layout = ::layout::Layout::new(layout, kind); + Box::into_raw(Box::new(layout)) + } +} + +const FALLBACK_LAYOUT_NAME: &str = "us"; + + +#[derive(Debug, Clone, PartialEq)] +enum DataSource { + File(PathBuf), + Resource(String), +} + +impl fmt::Display for DataSource { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + DataSource::File(path) => write!(f, "Path: {:?}", path.display()), + DataSource::Resource(name) => write!(f, "Resource: {}", name), + } + } +} + +/* All functions in this family carry around ArrangementKind, + * because it's not guaranteed to be preserved, + * and the resulting layout needs to know which version was loaded. + * See `squeek_layout_get_kind`. + * Possible TODO: since this is used only in styling, + * and makes the below code nastier than needed, maybe it should go. + */ + +/// Returns ordered names treating `name` as the base name, +/// ignoring any `+` inside. +fn _get_arrangement_names(name: &str, arrangement: ArrangementKind) + -> Vec<(ArrangementKind, String)> +{ + let name_with_arrangement = match arrangement { + ArrangementKind::Base => name.into(), + ArrangementKind::Wide => format!("{}_wide", name), + }; + + let mut ret = Vec::new(); + if name_with_arrangement != name { + ret.push((arrangement, name_with_arrangement)); + } + ret.push((ArrangementKind::Base, name.into())); + ret +} + +/// Returns names accounting for any `+` in the `name`, +/// including the fallback to the default layout. +fn get_preferred_names(name: &str, kind: ArrangementKind) + -> Vec<(ArrangementKind, String)> +{ + let mut ret = _get_arrangement_names(name, kind); + + let base_name_preferences = { + let mut parts = name.splitn(2, '+'); + match parts.next() { + Some(base) => { + // The name is already equal to base, so nothing to add + if base == name { + vec![] + } else { + _get_arrangement_names(base, kind) + } + }, + // The layout's base name starts with a "+". Weird but OK. + None => { + log_print!(logging::Level::Surprise, "Base layout name is empty: {}", name); + vec![] + } + } + }; + + ret.extend(base_name_preferences.into_iter()); + let fallback_names = _get_arrangement_names(FALLBACK_LAYOUT_NAME, kind); + ret.extend(fallback_names.into_iter()); + ret +} + +/// Includes the subdirectory before the forward slash. +type LayoutPath = String; + +// This is only used inside iter_fallbacks_with_meta. +// Placed at the top scope +// because `use LayoutPurpose::*;` +// complains about "not in scope" otherwise. +// This seems to be a Rust 2015 edition problem. +/// Helper for determining where to look up the layout. +enum LayoutPurpose<'a> { + Default, + Special(&'a str), +} + +/// Returns the directory string +/// where the layout should be looked up, including the slash. +fn get_directory_string( + content_purpose: ContentPurpose, + overlay: Option<&str>) -> String +{ + use self::LayoutPurpose::*; + + let layout_purpose = match overlay { + None => match content_purpose { + ContentPurpose::Number => Special("number"), + ContentPurpose::Digits => Special("number"), + ContentPurpose::Phone => Special("number"), + ContentPurpose::Terminal => Special("terminal"), + _ => Default, + }, + Some(overlay) => Special(overlay), + }; + + // For intuitiveness, + // default purpose layouts are stored in the root directory, + // as they correspond to typical text + // and are seen the most often. + match layout_purpose { + Default => "".into(), + Special(purpose) => format!("{}/", purpose), + } +} + +/// Returns an iterator over all fallback paths. +fn to_layout_paths( + name_fallbacks: Vec<(ArrangementKind, String)>, + content_purpose: ContentPurpose, + overlay: Option<&str>, +) -> impl Iterator { + let prepend_directory = get_directory_string(content_purpose, overlay); + + name_fallbacks.into_iter() + .map(move |(arrangement, name)| + (arrangement, format!("{}{}", prepend_directory, name)) + ) +} + +type LayoutSource = (ArrangementKind, DataSource); + +fn to_layout_sources( + layout_paths: impl Iterator, + filesystem_path: Option, +) -> impl Iterator { + layout_paths.flat_map(move |(arrangement, layout_path)| { + let mut sources = Vec::new(); + if let Some(path) = &filesystem_path { + sources.push(( + arrangement, + DataSource::File( + path.join(&layout_path) + .with_extension("yaml") + ) + )); + }; + sources.push((arrangement, DataSource::Resource(layout_path.clone()))); + sources.into_iter() + }) +} + +/// Returns possible sources, with first as the most preferred one. +/// Trying order: native lang of the right kind, native base, +/// fallback lang of the right kind, fallback base +fn iter_layout_sources( + name: &str, + arrangement: ArrangementKind, + purpose: ContentPurpose, + ui_overlay: Option<&str>, + layout_storage: Option, +) -> impl Iterator { + let names = get_preferred_names(name, arrangement); + let paths = to_layout_paths(names, purpose, ui_overlay); + to_layout_sources(paths, layout_storage) +} + +fn load_layout_data(source: DataSource) + -> Result<::layout::LayoutData, LoadError> +{ + let handler = logging::Print {}; + match source { + DataSource::File(path) => { + parsing::Layout::from_file(path.clone()) + .map_err(LoadError::BadData) + .and_then(|layout| + layout.build(handler).0.map_err(LoadError::BadKeyMap) + ) + }, + DataSource::Resource(name) => { + parsing::Layout::from_resource(&name) + .and_then(|layout| + layout.build(handler).0.map_err(LoadError::BadKeyMap) + ) + }, + } +} + +fn load_layout_data_with_fallback( + name: &str, + kind: ArrangementKind, + purpose: ContentPurpose, + overlay: Option<&str>, +) -> (ArrangementKind, ::layout::LayoutData) { + + // Build the path to the right keyboard layout subdirectory + let path = env::var_os("SQUEEKBOARD_KEYBOARDSDIR") + .map(PathBuf::from) + .or_else(|| xdg::data_path("squeekboard/keyboards")); + + for (kind, source) in iter_layout_sources(&name, kind, purpose, overlay, path) { + let layout = load_layout_data(source.clone()); + match layout { + Err(e) => match (e, source) { + ( + LoadError::BadData(Error::Missing(e)), + DataSource::File(file) + ) => log_print!( + logging::Level::Debug, + "Tried file {:?}, but it's missing: {}", + file, e + ), + (e, source) => log_print!( + logging::Level::Warning, + "Failed to load layout from {}: {}, skipping", + source, e + ), + }, + Ok(layout) => { + log_print!(logging::Level::Info, "Loaded layout {}", source); + return (kind, layout); + } + } + } + + panic!("No useful layout found!"); +} + + +#[cfg(test)] +mod tests { + use super::*; + + use ::logging::ProblemPanic; + + #[test] + fn parsing_fallback() { + assert!(parsing::Layout::from_resource(FALLBACK_LAYOUT_NAME) + .map(|layout| layout.build(ProblemPanic).0.unwrap()) + .is_ok() + ); + } + + /// First fallback should be to builtin, not to FALLBACK_LAYOUT_NAME + #[test] + fn test_fallback_basic_builtin() { + let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, None, None); + + assert_eq!( + sources.collect::>(), + vec!( + (ArrangementKind::Base, DataSource::Resource("nb".into())), + ( + ArrangementKind::Base, + DataSource::Resource(FALLBACK_LAYOUT_NAME.into()) + ), + ) + ); + } + + /// Prefer loading from file system before builtin. + #[test] + fn test_preferences_order_path() { + let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, None, Some(".".into())); + + assert_eq!( + sources.collect::>(), + vec!( + (ArrangementKind::Base, DataSource::File("./nb.yaml".into())), + (ArrangementKind::Base, DataSource::Resource("nb".into())), + ( + ArrangementKind::Base, + DataSource::File("./us.yaml".into()) + ), + ( + ArrangementKind::Base, + DataSource::Resource("us".into()) + ), + ) + ); + } + + /// If layout contains a "+", it should reach for what's in front of it too. + #[test] + fn test_preferences_order_base() { + let sources = iter_layout_sources("nb+aliens", ArrangementKind::Base, ContentPurpose::Normal, None, None); + + assert_eq!( + sources.collect::>(), + vec!( + (ArrangementKind::Base, DataSource::Resource("nb+aliens".into())), + (ArrangementKind::Base, DataSource::Resource("nb".into())), + ( + ArrangementKind::Base, + DataSource::Resource(FALLBACK_LAYOUT_NAME.into()) + ), + ) + ); + } + + #[test] + fn test_preferences_order_arrangement() { + let sources = iter_layout_sources("nb", ArrangementKind::Wide, ContentPurpose::Normal, None, None); + + assert_eq!( + sources.collect::>(), + vec!( + (ArrangementKind::Wide, DataSource::Resource("nb_wide".into())), + (ArrangementKind::Base, DataSource::Resource("nb".into())), + ( + ArrangementKind::Wide, + DataSource::Resource("us_wide".into()) + ), + ( + ArrangementKind::Base, + DataSource::Resource("us".into()) + ), + ) + ); + } + + #[test] + fn test_preferences_order_overlay() { + let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, Some("terminal"), None); + + assert_eq!( + sources.collect::>(), + vec!( + (ArrangementKind::Base, DataSource::Resource("terminal/nb".into())), + ( + ArrangementKind::Base, + DataSource::Resource("terminal/us".into()) + ), + ) + ); + } + + #[test] + fn test_preferences_order_hint() { + let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Terminal, None, None); + + assert_eq!( + sources.collect::>(), + vec!( + (ArrangementKind::Base, DataSource::Resource("terminal/nb".into())), + ( + ArrangementKind::Base, + DataSource::Resource("terminal/us".into()) + ), + ) + ); + } +} diff --git a/src/data/mod.rs b/src/data/mod.rs new file mode 100644 index 00000000..4bf66bd6 --- /dev/null +++ b/src/data/mod.rs @@ -0,0 +1,65 @@ +/* Copyright (C) 2020-2021 Purism SPC + * SPDX-License-Identifier: GPL-3.0+ + */ + +/*! Combined module for dealing with layout files */ + +mod loading; +pub mod parsing; + +use std::io; +use std::fmt; + +use ::keyboard::FormattingError; + +/// Errors encountered loading the layout into yaml +#[derive(Debug)] +pub enum Error { + Yaml(serde_yaml::Error), + Io(io::Error), + /// The file was missing. + /// It's distinct from Io in order to make it matchable + /// without calling io::Error::kind() + Missing(io::Error), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::Yaml(e) => write!(f, "YAML: {}", e), + Error::Io(e) => write!(f, "IO: {}", e), + Error::Missing(e) => write!(f, "Missing: {}", e), + } + } +} + +impl From for Error { + fn from(e: io::Error) -> Self { + let kind = e.kind(); + match kind { + io::ErrorKind::NotFound => Error::Missing(e), + _ => Error::Io(e), + } + } +} + + +#[derive(Debug)] +pub enum LoadError { + BadData(Error), + MissingResource, + BadResource(serde_yaml::Error), + BadKeyMap(FormattingError), +} + +impl fmt::Display for LoadError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use self::LoadError::*; + match self { + BadData(e) => write!(f, "Bad data: {}", e), + MissingResource => write!(f, "Missing resource"), + BadResource(e) => write!(f, "Bad resource: {}", e), + BadKeyMap(e) => write!(f, "Bad key map: {}", e), + } + } +} diff --git a/src/data.rs b/src/data/parsing.rs similarity index 62% rename from src/data.rs rename to src/data/parsing.rs index 29cd4ba4..d4b8dcf8 100644 --- a/src/data.rs +++ b/src/data/parsing.rs @@ -1,34 +1,30 @@ -/**! The parsing of the data files for layouts */ +/* Copyright (C) 2020-2021 Purism SPC + * SPDX-License-Identifier: GPL-3.0+ + */ -// TODO: find a nice way to make sure non-positive sizes don't break layouts +/*! Parsing of the data files containing layouts */ use std::cell::RefCell; use std::collections::{ HashMap, HashSet }; -use std::env; use std::ffi::CString; -use std::fmt; use std::fs; -use std::io; use std::path::PathBuf; use std::rc::Rc; use std::vec::Vec; -use std::convert::TryFrom; use xkbcommon::xkb; +use super::{ Error, LoadError }; + use ::action; use ::keyboard::{ KeyState, PressType, generate_keymaps, generate_keycodes, KeyCode, FormattingError }; use ::layout; -use ::layout::ArrangementKind; use ::logging; -use ::resources; -use ::util::c::as_str; use ::util::hash_map_map; -use ::xdg; -use ::imservice::ContentPurpose; +use ::resources; // traits, derives use serde::Deserialize; @@ -36,299 +32,7 @@ use std::io::BufReader; use std::iter::FromIterator; use ::logging::Warn; -/// Gathers stuff defined in C or called by C -pub mod c { - use super::*; - use std::os::raw::c_char; - - #[no_mangle] - pub extern "C" - fn squeek_load_layout( - name: *const c_char, // name of the keyboard - type_: u32, // type like Wide - variant: u32, // purpose variant like numeric, terminal... - overlay: *const c_char, // the overlay (looking for "terminal") - ) -> *mut ::layout::Layout { - let type_ = match type_ { - 0 => ArrangementKind::Base, - 1 => ArrangementKind::Wide, - _ => panic!("Bad enum value"), - }; - - let name = as_str(&name) - .expect("Bad layout name") - .expect("Empty layout name"); - - let variant = ContentPurpose::try_from(variant) - .or_print( - logging::Problem::Warning, - "Received invalid purpose value", - ) - .unwrap_or(ContentPurpose::Normal); - - let overlay_str = as_str(&overlay) - .expect("Bad overlay name") - .expect("Empty overlay name"); - let overlay_str = match overlay_str { - "" => None, - other => Some(other), - }; - - let (kind, layout) = load_layout_data_with_fallback(&name, type_, variant, overlay_str); - let layout = ::layout::Layout::new(layout, kind); - Box::into_raw(Box::new(layout)) - } -} - -const FALLBACK_LAYOUT_NAME: &str = "us"; - -#[derive(Debug)] -pub enum LoadError { - BadData(Error), - MissingResource, - BadResource(serde_yaml::Error), - BadKeyMap(FormattingError), -} - -impl fmt::Display for LoadError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use self::LoadError::*; - match self { - BadData(e) => write!(f, "Bad data: {}", e), - MissingResource => write!(f, "Missing resource"), - BadResource(e) => write!(f, "Bad resource: {}", e), - BadKeyMap(e) => write!(f, "Bad key map: {}", e), - } - } -} - -#[derive(Debug, Clone, PartialEq)] -enum DataSource { - File(PathBuf), - Resource(String), -} - -impl fmt::Display for DataSource { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - DataSource::File(path) => write!(f, "Path: {:?}", path.display()), - DataSource::Resource(name) => write!(f, "Resource: {}", name), - } - } -} - -/* All functions in this family carry around ArrangementKind, - * because it's not guaranteed to be preserved, - * and the resulting layout needs to know which version was loaded. - * See `squeek_layout_get_kind`. - * Possible TODO: since this is used only in styling, - * and makes the below code nastier than needed, maybe it should go. - */ - -/// Returns ordered names treating `name` as the base name, -/// ignoring any `+` inside. -fn _get_arrangement_names(name: &str, arrangement: ArrangementKind) - -> Vec<(ArrangementKind, String)> -{ - let name_with_arrangement = match arrangement { - ArrangementKind::Base => name.into(), - ArrangementKind::Wide => format!("{}_wide", name), - }; - - let mut ret = Vec::new(); - if name_with_arrangement != name { - ret.push((arrangement, name_with_arrangement)); - } - ret.push((ArrangementKind::Base, name.into())); - ret -} - -/// Returns names accounting for any `+` in the `name`, -/// including the fallback to the default layout. -fn get_preferred_names(name: &str, kind: ArrangementKind) - -> Vec<(ArrangementKind, String)> -{ - let mut ret = _get_arrangement_names(name, kind); - - let base_name_preferences = { - let mut parts = name.splitn(2, '+'); - match parts.next() { - Some(base) => { - // The name is already equal to base, so nothing to add - if base == name { - vec![] - } else { - _get_arrangement_names(base, kind) - } - }, - // The layout's base name starts with a "+". Weird but OK. - None => { - log_print!(logging::Level::Surprise, "Base layout name is empty: {}", name); - vec![] - } - } - }; - - ret.extend(base_name_preferences.into_iter()); - let fallback_names = _get_arrangement_names(FALLBACK_LAYOUT_NAME, kind); - ret.extend(fallback_names.into_iter()); - ret -} - -/// Includes the subdirectory before the forward slash. -type LayoutPath = String; - -// This is only used inside iter_fallbacks_with_meta. -// Placed at the top scope -// because `use LayoutPurpose::*;` -// complains about "not in scope" otherwise. -// This seems to be a Rust 2015 edition problem. -/// Helper for determining where to look up the layout. -enum LayoutPurpose<'a> { - Default, - Special(&'a str), -} - -/// Returns the directory string -/// where the layout should be looked up, including the slash. -fn get_directory_string( - content_purpose: ContentPurpose, - overlay: Option<&str>) -> String -{ - use self::LayoutPurpose::*; - - let layout_purpose = match overlay { - None => match content_purpose { - ContentPurpose::Number => Special("number"), - ContentPurpose::Digits => Special("number"), - ContentPurpose::Phone => Special("number"), - ContentPurpose::Terminal => Special("terminal"), - _ => Default, - }, - Some(overlay) => Special(overlay), - }; - - // For intuitiveness, - // default purpose layouts are stored in the root directory, - // as they correspond to typical text - // and are seen the most often. - match layout_purpose { - Default => "".into(), - Special(purpose) => format!("{}/", purpose), - } -} - -/// Returns an iterator over all fallback paths. -fn to_layout_paths( - name_fallbacks: Vec<(ArrangementKind, String)>, - content_purpose: ContentPurpose, - overlay: Option<&str>, -) -> impl Iterator { - let prepend_directory = get_directory_string(content_purpose, overlay); - - name_fallbacks.into_iter() - .map(move |(arrangement, name)| - (arrangement, format!("{}{}", prepend_directory, name)) - ) -} - -type LayoutSource = (ArrangementKind, DataSource); - -fn to_layout_sources( - layout_paths: impl Iterator, - filesystem_path: Option, -) -> impl Iterator { - layout_paths.flat_map(move |(arrangement, layout_path)| { - let mut sources = Vec::new(); - if let Some(path) = &filesystem_path { - sources.push(( - arrangement, - DataSource::File( - path.join(&layout_path) - .with_extension("yaml") - ) - )); - }; - sources.push((arrangement, DataSource::Resource(layout_path.clone()))); - sources.into_iter() - }) -} - -/// Returns possible sources, with first as the most preferred one. -/// Trying order: native lang of the right kind, native base, -/// fallback lang of the right kind, fallback base -fn iter_layout_sources( - name: &str, - arrangement: ArrangementKind, - purpose: ContentPurpose, - ui_overlay: Option<&str>, - layout_storage: Option, -) -> impl Iterator { - let names = get_preferred_names(name, arrangement); - let paths = to_layout_paths(names, purpose, ui_overlay); - to_layout_sources(paths, layout_storage) -} - -fn load_layout_data(source: DataSource) - -> Result<::layout::LayoutData, LoadError> -{ - let handler = logging::Print {}; - match source { - DataSource::File(path) => { - Layout::from_file(path.clone()) - .map_err(LoadError::BadData) - .and_then(|layout| - layout.build(handler).0.map_err(LoadError::BadKeyMap) - ) - }, - DataSource::Resource(name) => { - Layout::from_resource(&name) - .and_then(|layout| - layout.build(handler).0.map_err(LoadError::BadKeyMap) - ) - }, - } -} - -fn load_layout_data_with_fallback( - name: &str, - kind: ArrangementKind, - purpose: ContentPurpose, - overlay: Option<&str>, -) -> (ArrangementKind, ::layout::LayoutData) { - - // Build the path to the right keyboard layout subdirectory - let path = env::var_os("SQUEEKBOARD_KEYBOARDSDIR") - .map(PathBuf::from) - .or_else(|| xdg::data_path("squeekboard/keyboards")); - - for (kind, source) in iter_layout_sources(&name, kind, purpose, overlay, path) { - let layout = load_layout_data(source.clone()); - match layout { - Err(e) => match (e, source) { - ( - LoadError::BadData(Error::Missing(e)), - DataSource::File(file) - ) => log_print!( - logging::Level::Debug, - "Tried file {:?}, but it's missing: {}", - file, e - ), - (e, source) => log_print!( - logging::Level::Warning, - "Failed to load layout from {}: {}, skipping", - source, e - ), - }, - Ok(layout) => { - log_print!(logging::Level::Info, "Loaded layout {}", source); - return (kind, layout); - } - } - } - - panic!("No useful layout found!"); -} +// TODO: find a nice way to make sure non-positive sizes don't break layouts /// The root element describing an entire keyboard #[derive(Debug, Deserialize, PartialEq)] @@ -421,37 +125,6 @@ struct Outline { height: f64, } -/// Errors encountered loading the layout into yaml -#[derive(Debug)] -pub enum Error { - Yaml(serde_yaml::Error), - Io(io::Error), - /// The file was missing. - /// It's distinct from Io in order to make it matchable - /// without calling io::Error::kind() - Missing(io::Error), -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Error::Yaml(e) => write!(f, "YAML: {}", e), - Error::Io(e) => write!(f, "IO: {}", e), - Error::Missing(e) => write!(f, "Missing: {}", e), - } - } -} - -impl From for Error { - fn from(e: io::Error) -> Self { - let kind = e.kind(); - match kind { - io::ErrorKind::NotFound => Error::Missing(e), - _ => Error::Io(e), - } - } -} - pub fn add_offsets<'a, I: 'a, T, F: 'a>(iterator: I, get_size: F) -> impl Iterator + 'a where I: Iterator, @@ -871,10 +544,13 @@ fn extract_symbol_names<'a>(actions: &'a [(&str, action::Action)]) .map(|named_keysym| named_keysym.0) } + #[cfg(test)] mod tests { use super::*; - + + use std::env; + use ::logging::ProblemPanic; fn path_from_root(file: &'static str) -> PathBuf { @@ -1024,124 +700,6 @@ mod tests { ); } - #[test] - fn parsing_fallback() { - assert!(Layout::from_resource(FALLBACK_LAYOUT_NAME) - .map(|layout| layout.build(ProblemPanic).0.unwrap()) - .is_ok() - ); - } - - /// First fallback should be to builtin, not to FALLBACK_LAYOUT_NAME - #[test] - fn test_fallback_basic_builtin() { - let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, None, None); - - assert_eq!( - sources.collect::>(), - vec!( - (ArrangementKind::Base, DataSource::Resource("nb".into())), - ( - ArrangementKind::Base, - DataSource::Resource(FALLBACK_LAYOUT_NAME.into()) - ), - ) - ); - } - - /// Prefer loading from file system before builtin. - #[test] - fn test_preferences_order_path() { - let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, None, Some(".".into())); - - assert_eq!( - sources.collect::>(), - vec!( - (ArrangementKind::Base, DataSource::File("./nb.yaml".into())), - (ArrangementKind::Base, DataSource::Resource("nb".into())), - ( - ArrangementKind::Base, - DataSource::File("./us.yaml".into()) - ), - ( - ArrangementKind::Base, - DataSource::Resource("us".into()) - ), - ) - ); - } - - /// If layout contains a "+", it should reach for what's in front of it too. - #[test] - fn test_preferences_order_base() { - let sources = iter_layout_sources("nb+aliens", ArrangementKind::Base, ContentPurpose::Normal, None, None); - - assert_eq!( - sources.collect::>(), - vec!( - (ArrangementKind::Base, DataSource::Resource("nb+aliens".into())), - (ArrangementKind::Base, DataSource::Resource("nb".into())), - ( - ArrangementKind::Base, - DataSource::Resource(FALLBACK_LAYOUT_NAME.into()) - ), - ) - ); - } - - #[test] - fn test_preferences_order_arrangement() { - let sources = iter_layout_sources("nb", ArrangementKind::Wide, ContentPurpose::Normal, None, None); - - assert_eq!( - sources.collect::>(), - vec!( - (ArrangementKind::Wide, DataSource::Resource("nb_wide".into())), - (ArrangementKind::Base, DataSource::Resource("nb".into())), - ( - ArrangementKind::Wide, - DataSource::Resource("us_wide".into()) - ), - ( - ArrangementKind::Base, - DataSource::Resource("us".into()) - ), - ) - ); - } - - #[test] - fn test_preferences_order_overlay() { - let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, Some("terminal"), None); - - assert_eq!( - sources.collect::>(), - vec!( - (ArrangementKind::Base, DataSource::Resource("terminal/nb".into())), - ( - ArrangementKind::Base, - DataSource::Resource("terminal/us".into()) - ), - ) - ); - } - - #[test] - fn test_preferences_order_hint() { - let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Terminal, None, None); - - assert_eq!( - sources.collect::>(), - vec!( - (ArrangementKind::Base, DataSource::Resource("terminal/nb".into())), - ( - ArrangementKind::Base, - DataSource::Resource("terminal/us".into()) - ), - ) - ); - } - #[test] fn unicode_keysym() { let keysym = xkb::keysym_from_name( diff --git a/src/tests.rs b/src/tests.rs index 619ad321..2b5a034d 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,6 +1,6 @@ /*! Testing functionality */ -use ::data::Layout; +use ::data::parsing::Layout; use ::logging; use xkbcommon::xkb; From 99c04fd8f507c7dd752c826a811a55d509fc6f4d Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Mon, 5 Apr 2021 11:09:35 +0000 Subject: [PATCH 2/2] layout: Remove unused code --- src/layout.rs | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/layout.rs b/src/layout.rs index 0b8607b0..810bdf18 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -621,12 +621,6 @@ pub enum LatchedState { Not, } -impl LatchedState { - pub fn is_latched(&self) -> bool { - self != &LatchedState::Not - } -} - // TODO: split into sth like // Arrangement (views) + details (keymap) + State (keys) /// State of the UI, contains the backend as well @@ -776,23 +770,6 @@ impl Layout { } } } - - pub fn get_locked_keys(&self) -> Vec>> { - let mut out = Vec::new(); - let view = self.get_current_view(); - for (_, row) in view.get_rows() { - for (_, button) in &row.buttons { - let locked = { - let state = RefCell::borrow(&button.state).clone(); - state.action.is_locked(&self.current_view) - }; - if locked { - out.push(button.state.clone()); - } - } - } - out - } fn apply_view_transition( &mut self,