Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/awk.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ applyTo: "**/*.awk"
---

- **Virtual `mouse:` table prefix**: The `mouse:` prefix on table names is an internal routing convention within the AWK parser to separate mouse bindings from keyboard bindings. These are virtual names that never leave the script -- tmux itself never sees them. Tmux key table names cannot contain colons, so there is no collision risk with real tables. Do not flag this prefix as a potential namespace collision.
- **String comparison in sort**: The `sort_bindings` function uses `<=` for lexicographic comparison. Key values stored via `keys[table, idx] = key repeat` are string-typed because the concatenation with the `repeat` variable converts strnum field values to strings. Do not flag this as a numeric comparison issue.
22 changes: 22 additions & 0 deletions scripts/parse-bindings.awk
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,32 @@ function is_mouse_key(k, bare) {
return (bare ~ /^(Mouse|Wheel|DoubleClick|TripleClick)/)
}

# Insertion sort: order bindings within a table by key text (case-sensitive).
function sort_bindings(t, i, j, n, tmp_key, tmp_cmd, a, b) {
n = count[t]
for (i = 2; i <= n; i++) {
tmp_key = keys[t, i]
tmp_cmd = cmds[t, i]
a = tmp_key
j = i - 1
while (j >= 1) {
b = keys[t, j]
Comment thread
cboone marked this conversation as resolved.
if (b <= a) break
keys[t, j + 1] = keys[t, j]
cmds[t, j + 1] = cmds[t, j]
j--
}
keys[t, j + 1] = tmp_key
cmds[t, j + 1] = tmp_cmd
}
}

END {
for (i = 1; i <= order_count; i++) {
t = order_arr[i]
if (t ~ /^mouse:/) continue
if (count[t] == 0) continue
sort_bindings(t)
label = table_label[t]
if (label == "") label = t
printf "GROUP\t%s (%d)\n", label, count[t]
Expand All @@ -181,6 +202,7 @@ END {
t = order_arr[i]
if (t !~ /^mouse:/) continue
if (count[t] == 0) continue
sort_bindings(t)
label = table_label[t]
if (label == "") label = t
printf "GROUP\t%s (%d)\n", label, count[t]
Expand Down
2 changes: 1 addition & 1 deletion scripts/popup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

main() {
local data
data="$(tmux list-keys | awk -f "$CURRENT_DIR/parse-bindings.awk")"
data="$(tmux list-keys | LC_ALL=C awk -f "$CURRENT_DIR/parse-bindings.awk")"

if [[ -z "$data" ]]; then
tmux display-message "tmux-binding-help: no bindings found"
Expand Down
16 changes: 8 additions & 8 deletions tests/parse-bindings.scrut
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
$ printf '%s\n' \
> 'bind-key -T prefix c new-window' \
> 'bind-key -r -T prefix Up select-pane -U' \
> | awk -f scripts/parse-bindings.awk | tr '\t' '|'
> | LC_ALL=C awk -f scripts/parse-bindings.awk | tr '\t' '|'
GROUP|Prefix (2)
BIND|c|new-window
BIND|Up (repeat)|select-pane -U
BIND|c|new-window
```

# Handles -N and -F options before key
Expand All @@ -16,7 +16,7 @@ BIND|Up (repeat)|select-pane -U
$ printf '%s\n' \
> 'bind-key -N "pane split" -T prefix % split-window -h' \
> 'bind-key -F "#{pane_id}" -T root MouseDown1Pane select-pane -t = && display-menu -T "Pane #{pane_index}"' \
> | awk -f scripts/parse-bindings.awk | tr '\t' '|'
> | LC_ALL=C awk -f scripts/parse-bindings.awk | tr '\t' '|'
GROUP|Prefix (1)
BIND|%|split-window -h
GROUP|Mouse (root) (1)
Expand All @@ -30,11 +30,11 @@ $ printf '%s\n' \
> 'bind-key -T prefix C-\\ display-message hi' \
> 'bind-key -T prefix \# display-message hash' \
> 'bind-key -T prefix \; display-message semi' \
> | awk -f scripts/parse-bindings.awk | tr '\t' '|'
> | LC_ALL=C awk -f scripts/parse-bindings.awk | tr '\t' '|'
GROUP|Prefix (3)
BIND|C-\|display-message hi
BIND|#|display-message hash
BIND|;|display-message semi
BIND|C-\|display-message hi
```

# Appends custom tables after built-in order
Expand All @@ -44,7 +44,7 @@ $ printf '%s\n' \
> 'bind-key -T custom-table x display-message custom' \
> 'bind-key -T root c new-window' \
> 'bind-key -T prefix n next-window' \
> | awk -f scripts/parse-bindings.awk | tr '\t' '|'
> | LC_ALL=C awk -f scripts/parse-bindings.awk | tr '\t' '|'
GROUP|Prefix (1)
BIND|n|next-window
GROUP|Root (no prefix) (1)
Expand All @@ -63,15 +63,15 @@ $ printf '%s\n' \
> 'bind-key -T copy-mode-vi MouseDrag1Pane begin-selection' \
> 'bind-key -T copy-mode-vi v send-keys -X begin-selection' \
> 'bind-key -T root M-DoubleClick1Pane resize-pane -Z' \
> | awk -f scripts/parse-bindings.awk | tr '\t' '|'
> | LC_ALL=C awk -f scripts/parse-bindings.awk | tr '\t' '|'
GROUP|Root (no prefix) (1)
BIND|n|next-window
GROUP|Copy Mode (vi) (1)
BIND|v|send-keys -X begin-selection
GROUP|Mouse (root) (3)
BIND|M-DoubleClick1Pane|resize-pane -Z
BIND|MouseDown1Pane|select-pane
BIND|WheelUpPane|scroll-up
BIND|M-DoubleClick1Pane|resize-pane -Z
GROUP|Mouse (copy-mode-vi) (1)
BIND|MouseDrag1Pane|begin-selection
```