1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3
4pub mod combos;
5pub mod dofinitions;
6pub mod interaction;
7pub mod keyboard;
8mod macros;
9pub mod magic;
10pub mod prelude;
11
12use combos::{Combos, ParseCombos};
13use interaction::{KeyPos, Pos};
14use keyboard::{ParseKeyboard, PhysicalKey, PhysicalKeyboard};
15use magic::Magic;
16use serde::{Deserialize, Serialize};
17use serde_with::{serde_as, skip_serializing_none, DisplayFromStr};
18use thiserror::Error;
19
20use std::{collections::BTreeMap, num::ParseFloatError};
21
22use dofinitions::*;
23
24#[serde_as]
43#[skip_serializing_none]
44#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
45#[serde(try_from = "DofIntermediate", into = "DofIntermediate")]
46pub struct Dof {
47 name: String,
48 authors: Option<Vec<String>>,
49 board: PhysicalKeyboard,
50 parsed_board: ParseKeyboard,
51 year: Option<u32>,
52 description: Option<String>,
53 languages: Vec<Language>,
54 link: Option<String>,
55 layers: BTreeMap<String, Layer>,
56 anchor: Anchor,
57 magic: Magic,
58 combos: Combos,
60 fingering: Fingering,
61 fingering_name: Option<NamedFingering>,
62 has_generated_shift: bool,
63}
64
65impl Dof {
66 pub fn name(&self) -> &str {
68 &self.name
69 }
70
71 pub fn authors(&self) -> Option<&[String]> {
73 self.authors.as_deref()
74 }
75
76 pub const fn board(&self) -> &PhysicalKeyboard {
78 &self.board
79 }
80
81 pub fn board_type(&self) -> KeyboardType {
84 match &self.parsed_board {
85 ParseKeyboard::Named(n) => n.clone(),
86 _ => KeyboardType::Custom("".into()),
87 }
88 }
89
90 pub const fn year(&self) -> Option<u32> {
92 self.year
93 }
94
95 pub fn description(&self) -> Option<&str> {
97 self.description.as_deref()
98 }
99
100 pub fn link(&self) -> Option<&str> {
102 self.link.as_deref()
103 }
104
105 pub fn languages(&self) -> &[Language] {
107 &self.languages
108 }
109
110 pub fn layers(&self) -> &BTreeMap<String, Layer> {
112 &self.layers
113 }
114
115 pub const fn anchor(&self) -> Anchor {
118 self.anchor
119 }
120
121 pub fn shape(&self) -> Shape {
123 self.fingering().shape()
124 }
125
126 pub const fn fingering(&self) -> &Fingering {
129 &self.fingering
130 }
131
132 pub fn fingering_name(&self) -> Option<&NamedFingering> {
134 self.fingering_name.as_ref()
135 }
136
137 pub fn main_layer(&self) -> &Layer {
140 self.layers
141 .get("main")
142 .expect("Creating a Dof without a main layer should be impossible")
143 }
144
145 pub fn shift_layer(&self) -> &Layer {
148 self.layers
149 .get("shift")
150 .expect("Creating a Dof without a shift layer should be impossible")
151 }
152
153 pub fn layer(&self, name: &str) -> Option<&Layer> {
155 self.layers.get(name)
156 }
157
158 pub fn keys(&self) -> Vec<DescriptiveKey> {
161 self.layers()
162 .iter()
163 .flat_map(|(name, layer)| {
164 layer
165 .rows()
166 .enumerate()
167 .zip(self.fingering.rows())
168 .zip(self.board.rows())
169 .flat_map(move |(((row, key_row), finger_row), phys_row)| {
170 key_row
171 .iter()
172 .enumerate()
173 .zip(finger_row)
174 .zip(phys_row)
175 .map(move |(((col, key), &finger), phys)| {
176 DescriptiveKey::new(key, name, row, col, finger, phys)
177 })
178 })
179 })
180 .collect()
181 }
182}
183
184impl TryFrom<DofIntermediate> for Dof {
185 type Error = DofError;
186
187 fn try_from(mut inter: DofIntermediate) -> std::result::Result<Self, Self::Error> {
188 let main_layer = inter.main_layer()?;
189
190 inter.validate_layer_keys(main_layer)?;
191 inter.validate_layer_shapes(main_layer)?;
192
193 let explicit_fingering = inter.explicit_fingering(main_layer)?;
194 let implicit_fingering = match inter.fingering.clone().unwrap_or_default() {
195 ParsedFingering::Implicit(f) => Some(f),
196 _ => None,
197 };
198
199 let has_generated_shift = if !inter.layers.contains_key("shift") {
200 inter.layers.insert(
201 "shift".into(),
202 DofIntermediate::generate_shift_layer(main_layer),
203 );
204 true
205 } else {
206 false
207 };
208
209 let anchor = match inter.anchor {
210 None => inter.board.anchor(),
211 Some(a) => a,
212 };
213
214 let board = PhysicalKeyboard::try_from(inter.board.clone())?
215 .resized(anchor, explicit_fingering.shape())?
216 .into_iter()
217 .map(|v| {
218 v.into_iter()
219 .map(PhysicalKey::normalized)
220 .collect::<Vec<_>>()
221 })
222 .collect::<Vec<_>>()
223 .into();
224
225 let languages = match inter.languages {
226 Some(l) => l
227 .into_iter()
228 .map(|(lang, weight)| Language::new(&lang, weight))
229 .collect::<Vec<_>>(),
230 None => vec![Language::default()],
231 };
232
233 let combos = match inter.combos {
234 Some(combos) => combos.into_pos_layers(&inter.layers)?,
235 None => Default::default(),
236 };
240
241 let magic = inter.magic.unwrap_or_default();
242
243 Ok(Self {
244 name: inter.name,
245 authors: inter.authors,
246 board,
247 parsed_board: inter.board,
248 year: inter.year,
249 description: inter.description,
250 languages,
251 link: inter.link,
252 layers: inter.layers,
253 anchor,
254 magic,
255 combos,
256 fingering: explicit_fingering,
257 fingering_name: implicit_fingering,
258 has_generated_shift,
259 })
260 }
261}
262
263impl From<Dof> for DofIntermediate {
264 fn from(mut dof: Dof) -> DofIntermediate {
265 if dof.has_generated_shift {
266 dof.layers.remove("shift");
267 }
268
269 let fingering = dof
270 .fingering_name
271 .map(ParsedFingering::Implicit)
272 .unwrap_or(ParsedFingering::Explicit(dof.fingering));
273
274 let fingering = if fingering == ParsedFingering::default() {
275 None
276 } else {
277 Some(fingering)
278 };
279
280 let languages = match dof.languages.as_slice() {
281 [lang] if lang == &Language::default() => None,
282 _ => Some(
283 dof.languages
284 .into_iter()
285 .map(|l| (l.language, l.weight))
286 .collect(),
287 ),
288 };
289
290 let anchor = match &dof.parsed_board {
291 ParseKeyboard::Named(n) => match n.anchor() {
292 a if a == dof.anchor => None,
293 a => Some(a),
294 },
295 _ => None,
296 };
297
298 let magic = match dof.magic.is_empty() {
299 false => Some(dof.magic),
300 true => None,
301 };
302
303 let combos = dof.combos.into_parse_combos(&dof.layers);
304
305 DofIntermediate {
306 name: dof.name,
307 authors: dof.authors,
308 board: dof.parsed_board,
309 year: dof.year,
310 description: dof.description,
311 languages,
312 link: dof.link,
313 layers: dof.layers,
314 anchor,
315 magic,
316 combos,
317 fingering,
318 }
319 }
320}
321
322#[derive(Debug, Error, PartialEq)]
323enum DofErrorInner {
324 #[error("This layout is missing a main layer")]
325 NoMainLayer,
326 #[error("Found these layer keys '{0:?}' however these layers do not actually exist")]
327 LayersNotFound(Vec<String>),
328 #[error("The shape of these layers: '{0:?}' are not the same as the main layer")]
329 IncompatibleLayerShapes(Vec<String>),
330 #[error("The layer shapes do not match the fingering shape")]
331 IncompatibleFingeringShape,
332 #[error("The provided layout + anchor don't fit within the given fingering")]
333 LayoutDoesntFit,
334 #[error("The anchor provided is bigger than the layout it is used for")]
335 AnchorBiggerThanLayout,
336 #[error("Combo key provided is empty. If this was intended, provide `~` instead.")]
337 EmptyComboKey,
338
339 #[error("Layer {0} containing combo {1} does not exist")]
340 UnknownComboLayer(String, String),
341 #[error("Combo {0} references key {1} at index {2}, which doesn't exist")]
342 InvalidKeyIndex(String, String, usize),
343
344 #[error("Couldn't parse Finger from '{0}'")]
345 FingerParseError(String),
346 #[error("Can't combine keyboard type '{0}' with fingering '{1}'")]
347 UnsupportedKeyboardFingeringCombo(KeyboardType, NamedFingering),
348 #[error("Default fingering only exists for known keyboards: ansi, iso, ortho and colstag")]
349 FingeringForCustomKeyboard,
350
351 #[error("Couldn't parse physical key from '{0}' because a float couldn't be parsed")]
352 KeyParseError(String),
353 #[error("Couldn't parse physical key because the string is empty")]
354 EmptyPhysKey,
355 #[error("Expected 2, 3 or 4 values in physical key definition, found {0} for '{1}'")]
356 ValueAmountError(usize, String),
357 #[error("Keyboard type '{0}' does not match a default physical keyboard.")]
358 UnknownKeyboardType(KeyboardType),
359
360 #[error("the provided layer name '{0}' is invalid")]
361 LayerDoesntExist(String),
362 #[error("the given position ({0}, {1}) is not available on the keyboard")]
363 InvalidPosition(u8, u8),
364
365 #[error("{0}")]
366 Infallible(#[from] std::convert::Infallible),
367 #[error("{0}")]
368 ParseFloatError(#[from] std::num::ParseFloatError),
369 #[error("{0}")]
370 ParseIntError(#[from] std::num::ParseIntError),
371
372 #[error("{0}")]
373 Custom(String),
374}
375
376use DofErrorInner as DErr;
377
378type Result<T> = std::result::Result<T, DofError>;
379
380#[derive(Debug, Error, PartialEq)]
383#[error("{0}")]
384pub struct DofError(#[source] Box<DofErrorInner>);
385
386impl DofError {
387 pub fn custom(msg: &str) -> Self {
389 DofError(Box::new(DErr::Custom(msg.into())))
390 }
391}
392
393impl From<DofErrorInner> for DofError {
394 fn from(value: DofErrorInner) -> Self {
395 Self(Box::new(value))
396 }
397}
398
399impl From<ParseFloatError> for DofError {
400 fn from(value: ParseFloatError) -> Self {
401 DErr::ParseFloatError(value).into()
402 }
403}
404
405#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
411pub struct Language {
412 pub language: String,
414 pub weight: usize,
417}
418
419impl Default for Language {
420 fn default() -> Self {
421 Language {
422 language: "English".into(),
423 weight: 100,
424 }
425 }
426}
427
428impl Language {
429 pub fn new(language: &str, weight: usize) -> Self {
431 let language = language.into();
432 Self { language, weight }
433 }
434
435 pub fn only(language: &str) -> Self {
438 Self {
439 language: language.into(),
440 weight: 100,
441 }
442 }
443}
444
445pub trait Keyboard {
449 type K: Clone;
451
452 fn rows(&self) -> impl Iterator<Item = &Vec<Self::K>> {
454 self.inner().iter()
455 }
456
457 fn keys(&self) -> impl Iterator<Item = &Self::K> {
459 self.rows().flatten()
460 }
461
462 fn shape(&self) -> Shape {
464 self.rows().map(|r| r.len()).collect::<Vec<_>>().into()
465 }
466
467 fn row_count(&self) -> usize {
469 self.rows().count()
470 }
471
472 fn inner(&self) -> &[Vec<Self::K>];
474
475 fn into_inner(self) -> Vec<Vec<Self::K>>;
477
478 fn fits_in(&self, shape: &Shape) -> bool {
481 self.shape().fits_in(shape)
482 }
483
484 fn resized(&self, Anchor(x, y): Anchor, desired_shape: Shape) -> Result<Vec<Vec<Self::K>>> {
487 let (offset_x, offset_y) = (x as usize, y as usize);
488
489 let anchor_resized = self
490 .inner()
491 .get(offset_y..)
492 .ok_or(DErr::AnchorBiggerThanLayout)?
493 .iter()
494 .map(|r| r.get(offset_x..).ok_or(DErr::AnchorBiggerThanLayout.into()))
495 .collect::<Result<Vec<_>>>()?;
496
497 anchor_resized
498 .into_iter()
499 .zip(desired_shape.into_inner())
500 .map(|(row, shape_size)| {
501 row.get(..shape_size)
502 .ok_or(DErr::LayoutDoesntFit.into())
503 .map(|v| v.to_vec())
504 })
505 .collect::<Result<Vec<_>>>()
506 .map(Into::into)
507 }
508}
509
510#[serde_as]
512#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
513pub struct Fingering(#[serde_as(as = "Vec<FingeringStrAsRow>")] Vec<Vec<Finger>>);
514
515impl Keyboard for Fingering {
516 type K = Finger;
517
518 fn inner(&self) -> &[Vec<Self::K>] {
519 &self.0
520 }
521
522 fn into_inner(self) -> Vec<Vec<Self::K>> {
523 self.0
524 }
525}
526
527impl From<Vec<Vec<Finger>>> for Fingering {
528 fn from(f: Vec<Vec<Finger>>) -> Self {
529 Self(f)
530 }
531}
532
533keyboard_conv!(Finger, FingeringStrAsRow);
534
535#[serde_as]
538#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
539#[serde(untagged)]
540pub enum ParsedFingering {
541 Explicit(Fingering),
543 Implicit(#[serde_as(as = "DisplayFromStr")] NamedFingering),
546}
547
548impl Default for ParsedFingering {
549 fn default() -> Self {
550 Self::Implicit(Default::default())
551 }
552}
553
554#[serde_as]
556#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
557pub struct Layer(#[serde_as(as = "Vec<LayerStrAsRow>")] Vec<Vec<Key>>);
558
559impl Keyboard for Layer {
560 type K = Key;
561
562 fn inner(&self) -> &[Vec<Self::K>] {
563 &self.0
564 }
565
566 fn into_inner(self) -> Vec<Vec<Self::K>> {
567 self.0
568 }
569}
570
571impl From<Vec<Vec<Key>>> for Layer {
572 fn from(f: Vec<Vec<Key>>) -> Self {
573 Self(f)
574 }
575}
576
577keyboard_conv!(Key, LayerStrAsRow);
578
579#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
585pub struct Anchor(u8, u8);
586
587impl Anchor {
588 pub const fn new(x: u8, y: u8) -> Self {
590 Anchor(x, y)
591 }
592
593 pub const fn x(&self) -> usize {
595 self.0 as usize
596 }
597
598 pub const fn y(&self) -> usize {
600 self.1 as usize
601 }
602}
603
604#[derive(Clone, Debug, PartialEq)]
606pub struct DescriptiveKey<'a> {
607 output: &'a Key,
608 layer: &'a str,
609 pos: Pos,
610 finger: Finger,
611 phys: &'a PhysicalKey,
612}
613
614impl<'a> DescriptiveKey<'a> {
615 fn new(
617 output: &'a Key,
618 layer: &'a str,
619 row: usize,
620 col: usize,
621 finger: Finger,
622 physical_pos: &'a PhysicalKey,
623 ) -> Self {
624 let pos = Pos::new(row, col);
625 Self {
626 output,
627 layer,
628 pos,
629 finger,
630 phys: physical_pos,
631 }
632 }
633
634 pub fn keypos(&self) -> KeyPos {
637 KeyPos::new(self.layer, self.pos)
638 }
639
640 pub const fn pos(&self) -> Pos {
642 self.pos
643 }
644
645 pub const fn row(&self) -> usize {
647 self.pos.row()
648 }
649
650 pub const fn col(&self) -> usize {
652 self.pos.col()
653 }
654
655 pub const fn finger(&self) -> Finger {
657 self.finger
658 }
659
660 pub const fn output(&self) -> &Key {
662 self.output
663 }
664
665 pub const fn physical_pos(&self) -> &PhysicalKey {
667 self.phys
668 }
669
670 pub fn layer_name(&self) -> &str {
672 self.layer
673 }
674
675 pub const fn is_on_finger(&self, finger: Finger) -> bool {
677 (self.finger as u8) == (finger as u8)
678 }
679
680 pub fn is_on_fingers(&self, fingers: &[Finger]) -> bool {
682 fingers.iter().any(|f| self.finger == *f)
683 }
684
685 pub const fn is_on_left_hand(&self) -> bool {
687 self.finger.is_on_left_hand()
688 }
689
690 pub const fn is_on_right_hand(&self) -> bool {
692 self.finger.is_on_right_hand()
693 }
694
695 pub fn is_on_layer(&self, layer: &str) -> bool {
697 self.layer == layer
698 }
699
700 pub const fn is_char_key(&self) -> bool {
703 self.output.is_char()
704 }
705
706 pub const fn is_word_key(&self) -> bool {
709 self.output.is_word()
710 }
711
712 pub const fn is_empty_key(&self) -> bool {
715 self.output.is_empty()
716 }
717
718 pub const fn is_transparent_key(&self) -> bool {
721 self.output.is_transparent()
722 }
723
724 pub const fn is_layer_key(&self) -> bool {
727 self.output.is_layer()
728 }
729
730 pub const fn char_output(&self) -> Option<char> {
732 self.output.char_output()
733 }
734
735 pub fn word_output(&self) -> Option<&str> {
737 self.output.word_output()
738 }
739
740 pub fn layer_output(&self) -> Option<&str> {
742 self.output.layer_label()
743 }
744
745 pub fn magic_label(&self) -> Option<&str> {
747 self.output.magic_label()
748 }
749}
750
751#[allow(missing_docs)]
755#[serde_as]
756#[skip_serializing_none]
757#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
758pub struct DofIntermediate {
759 pub name: String,
760 pub authors: Option<Vec<String>>,
761 pub board: ParseKeyboard,
762 pub year: Option<u32>,
763 pub description: Option<String>,
764 pub languages: Option<BTreeMap<String, usize>>,
765 pub link: Option<String>,
766 pub layers: BTreeMap<String, Layer>,
767 pub anchor: Option<Anchor>,
768 pub magic: Option<Magic>,
769 pub combos: Option<ParseCombos>,
771 pub fingering: Option<ParsedFingering>,
772}
773
774impl DofIntermediate {
775 pub fn main_layer(&self) -> Result<&Layer> {
777 self.layers.get("main").ok_or(DErr::NoMainLayer.into())
778 }
779
780 pub fn generate_shift_layer(main: &Layer) -> Layer {
790 main.0
791 .iter()
792 .map(|row| row.iter().map(|k| k.shifted()).collect::<Vec<_>>())
793 .collect::<Vec<_>>()
794 .into()
795 }
796
797 pub fn validate_layer_keys(&self, main: &Layer) -> Result<()> {
800 let layers_dont_exist = main
801 .keys()
802 .filter_map(|k| match k {
803 Key::Layer { label: n } if !self.layers.contains_key(n) => Some(n.clone()),
804 _ => None,
805 })
806 .collect::<Vec<_>>();
807
808 if layers_dont_exist.is_empty() {
809 Ok(())
810 } else {
811 Err(DErr::LayersNotFound(layers_dont_exist).into())
812 }
813 }
814
815 pub fn validate_layer_shapes(&self, main: &Layer) -> Result<()> {
817 let main_shape = main.shape();
818
819 let incompatible_shapes = self
820 .layers
821 .iter()
822 .map(|(name, l)| (name, l.shape()))
823 .filter(|(_, shape)| shape != &main_shape)
824 .map(|(name, _)| name.clone())
825 .collect::<Vec<_>>();
826
827 if incompatible_shapes.is_empty() {
828 Ok(())
829 } else {
830 Err(DErr::IncompatibleLayerShapes(incompatible_shapes).into())
831 }
832 }
833
834 pub fn explicit_fingering(&self, main: &Layer) -> Result<Fingering> {
838 use ParsedFingering::*;
839
840 let d = Default::default();
841 let fingering = match &self.fingering {
842 Some(f) => f,
843 None => &d,
844 };
845
846 match fingering {
847 Explicit(f) if f.shape() == main.shape() => Ok(f.clone()),
848 Explicit(_) => Err(DErr::IncompatibleFingeringShape.into()),
849 Implicit(named) => {
850 let fingering = self.board.fingering(named)?;
851
852 let anchor = match self.anchor {
853 Some(a) => a,
854 None => self.board.anchor(),
855 };
856
857 fingering.resized(anchor, main.shape()).map(Into::into)
858 }
859 }
860 }
861}
862
863#[cfg(test)]
864mod tests {
865 use keyboard::{RelativeKey, RelativeKeyboard};
866
867 use crate::magic::MagicKey;
868
869 use super::*;
870
871 #[test]
872 fn no_main_layer() {
873 let minimal_test = DofIntermediate {
874 name: "Qwerty".into(),
875 authors: None,
876 board: ParseKeyboard::Named(KeyboardType::Ansi),
877 year: None,
878 description: None,
879 languages: Default::default(),
880 link: None,
881 anchor: None,
882 layers: BTreeMap::new(),
883 fingering: Some(ParsedFingering::Implicit(NamedFingering::Angle)),
884 combos: None,
885 magic: None,
886 };
887
888 let v = Dof::try_from(minimal_test);
889
890 assert_eq!(v, Err(DofError::from(DErr::NoMainLayer)));
891 }
892
893 #[test]
894 fn parse_minimal() {
895 let minimal_json = include_str!("../example_dofs/minimal_parsable.dof");
896
897 let minimal_test = DofIntermediate {
898 name: "Qwerty".into(),
899 authors: None,
900 board: ParseKeyboard::Named(KeyboardType::Ansi),
901 year: None,
902 description: None,
903 languages: None,
904 link: None,
905 anchor: None,
906 layers: BTreeMap::new(),
907 fingering: None,
908 combos: None,
909 magic: None,
910 };
911
912 let dof_minimal = serde_json::from_str::<DofIntermediate>(minimal_json)
913 .expect("couldn't parse implicit json");
914
915 assert_eq!(dof_minimal, minimal_test);
916 }
917
918 #[test]
919 fn minimal_succesful_dof() {
920 use Finger::*;
921 use Key::*;
922
923 let minimal_json = include_str!("../example_dofs/minimal_valid.dof");
924
925 let d = serde_json::from_str::<Dof>(minimal_json).expect("Couldn't serialize as Dof");
926
927 let d_manual = Dof {
928 name: "Qwerty".into(),
929 authors: None,
930 board: PhysicalKeyboard::try_from(ParseKeyboard::Named(KeyboardType::Ansi))
931 .unwrap()
932 .resized(KeyboardType::Ansi.anchor(), vec![10, 11, 10].into())
933 .unwrap()
934 .into(),
935 parsed_board: ParseKeyboard::Named(KeyboardType::Ansi),
936 year: None,
937 description: None,
938 languages: vec![Default::default()],
939 link: None,
940 anchor: Anchor::new(1, 1),
941 layers: BTreeMap::from_iter([
942 (
943 "main".into(),
944 vec![
945 vec![
946 Char('q'),
947 Char('w'),
948 Char('e'),
949 Char('r'),
950 Char('t'),
951 Char('y'),
952 Char('u'),
953 Char('i'),
954 Char('o'),
955 Char('p'),
956 ],
957 vec![
958 Char('a'),
959 Char('s'),
960 Char('d'),
961 Char('f'),
962 Char('g'),
963 Char('h'),
964 Char('j'),
965 Char('k'),
966 Char('l'),
967 Char(';'),
968 Char('\''),
969 ],
970 vec![
971 Char('z'),
972 Char('x'),
973 Char('c'),
974 Char('v'),
975 Char('b'),
976 Char('n'),
977 Char('m'),
978 Char(','),
979 Char('.'),
980 Char('/'),
981 ],
982 ]
983 .into(),
984 ),
985 (
986 "shift".into(),
987 Layer(vec![
988 vec![
989 Char('Q'),
990 Char('W'),
991 Char('E'),
992 Char('R'),
993 Char('T'),
994 Char('Y'),
995 Char('U'),
996 Char('I'),
997 Char('O'),
998 Char('P'),
999 ],
1000 vec![
1001 Char('A'),
1002 Char('S'),
1003 Char('D'),
1004 Char('F'),
1005 Char('G'),
1006 Char('H'),
1007 Char('J'),
1008 Char('K'),
1009 Char('L'),
1010 Char(':'),
1011 Char('\"'),
1012 ],
1013 vec![
1014 Char('Z'),
1015 Char('X'),
1016 Char('C'),
1017 Char('V'),
1018 Char('B'),
1019 Char('N'),
1020 Char('M'),
1021 Char('<'),
1022 Char('>'),
1023 Char('?'),
1024 ],
1025 ]),
1026 ),
1027 ]),
1028 combos: Default::default(),
1029 magic: Default::default(),
1030 fingering: {
1031 vec![
1032 vec![LP, LR, LM, LI, LI, RI, RI, RM, RR, RP],
1033 vec![LP, LR, LM, LI, LI, RI, RI, RM, RR, RP, RP],
1034 vec![LR, LM, LI, LI, LI, RI, RI, RM, RR, RP],
1035 ]
1036 .into()
1037 },
1038 fingering_name: Some(NamedFingering::Angle),
1039 has_generated_shift: true,
1040 };
1041
1042 assert_eq!(d, d_manual);
1043
1044 let reconvert_json =
1045 serde_json::to_string_pretty(&d).expect("Couldn't reconvert to json value");
1046
1047 println!("{reconvert_json}")
1048 }
1049
1050 #[test]
1051 fn parse_aptmak() {
1052 use Finger::*;
1053 use Key::*;
1054
1055 let aptmak_json = include_str!("../example_dofs/aptmak.dof");
1056
1057 let d = serde_json::from_str::<Dof>(aptmak_json).expect("Couldn't serialize as Dof");
1058
1059 let d_manual = Dof {
1060 name: "Aptmak".into(),
1061 authors: None,
1062 board: PhysicalKeyboard::try_from(ParseKeyboard::Named(KeyboardType::Colstag))
1063 .unwrap()
1064 .resized(KeyboardType::Colstag.anchor(), vec![10, 10, 10, 6].into())
1065 .unwrap()
1066 .into(),
1067 parsed_board: ParseKeyboard::Named(KeyboardType::Colstag),
1068 year: None,
1069 description: None,
1070 languages: vec![Default::default()],
1071 link: None,
1072 anchor: KeyboardType::Colstag.anchor(),
1073 layers: BTreeMap::from_iter([
1074 (
1075 "main".into(),
1076 vec![
1077 vec![
1078 Char('v'),
1079 Char('w'),
1080 Char('f'),
1081 Char('p'),
1082 Char('b'),
1083 Char('j'),
1084 Char('l'),
1085 Char('u'),
1086 Char('y'),
1087 Char('\''),
1088 ],
1089 vec![
1090 Char('r'),
1091 Char('s'),
1092 Char('t'),
1093 Char('h'),
1094 Char('k'),
1095 Char('x'),
1096 Char('n'),
1097 Char('a'),
1098 Char('i'),
1099 Char('o'),
1100 ],
1101 vec![
1102 Char(';'),
1103 Char('c'),
1104 Char('g'),
1105 Char('d'),
1106 Char('q'),
1107 Char('z'),
1108 Char('m'),
1109 Char(','),
1110 Char('.'),
1111 Char('/'),
1112 ],
1113 vec![
1114 Empty,
1115 Special(SpecialKey::Space),
1116 Empty,
1117 Empty,
1118 Char('e'),
1119 Empty,
1120 ],
1121 ]
1122 .into(),
1123 ),
1124 (
1125 "shift".into(),
1126 vec![
1127 vec![
1128 Char('V'),
1129 Char('W'),
1130 Char('F'),
1131 Char('P'),
1132 Char('B'),
1133 Char('J'),
1134 Char('L'),
1135 Char('U'),
1136 Char('Y'),
1137 Char('"'),
1138 ],
1139 vec![
1140 Char('R'),
1141 Char('S'),
1142 Char('T'),
1143 Char('H'),
1144 Char('K'),
1145 Char('X'),
1146 Char('N'),
1147 Char('A'),
1148 Char('I'),
1149 Char('O'),
1150 ],
1151 vec![
1152 Char(':'),
1153 Char('C'),
1154 Char('G'),
1155 Char('D'),
1156 Char('Q'),
1157 Char('Z'),
1158 Char('M'),
1159 Char('<'),
1160 Char('>'),
1161 Char('?'),
1162 ],
1163 vec![Empty, Transparent, Empty, Empty, Char('E'), Empty],
1164 ]
1165 .into(),
1166 ),
1167 ]),
1168 combos: Default::default(),
1169 magic: Default::default(),
1170 fingering: {
1171 vec![
1172 vec![LP, LR, LM, LI, LI, RI, RI, RM, RR, RP],
1173 vec![LP, LR, LM, LI, LI, RI, RI, RM, RR, RP],
1174 vec![LP, LR, LM, LI, LI, RI, RI, RM, RR, RP],
1175 vec![LT, LT, LT, RT, RT, RT],
1176 ]
1177 .into()
1178 },
1179 fingering_name: Some(NamedFingering::Traditional),
1180 has_generated_shift: true,
1181 };
1182
1183 assert_eq!(d, d_manual);
1184
1185 let reconvert_json =
1186 serde_json::to_string_pretty(&d).expect("Couldn't reconvert to json value");
1187
1188 println!("{reconvert_json}")
1189 }
1190
1191 #[test]
1192 fn maximal_succesful() {
1193 let maximal_json = include_str!("../example_dofs/maximal.dof");
1194
1195 serde_json::from_str::<Dof>(maximal_json).expect("Couldn't parse or validate Dof");
1196 }
1197
1198 #[test]
1199 fn deserialize_minimal() {
1200 let minimal_test = DofIntermediate {
1201 name: "Qwerty".into(),
1202 authors: None,
1203 board: ParseKeyboard::Named(KeyboardType::Ansi),
1204 year: None,
1205 description: None,
1206 languages: None,
1207 link: None,
1208 anchor: None,
1209 layers: BTreeMap::new(),
1210 fingering: Some(ParsedFingering::Implicit(NamedFingering::Angle)),
1211 combos: None,
1212 magic: None,
1213 };
1214
1215 let s = serde_json::to_string_pretty(&minimal_test).unwrap();
1216
1217 println!("{s}")
1218 }
1219
1220 #[test]
1221 fn buggy() {
1222 let buggy_json = include_str!("../example_dofs/buggy.dof");
1223
1224 let buggy = serde_json::from_str::<Dof>(buggy_json).expect("couldn't parse buggy json");
1225
1226 assert_eq!(buggy.layers.len(), 4);
1227 assert_eq!(buggy.anchor, Anchor(0, 0));
1228 }
1229
1230 fn rk(width: f64) -> RelativeKey {
1231 RelativeKey {
1232 width,
1233 has_key: true,
1234 }
1235 }
1236
1237 #[test]
1238 fn parse_maximal() {
1239 use combos::ck;
1240 use Finger::*;
1241 use Key::*;
1242 use SpecialKey::*;
1243
1244 let maximal_json = include_str!("../example_dofs/maximal.dof");
1245
1246 let maximal_test = DofIntermediate {
1247 name: "Qwerty".into(),
1248 authors: Some(vec!["Christopher Latham Sholes".into()]),
1249 year: Some(1878),
1250 description: Some("the OG. Without Qwerty, none of this would be necessary.".into()),
1251 languages: Some(BTreeMap::from_iter([("english".to_owned(), 100)])),
1252 link: Some("https://en.wikipedia.org/wiki/QWERTY".into()),
1253 anchor: Some(Anchor::new(0, 0)),
1254 layers: BTreeMap::from_iter([
1255 (
1256 "main".into(),
1257 crate::Layer::from(vec![
1258 vec![
1259 Char('`'),
1260 Char('1'),
1261 Char('2'),
1262 Char('3'),
1263 Char('4'),
1264 Char('5'),
1265 Char('6'),
1266 Char('7'),
1267 Char('8'),
1268 Char('9'),
1269 Char('0'),
1270 Char('-'),
1271 Char('='),
1272 Special(Backspace),
1273 ],
1274 vec![
1275 Special(Tab),
1276 Char('q'),
1277 Char('w'),
1278 Char('e'),
1279 Char('r'),
1280 Char('t'),
1281 Char('y'),
1282 Char('u'),
1283 Char('i'),
1284 Char('o'),
1285 Char('p'),
1286 Char('['),
1287 Char(']'),
1288 Char('\\'),
1289 ],
1290 vec![
1291 Special(Caps),
1292 Char('a'),
1293 Char('s'),
1294 Char('d'),
1295 Char('f'),
1296 Char('g'),
1297 Char('h'),
1298 Char('j'),
1299 Char('k'),
1300 Char('l'),
1301 Char(';'),
1302 Char('\''),
1303 Special(Enter),
1304 ],
1305 vec![
1306 Special(Shift),
1307 Char('z'),
1308 Char('x'),
1309 Char('c'),
1310 Char('v'),
1311 Char('b'),
1312 Char('n'),
1313 Char('m'),
1314 Char(','),
1315 Char('.'),
1316 Char('/'),
1317 Special(Shift),
1318 ],
1319 vec![
1320 Empty,
1321 Empty,
1322 Magic {
1323 label: "mgc".into()
1324 },
1325 Special(Space),
1326 Layer {
1327 label: "altgr".into(),
1328 },
1329 Empty,
1330 Empty,
1331 Char('ß'),
1332 ],
1333 ]),
1334 ),
1335 (
1336 "shift".into(),
1337 crate::Layer::from(vec![
1338 vec![
1339 Char('~'),
1340 Char('!'),
1341 Char('@'),
1342 Char('#'),
1343 Char('$'),
1344 Char('%'),
1345 Char('^'),
1346 Char('&'),
1347 Char('*'),
1348 Char('('),
1349 Char(')'),
1350 Char('_'),
1351 Char('+'),
1352 Special(Backspace),
1353 ],
1354 vec![
1355 Special(Tab),
1356 Char('Q'),
1357 Char('W'),
1358 Char('E'),
1359 Char('R'),
1360 Char('T'),
1361 Char('Y'),
1362 Char('U'),
1363 Char('I'),
1364 Char('O'),
1365 Char('P'),
1366 Char('{'),
1367 Char('}'),
1368 Char('|'),
1369 ],
1370 vec![
1371 Special(Caps),
1372 Char('A'),
1373 Char('S'),
1374 Char('D'),
1375 Char('F'),
1376 Char('G'),
1377 Char('H'),
1378 Char('J'),
1379 Char('K'),
1380 Char('L'),
1381 Char(':'),
1382 Char('\"'),
1383 Special(Enter),
1384 ],
1385 vec![
1386 Special(Shift),
1387 Char('Z'),
1388 Char('X'),
1389 Char('C'),
1390 Char('V'),
1391 Char('B'),
1392 Char('N'),
1393 Char('M'),
1394 Char('<'),
1395 Char('>'),
1396 Char('?'),
1397 Special(Shift),
1398 ],
1399 vec![
1400 Empty,
1401 Empty,
1402 Magic {
1403 label: "mgc".into()
1404 },
1405 Special(Space),
1406 Word("altgr".into()),
1407 Empty,
1408 Empty,
1409 Word("SS".into()),
1410 ],
1411 ]),
1412 ),
1413 (
1414 "altgr".into(),
1415 crate::Layer::from(vec![
1416 vec![
1417 Transparent,
1418 Transparent,
1419 Transparent,
1420 Transparent,
1421 Transparent,
1422 Transparent,
1423 Transparent,
1424 Transparent,
1425 Transparent,
1426 Transparent,
1427 Transparent,
1428 Transparent,
1429 Transparent,
1430 Special(Backspace),
1431 ],
1432 vec![
1433 Special(Tab),
1434 Transparent,
1435 Transparent,
1436 Transparent,
1437 Transparent,
1438 Word("tb".into()),
1439 Transparent,
1440 Char('ü'),
1441 Transparent,
1442 Char('ö'),
1443 Transparent,
1444 Transparent,
1445 Transparent,
1446 Transparent,
1447 ],
1448 vec![
1449 Special(Caps),
1450 Char('ä'),
1451 Transparent,
1452 Transparent,
1453 Transparent,
1454 Magic {
1455 label: "mgc2".into()
1456 },
1457 Transparent,
1458 Transparent,
1459 Transparent,
1460 Transparent,
1461 Transparent,
1462 Transparent,
1463 Special(Enter),
1464 ],
1465 vec![
1466 Special(Shift),
1467 Transparent,
1468 Transparent,
1469 Transparent,
1470 Transparent,
1471 Transparent,
1472 Transparent,
1473 Transparent,
1474 Transparent,
1475 Transparent,
1476 Transparent,
1477 Special(Shift),
1478 ],
1479 vec![
1480 Empty,
1481 Empty,
1482 Magic {
1483 label: "mgc".into()
1484 },
1485 Special(Space),
1486 Transparent,
1487 Empty,
1488 Empty,
1489 Empty,
1490 ],
1491 ]),
1492 ),
1493 ]),
1494 fingering: {
1495 Some(ParsedFingering::Explicit(Fingering::from(vec![
1496 vec![LP, LP, LR, LM, LI, LI, RI, RI, RM, RR, RP, RP, RP, RP],
1497 vec![LP, LP, LR, LM, LI, LI, RI, RI, RM, RR, RP, RP, RP, RP],
1498 vec![LP, LP, LR, LM, LI, LI, RI, RI, RM, RR, RP, RP, RP],
1499 vec![LP, LR, LM, LI, LI, LI, RI, RI, RM, RR, RP, RP],
1500 vec![LP, LP, LT, LT, LT, RT, RT, RP],
1501 ])))
1502 },
1503 board: ParseKeyboard::Relative(RelativeKeyboard::from(vec![
1504 vec![
1505 rk(1.0),
1506 rk(1.0),
1507 rk(1.0),
1508 rk(1.0),
1509 rk(1.0),
1510 rk(1.0),
1511 rk(1.0),
1512 rk(1.0),
1513 rk(1.0),
1514 rk(1.0),
1515 rk(1.0),
1516 rk(1.0),
1517 rk(1.0),
1518 rk(2.0),
1519 ],
1520 vec![
1521 rk(1.5),
1522 rk(1.0),
1523 rk(1.0),
1524 rk(1.0),
1525 rk(1.0),
1526 rk(1.0),
1527 rk(1.0),
1528 rk(1.0),
1529 rk(1.0),
1530 rk(1.0),
1531 rk(1.0),
1532 rk(1.0),
1533 rk(1.0),
1534 rk(1.5),
1535 ],
1536 vec![
1537 rk(1.75),
1538 rk(1.0),
1539 rk(1.0),
1540 rk(1.0),
1541 rk(1.0),
1542 rk(1.0),
1543 rk(1.0),
1544 rk(1.0),
1545 rk(1.0),
1546 rk(1.0),
1547 rk(1.0),
1548 rk(1.0),
1549 rk(2.25),
1550 ],
1551 vec![
1552 rk(2.25),
1553 rk(1.0),
1554 rk(1.0),
1555 rk(1.0),
1556 rk(1.0),
1557 rk(1.0),
1558 rk(1.0),
1559 rk(1.0),
1560 rk(1.0),
1561 rk(1.0),
1562 rk(1.0),
1563 rk(2.75),
1564 ],
1565 vec![
1566 rk(1.25),
1567 rk(1.25),
1568 rk(1.25),
1569 rk(6.25),
1570 rk(1.25),
1571 rk(1.25),
1572 rk(1.25),
1573 rk(1.25),
1574 ],
1575 ])),
1576 combos: Some(ParseCombos(BTreeMap::from([
1577 (
1578 "main".to_string(),
1579 BTreeMap::from([
1580 (vec![ck(Char('d'), 0), ck(Char('f'), 0)], Char('x')),
1581 (vec![ck(Char('j'), 0), ck(Char('k'), 0)], Char('6')),
1582 ]),
1583 ),
1584 (
1585 "shift".to_string(),
1586 BTreeMap::from([(vec![ck(Special(Shift), 1), ck(Char('?'), 0)], Char('X'))]),
1587 ),
1588 ]))),
1589 magic: Some(crate::magic::Magic {
1590 keys: BTreeMap::from([
1591 (
1592 "mgc".into(),
1593 MagicKey {
1594 label: "mgc".into(),
1595 rules: BTreeMap::from([
1596 ("a".into(), "b".into()),
1597 ("abc".into(), "defghijklmnopqrstuvwxyz".into()),
1598 ]),
1599 max_leading_length: 3,
1600 max_output_length: 23,
1601 },
1602 ),
1603 (
1604 "mgc2".into(),
1605 MagicKey {
1606 label: "mgc2".into(),
1607 rules: BTreeMap::from([("more".into(), " magic".into())]),
1608 max_leading_length: 4,
1609 max_output_length: 6,
1610 },
1611 ),
1612 ]),
1613 }),
1614 };
1615
1616 let dof_maximal = serde_json::from_str::<DofIntermediate>(maximal_json)
1617 .expect("couldn't parse explicit json");
1618
1619 assert_eq!(dof_maximal, maximal_test);
1620 }
1621
1622 #[test]
1623 fn lang_fn() {
1624 let languages = &[Language::new("English", 100)];
1625
1626 let languages = match languages {
1627 [lang] if lang == &Language::default() => None,
1628 _ => Some(languages),
1629 };
1630
1631 println!("{:?}", languages)
1632 }
1633}