kll_compiler/
types.rs

1use layouts_rs::{Layout, Layouts};
2use std::collections::HashMap;
3use std::fmt;
4use std::ops::Range;
5use std::str::FromStr;
6
7pub type Index = Range<usize>;
8pub type Indices = Vec<Index>;
9pub type Map<'a> = HashMap<&'a str, &'a str>;
10
11#[derive(Debug, Clone)]
12pub enum Error {
13    UnknownMatch { s: String },
14}
15
16pub fn format_indices(ranges: &[Index]) -> String {
17    ranges
18        .iter()
19        .map(|range| format!("{}-{}", range.start, range.end))
20        .collect::<Vec<_>>()
21        .join(", ")
22}
23
24pub fn maybe_quote(text: &str) -> String {
25    if text.contains(' ') {
26        format!("\"{}\"", text)
27    } else {
28        text.to_string()
29    }
30}
31
32#[derive(Debug, Clone)]
33pub struct Mapping<'a>(pub TriggerList<'a>, pub TriggerMode, pub ResultList<'a>);
34
35impl<'a> Mapping<'a> {
36    pub fn implied_state(&self) -> Option<Vec<Self>> {
37        // TODO Handle other combinations of implied state
38        if let Some(triggerlists) = self.0.implied_state() {
39            if let Some(resultlists) = self.2.implied_state() {
40                // TODO Allow for other combinations other than just simple cases
41                if triggerlists.len() == 2 && resultlists.len() == 2 {
42                    Some(vec![
43                        Self(
44                            triggerlists[0].clone(),
45                            self.1.clone(),
46                            resultlists[0].clone(),
47                        ),
48                        Self(
49                            triggerlists[1].clone(),
50                            self.1.clone(),
51                            resultlists[1].clone(),
52                        ),
53                    ])
54                } else {
55                    None
56                }
57            } else {
58                None
59            }
60        } else {
61            None
62        }
63    }
64}
65
66impl<'a> fmt::Display for Mapping<'a> {
67    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68        write!(f, "{} {} {}", self.0, self.1, self.2)
69    }
70}
71
72/// Intermediate data structure used as a hashable key
73#[derive(Debug, Clone, PartialEq, Eq, Hash)]
74pub struct TriggerConditionList(pub Vec<Vec<kll_core::TriggerCondition>>);
75
76#[derive(Debug, Clone)]
77pub struct TriggerList<'a>(pub Vec<Vec<Trigger<'a>>>);
78
79impl<'a> TriggerList<'a> {
80    pub fn iter(&self) -> impl Iterator<Item = &Trigger> + '_ {
81        self.0.iter().flatten()
82    }
83
84    /// Converts the TriggerList into a kll-core trigger guide
85    /// NOTE: The result of this type is *not* safely hashable
86    ///       as the binary format can change due to internal rust
87    ///       behaviour. Please use kll_core_capability_guide instead.
88    pub fn kll_core_guide(&self) -> Vec<u8> {
89        let mut buf = Vec::new();
90        for combo in &self.0 {
91            // Push the length of the combo
92            buf.push(combo.len() as u8);
93            // Push each combo element
94            for elem in combo {
95                unsafe {
96                    buf.extend_from_slice(elem.kll_core_condition().bytes());
97                }
98            }
99        }
100        // Push final 0-length combo to indicate sequence has finished
101        buf.push(0);
102        buf
103    }
104
105    /// Converts the TriggerList into a kll-core result capability guide
106    /// This type is safely hashable
107    pub fn kll_core_condition_guide(&self) -> TriggerConditionList {
108        let mut sequence_buf = Vec::new();
109        for combo in &self.0 {
110            let mut combo_buf = Vec::new();
111            // Push each combo element
112            for elem in combo {
113                combo_buf.push(elem.kll_core_condition());
114            }
115            sequence_buf.push(combo_buf);
116        }
117        TriggerConditionList(sequence_buf)
118    }
119
120    fn implied_state(&self) -> Option<Vec<Self>> {
121        // TODO
122        // Return permutations of implied TriggerList states
123        // TODO
124        // S1 : U"A"; => S1(P) : U"A"(P); S1(R) : U"A"(R);
125        assert!(
126            self.0.len() == 1,
127            "TriggerList must only have 1 sequence element. (may not be implemented yet)"
128        );
129        assert!(
130            self.0[0].len() == 1,
131            "TriggerList must only have 1 combo element. (feature may not be implemented yet)"
132        );
133        self.0[0][0].implied_state().map(|triggers| {
134            vec![
135                Self(vec![vec![triggers[0].clone()]]),
136                Self(vec![vec![triggers[1].clone()]]),
137            ]
138        })
139    }
140}
141
142impl<'a> fmt::Display for TriggerList<'a> {
143    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144        write!(
145            f,
146            "{}",
147            self.0
148                .iter()
149                .map(|combo| combo
150                    .iter()
151                    .map(|t| format!("{}", t))
152                    .collect::<Vec<_>>()
153                    .join(" + "))
154                .collect::<Vec<_>>()
155                .join(", ")
156        )
157    }
158}
159
160/// Intermediate data structure used as a hashable key
161#[derive(Debug, Clone, PartialEq, Eq, Hash)]
162pub struct ResultCapabilitiesList(pub Vec<Vec<kll_core::Capability>>);
163
164#[derive(Debug, Clone)]
165pub struct ResultList<'a>(pub Vec<Vec<Action<'a>>>);
166
167impl<'a> ResultList<'a> {
168    pub fn iter(&self) -> impl Iterator<Item = &Action> + '_ {
169        self.0.iter().flatten()
170    }
171
172    /// Converts the ResultList into a kll-core result guide
173    /// NOTE: The result of this type is *not* safely hashable
174    ///       as the binary format can change due to internal rust
175    ///       behaviour. Please use kll_core_capability_guide instead.
176    pub fn kll_core_guide(&self, layouts: &mut Layouts) -> Vec<u8> {
177        let mut buf = Vec::new();
178        for combo in &self.0 {
179            // Push the length of the combo
180            buf.push(combo.len() as u8);
181            // Push each combo element
182            for elem in combo {
183                unsafe {
184                    buf.extend_from_slice(elem.kll_core_condition(layouts).bytes());
185                }
186            }
187        }
188        // Push final 0-length combo to indicate sequence has finished
189        buf.push(0);
190        buf
191    }
192
193    /// Converts the ResultList into a kll-core result capability guide
194    /// This type is safely hashable
195    pub fn kll_core_capability_guide(&self, layouts: &mut Layouts) -> ResultCapabilitiesList {
196        let mut sequence_buf = Vec::new();
197        for combo in &self.0 {
198            let mut combo_buf = Vec::new();
199            // Push each combo element
200            for elem in combo {
201                combo_buf.push(elem.kll_core_condition(layouts));
202            }
203            sequence_buf.push(combo_buf);
204        }
205        ResultCapabilitiesList(sequence_buf)
206    }
207
208    fn implied_state(&self) -> Option<Vec<Self>> {
209        // TODO
210        // Return permutations of implied ResultList states
211        // TODO
212        // S1 : U"A"; => S1(P) : U"A"(P); S1(R) : U"A"(R);
213        assert!(
214            self.0.len() == 1,
215            "ResultList must only have 1 sequence element. (may not be implemented yet)"
216        );
217        assert!(
218            self.0[0].len() == 1,
219            "ResultList must only have 1 combo element. (feature may not be implemented yet)"
220        );
221        let results = self.0[0][0].implied_state().unwrap();
222        Some(vec![
223            Self(vec![vec![results[0].clone()]]),
224            Self(vec![vec![results[1].clone()]]),
225        ])
226    }
227}
228
229impl<'a> fmt::Display for ResultList<'a> {
230    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231        write!(
232            f,
233            "{}",
234            self.0
235                .iter()
236                .map(|combo| combo
237                    .iter()
238                    .map(|t| format!("{}", t))
239                    .collect::<Vec<_>>()
240                    .join(" + "))
241                .collect::<Vec<_>>()
242                .join(", ")
243        )
244    }
245}
246
247#[derive(Debug, Clone)]
248pub enum Statement<'a> {
249    Define((&'a str, &'a str)),
250    Variable((&'a str, Option<usize>, &'a str)),
251    Capability((&'a str, Capability<'a>)),
252    Keymap(Mapping<'a>),
253    Position((Indices, Position)),
254    Pixelmap((Indices, PixelDef)),
255    Animation((&'a str, Animation<'a>)),
256    Frame((&'a str, Indices, Vec<Pixel<'a>>)),
257    NOP,
258}
259
260impl<'a> fmt::Display for Statement<'a> {
261    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
262        match self {
263            Self::Define((name, val)) => write!(f, "{} = {};", name, maybe_quote(val)),
264            Self::Variable((name, index, val)) => {
265                if let Some(index) = index {
266                    write!(
267                        f,
268                        "{}[{}] = {};",
269                        maybe_quote(name),
270                        index,
271                        maybe_quote(val)
272                    )
273                } else {
274                    write!(f, "{} = {};", maybe_quote(name), maybe_quote(val))
275                }
276            }
277            Self::Capability((name, cap)) => write!(f, "{} = {};", name, cap),
278            Self::Keymap(mapping) => write!(f, "{};", mapping),
279            Self::Position((indices, pos)) => {
280                write!(f, "P[{}] <= {};", format_indices(indices), pos)
281            }
282            Self::Pixelmap((indices, map)) => write!(
283                f,
284                "P[{}]{} : {};",
285                format_indices(indices),
286                map.channels
287                    .iter()
288                    .map(|(c, w)| format!("{}:{}", c, w))
289                    .collect::<Vec<String>>()
290                    .join(", "),
291                map.scancode
292                    .map(|x| format!("S{}", x))
293                    .unwrap_or_else(|| "None".to_string())
294            ),
295            Self::Animation((name, anim)) => write!(f, "A[{}] <= {:?};", name, anim.modifiers),
296            Self::Frame((name, indices, frame)) => write!(
297                f,
298                "A[{}, {}] <= {:?};",
299                name,
300                format_indices(indices),
301                frame
302            ),
303            Self::NOP => Ok(()),
304        }
305    }
306}
307
308#[derive(Debug, Default, Clone, Merge)]
309pub struct Position {
310    pub x: f32,  // mm
311    pub y: f32,  // mm
312    pub z: f32,  // mm
313    pub rx: f32, // deg
314    pub ry: f32, // deg
315    pub rz: f32, // deg
316}
317
318impl Position {
319    pub fn from_map(map: Map) -> Self {
320        let mut pos = Position::default();
321        for (k, v) in map.iter() {
322            let v = v.parse::<f32>().unwrap();
323            match *k {
324                "x" => pos.x = v,
325                "y" => pos.y = v,
326                "z" => pos.z = v,
327                "rx" => pos.rx = v,
328                "ry" => pos.ry = v,
329                "rz" => pos.rz = v,
330                _ => {}
331            }
332        }
333
334        pos
335    }
336}
337
338impl fmt::Display for Position {
339    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
340        if self.x != 0. {
341            write!(f, "x:{}", self.x)?;
342        }
343        if self.y != 0. {
344            write!(f, "y:{}", self.y)?;
345        }
346        if self.z != 0. {
347            write!(f, "z:{}", self.z)?;
348        }
349        if self.rx != 0. {
350            write!(f, "x:{}", self.rx)?;
351        }
352        if self.ry != 0. {
353            write!(f, "y:{}", self.ry)?;
354        }
355        if self.rz != 0. {
356            write!(f, "z:{}", self.rz)?;
357        }
358        Ok(())
359    }
360}
361
362#[derive(Debug, Default, Clone, Merge)]
363pub struct PixelDef {
364    #[combine]
365    pub channels: Vec<(usize, usize)>,
366    pub scancode: Option<usize>,
367}
368
369impl PixelDef {
370    pub fn new(channelmap: Map, scancode: Option<usize>) -> Self {
371        let channels = channelmap
372            .iter()
373            .map(|(k, v)| {
374                let k = k.parse::<usize>().unwrap();
375                let v = v.parse::<usize>().unwrap();
376                (k, v)
377            })
378            .collect::<Vec<_>>();
379
380        PixelDef { scancode, channels }
381    }
382}
383
384#[derive(Debug, Default, Clone)]
385pub struct Animation<'a> {
386    pub modifiers: Map<'a>,
387    pub frames: Vec<Vec<Pixel<'a>>>,
388}
389
390#[derive(Debug, Default, PartialEq, Eq, Hash, Clone)]
391pub struct Capability<'a> {
392    pub function: &'a str,
393    //pub args: Map<'a>, // XXX: Can't hash a HashMap
394    pub args: Vec<&'a str>,
395}
396
397impl<'a> Capability<'a> {
398    pub fn new(function: &'a str, args: Vec<&'a str>) -> Self {
399        Capability { function, args }
400    }
401}
402
403impl<'a> fmt::Display for Capability<'a> {
404    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
405        write!(
406            f,
407            "{}({:?})",
408            self.function,
409            self.args
410                .iter()
411                .map(|arg| arg.to_string())
412                .collect::<Vec<_>>()
413                .join(", ")
414        )
415    }
416}
417
418#[derive(Debug, PartialEq, Eq, Hash, Clone)]
419pub enum LayerMode {
420    Normal,
421    Shift,
422    Latch,
423    Lock,
424}
425
426impl FromStr for LayerMode {
427    type Err = Error;
428
429    fn from_str(s: &str) -> Result<Self, Self::Err> {
430        Ok(match s {
431            "Layer" => Self::Normal,
432            "LayerShift" => Self::Shift,
433            "LayerLatch" => Self::Latch,
434            "LayerLock" => Self::Lock,
435            _ => {
436                return Err(Error::UnknownMatch { s: s.to_string() });
437            }
438        })
439    }
440}
441
442impl fmt::Display for LayerMode {
443    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
444        match self {
445            Self::Normal => write!(f, "Layer"),
446            Self::Shift => write!(f, "LayerShift"),
447            Self::Latch => write!(f, "LayerLatch"),
448            Self::Lock => write!(f, "LayerLock"),
449        }
450    }
451}
452
453#[derive(Debug, PartialEq, Eq, Hash, Clone)]
454pub enum TriggerType<'a> {
455    Key(Key<'a>),
456    Layer((LayerMode, Indices)),
457    Indicator(Indices),
458    Generic((usize, usize, Option<usize>)),
459    Animation(&'a str),
460}
461
462impl<'a> fmt::Display for TriggerType<'a> {
463    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
464        match self {
465            Self::Key(trigger) => write!(f, "{}", trigger),
466            Self::Layer((mode, layer)) => write!(f, "{}[{}]", mode, format_indices(layer)),
467            Self::Indicator(indicators) => {
468                if indicators.len() > 1 {
469                    write!(f, "I[{}]", format_indices(indicators))
470                } else {
471                    write!(f, "I{}", format_indices(indicators))
472                }
473            }
474            Self::Generic((bank, index, param)) => {
475                if let Some(param) = &param {
476                    write!(f, "T[{}, {}]({})", bank, index, param)
477                } else {
478                    write!(f, "T[{}, {}]", bank, index)
479                }
480            }
481            Self::Animation(name) => write!(f, "A[{}]", name),
482        }
483    }
484}
485
486#[derive(Debug, PartialEq, Eq, Hash, Clone)]
487pub struct Trigger<'a> {
488    pub trigger: TriggerType<'a>,
489    pub state: Option<StateMap>,
490}
491
492impl<'a> Trigger<'a> {
493    /// Converts to a kll-core TriggerCondition
494    ///
495    /// If no scheduling is defined, automatically generate
496    /// state scheduling parameters.
497    /// e.g. For S1 : U"A";
498    ///         S1(P) : U"A"(P);
499    ///         S1(R) : U"A"(R);
500    /// kll-core does not automatically deduce states like the original
501    /// controller firmware did.
502    /// TODO ^ Use a kll-compiler function to automatically duplicate so we don't have to do it
503    /// here.
504    pub fn kll_core_condition(&self) -> kll_core::TriggerCondition {
505        // State must be defined
506        // generate_state_scheduling() function can be used to compute if
507        // it's not defined.
508        assert!(self.state.is_some(), "state *must* be defined, use generate_state_scheduling() to convert implied state into implicit state.");
509        assert!(self.state.as_ref().unwrap().states.len() == 1, "StateMap *must* only have a single state defined, need to expand into a sequence first.");
510
511        match &self.trigger {
512            TriggerType::Key(key) => {
513                match key {
514                    Key::Scancode(index) => {
515                        kll_core::TriggerCondition::Switch {
516                            state: self.state.as_ref().unwrap().states[0].kind.phro(),
517                            index: *index as u16,
518                            loop_condition_index: 0, // TODO
519                        }
520                    }
521                    // NOTE: Only Scancodes are valid here
522                    //       The compiler should have turned everything
523                    //       into scancodes at this point.
524                    _ => kll_core::TriggerCondition::None,
525                }
526            }
527            TriggerType::Layer((_mode, _indices)) => {
528                panic!("Missing Layer");
529                /*
530                kll_core::TriggerCondition::Layer {
531                    state: kll_core::trigger::LayerState::ShiftActivate, // TODO compute
532                    loop_condition_index: 0,                             // TODO
533                    layer: 0,                                            // TODO
534                }
535                */
536            }
537            TriggerType::Indicator(_indices) => {
538                panic!("Missing indicator");
539                /*
540                kll_core::TriggerCondition::HidLed {
541                    state: kll_core::trigger::Aodo::Activate, // TODO compute
542                    loop_condition_index: 0,                  // TODO
543                    index: 0,                                 // TODO
544                }
545                */
546            }
547            TriggerType::Generic((_bank, _index, _param)) => {
548                panic!("Missing Generic");
549                // TODO
550                //kll_core::TriggerCondition::None
551            }
552            TriggerType::Animation(_name) => {
553                panic!("Missing Animation");
554                /*
555                kll_core::TriggerCondition::Animation {
556                    state: kll_core::trigger::Dro::Done, // TODO compute
557                    index: 0,                            // TODO
558                    loop_condition_index: 0,             // TODO
559                }
560                */
561            }
562        }
563    }
564
565    /// Generates state scheduling from implied state
566    /// Converts S1 : U"A"; to (trigger part)
567    ///    S1(P) : U"A"(P);
568    ///    S1(R) : U"A"(R);
569    fn implied_state(&self) -> Option<Vec<Self>> {
570        // No state (implied state), generate new triggers
571        if self.state.is_none() {
572            Some(vec![
573                Self {
574                    trigger: self.trigger.clone(),
575                    state: Some(StateMap::new(vec![State {
576                        kind: StateType::Press,
577                        time: None,
578                    }])),
579                },
580                Self {
581                    trigger: self.trigger.clone(),
582                    state: Some(StateMap::new(vec![State {
583                        kind: StateType::Release,
584                        time: None,
585                    }])),
586                },
587            ])
588        } else {
589            None
590        }
591    }
592}
593
594impl<'a> fmt::Display for Trigger<'a> {
595    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
596        if let Some(state) = &self.state {
597            write!(f, "{}({})", self.trigger, state)
598        } else {
599            write!(f, "{}", self.trigger)
600        }
601    }
602}
603
604#[derive(Debug, PartialEq, Eq, Hash, Clone)]
605pub struct State {
606    pub kind: StateType,
607    pub time: Option<usize>,
608}
609
610impl fmt::Display for State {
611    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
612        if let Some(time) = self.time {
613            write!(f, "{}:{}", self.kind, time)
614        } else {
615            write!(f, "{}", self.kind)
616        }
617    }
618}
619
620#[derive(Debug, Default, PartialEq, Eq, Hash, Clone)]
621pub struct StateMap {
622    pub states: Vec<State>,
623}
624
625impl StateMap {
626    pub fn new(states: Vec<State>) -> Self {
627        Self { states }
628    }
629
630    pub fn from_map(map: Map) -> Result<Self, Error> {
631        let mut states = vec![];
632        for (k, v) in map.iter() {
633            let mut state = State {
634                kind: StateType::from_str(k)?,
635                time: None,
636            };
637            if let Ok(v) = v.parse::<usize>() {
638                state.time = Some(v);
639            }
640            states.push(state);
641        }
642
643        Ok(StateMap { states })
644    }
645}
646
647impl fmt::Display for StateMap {
648    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
649        write!(
650            f,
651            "{}",
652            self.states
653                .iter()
654                .map(|x| x.to_string())
655                .collect::<Vec<_>>()
656                .join(",")
657        )
658    }
659}
660
661#[derive(Debug, PartialEq, Eq, Hash, Clone)]
662pub enum StateType {
663    // Key
664    Press,         // (P)
665    Hold,          // (H)
666    Release,       // (R)
667    Unpressed,     // (O)
668    UniquePress,   // (UP)
669    UniqueRelease, // (UR)
670    Analog(usize), // 0-100
671
672    // Other
673    Activate,   // (A)
674    On,         // (On)
675    Deactivate, // (D)
676    Off,        // (Off)
677}
678
679impl StateType {
680    /// Converts StateType into a kll_core phro state
681    pub fn phro(&self) -> kll_core::trigger::Phro {
682        match self {
683            StateType::Hold => kll_core::trigger::Phro::Hold,
684            StateType::Off => kll_core::trigger::Phro::Off,
685            StateType::Press => kll_core::trigger::Phro::Press,
686            StateType::Release => kll_core::trigger::Phro::Release,
687            _ => {
688                panic!("Invalid phro StateType: {:?}", self);
689            }
690        }
691    }
692
693    /// Converts StateType into a kll_core CapabilityState
694    pub fn capability_state(&self) -> kll_core::CapabilityState {
695        match self {
696            StateType::Press => kll_core::CapabilityState::Initial,
697            StateType::Release => kll_core::CapabilityState::Last,
698            _ => {
699                panic!("{:?} not implemented/unsupported", self);
700            }
701        }
702    }
703}
704
705impl FromStr for StateType {
706    type Err = Error;
707
708    fn from_str(s: &str) -> Result<Self, Self::Err> {
709        Ok(match s {
710            // Key
711            "P" => Self::Press,
712            "H" => Self::Hold,
713            "R" => Self::Release,
714            "O" => Self::Unpressed,
715            "UP" => Self::UniquePress,
716            "UR" => Self::UniqueRelease,
717
718            // Other
719            "A" => Self::Activate,
720            "On" => Self::On,
721            "D" => Self::Deactivate,
722            "Off" => Self::Off,
723            _ => {
724                return Err(Error::UnknownMatch { s: s.to_string() });
725            }
726        })
727    }
728}
729
730impl fmt::Display for StateType {
731    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
732        match self {
733            // Key
734            Self::Press => write!(f, "P"),
735            Self::Hold => write!(f, "H"),
736            Self::Release => write!(f, "R"),
737            Self::Unpressed => write!(f, "O"),
738            Self::UniquePress => write!(f, "UP"),
739            Self::UniqueRelease => write!(f, "UR"),
740            Self::Analog(v) => write!(f, "{}", v),
741
742            // Other
743            Self::Activate => write!(f, "A"),
744            Self::On => write!(f, "On"),
745            Self::Deactivate => write!(f, "D"),
746            Self::Off => write!(f, "Off"),
747        }
748    }
749}
750
751#[derive(Debug, PartialEq, Eq, Hash, Clone)]
752pub enum Key<'a> {
753    Scancode(usize),
754    Char(&'a str),
755    Usb(&'a str),
756    Consumer(&'a str),
757    System(&'a str),
758    Unicode(&'a str),
759    None,
760}
761
762/// Converts from string to int, returing None if None was passed as the input
763fn parse_int_option(input: Option<&String>) -> Option<usize> {
764    use crate::parser::parse_int;
765    input.map(|val| parse_int(val))
766}
767
768impl<'a> Key<'a> {
769    pub fn value(&self, layout: &Layout) -> Option<usize> {
770        match self {
771            Key::Scancode(num) => Some(*num),
772            Key::Char(c) => parse_int_option(layout.from_hid_keyboard.get(*c)),
773            Key::Usb(name) => parse_int_option(layout.from_hid_keyboard.get(*name)),
774            Key::Consumer(name) => parse_int_option(layout.from_hid_consumer.get(*name)),
775            Key::System(name) => parse_int_option(layout.from_hid_sysctrl.get(*name)),
776            Key::Unicode(_) => None, // xxx
777            Key::None => None,
778        }
779    }
780}
781
782impl<'a> fmt::Display for Key<'a> {
783    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
784        match self {
785            Key::Scancode(num) => write!(f, "S{}", num),
786            Key::Char(num) => write!(f, "'{}'", num),
787            Key::Usb(name) => write!(f, "U\"{}\"", name),
788            Key::Consumer(name) => write!(f, "CONS\"{}\"", name),
789            Key::System(name) => write!(f, "SYS\"{}\"", name),
790            Key::Unicode(name) => write!(f, "U+{}", name),
791            Key::None => write!(f, "None"),
792        }
793    }
794}
795
796#[derive(Debug, PartialEq, Eq, Hash, Clone)]
797pub enum ResultType<'a> {
798    Output(Key<'a>),
799    Layer((LayerMode, Indices)),
800    Animation(AnimationResult<'a>),
801    Pixel(Pixel<'a>),
802    PixelLayer(Pixel<'a>),
803    Capability((Capability<'a>, Option<StateMap>)),
804    Text(&'a str),
805    UnicodeText(&'a str),
806    NOP,
807}
808
809impl<'a> fmt::Display for ResultType<'a> {
810    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
811        match self {
812            Self::Output(trigger) => write!(f, "{}", trigger),
813            Self::Layer((mode, layers)) => write!(f, "{}[{}]", mode, format_indices(layers)),
814            Self::Animation(trigger) => write!(f, "{}", trigger),
815            Self::Pixel(trigger) => write!(f, "{}", trigger),
816            Self::PixelLayer(trigger) => write!(f, "{}", trigger),
817            Self::Capability((trigger, state)) => {
818                if let Some(state) = state {
819                    write!(f, "{}({})", trigger, state)
820                } else {
821                    write!(f, "{}", trigger)
822                }
823            }
824            Self::Text(text) => write!(f, "\"{}\"", text),
825            Self::UnicodeText(text) => write!(f, "u\"{}\"", text),
826            Self::NOP => write!(f, "None"),
827        }
828    }
829}
830
831#[derive(Debug, PartialEq, Eq, Hash, Clone)]
832pub struct Action<'a> {
833    pub result: ResultType<'a>,
834    pub state: Option<StateMap>,
835}
836
837impl<'a> Action<'a> {
838    /// Converts to a kll-core Capability definition
839    pub fn kll_core_condition(&self, layouts: &mut Layouts) -> kll_core::Capability {
840        // State must be defined
841        // generate_state_scheduling() function can be used to compute if
842        // it's not defined.
843        assert!(self.state.is_some(), "state *must* be defined, use generate_state_scheduling() to convert implied state into implicit state.");
844        assert!(self.state.as_ref().unwrap().states.len() == 1, "StateMap *must* only have a single state defined, need to expand into a sequence first.");
845
846        let layout = layouts.get_layout("base/base.json");
847        match &self.result {
848            ResultType::Output(key) => {
849                let id = match key.value(&layout) {
850                    Some(id) => id,
851                    None => {
852                        panic!("{:?} doesn't match a USB HID key.", key);
853                    }
854                };
855                match key {
856                    Key::Usb(_value) => {
857                        kll_core::Capability::HidKeyboard {
858                            state: self.state.as_ref().unwrap().states[0]
859                                .kind
860                                .capability_state(),
861                            loop_condition_index: 0, // TODO
862                            id: kll_core::kll_hid::Keyboard::from(id as u16),
863                        }
864                    }
865                    _ => kll_core::Capability::NoOp {
866                        state: kll_core::CapabilityState::None,
867                        loop_condition_index: 0,
868                    },
869                }
870            }
871            ResultType::Layer((_mode, _indices)) => {
872                panic!("Incomplete {:?}", &self.result);
873            }
874            ResultType::Animation(_animation_result) => {
875                panic!("Incomplete {:?}", &self.result);
876            }
877            ResultType::Capability((_capability, _state)) => {
878                panic!("Incomplete {:?}", &self.result);
879            }
880            ResultType::Text(_text) => {
881                panic!("Incomplete {:?}", &self.result);
882            }
883            ResultType::UnicodeText(_text) => {
884                panic!("Incomplete {:?}", &self.result);
885            }
886            ResultType::NOP => kll_core::Capability::NoOp {
887                state: kll_core::CapabilityState::None,
888                loop_condition_index: 0,
889            },
890            _ => {
891                panic!("Incomplete {:?}", &self.result);
892            }
893        }
894    }
895
896    /// Generates state scheduling from implied state
897    /// Converts S1 : U"A"; to (action/result part)
898    ///    S1(P) : U"A"(P);
899    ///    S1(R) : U"A"(R);
900    fn implied_state(&self) -> Option<Vec<Self>> {
901        // No state (implied state), generate new actions
902        if self.state.is_none() {
903            Some(vec![
904                Self {
905                    result: self.result.clone(),
906                    state: Some(StateMap::new(vec![State {
907                        kind: StateType::Press,
908                        time: None,
909                    }])),
910                },
911                Self {
912                    result: self.result.clone(),
913                    state: Some(StateMap::new(vec![State {
914                        kind: StateType::Release,
915                        time: None,
916                    }])),
917                },
918            ])
919        } else {
920            None
921        }
922    }
923}
924
925impl<'a> fmt::Display for Action<'a> {
926    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
927        if let Some(state) = &self.state {
928            write!(f, "{}:{}", self.result, state)
929        } else {
930            write!(f, "{}", self.result)
931        }
932    }
933}
934
935#[derive(Debug, PartialEq, Eq, Hash, Clone)]
936pub enum TriggerMode {
937    Replace,            // :
938    SoftReplace,        // ::
939    Add,                // :+
940    Remove,             // :-
941    IsolateReplace,     // i:
942    IsolateSoftReplace, // i::
943    IsolateAdd,         // i:+
944    IsolateRemove,      // i:-
945}
946
947impl FromStr for TriggerMode {
948    type Err = Error;
949
950    fn from_str(s: &str) -> Result<Self, Self::Err> {
951        Ok(match s {
952            ":" => Self::Replace,
953            "::" => Self::SoftReplace,
954            ":+" => Self::Add,
955            ":-" => Self::Remove,
956            "i:" => Self::IsolateReplace,
957            "i::" => Self::IsolateSoftReplace,
958            "i:+" => Self::IsolateAdd,
959            "i:-" => Self::IsolateRemove,
960            _ => {
961                return Err(Error::UnknownMatch { s: s.to_string() });
962            }
963        })
964    }
965}
966
967impl fmt::Display for TriggerMode {
968    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
969        match self {
970            Self::Replace => write!(f, ":"),
971            Self::SoftReplace => write!(f, "::"),
972            Self::Add => write!(f, ":+"),
973            Self::Remove => write!(f, ":-"),
974            Self::IsolateReplace => write!(f, "i:"),
975            Self::IsolateSoftReplace => write!(f, "i::"),
976            Self::IsolateAdd => write!(f, "i:+"),
977            Self::IsolateRemove => write!(f, "i:-"),
978        }
979    }
980}
981
982#[derive(Debug, PartialEq, Eq, Hash, Clone)]
983pub enum PixelAddr {
984    Absolute(usize),
985    RelativeInt(usize),
986    RelativePercent(usize),
987}
988
989impl FromStr for PixelAddr {
990    type Err = <usize as FromStr>::Err;
991
992    fn from_str(s: &str) -> Result<Self, Self::Err> {
993        Ok(PixelAddr::Absolute(s.parse::<usize>()?))
994    }
995}
996
997impl fmt::Display for PixelAddr {
998    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
999        match self {
1000            Self::Absolute(v) => write!(f, "{}", v),
1001            Self::RelativeInt(v) => write!(f, "{:+}", v),
1002            Self::RelativePercent(v) => write!(f, "{:+}%", v),
1003        }
1004    }
1005}
1006
1007#[derive(Debug, Default, PartialEq, Eq, Hash, Clone)]
1008pub struct PixelRange<'a> {
1009    pub index: Option<PixelAddr>,
1010    pub row: Option<PixelAddr>,
1011    pub col: Option<PixelAddr>,
1012    pub key: Option<Key<'a>>,
1013}
1014
1015impl<'a> PixelRange<'a> {
1016    pub fn from_map(map: Map) -> Result<Self, <usize as FromStr>::Err> {
1017        let mut pos = PixelRange::default();
1018        for (k, v) in map.iter() {
1019            match *k {
1020                "i" => pos.index = Some(PixelAddr::from_str(v)?),
1021                "r" => pos.row = Some(PixelAddr::from_str(v)?),
1022                "c" => pos.col = Some(PixelAddr::from_str(v)?),
1023                _ => {}
1024            }
1025        }
1026
1027        Ok(pos)
1028    }
1029}
1030
1031impl<'a> fmt::Display for PixelRange<'a> {
1032    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1033        if let Some(index) = &self.index {
1034            write!(f, "{}", index)?;
1035        }
1036        if let Some(row) = &self.row {
1037            write!(f, "r:{}", row)?;
1038        }
1039        if let Some(col) = &self.col {
1040            write!(f, "c:{}", col)?;
1041        }
1042        Ok(())
1043    }
1044}
1045
1046#[derive(Debug, PartialEq, Eq, Hash, Clone)]
1047pub struct AnimationResult<'a> {
1048    pub name: &'a str,
1049    pub args: Vec<&'a str>,
1050}
1051
1052impl<'a> fmt::Display for AnimationResult<'a> {
1053    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1054        write!(f, "A[{}]({})", self.name, self.args.join(", "))
1055    }
1056}
1057
1058#[derive(Debug, Default, PartialEq, Eq, Hash, Clone)]
1059pub struct Pixel<'a> {
1060    pub range: PixelRange<'a>,
1061    pub channel_values: Vec<PixelColor>,
1062}
1063
1064impl<'a> fmt::Display for Pixel<'a> {
1065    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1066        write!(
1067            f,
1068            "P[{}]({})",
1069            self.range,
1070            self.channel_values
1071                .iter()
1072                .map(|x| x.to_string())
1073                .collect::<Vec<String>>()
1074                .join(", ")
1075        )
1076    }
1077}
1078
1079#[derive(Debug, PartialEq, Eq, Hash, Clone)]
1080pub enum PixelColor {
1081    Rgb(usize),
1082    Relative(isize),
1083    RelativeNoRoll(isize),
1084    Shift(isize),
1085}
1086
1087impl fmt::Display for PixelColor {
1088    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1089        match self {
1090            Self::Rgb(v) => write!(f, "{}", v),
1091            Self::Relative(v) => write!(f, "{:+}", v),
1092            Self::RelativeNoRoll(v) => write!(f, ":{:+}", v),
1093            Self::Shift(v) => write!(f, "<{:+}", v),
1094        }
1095    }
1096}
1097
1098#[derive(Debug, Default, Clone)]
1099pub struct KllFile<'a> {
1100    pub statements: Vec<Statement<'a>>,
1101}
1102
1103impl<'a> fmt::Display for KllFile<'a> {
1104    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1105        for statement in &self.statements {
1106            writeln!(f, "{}", statement)?;
1107        }
1108        Ok(())
1109    }
1110}