kbvm 0.1.5

An implementation of the XKB specification
Documentation
use {
    crate::{
        Keycode, Keysym, ModifierIndex, ModifierMask,
        builder::Redirect,
        xkb::{
            controls::ControlMask,
            group::{GroupChange, GroupIdx, GroupMask},
            group_component::GroupComponent,
            indicator::IndicatorIdx,
            interner::Interned,
            keymap::KeyOverlay,
            level::Level,
            mod_component::ModComponentMask,
            modmap::{ModifierTree, Vmodmap},
            radio_group::RadioGroup,
            span::{Span, Spanned},
        },
    },
    hashbrown::{DefaultHashBuilder, HashMap},
    indexmap::IndexMap,
    linearize::Linearize,
    smallvec::SmallVec,
};

#[derive(Debug)]
pub(crate) struct Resolved {
    pub(crate) name: Option<Spanned<Interned>>,
    pub(crate) mods: Vmodmap,
    pub(crate) keycodes: ResolvedKeycodes,
    pub(crate) types: ResolvedTypes,
    pub(crate) compat: ResolvedCompat,
    pub(crate) symbols: ResolvedSymbols,
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub(crate) struct Filter {
    pub(crate) predicate: Predicate,
    pub(crate) mask: Spanned<ModifierMask>,
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub(crate) enum Predicate {
    NoneOf,
    AnyOfOrNone,
    AnyOf,
    AllOf,
    Exactly,
}

#[derive(Default, Debug)]
pub(crate) struct ResolvedKeycodes {
    pub(crate) indicators: Vec<Indicator>,
    pub(crate) keycode_to_name: HashMap<Keycode, Interned>,
    pub(crate) name_to_key: HashMap<Interned, ResolvedKey>,
}

#[derive(Debug)]
pub(crate) struct ResolvedKey {
    pub(crate) name: Spanned<Interned>,
    pub(crate) kind: ResolvedKeyKind,
}

#[derive(Copy, Clone, Debug)]
pub(crate) enum ResolvedKeyKind {
    Real(Spanned<Keycode>),
    Alias(Spanned<Interned>, Keycode, Option<Spanned<Interned>>),
}

#[derive(Debug)]
pub(crate) struct Indicator {
    pub(crate) idx: Spanned<IndicatorIdx>,
    pub(crate) name: Spanned<Interned>,
    pub(crate) virt: Option<Span>,
}

#[derive(Default, Debug)]
pub(crate) struct ResolvedTypes {
    pub(crate) default: ResolvedKeyType,
    pub(crate) key_types: HashMap<Interned, ResolvedKeyTypeWithName>,
}

#[derive(Clone, Debug)]
pub(crate) struct ResolvedKeyTypeWithName {
    pub(crate) name: Spanned<Interned>,
    pub(crate) ty: ResolvedKeyType,
}

#[derive(Clone, Default, Debug)]
pub(crate) struct ResolvedKeyType {
    pub(crate) modifiers: Option<Spanned<ModifierTree>>,
    pub(crate) map: Vec<(ModifierTree, Spanned<Level>)>,
    pub(crate) preserved: Vec<(ModifierTree, Spanned<ModifierTree>)>,
    pub(crate) map_preserve: Vec<(ModifierMask, Spanned<Level>, Option<Spanned<ModifierMask>>)>,
    pub(crate) names: HashMap<Level, Spanned<Interned>>,
    pub(crate) num_levels: usize,
}

#[derive(Default, Debug)]
pub(crate) struct ResolvedCompat {
    pub(crate) interp_default: Interp,
    pub(crate) interps:
        IndexMap<(Option<Keysym>, Option<Filter>), InterpWithKey, DefaultHashBuilder>,
    pub(crate) interps_sorted: Vec<InterpWithKey>,
    pub(crate) indicator_map_default: IndicatorMap,
    pub(crate) indicator_maps: IndexMap<Interned, IndicatorMapWithKey, DefaultHashBuilder>,
    pub(crate) action_defaults: ActionDefaults,
}

#[derive(Default, Debug)]
pub(crate) struct ActionDefaults {
    pub(crate) no_action: ResolvedNoAction,
    pub(crate) void_action: ResolvedVoidAction,
    pub(crate) mods_set: ResolvedModsSet,
    pub(crate) mods_latch: ResolvedModsLatch,
    pub(crate) mods_lock: ResolvedModsLock,
    pub(crate) group_set: ResolvedGroupSet,
    pub(crate) group_latch: ResolvedGroupLatch,
    pub(crate) group_lock: ResolvedGroupLock,
    pub(crate) redirect_key: ResolvedRedirectKey,
    pub(crate) set_controls: ResolvedSetControls,
    pub(crate) lock_controls: ResolvedLockControls,
}

#[derive(Debug)]
pub(crate) struct InterpWithKey {
    pub(crate) keysym: Option<Spanned<Keysym>>,
    pub(crate) filter: Option<Spanned<Filter>>,
    pub(crate) interp: Interp,
    pub(crate) version: u64,
}

#[derive(Clone, Default, Debug)]
pub(crate) struct Interp {
    pub(crate) actions: Option<Spanned<SmallVec<[Spanned<ResolvedAction>; 1]>>>,
    pub(crate) virtual_modifier: Option<Spanned<ModifierIndex>>,
    pub(crate) repeat: Option<Spanned<bool>>,
    pub(crate) level_one_only: Option<Spanned<bool>>,
    pub(crate) locking: Option<Spanned<bool>>,
}

impl Interp {
    pub(crate) fn level_one_only(&self) -> bool {
        self.level_one_only.map(|l| l.val).unwrap_or_default()
    }
}

#[derive(Debug)]
pub(crate) struct IndicatorMapWithKey {
    pub(crate) name: Spanned<Interned>,
    pub(crate) indicator_map: IndicatorMap,
}

#[derive(Clone, Default, Debug)]
pub(crate) struct IndicatorMap {
    pub(crate) idx: Option<IndicatorIdx>,
    pub(crate) virt: bool,
    pub(crate) modifiers: Option<Spanned<ModifierTree>>,
    pub(crate) groups: Option<Spanned<GroupMask>>,
    pub(crate) controls: Option<Spanned<ControlMask>>,
    pub(crate) which_modifier_state: Option<Spanned<ModComponentMask>>,
    pub(crate) which_group_state: Option<Spanned<GroupComponent>>,
}

#[derive(Default, Clone, Debug)]
pub(crate) struct SymbolsKey {
    pub(crate) groups: Vec<SymbolsKeyGroup>,
    pub(crate) default_key_type: Option<Spanned<KeyTypeRef>>,
    pub(crate) virtualmodifiers: Option<Spanned<ModifierMask>>,
    pub(crate) repeating: Option<Spanned<Option<bool>>>,
    pub(crate) groups_redirect: Option<Spanned<GroupsRedirect>>,
    pub(crate) modmap: ModifierMask,
    pub(crate) behavior: Option<Spanned<SymbolsKeyBehavior>>,
    pub(crate) allow_none: u32,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub(crate) enum SymbolsKeyBehavior {
    Locks(bool),
    Overlay((KeyOverlay, Interned, Keycode)),
    RadioGroup(bool, RadioGroup),
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub(crate) enum GroupsRedirect {
    Wrap,
    Clamp,
    Redirect(GroupIdx),
}

#[derive(Default, Clone, Debug)]
pub(crate) struct SymbolsKeyGroup {
    pub(crate) levels: Vec<SymbolsKeyLevel>,
    pub(crate) reachable_levels: usize,
    pub(crate) key_type: Option<KeyTypeRef>,
    pub(crate) has_explicit_symbols: bool,
    pub(crate) has_explicit_actions: bool,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Linearize)]
pub(crate) enum BuiltInKeytype {
    OneLevel,
    Alphabetic,
    Keypad,
    TwoLevel,
    FourLevelAlphabetic,
    FourLevelSemialphabetic,
    FourLevelKeypad,
    FourLevel,
}

impl BuiltInKeytype {
    pub(crate) const fn name(self) -> &'static str {
        match self {
            BuiltInKeytype::OneLevel => "ONE_LEVEL",
            BuiltInKeytype::Alphabetic => "ALPHABETIC",
            BuiltInKeytype::Keypad => "KEYPAD",
            BuiltInKeytype::TwoLevel => "TWO_LEVEL",
            BuiltInKeytype::FourLevelAlphabetic => "FOUR_LEVEL_ALPHABETIC",
            BuiltInKeytype::FourLevelSemialphabetic => "FOUR_LEVEL_SEMIALPHABETIC",
            BuiltInKeytype::FourLevelKeypad => "FOUR_LEVEL_KEYPAD",
            BuiltInKeytype::FourLevel => "FOUR_LEVEL",
        }
    }
}

#[derive(Copy, Clone, Debug)]
pub(crate) enum KeyTypeRef {
    BuiltIn(BuiltInKeytype),
    Named(Spanned<Interned>),
}

#[derive(Default, Clone, Debug)]
pub(crate) struct SymbolsKeyLevel {
    pub(crate) symbols: SmallVec<[Spanned<Keysym>; 1]>,
    pub(crate) actions: SmallVec<[Spanned<ResolvedAction>; 1]>,
}

#[derive(Debug)]
pub(crate) struct SymbolsKeyWithKey {
    pub(crate) name: Spanned<Interned>,
    pub(crate) code: Keycode,
    pub(crate) key: SymbolsKey,
}

#[derive(Debug)]
pub(crate) struct ModMapEntryWithKey {
    pub(crate) key: Spanned<ModMapField>,
    pub(crate) modifier: Option<Spanned<ModifierIndex>>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub(crate) enum ModMapField {
    Keysym(Keysym, Option<Keycode>),
    Keycode(Keycode),
}

#[derive(Default, Debug)]
pub(crate) struct ResolvedSymbols {
    pub(crate) mod_map_entries: IndexMap<ModMapField, ModMapEntryWithKey, DefaultHashBuilder>,
    pub(crate) action_defaults: ActionDefaults,
    pub(crate) key_default: SymbolsKey,
    pub(crate) keys: HashMap<Keycode, SymbolsKeyWithKey>,
    pub(crate) group_names: Vec<Option<(GroupIdx, Spanned<Interned>)>>,
}

#[expect(clippy::enum_variant_names)]
#[derive(Clone, Debug)]
pub(crate) enum ResolvedAction {
    ResolvedNoAction(ResolvedNoAction),
    ResolvedVoidAction(ResolvedVoidAction),
    ResolvedModsSet(ResolvedModsSet),
    ResolvedModsLatch(ResolvedModsLatch),
    ResolvedModsLock(ResolvedModsLock),
    ResolvedGroupSet(ResolvedGroupSet),
    ResolvedGroupLatch(ResolvedGroupLatch),
    ResolvedGroupLock(ResolvedGroupLock),
    ResolvedRedirectKey(ResolvedRedirectKey),
    ResolvedSetControls(ResolvedSetControls),
    ResolvedLockControls(ResolvedLockControls),
}

#[derive(Copy, Clone, Debug, Default)]
pub(crate) struct ResolvedNoAction;

#[derive(Copy, Clone, Default, Debug)]
pub(crate) struct ResolvedVoidAction;

#[derive(Clone, Debug)]
pub(crate) enum ResolvedActionMods {
    ModMap,
    Explicit(ModifierTree),
}

#[derive(Copy, Clone, Debug)]
pub(crate) struct ResolvedActionAffect {
    pub(crate) lock: bool,
    pub(crate) unlock: bool,
}

#[derive(Clone, Default, Debug)]
pub(crate) struct ResolvedModsSet {
    pub(crate) clear_locks: Option<Spanned<bool>>,
    pub(crate) modifiers: Option<Spanned<ResolvedActionMods>>,
}

#[derive(Clone, Default, Debug)]
pub(crate) struct ResolvedModsLatch {
    pub(crate) clear_locks: Option<Spanned<bool>>,
    pub(crate) latch_to_lock: Option<Spanned<bool>>,
    pub(crate) modifiers: Option<Spanned<ResolvedActionMods>>,
}

#[derive(Clone, Default, Debug)]
pub(crate) struct ResolvedModsLock {
    pub(crate) modifiers: Option<Spanned<ResolvedActionMods>>,
    pub(crate) affect: Option<Spanned<ResolvedActionAffect>>,
}

#[derive(Copy, Clone, Default, Debug)]
pub(crate) struct ResolvedGroupSet {
    pub(crate) group: Option<Spanned<GroupChange>>,
    pub(crate) clear_locks: Option<Spanned<bool>>,
}

#[derive(Copy, Clone, Default, Debug)]
pub(crate) struct ResolvedGroupLatch {
    pub(crate) group: Option<Spanned<GroupChange>>,
    pub(crate) clear_locks: Option<Spanned<bool>>,
    pub(crate) latch_to_lock: Option<Spanned<bool>>,
}

#[derive(Copy, Clone, Default, Debug)]
pub(crate) struct ResolvedGroupLock {
    pub(crate) group: Option<Spanned<GroupChange>>,
}

impl GroupsRedirect {
    pub(crate) fn to_redirect(self) -> Redirect {
        match self {
            GroupsRedirect::Wrap => Redirect::Wrap,
            GroupsRedirect::Clamp => Redirect::Clamp,
            GroupsRedirect::Redirect(r) => Redirect::Fixed(r.to_offset()),
        }
    }
}

#[derive(Clone, Default, Debug)]
pub(crate) struct ResolvedRedirectKey {
    pub(crate) keycode: Option<Spanned<(Interned, Keycode)>>,
    pub(crate) mods_to_set: Option<Spanned<ResolvedActionMods>>,
    pub(crate) mods_to_clear: Option<Spanned<ResolvedActionMods>>,
}

#[derive(Copy, Clone, Default, Debug)]
pub(crate) struct ResolvedSetControls {
    pub(crate) controls: Option<Spanned<ControlMask>>,
}

#[derive(Copy, Clone, Default, Debug)]
pub(crate) struct ResolvedLockControls {
    pub(crate) controls: Option<Spanned<ControlMask>>,
    pub(crate) affect: Option<Spanned<ResolvedActionAffect>>,
}