commit c21f2724910f8785e5ae2fbb36881e55162d7910 Author: Felix Förtsch Date: Tue Mar 10 13:58:08 2026 +0100 initial commit: tmux cheat sheet alfred workflow Co-Authored-By: Claude Opus 4.6 diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 0000000..37f7e62 --- /dev/null +++ b/.gitea/workflows/build.yml @@ -0,0 +1,30 @@ +name: Build Workflow + +on: + push: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Run tests + run: bash tests/test_tmux_search.sh + + - name: Build .alfredworkflow + run: bash build/build_workflow.sh + + - name: Extract version + id: version + run: | + VERSION=$(grep -A1 'version' info.plist | grep '' | sed 's/.*//;s/<\/string>.*//') + echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + + - name: Create release + uses: softprops/action-gh-release@v2 + with: + tag_name: v${{ steps.version.outputs.version }} + name: v${{ steps.version.outputs.version }} + files: dist/alfred-tmux-cheat-sheet.alfredworkflow diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..39cea69 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +dist/ +.DS_Store +.claude/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..7d20637 --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# tmux Cheat Sheet (Alfred Workflow) + +Quickly look up tmux commands, key bindings, and practical examples directly from Alfred. + +## Install + +Download `alfred-tmux-cheat-sheet.alfredworkflow` from the [latest release](https://git.felixfoertsch.de/felixfoertsch/alfred-tmux-cheat-sheet/releases/latest) and open it — Alfred imports it automatically. + +## Usage + +1. Open Alfred and type `tmux` followed by your query. +2. Results are ranked by how commonly they are needed. +3. Press **Enter** to copy the result to clipboard. +4. Press **Cmd+L** for a large type view. + +### Examples + +| Query | Finds | +|---|---| +| `tmux new session name` | `tmux new -s mysession` | +| `tmux split` | Key bindings (Ctrl+b %, Ctrl+b ") and commands | +| `tmux attach` | All ways to attach to a session | +| `tmux copy` | Copy mode shortcuts and buffer commands | +| `tmux mouse` | `tmux set -g mouse on` | + +## Configuration + +Open **Alfred → Workflows → tmux Cheat Sheet → Configure Workflow** to change the prefix key (default: `Ctrl+b`). + +## Development + +**Data sources:** +- **Key bindings** are parsed from your local `man tmux` via `bash scripts/parse_manual.sh`. +- **Practical examples** are curated in `data/examples.tsv` — add your own by appending a line: `command-name\tdescription\ttmux command`. +- **Tier ordering** controls result priority in `data/tiers.tsv` (1 = essential, 4 = rare). + +**Regenerate** the cheat sheet after a tmux update: `bash scripts/parse_manual.sh` + +**Run tests:** `bash tests/test_tmux_search.sh` + +**Build locally:** `bash build/build_workflow.sh` diff --git a/build/build_workflow.sh b/build/build_workflow.sh new file mode 100755 index 0000000..82b9c98 --- /dev/null +++ b/build/build_workflow.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +OUT_DIR="${ROOT_DIR}/dist" +STAGE_DIR="${OUT_DIR}/tmux-workflow" +WORKFLOW_FILE="${OUT_DIR}/alfred-tmux-cheat-sheet.alfredworkflow" + +rm -rf "${STAGE_DIR}" +mkdir -p "${STAGE_DIR}" "${OUT_DIR}" + +cp "${ROOT_DIR}/info.plist" "${STAGE_DIR}/" +cp "${ROOT_DIR}/icon.png" "${STAGE_DIR}/" +cp -R "${ROOT_DIR}/scripts" "${STAGE_DIR}/" +cp -R "${ROOT_DIR}/data" "${STAGE_DIR}/" + +( + cd "${STAGE_DIR}" + zip -rq "${WORKFLOW_FILE}" . +) + +echo "Created ${WORKFLOW_FILE}" diff --git a/data/examples.tsv b/data/examples.tsv new file mode 100644 index 0000000..d7f6c72 --- /dev/null +++ b/data/examples.tsv @@ -0,0 +1,106 @@ +new-session Start a new session tmux new +new-session Start a named session tmux new -s mysession +new-session Start a session with a named window tmux new -s mysession -n mywindow +new-session Start or attach to existing session tmux new -A -s mysession +attach-session Attach to last session tmux attach +attach-session Attach to a session by name tmux a -t mysession +detach-client Detach from current session tmux detach +list-sessions List all sessions tmux ls +kill-session Kill a session by name tmux kill-session -t mysession +kill-session Kill all sessions but current tmux kill-session -a +kill-session Kill all sessions except one tmux kill-session -a -t mysession +kill-server Kill tmux server and all sessions tmux kill-server +rename-session Rename current session tmux rename-session newname +switch-client Switch to another session tmux switch-client -t mysession +has-session Check if a session exists tmux has-session -t mysession +new-window Create a new window tmux new-window +new-window Create a named window tmux new-window -n editor +rename-window Rename current window tmux rename-window newname +kill-window Kill current window tmux kill-window +select-window Select window by number tmux select-window -t :2 +next-window Go to next window tmux next-window +previous-window Go to previous window tmux previous-window +last-window Toggle last active window tmux last-window +swap-window Swap two windows tmux swap-window -s 2 -t 1 +swap-window Move current window left tmux swap-window -t -1 +move-window Move window between sessions tmux move-window -s foo:0 -t bar:9 +move-window Renumber windows to remove gaps tmux move-window -r +list-windows List windows tmux list-windows +link-window Link window from another session tmux link-window -s src:1 -t dst +unlink-window Unlink a window tmux unlink-window -t :1 +split-window Split pane vertically (left/right) tmux split-window -h +split-window Split pane horizontally (top/bottom) tmux split-window -v +split-window Split pane with specific size tmux split-window -h -l 30% +select-pane Select pane by number tmux select-pane -t 1 +select-pane Select pane to the left tmux select-pane -L +select-pane Select pane above tmux select-pane -U +resize-pane Resize pane left tmux resize-pane -L 10 +resize-pane Resize pane right tmux resize-pane -R 10 +resize-pane Resize pane up tmux resize-pane -U 5 +resize-pane Resize pane down tmux resize-pane -D 5 +resize-pane Zoom/unzoom pane tmux resize-pane -Z +kill-pane Kill current pane tmux kill-pane +swap-pane Swap two panes tmux swap-pane -s 0 -t 1 +join-pane Move pane from another window tmux join-pane -s :1 +break-pane Move pane to its own window tmux break-pane +display-panes Show pane numbers tmux display-panes +move-pane Move pane to another window tmux move-pane -t :2 +last-pane Toggle last active pane tmux last-pane +rotate-window Rotate panes tmux rotate-window +pipe-pane Log pane output to file tmux pipe-pane -o 'cat >> ~/tmux.log' +copy-mode Enter copy mode tmux copy-mode +capture-pane Capture pane content to buffer tmux capture-pane -pS -200 +list-buffers List all paste buffers tmux list-buffers +show-buffer Show buffer contents tmux show-buffer +choose-buffer Choose and paste a buffer tmux choose-buffer +save-buffer Save buffer to file tmux save-buffer ~/tmux-buffer.txt +paste-buffer Paste buffer tmux paste-buffer +delete-buffer Delete a buffer tmux delete-buffer -b 0 +set-buffer Set buffer content tmux set-buffer "text" +load-buffer Load file into buffer tmux load-buffer ~/file.txt +send-keys Send keys to a pane tmux send-keys -t :1 "ls" Enter +send-keys Send keys to a session tmux send-keys -t mysession "cmd" Enter +set-option Enable mouse mode tmux set -g mouse on +set-option Set vi mode keys tmux set -g mode-keys vi +set-option Set base index to 1 tmux set -g base-index 1 +set-option Set escape time tmux set -sg escape-time 0 +set-option Set history limit tmux set -g history-limit 10000 +set-option Set default terminal tmux set -g default-terminal "screen-256color" +set-window-option Set pane base index tmux setw -g pane-base-index 1 +set-window-option Enable automatic rename tmux setw -g automatic-rename on +show-options Show all global options tmux show-options -g +show-options Show a specific option tmux show-options -g status-style +source-file Reload tmux config tmux source-file ~/.tmux.conf +bind-key Bind key to reload config tmux bind r source-file ~/.tmux.conf \; display "Reloaded" +bind-key Bind key to split vertical tmux bind | split-window -h +unbind-key Remove a key binding tmux unbind-key r +list-keys List all key bindings tmux list-keys +list-keys Show bindings for a key tmux list-keys -T prefix C-a +choose-tree Interactive session/window chooser tmux choose-tree +choose-tree Interactive session chooser tmux choose-tree -s +display-message Show a message tmux display-message "Hello" +display-message Show pane title tmux display-message -p "#{pane_title}" +command-prompt Open command prompt tmux command-prompt +show-environment Show environment variables tmux show-environment -g +set-environment Set environment variable tmux set-environment -g EDITOR nvim +run-shell Run shell command tmux run-shell "script.sh" +if-shell Run command conditionally tmux if-shell "test -f ~/.tmux.conf" "source ~/.tmux.conf" +display-popup Show a popup window tmux display-popup -w 80% -h 80% +display-menu Show a menu tmux display-menu -T "Title" "Item1" i "run cmd1" +clock-mode Show clock tmux clock-mode +clear-history Clear pane history tmux clear-history +confirm-before Ask before running command tmux confirm-before kill-session +refresh-client Refresh client display tmux refresh-client +respawn-pane Restart a dead pane tmux respawn-pane -k +respawn-window Restart a dead window tmux respawn-window -k +lock-server Lock the server tmux lock-server +suspend-client Suspend the client tmux suspend-client +wait-for Wait for a signal tmux wait-for signal-name +list-commands List all tmux commands tmux list-commands +show-messages Show log messages tmux show-messages +find-window Find window by name tmux find-window -N "editor" +select-layout Set pane layout tmux select-layout even-horizontal +select-layout Set tiled layout tmux select-layout tiled +customize-mode Enter customize mode tmux customize-mode +set-hook Set a hook tmux set-hook after-new-window "select-layout tiled" +show-hooks Show all hooks tmux show-hooks -g diff --git a/data/tiers.tsv b/data/tiers.tsv new file mode 100644 index 0000000..2db77df --- /dev/null +++ b/data/tiers.tsv @@ -0,0 +1,138 @@ +key-c 1 +key-d 1 +key-" 1 +key-% 1 +key-x 1 +key-z 1 +key-o 1 +key-0-to-9 1 +key-n 1 +key-p 1 +key-, 1 +key-$ 1 +key-w 1 +key-[ 1 +key-] 1 +key-: 1 +key-? 1 +new-session 1 +attach-session 1 +detach-client 1 +list-sessions 1 +kill-session 1 +kill-server 1 +split-window 1 +select-pane 1 +new-window 1 +select-window 1 +rename-window 1 +kill-window 1 +kill-pane 1 +resize-pane 1 +source-file 1 +copy-mode 1 +set-option 1 +key-C-b 2 +key-; 2 +key-l 2 +key-s 2 +key-& 2 +key-! 2 +key-{ 2 +key-} 2 +key-D 2 +key-L 2 +key-( 2 +key-) 2 +key-f 2 +key-q 2 +key-Page-Up 2 +key-Space 2 +key-' 2 +key-. 2 +key-# 2 +key-= 2 +key-- 2 +rename-session 2 +switch-client 2 +next-window 2 +previous-window 2 +last-window 2 +last-pane 2 +swap-pane 2 +swap-window 2 +move-window 2 +join-pane 2 +break-pane 2 +list-windows 2 +list-panes 2 +send-keys 2 +show-options 2 +bind-key 2 +unbind-key 2 +list-keys 2 +display-message 2 +has-session 2 +list-clients 2 +choose-tree 2 +choose-client 2 +command-prompt 2 +set-window-option 2 +key-C-o 3 +key-C-z 3 +key-i 3 +key-m 3 +key-M 3 +key-r 3 +key-t 3 +key-~ 3 +key-M-n 3 +key-M-o 3 +key-M-p 3 +capture-pane 3 +rotate-window 3 +select-layout 3 +next-layout 3 +previous-layout 3 +move-pane 3 +resize-window 3 +link-window 3 +unlink-window 3 +pipe-pane 3 +find-window 3 +display-panes 3 +paste-buffer 3 +choose-buffer 3 +list-buffers 3 +delete-buffer 3 +set-buffer 3 +save-buffer 3 +load-buffer 3 +show-buffer 3 +clear-history 3 +set-hook 3 +show-hooks 3 +set-environment 3 +show-environment 3 +respawn-pane 3 +respawn-window 3 +confirm-before 3 +display-popup 3 +display-menu 3 +run-shell 3 +if-shell 3 +send-prefix 3 +clock-mode 3 +refresh-client 3 +lock-server 3 +lock-client 3 +lock-session 3 +customize-mode 3 +suspend-client 4 +start-server 4 +server-access 4 +show-messages 4 +list-commands 4 +clear-prompt-history 4 +show-prompt-history 4 +wait-for 4 diff --git a/data/tmux_commands.tsv b/data/tmux_commands.tsv new file mode 100644 index 0000000..09aa45b --- /dev/null +++ b/data/tmux_commands.tsv @@ -0,0 +1,156 @@ +attach-session Attach to a session by name tmux a -t mysession +attach-session Attach to last session tmux attach +copy-mode Enter copy mode tmux copy-mode +detach-client Detach from current session tmux detach +key-, Rename the current window. {prefix} , +key-: Enter the tmux command prompt. {prefix} : +key-? List all key bindings. {prefix} ? +key-" Split the current pane into two, top and bottom. {prefix} " +key-[ Enter copy mode to copy text or view the history. {prefix} [ +key-] Paste the most recently copied buffer of text. {prefix} ] +key-% Split the current pane into two, left and right. {prefix} % +key-$ Rename the current session. {prefix} $ +key-0-to-9 Select windows 0 to 9. {prefix} 0 to 9 +key-c Create a new window. {prefix} c +key-d Detach the current client. {prefix} d +key-n Change to the next window. {prefix} n +key-o Select the next pane in the current window. {prefix} o +key-p Change to the previous window. {prefix} p +key-w Choose the current window interactively. {prefix} w +key-x Kill the current pane. {prefix} x +key-z Toggle zoom state of the current pane. {prefix} z +kill-pane Kill current pane tmux kill-pane +kill-server Kill tmux server and all sessions tmux kill-server +kill-session Kill a session by name tmux kill-session -t mysession +kill-session Kill all sessions but current tmux kill-session -a +kill-session Kill all sessions except one tmux kill-session -a -t mysession +kill-window Kill current window tmux kill-window +list-sessions List all sessions tmux ls +new-session Start a named session tmux new -s mysession +new-session Start a new session tmux new +new-session Start a session with a named window tmux new -s mysession -n mywindow +new-session Start or attach to existing session tmux new -A -s mysession +new-window Create a named window tmux new-window -n editor +new-window Create a new window tmux new-window +rename-window Rename current window tmux rename-window newname +resize-pane Resize pane down tmux resize-pane -D 5 +resize-pane Resize pane left tmux resize-pane -L 10 +resize-pane Resize pane right tmux resize-pane -R 10 +resize-pane Resize pane up tmux resize-pane -U 5 +resize-pane Zoom/unzoom pane tmux resize-pane -Z +select-pane Select pane above tmux select-pane -U +select-pane Select pane by number tmux select-pane -t 1 +select-pane Select pane to the left tmux select-pane -L +select-window Select window by number tmux select-window -t :2 +set-option Enable mouse mode tmux set -g mouse on +set-option Set base index to 1 tmux set -g base-index 1 +set-option Set default terminal tmux set -g default-terminal "screen-256color" +set-option Set escape time tmux set -sg escape-time 0 +set-option Set history limit tmux set -g history-limit 10000 +set-option Set vi mode keys tmux set -g mode-keys vi +source-file Reload tmux config tmux source-file ~/.tmux.conf +split-window Split pane horizontally (top/bottom) tmux split-window -v +split-window Split pane vertically (left/right) tmux split-window -h +split-window Split pane with specific size tmux split-window -h -l 30% +bind-key Bind key to reload config tmux bind r source-file ~/.tmux.conf \; display "Reloaded" +bind-key Bind key to split vertical tmux bind | split-window -h +break-pane Move pane to its own window tmux break-pane +choose-tree Interactive session chooser tmux choose-tree -s +choose-tree Interactive session/window chooser tmux choose-tree +command-prompt Open command prompt tmux command-prompt +display-message Show a message tmux display-message "Hello" +display-message Show pane title tmux display-message -p "#{pane_title}" +has-session Check if a session exists tmux has-session -t mysession +join-pane Move pane from another window tmux join-pane -s :1 +key-- Delete the most recently copied buffer of text. {prefix} - +key-; Move to the previously active pane. {prefix} ; +key-! Break the current pane out of the window. {prefix} ! +key-. Prompt for an index to move the current window. {prefix} . +key-' Prompt for a window index to select. {prefix} ' +key-( Switch the attached client to the previous session. {prefix} ( +key-) Switch the attached client to the next session. {prefix} ) +key-{ Swap the current pane with the previous pane. {prefix} { +key-} Swap the current pane with the next pane. {prefix} } +key-& Kill the current window. {prefix} & +key-# List all paste buffers. {prefix} # +key-= Choose which buffer to paste interactively from a list. {prefix} = +key-C-b Send the prefix key (C-b) through to the application. {prefix} Ctrl+b +key-D Choose a client to detach. {prefix} D +key-f Prompt to search for text in open windows. {prefix} f +key-l Move to the previously selected window. {prefix} l +key-L Switch the attached client back to the last session. {prefix} L +key-Page-Up Enter copy mode and scroll one page up. {prefix} Page Up +key-q Briefly display pane indexes. {prefix} q +key-s Select a new session for the attached client {prefix} s +key-Space Arrange the current window in the next preset layout. {prefix} Space +last-pane Toggle last active pane tmux last-pane +last-window Toggle last active window tmux last-window +list-keys List all key bindings tmux list-keys +list-keys Show bindings for a key tmux list-keys -T prefix C-a +list-windows List windows tmux list-windows +move-window Move window between sessions tmux move-window -s foo:0 -t bar:9 +move-window Renumber windows to remove gaps tmux move-window -r +next-window Go to next window tmux next-window +previous-window Go to previous window tmux previous-window +rename-session Rename current session tmux rename-session newname +send-keys Send keys to a pane tmux send-keys -t :1 "ls" Enter +send-keys Send keys to a session tmux send-keys -t mysession "cmd" Enter +set-window-option Enable automatic rename tmux setw -g automatic-rename on +set-window-option Set pane base index tmux setw -g pane-base-index 1 +show-options Show a specific option tmux show-options -g status-style +show-options Show all global options tmux show-options -g +swap-pane Swap two panes tmux swap-pane -s 0 -t 1 +swap-window Move current window left tmux swap-window -t -1 +swap-window Swap two windows tmux swap-window -s 2 -t 1 +switch-client Switch to another session tmux switch-client -t mysession +unbind-key Remove a key binding tmux unbind-key r +capture-pane Capture pane content to buffer tmux capture-pane -pS -200 +choose-buffer Choose and paste a buffer tmux choose-buffer +clear-history Clear pane history tmux clear-history +clock-mode Show clock tmux clock-mode +confirm-before Ask before running command tmux confirm-before kill-session +customize-mode Enter customize mode tmux customize-mode +delete-buffer Delete a buffer tmux delete-buffer -b 0 +display-menu Show a menu tmux display-menu -T "Title" "Item1" i "run cmd1" +display-panes Show pane numbers tmux display-panes +display-popup Show a popup window tmux display-popup -w 80% -h 80% +find-window Find window by name tmux find-window -N "editor" +if-shell Run command conditionally tmux if-shell "test -f ~/.tmux.conf" "source ~/.tmux.conf" +key-~ Show previous messages from tmux, if any. {prefix} ~ +key-C-o Rotate the panes in the current window forwards. {prefix} Ctrl+o +key-C-z Suspend the tmux client. {prefix} Ctrl+z +key-i Display some information about the current window. {prefix} i +key-M Clear the marked pane. {prefix} M +key-m Mark the current pane (see select-pane -m). {prefix} m +key-M-1-to-M-7 Arrange panes in one of the seven preset layouts: even- {prefix} Alt+1 to Alt+7 +key-M-n Move to the next window with a bell or activity marker. {prefix} Alt+n +key-M-o Rotate the panes in the current window backwards. {prefix} Alt+o +key-M-p Move to the previous window with a bell or activity {prefix} Alt+p +key-r Force redraw of the attached client. {prefix} r +key-t Show the time. {prefix} t +link-window Link window from another session tmux link-window -s src:1 -t dst +list-buffers List all paste buffers tmux list-buffers +load-buffer Load file into buffer tmux load-buffer ~/file.txt +lock-server Lock the server tmux lock-server +move-pane Move pane to another window tmux move-pane -t :2 +paste-buffer Paste buffer tmux paste-buffer +pipe-pane Log pane output to file tmux pipe-pane -o 'cat >> ~/tmux.log' +refresh-client Refresh client display tmux refresh-client +respawn-pane Restart a dead pane tmux respawn-pane -k +respawn-window Restart a dead window tmux respawn-window -k +rotate-window Rotate panes tmux rotate-window +run-shell Run shell command tmux run-shell "script.sh" +save-buffer Save buffer to file tmux save-buffer ~/tmux-buffer.txt +select-layout Set pane layout tmux select-layout even-horizontal +select-layout Set tiled layout tmux select-layout tiled +set-buffer Set buffer content tmux set-buffer "text" +set-environment Set environment variable tmux set-environment -g EDITOR nvim +set-hook Set a hook tmux set-hook after-new-window "select-layout tiled" +show-buffer Show buffer contents tmux show-buffer +show-environment Show environment variables tmux show-environment -g +show-hooks Show all hooks tmux show-hooks -g +unlink-window Unlink a window tmux unlink-window -t :1 +list-commands List all tmux commands tmux list-commands +show-messages Show log messages tmux show-messages +suspend-client Suspend the client tmux suspend-client +wait-for Wait for a signal tmux wait-for signal-name diff --git a/icon.png b/icon.png new file mode 100644 index 0000000..f2dbd53 Binary files /dev/null and b/icon.png differ diff --git a/info.plist b/info.plist new file mode 100644 index 0000000..e769dbf --- /dev/null +++ b/info.plist @@ -0,0 +1,135 @@ + + + + + bundleid + de.felixfoertsch.alfred-tmux-cheatsheet + connections + + 710D59E1-6AE3-40F9-BAA8-C0C0359DF7D3 + + + destinationuid + A1B2C3D4-COPY-CLIP-BOARD-E5F6G7H8I9J0 + modifiers + 0 + modifiersubtext + + vitowards + right + + + + createdby + Felix Foertsch + description + Quickly look up tmux commands, key bindings, and practical examples. + disabled + + name + tmux Cheat Sheet + objects + + + config + + alfredfiltersresults + + argumenttrimmode + 0 + argumenttype + 1 + escaping + 102 + keyword + tmux + queuedelaycustom + 1 + queuedelayimmediatelyinitially + + queuemode + 2 + runningsubtext + Searching tmux commands... + script + bash scripts/tmux_search.sh "{query}" + subtext + 1 + title + Search tmux commands + type + 0 + withspace + + + type + alfred.workflow.input.scriptfilter + uid + 710D59E1-6AE3-40F9-BAA8-C0C0359DF7D3 + version + 3 + + + config + + clipboardtext + {query} + transient + + + type + alfred.workflow.output.clipboard + uid + A1B2C3D4-COPY-CLIP-BOARD-E5F6G7H8I9J0 + version + 3 + + + readme + tmux Cheat Sheet — quickly look up tmux commands and key bindings from Alfred. + +Usage: + 1. Type "tmux" followed by your query (e.g. "tmux split", "tmux new session name") + 2. Results show practical commands and default key bindings + 3. Press Enter to copy the result to clipboard + 4. Press Cmd+L for large type view + +Configuration: + Go to Configure Workflow to change the prefix key (default: Ctrl+b). + +Data: + Key bindings are parsed from your local tmux manual. + Practical examples are curated in data/examples.tsv. + Run "bash scripts/parse_manual.sh" to regenerate after a tmux update. + uid + B92B9447-7F37-440D-B747-F0F504688948 + userconfigurationconfig + + + config + + default + Ctrl+b + placeholder + Ctrl+b + trim + + + description + The tmux prefix key combination (e.g. Ctrl+b or Ctrl+a) + label + Prefix Key + type + textfield + variable + prefix + + + variablesdontexport + + version + 2026.03.10 + webaddress + https://git.felixfoertsch.de/felixfoertsch/alfred-tmux-cheatsheet + + diff --git a/scripts/parse_manual.sh b/scripts/parse_manual.sh new file mode 100644 index 0000000..4cb42ee --- /dev/null +++ b/scripts/parse_manual.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# Build the tmux cheat sheet TSV from curated examples + man page key bindings. +# Output format: name\tdescription\tcommand\tshortcut +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +OUT="${SCRIPT_DIR}/../data/tmux_commands.tsv" +EXAMPLES="${SCRIPT_DIR}/../data/examples.tsv" +TIERS="${SCRIPT_DIR}/../data/tiers.tsv" + +man tmux | col -b > /tmp/tmux_man_raw.txt + +# Extract key bindings from man page, then append curated examples, then sort by tier +{ + # 1. Key bindings from the man page + awk ' + /^DEFAULT KEY BINDINGS/ { in_keys=1; next } + in_keys && /^[A-Z][A-Z ]/ && !/^DEFAULT/ { flush(); in_keys=0 } + + function flush() { + if (cur_key != "" && cur_desc != "") { + shortcut = "{prefix} " cur_key + gsub(/C-/, "Ctrl+", shortcut) + gsub(/M-/, "Alt+", shortcut) + first = cur_desc + sub(/\. .*/, ".", first) + name = "key-" cur_key + gsub(/[[:space:]]/, "-", name) + printf "%s\t%s\t\t%s\n", name, first, shortcut + } + cur_key = "" + cur_desc = "" + } + + in_keys && /^\t/ && /[^ \t]/ { + flush() + line = $0 + gsub(/^[[:space:]]+/, "", line) + n = match(line, /\t| +/) + if (n > 0) { + cur_key = substr(line, 1, n-1) + cur_desc = substr(line, n) + gsub(/^[[:space:]]+/, "", cur_desc) + gsub(/[[:space:]]+$/, "", cur_desc) + gsub(/[[:space:]]+$/, "", cur_key) + } + next + } + in_keys && /^\t\t/ && cur_key != "" { + line = $0 + gsub(/^[[:space:]]+/, "", line) + gsub(/[[:space:]]+$/, "", line) + cur_desc = cur_desc " " line + next + } + + END { flush() } + ' /tmp/tmux_man_raw.txt + + # 2. Curated examples (name\tdescription\tcommand, no shortcut) + awk -F'\t' '{ printf "%s\t%s\t%s\t\n", $1, $2, $3 }' "${EXAMPLES}" + +} | awk -F'\t' ' +NR == FNR { + tier[$1] = $2 + next +} +{ + split($1, parts, /[[:space:]]/) + cmd = parts[1] + t = (cmd in tier) ? tier[cmd] : 3 + print t "\t" $0 +} +' "${TIERS}" - | sort -t$'\t' -k1,1n | cut -f2- > "${OUT}" + +count="$(wc -l < "${OUT}" | tr -d ' ')" +echo "Wrote ${count} entries to ${OUT}" diff --git a/scripts/tmux_search.sh b/scripts/tmux_search.sh new file mode 100755 index 0000000..cd0a5d8 --- /dev/null +++ b/scripts/tmux_search.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +DATA_FILE="${SCRIPT_DIR}/../data/tmux_commands.tsv" +QUERY="${1:-}" +PREFIX="${prefix:-Ctrl+b}" + +awk -F'\t' -v query="${QUERY}" -v max=25 -v pfx="${PREFIX}" ' +BEGIN { + n = split(tolower(query), words, /[[:space:]]+/) + count = 0 + printf "{\"items\":[" +} + +{ + name = $1; desc = $2; cmd = $3; shortcut = $4 + if (name == "") next + gsub(/{prefix}/, pfx, shortcut) + + blob = tolower(name " " desc " " cmd " " shortcut) + for (i = 1; i <= n; i++) { + if (index(blob, words[i]) == 0) next + } + + if (count >= max) exit + + # Key bindings: title = shortcut + desc, subtitle = empty + # Commands: title = desc, subtitle = command + if (shortcut != "") { + title = shortcut " — " desc + subtitle = cmd + copy = shortcut + } else { + title = desc + subtitle = cmd + copy = cmd + } + + # arg = both lines for clipboard + if (subtitle != "") { + arg = title "\n" subtitle + } else { + arg = title + } + + if (count > 0) printf "," + count++ + + printf "{\"uid\":\"%s\",", escape(name "-" count) + printf "\"title\":\"%s\",", escape(title) + printf "\"subtitle\":\"%s\",", escape(subtitle) + printf "\"arg\":\"%s\",", escape(arg) + printf "\"match\":\"%s\",", escape(name " " desc " " cmd " " shortcut) + printf "\"text\":{\"copy\":\"%s\",\"largetype\":\"%s\"},", escape(copy), escape(arg) + printf "\"quicklookurl\":\"https://tmuxcheatsheet.com\"}" +} + +END { + if (count == 0) { + printf "{\"uid\":\"no-results\"," + printf "\"title\":\"No tmux commands found\"," + printf "\"subtitle\":\"Try a broader query (e.g. split, session, pane, copy)\"," + printf "\"valid\":false}" + } + printf "]}" +} + +function escape(s) { + gsub(/\\/, "\\\\", s) + gsub(/"/, "\\\"", s) + gsub(/\t/, " ", s) + gsub(/\n/, "\\n", s) + return s +} +' "${DATA_FILE}" diff --git a/tests/test_tmux_search.sh b/tests/test_tmux_search.sh new file mode 100755 index 0000000..ac82c80 --- /dev/null +++ b/tests/test_tmux_search.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +SCRIPT="${ROOT_DIR}/scripts/tmux_search.sh" + +assert_contains() { + local haystack="${1}" + local needle="${2}" + if [[ "${haystack}" != *"${needle}"* ]]; then + echo "assertion failed: expected output to contain: ${needle}" >&2 + exit 1 + fi +} + +# Test: session search returns practical results +out_session="$(bash "${SCRIPT}" "attach session")" +assert_contains "${out_session}" 'Attach to last session' +assert_contains "${out_session}" 'tmux attach' + +# Test: new session with name +out_new="$(bash "${SCRIPT}" "new session name")" +assert_contains "${out_new}" 'Start a named session' +assert_contains "${out_new}" 'tmux new -s mysession' + +# Test: key bindings show shortcut, not "key-" prefix +out_split="$(bash "${SCRIPT}" "split")" +assert_contains "${out_split}" 'Ctrl+b %' +if [[ "${out_split}" == *'"title":"key-'* ]]; then + echo "assertion failed: title should not contain key- prefix" >&2 + exit 1 +fi + +# Test: practical command in subtitle +assert_contains "${out_split}" 'tmux split-window -h' + +# Test: configurable prefix +out_custom="$(prefix="Ctrl+a" bash "${SCRIPT}" "split")" +assert_contains "${out_custom}" 'Ctrl+a %' + +# Test: no results +out_none="$(bash "${SCRIPT}" "definitely-not-a-real-command")" +assert_contains "${out_none}" '"uid":"no-results"' + +echo "tests passed"