detached 30529e3

test(keymap): pin wayland-format keymaps for fd reference cases

commit
30529e3b69ce8dbb82f1535aba7f2f46ffd3f694
author
brice · · 2026-09-28 07:10 UTC
parent
4e91a36
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
6 files · +8495 -20
M README.md +1 -1
@@ -15,6 +15,6 @@ defer state.Close()
1515 text, err := state.UTF8(xkbcommon.WaylandKeycode(evdevKeycode))
1616 ```
1717
18-Use `NewKeymapFD(fd, size)` for Wayland `xkb_v1` keymaps; it maps the supplied size with `PROT_READ|MAP_PRIVATE` and requires a trailing NUL. **The caller retains and must close the FD**, on success and failure. `UpdateMask` accepts Wayland modifier masks and group indices. `ComposeState.Feed` and `Status` distinguish composing, composed, cancelled, and ignored keysyms; use `UTF8` only for a composed result. Objects retain their native parents; close each object, in any order. Do not copy value structs containing a mutex.
18+Use `NewKeymapFD(fd, size)` for Wayland `xkb_v1` keymaps; it copies exactly `size` bytes with `pread` (at most 16 MiB), fails on a short read, and accepts an optional trailing NUL. **The caller retains and must close the FD**, on success and failure. `UpdateMask` accepts Wayland modifier masks and group indices. `ComposeState.Feed` and `Status` distinguish composing, composed, cancelled, and ignored keysyms; use `UTF8` only for a composed result. Objects retain their native parents; close each object, in any order. Do not copy value structs containing a mutex.
1919
2020 Pinned upstream headers and licenses are in `upstream/`; `upstream/METADATA` and `SHA256SUMS` identify their exact source. Run `GOWORK=off go generate ./...` to regenerate `raw/generated.go`; consumers do not run generation. The generator checks the selected ABI declarations against the headers. `github.com/bnema/purego v0.13.0-bnema.1` matches purego-vulkan and supports `Dlopen`, `Dlsym`, and `RegisterFunc` with cgo disabled.
@@ -15,6 +15,6 @@ defer state.Close()
15 text, err := state.UTF8(xkbcommon.WaylandKeycode(evdevKeycode))15 text, err := state.UTF8(xkbcommon.WaylandKeycode(evdevKeycode))
16 ```16 ```
17 17
18-Use `NewKeymapFD(fd, size)` for Wayland `xkb_v1` keymaps; it maps the supplied size with `PROT_READ|MAP_PRIVATE` and requires a trailing NUL. **The caller retains and must close the FD**, on success and failure. `UpdateMask` accepts Wayland modifier masks and group indices. `ComposeState.Feed` and `Status` distinguish composing, composed, cancelled, and ignored keysyms; use `UTF8` only for a composed result. Objects retain their native parents; close each object, in any order. Do not copy value structs containing a mutex.18+Use `NewKeymapFD(fd, size)` for Wayland `xkb_v1` keymaps; it copies exactly `size` bytes with `pread` (at most 16 MiB), fails on a short read, and accepts an optional trailing NUL. **The caller retains and must close the FD**, on success and failure. `UpdateMask` accepts Wayland modifier masks and group indices. `ComposeState.Feed` and `Status` distinguish composing, composed, cancelled, and ignored keysyms; use `UTF8` only for a composed result. Objects retain their native parents; close each object, in any order. Do not copy value structs containing a mutex.
19 19
20 Pinned upstream headers and licenses are in `upstream/`; `upstream/METADATA` and `SHA256SUMS` identify their exact source. Run `GOWORK=off go generate ./...` to regenerate `raw/generated.go`; consumers do not run generation. The generator checks the selected ABI declarations against the headers. `github.com/bnema/purego v0.13.0-bnema.1` matches purego-vulkan and supports `Dlopen`, `Dlsym`, and `RegisterFunc` with cgo disabled.20 Pinned upstream headers and licenses are in `upstream/`; `upstream/METADATA` and `SHA256SUMS` identify their exact source. Run `GOWORK=off go generate ./...` to regenerate `raw/generated.go`; consumers do not run generation. The generator checks the selected ABI declarations against the headers. `github.com/bnema/purego v0.13.0-bnema.1` matches purego-vulkan and supports `Dlopen`, `Dlsym`, and `RegisterFunc` with cgo disabled.
A testdata/keymaps/de.xkb +2090 -0 large diff (2090 lines changed): collapsed
A testdata/keymaps/fr.xkb +2084 -0 large diff (2084 lines changed): collapsed
A testdata/keymaps/us.xkb +2081 -0 large diff (2081 lines changed): collapsed
A testdata/keymaps/us_fr.xkb +2227 -0 large diff (2227 lines changed): collapsed
M xkbcommon_test.go +12 -19
@@ -238,9 +238,6 @@ func TestLayoutsAndDifferential(t *testing.T) {
238238 // binding under test. Every case compiles through the Wayland FD path.
239239 func TestFDReferenceKeyEvents(t *testing.T) {
240240 c := live(t)
241- if _, e := exec.LookPath("xkbcli"); e != nil {
242- t.Logf("xkbcli compile-keymap/how-to-type comparison skipped: %v", e)
243- }
244241 for _, tc := range []struct {
245242 layout, key, utf8, modifiers string
246243 evdev, group, sym uint32
@@ -256,23 +253,19 @@ func TestFDReferenceKeyEvents(t *testing.T) {
256253 {"us,fr", "a", "a", "", 16, 1, raw.XKB_KEY_a},
257254 } {
258255 t.Run(tc.layout+"/"+tc.key+"/"+tc.modifiers, func(t *testing.T) {
259- // xkbcli independently compiles the text used by the Wayland FD path.
260- // Without it, still check the fixed reference table against rules.
261- var k *Keymap
262- if _, e := exec.LookPath("xkbcli"); e == nil {
263- text, e := exec.Command("xkbcli", "compile-keymap", "--layout", tc.layout, "--output-format", "1").Output()
264- if e != nil {
265- t.Fatal(e)
266- }
267- f := keymapFile(t, append(text, 0))
268- k, e = c.NewKeymapFD(int(f.Fd()), len(text)+1)
269- if e != nil {
270- t.Fatal(e)
271- }
272- t.Cleanup(func() { k.Close() })
273- } else {
274- k = rules(t, c, tc.layout)
256+ // Wayland-format keymaps pinned in testdata/keymaps were produced by
257+ // `xkbcli compile-keymap --output-format 1` (libxkbcommon 1.13.2), so
258+ // the FD path is always exercised without optional tools.
259+ text, e := os.ReadFile("testdata/keymaps/" + strings.ReplaceAll(tc.layout, ",", "_") + ".xkb")
260+ if e != nil {
261+ t.Fatal(e)
262+ }
263+ f := keymapFile(t, append(text, 0))
264+ k, e := c.NewKeymapFD(int(f.Fd()), len(text)+1)
265+ if e != nil {
266+ t.Fatal(e)
275267 }
268+ t.Cleanup(func() { k.Close() })
276269 s := state(t, k)
277270 var mask uint32
278271 if tc.modifiers != "" {
@@ -238,9 +238,6 @@ func TestLayoutsAndDifferential(t *testing.T) {
238 // binding under test. Every case compiles through the Wayland FD path.238 // binding under test. Every case compiles through the Wayland FD path.
239 func TestFDReferenceKeyEvents(t *testing.T) {239 func TestFDReferenceKeyEvents(t *testing.T) {
240 c := live(t)240 c := live(t)
241- if _, e := exec.LookPath("xkbcli"); e != nil {
242- t.Logf("xkbcli compile-keymap/how-to-type comparison skipped: %v", e)
243- }
244 for _, tc := range []struct {241 for _, tc := range []struct {
245 layout, key, utf8, modifiers string242 layout, key, utf8, modifiers string
246 evdev, group, sym uint32243 evdev, group, sym uint32
@@ -256,23 +253,19 @@ func TestFDReferenceKeyEvents(t *testing.T) {
256 {"us,fr", "a", "a", "", 16, 1, raw.XKB_KEY_a},253 {"us,fr", "a", "a", "", 16, 1, raw.XKB_KEY_a},
257 } {254 } {
258 t.Run(tc.layout+"/"+tc.key+"/"+tc.modifiers, func(t *testing.T) {255 t.Run(tc.layout+"/"+tc.key+"/"+tc.modifiers, func(t *testing.T) {
259- // xkbcli independently compiles the text used by the Wayland FD path.256+ // Wayland-format keymaps pinned in testdata/keymaps were produced by
260- // Without it, still check the fixed reference table against rules.257+ // `xkbcli compile-keymap --output-format 1` (libxkbcommon 1.13.2), so
261- var k *Keymap258+ // the FD path is always exercised without optional tools.
262- if _, e := exec.LookPath("xkbcli"); e == nil {259+ text, e := os.ReadFile("testdata/keymaps/" + strings.ReplaceAll(tc.layout, ",", "_") + ".xkb")
263- text, e := exec.Command("xkbcli", "compile-keymap", "--layout", tc.layout, "--output-format", "1").Output()260+ if e != nil {
264- if e != nil {261+ t.Fatal(e)
265- t.Fatal(e)262+ }
266- }263+ f := keymapFile(t, append(text, 0))
267- f := keymapFile(t, append(text, 0))264+ k, e := c.NewKeymapFD(int(f.Fd()), len(text)+1)
268- k, e = c.NewKeymapFD(int(f.Fd()), len(text)+1)265+ if e != nil {
269- if e != nil {266+ t.Fatal(e)
270- t.Fatal(e)
271- }
272- t.Cleanup(func() { k.Close() })
273- } else {
274- k = rules(t, c, tc.layout)
275 }267 }
268+ t.Cleanup(func() { k.Close() })
276 s := state(t, k)269 s := state(t, k)
277 var mask uint32270 var mask uint32
278 if tc.modifiers != "" {271 if tc.modifiers != "" {

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 2

↑↓ moveenter openesc close