mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00

**Context** Currently, if there are multiple keybindings with a shared prefix, they are grouped into a nested series of Binding.Sets. For example, as reported in #2734, the following bindings: keybind = ctrl+z>1=goto_tab:1 keybind = ctrl+z>2=goto_tab:2 keybind = ctrl+z>3=goto_tab:3 Result in roughly the following structure (in pseudo-code): Keybinds{ Trigger("ctrl+z"): Value.leader{ Trigger("1"): Value.leaf{action: "goto_tab:1"}, Trigger("2"): Value.leaf{action: "goto_tab:2"}, Trigger("3"): Value.leaf{action: "goto_tab:3"}, } } When this is formatted into a string (and therefore in +list-keybinds), it is turned into the following as Value.format just concatenates all the sibling bindings ('1', '2', '3') into consecutive bindings, and this is then fed into a single configuration entry: keybind = ctrl+z>1=goto_tab:1>3=goto_tab:3>2=goto_tab:2 **Fix** To fix this, Value needs to produce a separate configuration entry for each sibling binding in the Value.leader case. So we can't produce the entry (formatter.formatEntry) in Keybinds and need to pass information down the Value tree to the leaf nodes, each of which will produce a separate entry with that function. This is accomplished with the help of a new Value.formatEntries method that recursively builds up the prefix for the keybinding, finally flushing it to the formatter when it reaches a leaf node. This is done without extra allocations by using a FixedBufferStream with the same buffer as before, sharing it between calls to nested siblings of the same prefix. **Testing** Besides the included unit tests, I ran the GLFW-based app and verified that the resulting binary produced the correct output with `ghostty +show-config`: ``` ❯ .zig-cache//o/02a32e7ba516d2692577a46f1a0df682/ghostty +show-config 2>/dev/null | grep goto_tab keybind = ctrl+z>1=goto_tab:1 keybind = ctrl+z>3=goto_tab:3 keybind = ctrl+z>2=goto_tab:2 ``` **Caveats** We do not track the order in which the bindings were added so the order is not retained in the formatConfig output. Resolves #2734