use serde::Deserialize;
use serde_xml_rs as xml;
use std::fs::File;
use std::io::{self, BufReader};
const X11_BASE_RULES: &str = "/usr/share/X11/xkb/rules/base.xml";
const X11_EXTRAS_RULES: &str = "/usr/share/X11/xkb/rules/base.extras.xml";
#[derive(Debug, Deserialize, Clone)]
pub struct KeyboardLayouts {
#[serde(rename = "layoutList")]
pub layout_list: LayoutList,
}
impl KeyboardLayouts {
pub fn layouts(&self) -> &[KeyboardLayout] { &self.layout_list.layout }
pub fn layouts_mut(&mut self) -> &mut [KeyboardLayout] { &mut self.layout_list.layout }
}
#[derive(Debug, Deserialize, Clone)]
pub struct LayoutList {
pub layout: Vec<KeyboardLayout>,
}
#[derive(Debug, Deserialize, Clone)]
pub struct KeyboardLayout {
#[serde(rename = "configItem")]
pub config_item: ConfigItem,
#[serde(rename = "variantList")]
pub variant_list: Option<VariantList>,
}
impl KeyboardLayout {
pub fn name(&self) -> &str { &self.config_item.name }
pub fn description(&self) -> &str { &self.config_item.description }
pub fn variants(&self) -> Option<&Vec<KeyboardVariant>> {
self.variant_list.as_ref().and_then(|x| x.variant.as_ref())
}
}
#[derive(Debug, Deserialize, Clone)]
pub struct ConfigItem {
pub name: String,
#[serde(rename = "shortDescription")]
pub short_description: Option<String>,
pub description: String,
}
#[derive(Debug, Deserialize, Clone)]
pub struct VariantList {
pub variant: Option<Vec<KeyboardVariant>>,
}
#[derive(Debug, Deserialize, Clone)]
pub struct KeyboardVariant {
#[serde(rename = "configItem")]
pub config_item: ConfigItem,
}
impl KeyboardVariant {
pub fn name(&self) -> &str { &self.config_item.name }
pub fn description(&self) -> &str { &self.config_item.description }
}
pub fn get_keyboard_layouts(path: &str) -> io::Result<KeyboardLayouts> {
xml::from_reader(BufReader::new(File::open(path)?))
.map_err(|why| io::Error::new(io::ErrorKind::InvalidData, format!("{}", why)))
}
pub fn keyboard_layouts() -> io::Result<KeyboardLayouts> {
get_keyboard_layouts(X11_BASE_RULES)
}
pub fn extra_keyboard_layouts() -> io::Result<KeyboardLayouts> {
get_keyboard_layouts(X11_EXTRAS_RULES)
}
pub fn all_keyboard_layouts() -> io::Result<KeyboardLayouts> {
let base_rules = keyboard_layouts();
let extras_rules = extra_keyboard_layouts();
match (base_rules, extras_rules,) {
(Ok(base_rules), Ok(extras_rules)) => return Ok(merge_rules(base_rules, extras_rules)),
(Err(why), _) => return Err(io::Error::new(io::ErrorKind::InvalidData, format!("{}", why))),
(_, Err(why)) => return Err(io::Error::new(io::ErrorKind::InvalidData, format!("{}", why))),
}
}
fn merge_rules(base: KeyboardLayouts, extras: KeyboardLayouts) -> KeyboardLayouts {
KeyboardLayouts {
layout_list: concat_layout_lists(vec![base.layout_list, extras.layout_list])
}
}
fn concat_layout_lists(layouts: Vec<LayoutList>) -> LayoutList {
let mut new_layouts = vec![];
for layout_list in layouts.into_iter() {
new_layouts.extend(layout_list.layout);
}
return LayoutList { layout: new_layouts }
}