Skip to content

Commit

Permalink
rules: Add support for index ranges
Browse files Browse the repository at this point in the history
There is a lot of repetition in the current rules files provided by
xkeyboard-config, because the MLVO mappings need to match on the exact
layout/variant index. This also prevents to increase the number of
maximum groups, because it does not scale.

We introduces the following new special layout/variant indexes:
- “single”: matches a single layout; same as with no index.
- “first”: matches the first layout/variant, no matter how many layouts
  are in the RMLVO configuration. It allows to merge `layout` and
  `layout[1]` patterns.
- “later”: matches all but the first layout. This is an index range.
- “any”: matches layout at any position. This is an index range.

We also introduces the new `%i` expansion, which correspond to the index
of the matched layout in a mapping with an index range. Example:

    layout[later] = symbols
    my_layout     = +my_symbols:%i
    *             = +%l[%i]:%i

Let’s have a look at concrete examples from xkeyboard-config:

    ! model     layout     = symbols
      *         *          = pc+%l%(v)
    ! model     layout[1]  = symbols
      *         *          = pc+%l[1]%(v[1])
    ! model     layout[2]  = symbols
      *         *          = +%l[2]%(v[2])
    ! model     layout[3]  = symbols
      *         *          = +%l[3]%(v[3])
    ! model     layout[4]  = symbols
      *         *          = +%l[4]%(v[4])

    ! layout    option     = symbols
      *         grp:toggle = +group(toggle)
    ! layout[1] option     = symbols
      *         grp:toggle = +group(toggle):1
    ! layout[2] option     = symbols
      *         grp:toggle = +group(toggle):2
    ! layout[3] option     = symbols
      *         grp:toggle = +group(toggle):3
    ! layout[4] option     = symbols
      *         grp:toggle = +group(toggle):4

With this commit we can now simplify it into:

    ! model    layout[first] = symbols
      *        *             = pc+%l[%i]%(v[%i])
    ! model    layout[later] = symbols
      *        *             = +%l[%i]%(v[%i]):%i

    ! layout[any] option     = symbols
      *           grp:toggle = +group(toggle):%i

The latter rule will work even if we increase XKB_MAX_GROUPS, whereas
the former would require to add the missing entries for the new groups.

In order to maintain consistent rules, we now disallow layout and
variant to have different indexes. For example, the following mapping
are now invalid:
- layout variant[1]
- layout[1] variant[2]
- layout[1] variant
- layout[first] variant[1]
- layout[first] variant
- layout variant[any]
- etc.
  • Loading branch information
wismill committed Sep 26, 2024
1 parent 93244b1 commit 1f9d39e
Show file tree
Hide file tree
Showing 11 changed files with 1,409 additions and 157 deletions.
14 changes: 14 additions & 0 deletions changes/api/+modern-rules.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Rules: Added support for special layouts indexes:
- *single*: matches a single layout; `layout[single]` is the same as without
explicit index: `layout`.
- *first*: matches the first layout/variant, no matter how many layouts are in
the RMLVO configuration. Acts as both `layout` and `layout[1]`.
- *later*: matches all but the first layout. This is an index range. Acts as
`layout[2]` .. `layout[4]`.
- *any*: matches layout at any position. This is an index range.

Also added the special index `%i` which correspond to the index of the matched
layout.

See the [documentation](https://xkbcommon.org/doc/current/rule-file-format.html)
for further information.
57 changes: 55 additions & 2 deletions doc/rules-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,9 @@ RuleSet ::= Mapping { Rule }
Mapping ::= { Mlvo } "=" { Kccgst } "\n"
Mlvo ::= "model" | "option" | ("layout" | "variant") [ Index ]
Index ::= "[" 1..XKB_NUM_GROUPS "]"
Index ::= "[" ({ NumericIndex } | { SpecialIndex }) "]"
NumericIndex ::= 1..XKB_MAX_GROUPS
SpecialIndex ::= "single" | "first" | "later" | "any"
Kccgst ::= "keycodes" | "symbols" | "types" | "compat" | "geometry"
Rule ::= { MlvoValue } "=" { KccgstValue } "\n"
Expand Down Expand Up @@ -176,12 +178,42 @@ or %%H seems to do the job though.
</dd>
</dl>

- @anchor rules-special-indexes
Special indexes `single`, `first`, `later` and `any` were introduced in
version `1.8.0`.

<dl>
<dt>`single`</dt>
<dd>
Matches a single layout; `layout[single]` is the same as without
explicit index: `layout`.
</dd>
<dt>`first`</dt>
<dd>
Matches the first layout/variant, no matter how many layouts are in
the RMLVO configuration. Acts as both `layout` and `layout[1]`.
</dd>
<dt>`later`</dt>
<dd>
Matches all but the first layout. This is an index *range*.
Acts as `layout[2]` .. `layout[4]`.
</dd>
<dt>any</dt>
<dd>
Matches layout at any position. This is an index *range*.
Acts as `layout`, `layout[1]` .. `layout[4]`.
</dd>
</dl>

When using a layout index *range* (`later`, `any`), the @ref rules-i-expansion "%i expansion"
can be used in the `KccgstValue` to refer to the matched layout.

- 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`.

- If a `Rule` is matched, **%-expansion** is performed on the
`KccgstValue`, as follows:
`KccgstValue`, as follows:

<dl>
<dt><code>\%m</code>, <code>\%l</code>, <code>\%v</code></dt>
Expand Down Expand Up @@ -216,6 +248,17 @@ or %%H seems to do the job though.
<dd>
As above, but prefixed by ‘(’ and suffixed by ‘)’.
</dd>
<dt>
@anchor rules-i-expansion
`%%i`,
`%%l[%%i]`,
`%(l[%%i])`,
etc.
</dt>
<dd>
In case the mapping uses a @ref rules-special-indexes "special index",
`%%i` corresponds to the index of the matched layout.
</dd>
</dl>

In case the expansion is *invalid*, as described above, it is *skipped*
Expand Down Expand Up @@ -329,6 +372,16 @@ we would have the following resolutions of <em>[symbols]</em>:
| `us,es` | | `pc+us+es:2` | #2, #3 |
| `us,es,fr` | `intl,,bepo` | `pc+us(intl)+es:2+fr(bepo):3` | #2, #3, #4 |

Since version `1.8.0`, the previous code can be replaced with simply:

```c
! layout[first] = symbols
* = pc+%l[%i]%(v[%i])

! layout[later] = symbols
* = +%l[%i]%(v[%i]):%i
```

### Example: layout, option and symbols {#rules-options-example}

Using the following example:
Expand Down
1 change: 1 addition & 0 deletions src/darray.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ typedef darray (unsigned long) darray_ulong;
/*** Access ***/

#define darray_item(arr, i) ((arr).item[i])
#define darray_items(arr) ((arr).item)
#define darray_size(arr) ((arr).size)
#define darray_empty(arr) ((arr).size == 0)

Expand Down
Loading

0 comments on commit 1f9d39e

Please sign in to comment.