diff --git a/doc/diagrams/xkb-configuration.dot b/doc/diagrams/xkb-configuration.dot
index e547f0025..c5ec60b3c 100644
--- a/doc/diagrams/xkb-configuration.dot
+++ b/doc/diagrams/xkb-configuration.dot
@@ -11,7 +11,8 @@ digraph {
RMLVO_resolution [
label=<RMLVO resolution
Determine KcCGST using the specified rules file:
match the given model, layout, variant and options fields>,
style=rounded,
- color=blue
+ color=blue,
+ href="@ref rmlvo-resolution"
];
KcCGST [
label=<Layout database configuration
KcCGST: Keycodes, Compat, Geometry, Symbols, Types>,
@@ -24,7 +25,7 @@ digraph {
color=blue
];
Keymap [
- label=<Window server configuration
Complete keymap>,
+ label=<Display server configuration
Complete keymap>,
penwidth=3,
href="@ref keymap-intro"
];
@@ -34,12 +35,12 @@ digraph {
Layout Database |
- Rules files |
- Keycodes files |
- Compat files |
- (Geometry files) |
- Symbols files |
- Types files |
+ Rules files |
+ Keycodes files |
+ Compat files |
+ (Geometry files) |
+ Symbols files |
+ Types files |
>];
diff --git a/doc/doxygen-extra.css b/doc/doxygen-extra.css
index 97aa72e3c..ac00c9063 100644
--- a/doc/doxygen-extra.css
+++ b/doc/doxygen-extra.css
@@ -12,6 +12,10 @@ dl.todo dt::before {
content: 'π§ ';
}
+dl.note dd {
+ margin-inline-start: revert;
+}
+
span.todo::before {
content: 'π§ ';
}
diff --git a/doc/introduction-to-xkb.md b/doc/introduction-to-xkb.md
index 776786706..4588bb463 100644
--- a/doc/introduction-to-xkb.md
+++ b/doc/introduction-to-xkb.md
@@ -58,7 +58,7 @@ implementation.
The RMLVO configuration consists of the following components:
- - Rules
+ - Rules @anchor config-rules-def
-
The rules define the _mapping_ from high to low level components.
The rules _component_ is the file containing the set of rules to use.
@@ -66,7 +66,7 @@ implementation.
See the [rules file format](doc/rules-format.md) for further details.
- - Model
+ - Model @anchor config-model-def
-
The name of the model of the keyboard hardware in use.
It may depend on:
@@ -80,16 +80,16 @@ implementation.
- The keyboard _vendor:_ keyboard may have a set of keys that are not
standard, or may be specific to an OS.
- - Layout
+ - Layout @anchor config-layout-def
-
The identifier of the general layout to use. It usually refers to a
country or a language.
- - Variant
+ - Variant @anchor config-variant-def
-
Any minor variants on the general layout. It may be national variants
- - Options
+ - Options @anchor config-options-def
-
Set of extra options to customize the standard layouts.
@@ -113,28 +113,28 @@ implementation.
The KcCGST configuration consists of the following components:
- - Key codes
+ - Key codes @anchor config-keycodes-def
-
A translation of the raw [key codes] from the keyboard into
symbolic names.
- - Compatibility
+ - Compatibility @anchor config-compat-def
-
A specification of what internal actions modifiers and various
special-purpose keys produce.
- - Geometry
+ - Geometry @anchor config-geometry-def
-
A description of the physical layout of a keyboard.
@attention This legacy feature is [not supported](@ref geometry-support)
by _xkbcommon_.
- - Key symbols
+ - Key symbols @anchor config-symbols-def
-
A translation of symbolic key codes into actual [key symbols] \(keysyms).
- - Key types
+ - Key types @anchor config-types-def
-
Types describe how a pressed key is affected by active [modifiers]
such as Shift, Control, Alt, etc.
diff --git a/doc/keymap-format-text-v1.md b/doc/keymap-format-text-v1.md
index ec4914102..365d33ea1 100644
--- a/doc/keymap-format-text-v1.md
+++ b/doc/keymap-format-text-v1.md
@@ -1532,6 +1532,13 @@ another file. Here it would include the `xkb_symbols` section called
`nordic_base`, from the file `rx-51` located in the `nokia_vndr` folder, itself
located in an XKB include path.
+@anchor merge-mode-def
+One can use a **merge mode** *prefix* to specify the merge mode of the file:
+- β+β selects the **override** merge mode.
+- β|β selects the **augment** merge mode.
+
+@todo dedicated section for merge mode
+
### Key statement
Statements of the form:
diff --git a/doc/rules-format.md b/doc/rules-format.md
index eab5bd22c..5c9dae816 100644
--- a/doc/rules-format.md
+++ b/doc/rules-format.md
@@ -3,48 +3,132 @@ The rules file {#rule-file-format}
The purpose of the rules file is to map between configuration values
that are easy for a user to specify and understand, and the
-configuration values xkbcomp uses and understands.
+configuration values that the keymap compiler, `xkbcomp`, uses and
+understands. The following diagram presents an overview of this
+process. See the [XKB introduction] for further details on the
+components.
-xkbcomp uses the `xkb_component_names` struct, which maps directly to
-include statements of the appropriate sections, called for short
-[KcCGST] \(see the [XKB introduction]; 'G' stands for "geometry",
-which is not supported). These are not really intuitive nor
-straightforward for the uninitiated.
+@dotfile xkb-configuration "XKB keymap configurations"
-[KcCGST]: @ref KcCGST-intro
-[XKB introduction]: @ref xkb-intro
+@tableofcontents{html:2}
+
+`xkbcomp` uses the `xkb_component_names` struct internally, which maps
+directly to [include statements] of the appropriate [sections] \(called
+[KcCGST] for short):
+
+- [key codes],
+- [compatibility],
+- geometry ([not supported](@ref geometry-support) by xkbcommon),
+- [symbols],
+- [types].
+These are not really intuitive nor straightforward for the uninitiated.
Instead, the user passes in a `xkb_rule_names` struct, which consists
-of the name of a rules file (in Linux this is usually "evdev"), a
-keyboard model (e.g. "pc105"), a set of layouts (which will end up
-in different groups, e.g. "us,fr"), variants (used to alter/augment
-the respective layout, e.g. "intl,dvorak"), and a set of options
-(used to tweak some general behavior of the keyboard, e.g.
-"ctrl:nocaps,compose:menu" to make the Caps Lock key act like Ctrl
-and the Menu key like Compose). We call these
-[RMLVO](@ref RMLVO-intro).
+of the following fields (called [RMLVO] for short):
+
+- the name of a [rules] file (in Linux this is usually βevdevβ),
+- a keyboard [model] \(e.g. βpc105β),
+- a set of [layouts][layout] (which will end up in different
+ groups, e.g. βus,frβ),
+- a set of [variants][variant] (used to alter/augment the respective
+ layout, e.g. βintl,dvorakβ),
+- a set of [options] \(used to tweak some general
+ behavior of the keyboard, e.g. βctrl:nocaps,compose:menuβ to make
+ the Caps Lock key act like Ctrl and the Menu key like Compose).
+
+[KcCGST]: @ref KcCGST-intro
+[RMLVO]: @ref RMLVO-intro
+[MLVO]: @ref RMLVO-intro
+[XKB introduction]: @ref xkb-intro
+[include statements]: @ref xkb-include
+[sections]: @ref keymap-section-def
+[key codes]: @ref the-xkb_keycodes-section
+[compatibility]: @ref the-xkb_compat-section
+[symbols]: @ref the-xkb_symbols-section
+[types]: @ref the-xkb_types-section
+[rules]: @ref config-rules-def
+[model]: @ref config-model-def
+[layout]: @ref config-layout-def
+[variant]: @ref config-variant-def
+[option]: @ref config-options-def
+[options]: @ref config-options-def
Format of the file
------------------
-The file consists of rule sets, each consisting of rules (one per
-line), which match the MLVO values on the left hand side, and, if
-the values match to the values the user passed in, results in the
-values on the right hand side being added to the resulting KcCGST.
+@anchor rule-set-def
+@anchor rule-def
+The file consists of **rule sets**, each consisting of **rules** (one
+per line), which match the [MLVO] values on the left hand side, and,
+if the values match to the values the user passed in, results in the
+values on the right hand side being [added][value update] to the
+resulting [KcCGST]. See @ref rmlvo-resolution for further details.
+
+[rule set]: @ref rule-set-def
+[rule sets]: @ref rule-set-def
+[rule]: @ref rule-def
+
+```c
+// This is a comment
+
+// The following line is a rule header.
+// It starts with β!β and introduces a rules set.
+// It indicates that the rules map MLVO options to KcCGST symbols.
+! option = symbols
+ // The following lines are rules that add symbols of the RHS when the
+ // LHS matches an option.
+ ctrl:nocaps = +ctrl(nocaps)
+ compose:menu = +compose(menu)
+
+// One may use multiple MLVO components on the LHS
+! layout option = symbols
+ be caps:digits_row = +capslock(digits_row)
+ fr caps:digits_row = +capslock(digits_row)
+```
+
+@anchor rules-group-def
Since some values are related and repeated often, it is possible
-to group them together and refer to them by a group name in the
+to *group* them together and refer to them by a **group name** in the
rules.
-Along with matching values by simple string equality, and for
-membership in a group defined previously, rules may also contain
-"wildcard" values - "*" - which always match. These usually appear
-near the end.
+[group]: @ref rules-group-def
+
+```c
+// Letβs rewrite the previous rules set using groups.
+// Groups starts with β$β.
+
+// Define a group for countries with AZERTY layouts
+! $azerty = be fr
+
+// The following rule will match option `caps:digits_row` only for
+// layouts in the $azerty group, i.e. `fr` and `be`.
+! layout option = symbols
+ $azerty caps:digits_row = +capslock(digits_row)
+```
+
+@anchor rules-wildcard-def
+Along with matching values by simple string equality and for
+membership in a [group] defined previously, rules may also contain
+**wildcard** values β\*β which *always match*. These usually appear
+near the end of a rule set to set *default* values.
+
+```c
+! layout = keycodes
+ // The following two lines only match exactly their respective groups.
+ $azerty = +aliases(azerty)
+ $qwertz = +aliases(qwertz)
+ // This line will match layouts that are neither in $azerty nor in
+ // $qwertz groups.
+ * = +aliases(qwerty)
+```
Grammar
-------
-(It might be helpful to look at a file like rules/evdev along with
-this grammar. Comments, whitespace, etc. are not shown.)
+It is advised to look at a file like `rules/evdev` along with
+this grammar.
-```
+@note Comments, whitespace, etc. are not shown.
+
+```bnf
File ::= { "!" (Include | Group | RuleSet) }
Include ::= "include"
@@ -65,49 +149,210 @@ MlvoValue ::= "*" | GroupName |
KccgstValue ::=
```
-Notes:
+
+@note
+- Include processes the rules in the file path specified in the `ident`,
+ in order. **%-expansion** is performed, as follows:
+
+ - `%%`
+ - A literal %.
+ \%H
+ - The value of the `$HOME` environment variable.
+ \%E
+ -
+ The extra lookup path for system-wide XKB data (usually
+ `/etc/xkb/rules`).
+
+ \%S
+ -
+ The system-installed rules directory (usually
+ `/usr/share/X11/xkb/rules`).
+
+
-- Include processes the rules in the file path specified in the ident,
- in order. %-expansion is performed, as follows:
+- The order of values in a `Rule` must be the same as the `Mapping` it
+ follows. The mapping line determines the meaning of the values in
+ the rules which follow in the `RuleSet`.
-```
- %%:
- A literal %.
+- If a `Rule` is matched, **%-expansion** is performed on the
+`KccgstValue`, as follows:
- %H:
- The value of the HOME environment variable.
+
+ \%m
, \%l
, \%v
+ -
+ The [model], [layout] or [variant], if *only one* was given
+ (e.g.
\%l
for βus,ilβ is invalid).
+
+ -
+
\%l[1]
, \%l[2]
, β¦,
+ \%v[1]
, \%v[2]
, β¦
+
+ -
+ [Layout][layout] or [variant] for the specified layout `Index`,
+ if *more than one* was given, e.g.:
\%l[1]
is
+ invalid for βusβ but expands to βusβ for βus,deβ.
+
+ -
+ `%+m`,
+ `%+l`, `%+l[1]`, `%+l[2]`, β¦,
+ `%+v`, `%+v[1]`, `%+v[2]`, β¦
+
+ -
+ As above, but prefixed with β+β. Similarly, β|β, β-β, β_β may be
+ used instead of β+β. See the [merge mode] documentation for the
+ special meaning of β+β and β|β.
+
+ -
+ `%(m)`,
+ `%(l)`, `%(l[1])`, `%(l[2])`, β¦,
+ `%(v)`, `%(v[1])`, `%(v[2])`, β¦
+
+ -
+ As above, but prefixed by β(β and suffixed by β)β.
+
+
- %E:
- The extra lookup path for system-wide XKB data (usually /etc/xkb/rules).
+ In case the expansion is *invalid*, as described above, it is *skipped*
+ (the rest of the string is still processed); this includes the prefix
+ and suffix. This is why one should use e.g. %(v[1])
+ instead of (\%v[1])
. See @ref rules-symbols-example for
+ an illustration.
- %S:
- The system-installed rules directory (usually /usr/share/X11/xkb/rules).
-```
+RMLVO resolution process {#rmlvo-resolution}
+------------------------
-- The order of values in a Rule must be the same as the Mapping it
- follows. The mapping line determines the meaning of the values in
- the rules which follow in the RuleSet.
+First of all, the rules *file* is extracted from the provided
+[RMLVO][RMLVO] configuration (usually `evdev`). Then its path
+is resolved and the file is parsed to get the [rule sets].
+
+Then *each rule set* is checked against the provided [MLVO] configuration,
+following their *order* in the rules file.
+
+If a [rule] matches in a @ref rule-set-def "rule set", then:
+
+
+
+ -
+ @anchor rules-kccgst-value-update
+ The *KcCGST* value of the rule is used to update the [KcCGST]
+ configuration, using the following instructions. Note that `foo`
+ and `bar` are placeholders; β+β specifies the *override* [merge mode]
+ and can be replaced by β|β to specify the *augment* merge mode instead.
+
+ | Rule value | Old KcCGST value | New KcCGST value |
+ | ----------------- | ---------------- | --------------------- |
+ | `bar` | | `bar` |
+ | `bar` | `foo` | `foo` (*skip* `bar`) |
+ | `bar` | `+foo` | `bar+foo` (*prepend*) |
+ | `+bar` | | `+bar` |
+ | `+bar` | `foo` | `foo+bar` |
+ | `+bar` | `+foo` | `+foo+bar` |
+
+ -
+ The rest of the set will be *skipped*, except if the set matches
+ against [options]. Indeed, those may contain *multiple* legitimate
+ rules, so they are processed entirely. See @ref rules-options-example
+ for an illustration.
+
+
-- If a Rule is matched, %-expansion is performed on the KccgstValue,
- as follows:
+[value update]: @ref rules-kccgst-value-update
+[merge mode]: @ref merge-mode-def
+### Example: key codes
+
+Using the following example:
+
+```c
+! $jollamodels = jollasbj
+! $azerty = be fr
+! $qwertz = al ch cz de hr hu ro si sk
+
+! model = keycodes
+ $jollamodels = evdev+jolla(jolla)
+ olpc = evdev+olpc(olpc)
+ * = evdev
+
+! layout = keycodes
+ $azerty = +aliases(azerty)
+ $qwertz = +aliases(qwertz)
+ * = +aliases(qwerty)
```
- %m, %l, %v:
- The model, layout or variant, if only one was given (e.g.
- %l for "us,il" is invalid).
- %l[1], %v[1]:
- Layout or variant for the specified group Index, if more than
- one was given (e.g. %l[1] for "us" is invalid).
+we would have the following resolutions of [key codes]:
+
+| Model | Layout | Keycodes |
+| ---------- | :------: | :----------------------------------- |
+| `jollasbj` | `us` | `evdev+jolla(jolla)+aliases(qwerty)` |
+| `olpc` | `be` | `evdev+olpc(olpc)+aliases(azerty)` |
+| `pc` | `al` | `evdev+aliases(qwertz)` |
+
+### Example: layouts, variants and symbols {#rules-symbols-example}
- %+m, %+l, %+v, %+l[1], %+v[1]
- As above, but prefixed with '+'. Similarly, '|', '-', '_' may be
- used instead of '+'.
+Using the following example:
- %(m), %(l), %(l[1]), %(v), %(v[1]):
- As above, but prefixed by '(' and suffixed by ')'.
+```c
+! layout = symbols
+ * = pc+%l%(v)
+// The following would not work: syntax for *multiple* layouts
+// in a rule set for *single* layout.
+//* = pc+%l[1]%(v[1])
+
+! layout[1] = symbols
+ * = pc+%l[1]%(v[1])
+// The following would not work: syntax for *single* layout
+// in a rule set for *multiple* layouts.
+//* = pc+%l%(v)
+
+! layout[2] = symbols
+ * = +%l[2]%(v[2]):2
+
+! layout[3] = symbols
+ * = +%l[3]%(v[3]):3
```
- In case the expansion is invalid, as described above, it is
- skipped (the rest of the string is still processed); this includes
- the prefix and suffix (that's why you shouldn't use e.g. "(%v[1])").
+we would have the following resolutions of [symbols]:
+
+| Layout | Variant | Symbols | Rules sets used |
+| ---------- | ------------ | ----------------------------- | --------------- |
+| `us` | | `pc+us` | #1 |
+| `us` | `intl` | `pc+us(intl)` | #1 |
+| `us,es` | | `pc+us+es:2` | #2, #3 |
+| `us,es,fr` | `intl,,bepo` | `pc+us(intl)+es:2+fr(bepo):3` | #2, #3, #4 |
+
+### Example: layout, option and symbols {#rules-options-example}
+
+Using the following example:
+
+```c
+! $azerty = be fr
+
+! layout = symbols
+ * = pc+%l%(v)
+
+! layout option = symbols
+ $azerty caps:digits_row = +capslock(digits_row)
+ * misc:typo = +typo(base)
+ * lv3:ralt_alt = +level3(ralt_alt)
+ ```
+
+we would have the following resolutions of [symbols]:
+
+| Layout | Option | Symbols |
+| ------- | ---------------------------------------- | -------------------------------------------------------- |
+| `be` | `caps:digits_row` | `pc+be+capslock(digits_row)` |
+| `gb` | `caps:digits_row` | `pc+gb` |
+| `fr` | `misc:typo` | `pc+fr+typo(base)` |
+| `fr` | `misc:typo,caps:digits_row` | `pc+fr+capslock(digits_row)+typo(base)` |
+| `fr` | `lv3:ralt_alt,caps:digits_row,misc:typo` | `pc+fr+capslock(digits_row)+typo(base)+level3(ralt_alt)` |
+
+Note that the configuration with `gb` [layout] has no match for the [option]
+and that the order of the [options] in the [RMLVO] configuration has no
+influence on the resulting [symbols].