kbvm/xkb/
format.rs

1use {
2    crate::{
3        xkb::{
4            controls::ControlMask,
5            group::GroupChange,
6            group_component::GroupComponent,
7            keymap::{
8                self,
9                actions::{
10                    ControlsLockAction, ControlsSetAction, GroupLatchAction, GroupLockAction,
11                    GroupSetAction, ModsLatchAction, ModsLockAction, ModsSetAction,
12                    RedirectKeyAction,
13                },
14                Action, Indicator, KeyBehavior, KeyGroup, KeyLevel, KeyOverlay, KeyType,
15            },
16            mod_component::ModComponentMask,
17            resolved::GroupsRedirect,
18            rmlvo::{self, MergeMode},
19            Keymap,
20        },
21        Keysym, ModifierMask,
22    },
23    debug_fn::debug_fn,
24    hashbrown::{HashMap, HashSet},
25    isnt::std_1::vec::IsntVecExt,
26    smallvec::SmallVec,
27    std::{
28        fmt::{self, Display, Formatter, Write},
29        sync::Arc,
30    },
31};
32
33pub(crate) struct FormatFormat<'a, T>(pub(crate) &'a T);
34
35impl<T> Display for FormatFormat<'_, T>
36where
37    T: Format,
38{
39    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
40        let mut writer = Writer {
41            nesting: 0,
42            multi_line: f.alternate(),
43            lookup_only: false,
44            omit_multiple_actions: false,
45            long_keys: None,
46            newline: match f.alternate() {
47                true => "\n",
48                false => " ",
49            },
50            f,
51        };
52        self.0.format(&mut writer)
53    }
54}
55
56struct Writer<'a, 'b> {
57    nesting: usize,
58    multi_line: bool,
59    lookup_only: bool,
60    omit_multiple_actions: bool,
61    long_keys: Option<HashMap<Arc<String>, String>>,
62    newline: &'static str,
63    f: &'a mut Formatter<'b>,
64}
65
66trait Format {
67    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result;
68}
69
70impl Writer<'_, '_> {
71    fn write(&mut self, s: &str) -> fmt::Result {
72        self.f.write_str(s)
73    }
74
75    fn write_newline(&mut self) -> fmt::Result {
76        self.f.write_str(self.newline)
77    }
78
79    fn write_string(&mut self, s: &str) -> fmt::Result {
80        self.write("\"")?;
81        for c in s.chars() {
82            match c {
83                '\\' => self.write(r"\\")?,
84                '\n' => self.write(r"\n")?,
85                '\r' => self.write(r"\r")?,
86                '\t' => self.write(r"\t")?,
87                _ if (c as u32) < 0x20 || c == '\x7f' || c == '"' => {
88                    write!(self.f, r"\{:03o}", c as u32)?
89                }
90                _ => self.f.write_char(c)?,
91            }
92        }
93        self.write("\"")?;
94        Ok(())
95    }
96
97    fn write_key_name(&mut self, name: &Arc<String>) -> fmt::Result {
98        if name.len() > 4 {
99            if let Some(names) = &mut self.long_keys {
100                if let Some(name) = names.get(name) {
101                    return self.f.write_str(name);
102                }
103            }
104        }
105        self.write(name)
106    }
107
108    fn write_nesting(&mut self) -> fmt::Result {
109        if self.multi_line {
110            let spaces = self.nesting * 4;
111            write!(self.f, "{:spaces$}", "", spaces = spaces)?;
112        }
113        Ok(())
114    }
115
116    fn write_nested(&mut self, f: impl FnOnce(&mut Self) -> fmt::Result) -> fmt::Result {
117        self.write_newline()?;
118        self.nesting += 1;
119        f(self)?;
120        self.nesting -= 1;
121        Ok(())
122    }
123
124    fn write_inline_list<T>(
125        &mut self,
126        items: &[T],
127        mut f: impl FnMut(&mut Self, &T) -> fmt::Result,
128    ) -> fmt::Result {
129        for (idx, item) in items.iter().enumerate() {
130            if idx == 0 {
131                self.write(" ")?;
132            } else {
133                self.write(", ")?;
134            }
135            f(self, item)?;
136        }
137        Ok(())
138    }
139}
140
141impl Display for keymap::Formatter<'_> {
142    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
143        let mut long_keys = None;
144        if self.rename_long_keys {
145            let mut has_any = false;
146            let mut conflicts = HashSet::new();
147            for key in &self.keymap.keycodes {
148                if key.name.len() > 4 {
149                    has_any = true;
150                }
151                if key.name.len() == 4
152                    && key.name.as_bytes()[0] == b'K'
153                    && key.name.as_bytes()[1..].iter().all(|b| b.is_ascii_digit())
154                {
155                    conflicts.insert(key.name.clone());
156                }
157            }
158            let mut names = HashMap::new();
159            if has_any {
160                let mut next = 0u64;
161                for key in &self.keymap.keycodes {
162                    if key.name.len() <= 4 {
163                        continue;
164                    }
165                    let name = loop {
166                        let name = format!("K{:03}", next);
167                        next += 1;
168                        if !conflicts.contains(&name) {
169                            break name;
170                        }
171                    };
172                    names.insert(key.name.clone(), name);
173                }
174            }
175            if !names.is_empty() {
176                long_keys = Some(names);
177            }
178        }
179        let mut writer = Writer {
180            nesting: 0,
181            multi_line: !self.single_line,
182            lookup_only: self.lookup_only,
183            omit_multiple_actions: !self.multiple_actions_per_level,
184            long_keys,
185            newline: match self.single_line {
186                false => "\n",
187                true => " ",
188            },
189            f,
190        };
191        Format::format(self.keymap, &mut writer)
192    }
193}
194
195impl Format for Keymap {
196    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
197        f.write_nesting()?;
198        f.write("xkb_keymap ")?;
199        if let Some(name) = &self.name {
200            f.write_string(name)?;
201            f.write(" ")?;
202        }
203        f.write("{")?;
204        f.write_nested(|f| {
205            Keycodes(self).format(f)?;
206            f.write_newline()?;
207            f.write_newline()?;
208            Types(self).format(f)?;
209            f.write_newline()?;
210            f.write_newline()?;
211            Compat(self).format(f)?;
212            f.write_newline()?;
213            f.write_newline()?;
214            Symbols(self).format(f)?;
215            f.write_newline()?;
216            Ok(())
217        })?;
218        f.write_nesting()?;
219        f.write("};")?;
220        Ok(())
221    }
222}
223
224struct Keycodes<'a>(&'a Keymap);
225
226impl Format for Keycodes<'_> {
227    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
228        let m = self.0;
229        f.write_nesting()?;
230        f.write("xkb_keycodes {")?;
231        f.write_nested(|f| {
232            f.write_nesting()?;
233            f.write("minimum = 8;")?;
234            f.write_newline()?;
235            f.write_nesting()?;
236            write!(f.f, "maximum = {};", m.max_keycode)?;
237            f.write_newline()?;
238            f.write_newline()?;
239            for i in &m.indicators {
240                KeycodeIndicator(i).format(f)?;
241                f.write_newline()?;
242            }
243            if m.keycodes.is_not_empty() {
244                f.write_newline()?;
245                KeycodeKeys(m).format(f)?;
246            }
247            Ok(())
248        })?;
249        f.write_nesting()?;
250        f.write("};")?;
251        Ok(())
252    }
253}
254
255struct Compat<'a>(&'a Keymap);
256
257impl Format for Compat<'_> {
258    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
259        let m = self.0;
260        f.write_nesting()?;
261        f.write("xkb_compat {")?;
262        f.write_nested(|f| {
263            let mut wrote_any_indicators = false;
264            for i in &m.indicators {
265                let write = i.modifier_mask.0 != 0
266                    || i.group_mask.0 != 0
267                    || i.group_component != GroupComponent::Effective
268                    || i.controls != ControlMask::NONE;
269                if write {
270                    wrote_any_indicators = true;
271                    CompatIndicator(i).format(f)?;
272                    f.write_newline()?;
273                }
274            }
275            if wrote_any_indicators {
276                f.write_newline()?;
277            }
278            // https://gitlab.freedesktop.org/xorg/lib/libxkbfile/-/issues/12
279            f.write_nesting()?;
280            f.write("interpret VoidSymbol {")?;
281            f.write_nested(|f| {
282                f.write_nesting()?;
283                f.write("repeat = false;")?;
284                f.write_newline()
285            })?;
286            f.write_nesting()?;
287            f.write("};")?;
288            f.write_newline()?;
289            Ok(())
290        })?;
291        f.write_nesting()?;
292        f.write("};")?;
293        Ok(())
294    }
295}
296
297struct KeycodeIndicator<'a>(&'a Indicator);
298
299impl Format for KeycodeIndicator<'_> {
300    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
301        let i = self.0;
302        f.write_nesting()?;
303        if i.virt {
304            f.write("virtual ")?;
305        }
306        f.write("indicator ")?;
307        write!(f.f, "{}", i.index.raw())?;
308        f.write(" = ")?;
309        f.write_string(&i.name)?;
310        f.write(";")?;
311        Ok(())
312    }
313}
314
315struct CompatIndicator<'a>(&'a Indicator);
316
317impl Format for CompatIndicator<'_> {
318    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
319        let i = self.0;
320        f.write_nesting()?;
321        f.write("indicator ")?;
322        f.write_string(&i.name)?;
323        f.write(" {")?;
324        f.write_nested(|f| {
325            if i.modifier_mask.0 != 0 {
326                f.write_nesting()?;
327                write!(f.f, "modifiers = {};", modifier_mask(i.modifier_mask))?;
328                f.write_newline()?;
329                if i.mod_components != ModComponentMask::EFFECTIVE {
330                    f.write_nesting()?;
331                    write!(f.f, "whichModState = {};", i.mod_components)?;
332                    f.write_newline()?;
333                }
334            }
335            if i.group_mask.0 != 0 {
336                f.write_nesting()?;
337                write!(f.f, "groups = 0x{:08x};", i.group_mask.0)?;
338                f.write_newline()?;
339            }
340            if i.group_component != GroupComponent::Effective {
341                f.write_nesting()?;
342                write!(f.f, "whichGroupState = {};", i.group_component)?;
343                f.write_newline()?;
344            }
345            if i.controls != ControlMask::NONE {
346                f.write_nesting()?;
347                write!(f.f, "controls = {};", i.controls)?;
348                f.write_newline()?;
349            }
350            Ok(())
351        })?;
352        f.write_nesting()?;
353        f.write("};")?;
354        Ok(())
355    }
356}
357
358struct KeycodeKeys<'a>(&'a Keymap);
359
360impl Format for KeycodeKeys<'_> {
361    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
362        for k in &self.0.keycodes {
363            f.write_nesting()?;
364            f.write("<")?;
365            f.write_key_name(&k.name)?;
366            write!(f.f, "> = {};", k.keycode.0)?;
367            f.write_newline()?;
368        }
369        Ok(())
370    }
371}
372
373struct Types<'a>(&'a Keymap);
374
375impl Format for Types<'_> {
376    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
377        let m = self.0;
378        f.write_nesting()?;
379        f.write("xkb_types {")?;
380        f.write_nested(|f| {
381            VirtualModifiers(m).format(f)?;
382            for i in &m.types {
383                f.write_newline()?;
384                TypesKeyType(i).format(f)?;
385                f.write_newline()?;
386            }
387            Ok(())
388        })?;
389        f.write_nesting()?;
390        f.write("};")?;
391        Ok(())
392    }
393}
394
395struct TypesKeyType<'a>(&'a KeyType);
396
397impl Format for TypesKeyType<'_> {
398    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
399        let m = self.0;
400        f.write_nesting()?;
401        f.write("type ")?;
402        f.write_string(&m.name)?;
403        f.write(" {")?;
404        f.write_nested(|f| {
405            f.write_nesting()?;
406            write!(f.f, "modifiers = {};", modifier_mask(m.modifiers))?;
407            f.write_newline()?;
408            for (l, n) in &m.level_names {
409                f.write_nesting()?;
410                write!(f.f, "level_name[Level{}] = ", l.raw())?;
411                f.write_string(n)?;
412                f.write(";")?;
413                f.write_newline()?;
414            }
415            for level in &m.mappings {
416                f.write_nesting()?;
417                let mask = modifier_mask(level.modifiers);
418                write!(f.f, "map[{}] = Level{};", mask, level.level.raw())?;
419                f.write_newline()?;
420                if level.preserved.0 != 0 {
421                    f.write_nesting()?;
422                    write!(
423                        f.f,
424                        "preserve[{}] = {};",
425                        mask,
426                        modifier_mask(level.preserved)
427                    )?;
428                    f.write_newline()?;
429                }
430            }
431            Ok(())
432        })?;
433        f.write_nesting()?;
434        f.write("};")?;
435        Ok(())
436    }
437}
438
439struct VirtualModifiers<'a>(&'a Keymap);
440
441impl Format for VirtualModifiers<'_> {
442    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
443        let m = self.0;
444        for v in &m.virtual_modifiers {
445            f.write_nesting()?;
446            f.write("virtual_modifiers ")?;
447            f.write(&v.name)?;
448            if v.values.0 != 0 {
449                f.write(" = ")?;
450                write!(f.f, "{}", modifier_mask(v.values))?;
451            }
452            f.write(";")?;
453            f.write_newline()?;
454        }
455        Ok(())
456    }
457}
458
459impl Format for Action {
460    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
461        match self {
462            Action::ModsSet(e) => e.format(f),
463            Action::ModsLatch(e) => e.format(f),
464            Action::ModsLock(e) => e.format(f),
465            Action::GroupSet(e) => e.format(f),
466            Action::GroupLatch(e) => e.format(f),
467            Action::GroupLock(e) => e.format(f),
468            Action::RedirectKey(e) => e.format(f),
469            Action::ControlsSet(e) => e.format(f),
470            Action::ControlsLock(e) => e.format(f),
471        }
472    }
473}
474
475impl Format for ModsSetAction {
476    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
477        f.write("SetMods(")?;
478        write!(f.f, "modifiers = {}", modifier_mask(self.modifiers))?;
479        if self.clear_locks {
480            f.write(", clearLocks")?;
481        }
482        f.write(")")?;
483        Ok(())
484    }
485}
486
487impl Format for ModsLatchAction {
488    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
489        f.write("LatchMods(")?;
490        write!(f.f, "modifiers = {}", modifier_mask(self.modifiers))?;
491        if self.clear_locks {
492            f.write(", clearLocks")?;
493        }
494        if self.latch_to_lock {
495            f.write(", latchToLock")?;
496        }
497        f.write(")")?;
498        Ok(())
499    }
500}
501
502impl Format for ModsLockAction {
503    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
504        write!(
505            f.f,
506            "LockMods(modifiers = {}{})",
507            modifier_mask(self.modifiers),
508            affect(self.lock, self.unlock),
509        )
510    }
511}
512
513impl Format for GroupSetAction {
514    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
515        f.write("SetGroup(")?;
516        write!(f.f, "group = {}", group_change(self.group))?;
517        if self.clear_locks {
518            f.write(", clearLocks")?;
519        }
520        f.write(")")?;
521        Ok(())
522    }
523}
524
525impl Format for GroupLatchAction {
526    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
527        f.write("LatchGroup(")?;
528        write!(f.f, "group = {}", group_change(self.group))?;
529        if self.clear_locks {
530            f.write(", clearLocks")?;
531        }
532        if self.latch_to_lock {
533            f.write(", latchToLock")?;
534        }
535        f.write(")")?;
536        Ok(())
537    }
538}
539
540impl Format for GroupLockAction {
541    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
542        f.write("LockGroup(")?;
543        write!(f.f, "group = {}", group_change(self.group))?;
544        f.write(")")?;
545        Ok(())
546    }
547}
548
549impl Format for RedirectKeyAction {
550    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
551        f.write("RedirectKey(")?;
552        f.write("key = <")?;
553        f.write_key_name(&self.key_name)?;
554        f.write(">")?;
555        if self.mods_to_clear.0 != 0 {
556            write!(f.f, ", clearMods = {}", modifier_mask(self.mods_to_clear))?;
557        }
558        if self.mods_to_set.0 != 0 {
559            write!(f.f, ", mods = {}", modifier_mask(self.mods_to_set))?;
560        }
561        f.write(")")?;
562        Ok(())
563    }
564}
565
566impl Format for ControlsSetAction {
567    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
568        write!(f.f, "SetControls(controls = {})", self.controls)?;
569        Ok(())
570    }
571}
572
573impl Format for ControlsLockAction {
574    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
575        write!(
576            f.f,
577            "LockControls(controls = {}{})",
578            self.controls,
579            affect(self.lock, self.unlock),
580        )
581    }
582}
583
584struct Symbols<'a>(&'a Keymap);
585
586impl Format for Symbols<'_> {
587    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
588        let m = self.0;
589        f.write_nesting()?;
590        f.write("xkb_symbols {")?;
591        f.write_nested(|f| {
592            let mut need_newline = false;
593            if m.mod_maps.is_not_empty() {
594                ModMaps(m).format(f)?;
595                need_newline = true;
596            }
597            if m.group_names.is_not_empty() {
598                if need_newline {
599                    f.write_newline()?;
600                }
601                GroupNames(m).format(f)?;
602                need_newline = true;
603            }
604            if m.keys.len() > 0 {
605                if need_newline {
606                    f.write_newline()?;
607                }
608                Keys(m).format(f)?;
609            }
610            Ok(())
611        })?;
612        f.write_nesting()?;
613        f.write("};")?;
614        Ok(())
615    }
616}
617
618struct Keys<'a>(&'a Keymap);
619
620impl Format for Keys<'_> {
621    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
622        let m = self.0;
623        f.write_nesting()?;
624        f.write("key.repeat = true;")?;
625        f.write_newline()?;
626        f.write_newline()?;
627        for key in m.keys.values() {
628            f.write_nesting()?;
629            f.write("key <")?;
630            f.write_key_name(&key.key_name)?;
631            f.write("> {")?;
632            f.write_nested(|f| {
633                let mut needs_newline = false;
634                fn handle_newline(needs_newline: &mut bool, f: &mut Writer<'_, '_>) -> fmt::Result {
635                    if *needs_newline {
636                        f.write(",")?;
637                        f.write_newline()?;
638                    }
639                    *needs_newline = false;
640                    Ok(())
641                }
642                if !key.repeat {
643                    f.write_nesting()?;
644                    f.write("repeat = false")?;
645                    needs_newline = true;
646                }
647                if !f.lookup_only {
648                    if let Some(behavior) = &key.behavior {
649                        handle_newline(&mut needs_newline, f)?;
650                        f.write_nesting()?;
651                        match behavior {
652                            KeyBehavior::Lock => {
653                                f.write("locks = true")?;
654                            }
655                            KeyBehavior::Overlay(b) => {
656                                let idx = match b.overlay() {
657                                    KeyOverlay::Overlay1 => 1,
658                                    KeyOverlay::Overlay2 => 2,
659                                };
660                                write!(f.f, "overlay{idx} = <")?;
661                                f.write_key_name(&b.key_name)?;
662                                f.write(">")?;
663                            }
664                            KeyBehavior::RadioGroup(g) => {
665                                if g.allow_none {
666                                    write!(f.f, "allownone")?;
667                                    needs_newline = true;
668                                    handle_newline(&mut needs_newline, f)?;
669                                    f.write_nesting()?;
670                                }
671                                write!(f.f, "radiogroup = {}", g.radio_group.raw())?;
672                            }
673                        }
674                        needs_newline = true;
675                    }
676                }
677                if key.redirect != GroupsRedirect::Wrap {
678                    handle_newline(&mut needs_newline, f)?;
679                    f.write_nesting()?;
680                    match key.redirect {
681                        GroupsRedirect::Wrap => {}
682                        GroupsRedirect::Clamp => {
683                            f.write("groupsClamp = true")?;
684                        }
685                        GroupsRedirect::Redirect(n) => {
686                            write!(f.f, "groupsRedirect = Group{}", n.raw())?;
687                        }
688                    }
689                    needs_newline = true;
690                }
691                for (offset, group) in key.groups.iter().enumerate() {
692                    if let Some(group) = group {
693                        if group.levels.len() == 0 {
694                            continue;
695                        }
696                        let idx = offset + 1;
697                        handle_newline(&mut needs_newline, f)?;
698                        f.write_nesting()?;
699                        write!(f.f, "type[Group{idx}] = ")?;
700                        f.write_string(&group.key_type.name)?;
701                        needs_newline = true;
702                    }
703                }
704                for (offset, group) in key.groups.iter().enumerate() {
705                    if let Some(group) = group {
706                        let idx = offset + 1;
707                        #[expect(clippy::too_many_arguments)]
708                        fn write_levels<T: Format>(
709                            needs_newline: &mut bool,
710                            idx: usize,
711                            group: &KeyGroup,
712                            f: &mut Writer<'_, '_>,
713                            name: &str,
714                            absent: &str,
715                            field: impl Fn(&KeyLevel) -> &SmallVec<[T; 1]>,
716                            is_actions: bool,
717                        ) -> fmt::Result {
718                            if group.levels.iter().all(|l| field(l).is_empty()) {
719                                return Ok(());
720                            }
721                            handle_newline(needs_newline, f)?;
722                            f.write_nesting()?;
723                            write!(f.f, "{name}[Group{idx}] = [")?;
724                            f.write_inline_list(&group.levels, |f, l| {
725                                let mut list = &**field(l);
726                                if is_actions && f.omit_multiple_actions && list.len() > 1 {
727                                    list = &[];
728                                }
729                                if list.is_empty() {
730                                    f.write(absent)?;
731                                } else if list.len() == 1 {
732                                    list[0].format(f)?;
733                                } else {
734                                    f.write("{")?;
735                                    f.write_inline_list(list, |f, a| a.format(f))?;
736                                    f.write(" }")?;
737                                }
738                                Ok(())
739                            })?;
740                            f.write(" ]")?;
741                            *needs_newline = true;
742                            Ok(())
743                        }
744                        write_levels(
745                            &mut needs_newline,
746                            idx,
747                            group,
748                            f,
749                            "symbols",
750                            "NoSymbol",
751                            |l| &l.symbols,
752                            false,
753                        )?;
754                        if !f.lookup_only {
755                            write_levels(
756                                &mut needs_newline,
757                                idx,
758                                group,
759                                f,
760                                "actions",
761                                "NoAction()",
762                                |l| &l.actions,
763                                true,
764                            )?;
765                        }
766                    }
767                }
768                if !needs_newline {
769                    f.write_nesting()?;
770                    f.write("repeat = true")?;
771                }
772                f.write_newline()?;
773                Ok(())
774            })?;
775            f.write_nesting()?;
776            f.write("};")?;
777            f.write_newline()?;
778        }
779        Ok(())
780    }
781}
782
783impl Format for Keysym {
784    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
785        Display::fmt(self, f.f)
786    }
787}
788
789struct ModMaps<'a>(&'a Keymap);
790
791impl Format for ModMaps<'_> {
792    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
793        for (idx, kc) in &self.0.mod_maps {
794            f.write_nesting()?;
795            write!(f.f, "modmap {} {{ ", modifier_mask(idx.to_mask()))?;
796            if let Some(s) = kc.key_sym {
797                s.format(f)?;
798            } else {
799                f.write("<")?;
800                f.write_key_name(&kc.key_name)?;
801                f.write(">")?;
802            }
803            f.write(" };")?;
804            if kc.key_sym.is_some() && f.multi_line {
805                write!(f.f, " // <{}>", kc.key_name)?;
806            }
807            f.write_newline()?;
808        }
809        Ok(())
810    }
811}
812
813struct GroupNames<'a>(&'a Keymap);
814
815impl Format for GroupNames<'_> {
816    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
817        for (idx, kc) in &self.0.group_names {
818            f.write_nesting()?;
819            write!(f.f, "name[Group{}] = ", idx.raw())?;
820            f.write_string(kc)?;
821            f.write(";")?;
822            f.write_newline()?;
823        }
824        Ok(())
825    }
826}
827
828fn group_change(gc: GroupChange) -> impl Display {
829    debug_fn(move |f| match gc {
830        GroupChange::Absolute(g) => {
831            write!(f, "Group{}", g.raw())
832        }
833        GroupChange::Rel(r) => {
834            if r > 0 {
835                f.write_str("+")?;
836            }
837            Display::fmt(&r, f)
838        }
839    })
840}
841
842fn affect(lock: bool, unlock: bool) -> impl Display {
843    debug_fn(move |f| {
844        let affect = match (lock, unlock) {
845            (false, false) => "neither",
846            (true, false) => "lock",
847            (false, true) => "unlock",
848            _ => return Ok(()),
849        };
850        write!(f, ", affect={}", affect)
851    })
852}
853
854fn modifier_mask(mm: ModifierMask) -> impl Display {
855    debug_fn(move |f| {
856        if mm.0 == 0 {
857            f.write_str("None")
858        } else if mm.0 & !0xff != 0 {
859            write!(f, "0x{:08x}", mm.0)
860        } else {
861            let mut first = true;
862            macro_rules! one {
863                ($n:expr, $name:expr) => {
864                    if mm.0 & (1 << $n) != 0 {
865                        if !first {
866                            f.write_str("+")?;
867                        }
868                        first = false;
869                        f.write_str($name)?;
870                    }
871                };
872            }
873            one!(0, "Shift");
874            one!(1, "Lock");
875            one!(2, "Control");
876            one!(3, "Mod1");
877            one!(4, "Mod2");
878            one!(5, "Mod3");
879            one!(6, "Mod4");
880            one!(7, "Mod5");
881            let _ = first;
882            Ok(())
883        }
884    })
885}
886
887impl Format for rmlvo::Expanded {
888    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
889        f.write_nesting()?;
890        f.write("xkb_keymap {")?;
891        f.write_nested(|f| {
892            let elements = [
893                ("xkb_keycodes", &self.keycodes),
894                ("xkb_types", &self.types),
895                ("xkb_compat", &self.compat),
896                ("xkb_symbols", &self.symbols),
897                ("xkb_geometry", &self.geometry),
898            ];
899            for (name, elements) in elements {
900                f.write_nesting()?;
901                f.write(name)?;
902                f.write(" {")?;
903                f.write_nested(|f| RmlvoIncludes(elements).format(f))?;
904                f.write_nesting()?;
905                f.write("};")?;
906                f.write_newline()?;
907            }
908            Ok(())
909        })?;
910        f.write_nesting()?;
911        f.write("};")?;
912        Ok(())
913    }
914}
915
916struct RmlvoIncludes<'a>(&'a [rmlvo::Element]);
917
918impl Format for RmlvoIncludes<'_> {
919    fn format(&self, f: &mut Writer<'_, '_>) -> fmt::Result {
920        for e in self.0 {
921            f.write_nesting()?;
922            match e.merge_mode {
923                MergeMode::Augment => f.write("augment ")?,
924                MergeMode::Override => f.write("override ")?,
925                MergeMode::Replace => f.write("replace ")?,
926            }
927            f.write_string(&e.include)?;
928            f.write_newline()?;
929        }
930        Ok(())
931    }
932}
933
934#[cfg(feature = "compose")]
935mod compose {
936    use crate::xkb::{
937        compose::{ComposeTable, MatchRule, MatchStep},
938        format::{Format, Writer},
939    };
940
941    impl Format for MatchStep<'_> {
942        fn format(&self, f: &mut Writer<'_, '_>) -> std::fmt::Result {
943            f.write("<")?;
944            self.node.keysym.format(f)?;
945            f.write(">")?;
946            Ok(())
947        }
948    }
949
950    impl Format for MatchRule<'_, '_> {
951        fn format(&self, f: &mut Writer<'_, '_>) -> std::fmt::Result {
952            for (idx, step) in self.steps.iter().enumerate() {
953                if idx > 0 {
954                    f.write(" ")?;
955                }
956                step.format(f)?;
957            }
958            f.write(":")?;
959            if let Some(s) = &self.payload.string {
960                f.write(" ")?;
961                f.write_string(s)?;
962            }
963            if let Some(s) = self.payload.keysym {
964                f.write(" ")?;
965                s.format(f)?;
966            }
967            Ok(())
968        }
969    }
970
971    impl Format for ComposeTable {
972        fn format(&self, f: &mut Writer<'_, '_>) -> std::fmt::Result {
973            let mut iter = self.iter();
974            let mut first = true;
975            while let Some(rule) = iter.next() {
976                if !first {
977                    f.write("\n")?;
978                }
979                first = false;
980                rule.format(f)?;
981            }
982            Ok(())
983        }
984    }
985}