use { crate::{ config::{ Shortcut, context::Context, extractor::{Extractor, ExtractorError, opt, recover, str, val}, parser::{DataType, ParseResult, Parser, UnexpectedDataType}, parsers::shortcuts::{ComplexShortcutsParser, ShortcutsParser, ShortcutsParserError}, spanned::SpannedErrorExt, }, toml::{ toml_span::{DespanExt, Span, Spanned}, toml_value::Value, }, }, ahash::{AHashMap, AHashSet}, indexmap::IndexMap, std::collections::HashSet, thiserror::Error, }; #[derive(Debug, Error)] pub enum InputModeParserError { #[error(transparent)] Expected(#[from] UnexpectedDataType), #[error(transparent)] ExtractorError(#[from] ExtractorError), #[error("Could not parse the shortcuts")] ParseShortcuts(#[source] ShortcutsParserError), } #[derive(Clone, Debug)] pub struct InputMode { pub parent: Option, pub shortcuts: Vec, } pub struct InputModesParser<'a>(pub &'a Context<'a>); impl Parser for InputModesParser<'_> { type Value = AHashMap; type Error = InputModeParserError; const EXPECTED: &'static [DataType] = &[DataType::Table]; fn parse_table( &mut self, _span: Span, table: &IndexMap, Spanned>, ) -> ParseResult { let mut modes = AHashMap::new(); let mut used = AHashSet::new(); for (key, value) in table.iter() { let mode = match value.parse(&mut InputModeParser(self.0)) { Ok(m) => m, Err(e) => { log::warn!( "Could not parse input mode {}: {}", key.value, self.0.error(e) ); continue; } }; log_used(self.0, &mut used, key); modes.insert(key.value.to_string(), mode); } Ok(modes) } } pub struct InputModeParser<'a>(pub &'a Context<'a>); impl Parser for InputModeParser<'_> { type Value = InputMode; type Error = InputModeParserError; const EXPECTED: &'static [DataType] = &[DataType::Table]; fn parse_table( &mut self, span: Span, table: &IndexMap, Spanned>, ) -> ParseResult { let mut ext = Extractor::new(self.0, span, table); let (parent, shortcuts_val, complex_shortcuts_val) = ext.extract(( recover(opt(str("parent"))), opt(val("shortcuts")), opt(val("complex-shortcuts")), ))?; let mut used_keys = HashSet::new(); let mut shortcuts = vec![]; if let Some(value) = shortcuts_val { value .parse(&mut ShortcutsParser { cx: self.0, used_keys: &mut used_keys, shortcuts: &mut shortcuts, }) .map_spanned_err(InputModeParserError::ParseShortcuts)?; } if let Some(value) = complex_shortcuts_val { value .parse(&mut ComplexShortcutsParser { cx: self.0, used_keys: &mut used_keys, shortcuts: &mut shortcuts, }) .map_spanned_err(InputModeParserError::ParseShortcuts)?; } Ok(InputMode { parent: parent.despan_into(), shortcuts, }) } } fn log_used(cx: &Context<'_>, used: &mut AHashSet>, key: &Spanned) { if let Some(prev) = used.get(key) { log::warn!( "Duplicate input mode overrides previous definition: {}", cx.error3(key.span) ); log::info!("Previous definition here: {}", cx.error3(prev.span)); } used.insert(key.clone()); }