In my previous post, I wrote about how awesome tmux is for managing multiple terminals. However, even though it is widely used, I haven't been able to find a good Bash completion script for it. The tmux package does come with bash_completion_tmux.sh
but this does not complete command options or command aliases. So I wrote a better version which completes tmux
commands, aliases and their options. However, there is still room for improvement. It would be nice if it could complete session and window names too, but I haven't found the time to implement this yet.
Here is a demo:
$ tmux lis[TAB]
list-buffers list-clients list-commands
list-keys list-panes list-sessions list-windows
$ tmux list-windows -[TAB]
-a -t
$ tmux list-windows -a
sharfah:0: less [180x82] [layout f0de,180x82,0,0]
sharfah:1: tmp [180x82] [layout f0de,180x82,0,0] (active)
sharfah:2: isengard [180x82] [layout f0de,180x82,0,0]
sharfah:3: java [180x82] [layout f0de,180x82,0,0]
My completion script is shown below. You need to source it in your Bash profile. Alternatively, save it to your Bash completion directory e.g. ~/.bash/.bash/.bash_completion.d
and it should automatically get picked up.
The script is also available in my GitHub dotfiles repository. If you can improve it, fork it and send me a pull request!
#
# tmux completion
# by Fahd Shariff
#
_tmux() {
# an array of commands and their options
declare -A tmux_cmd_map
tmux_cmd_map=( ["attach-session"]="-dr -t target-session" \
["bind-key"]="-cnr -t key-table key command arguments" \
["break-pane"]="-d -t target-pane" \
["capture-pane"]="-b buffer-index -E end-line -S start-line -t target-pane" \
["choose-buffer"]="-t target-window template" \
["choose-client"]="-t target-window template" \
["choose-session"]="-t target-window template" \
["choose-window"]="-t target-window template" \
["clear-history"]="-t target-pane" \
["clock-mode"]="-t target-pane" \
["command-prompt"]="-I inputs -p prompts -t target-client template" \
["confirm-before"]="-p prompt -t target-client command" \
["copy-mode"]="-u -t target-pane" \
["delete-buffer"]="-b buffer-index" \
["detach-client"]="-P -s target-session -t target-client" \
["display-message"]="-p -c target-client -t target-pane message" \
["display-panes"]="-t target-client" \
["find-window"]="-t target-window match-string" \
["has-session"]="-t target-session" \
["if-shell"]="shell-command command" \
["join-pane"]="-dhv -p percentage|-l size -s src-pane -t dst-pane" \
["kill-pane"]="-a -t target-pane" \
["kill-server"]="kill-server" \
["kill-session"]="-t target-session" \
["kill-window"]="-t target-window" \
["last-pane"]="-t target-window" \
["last-window"]="-t target-session" \
["link-window"]="-dk -s src-window -t dst-window" \
["list-buffers"]="list-buffers" \
["list-clients"]="-t target-session" \
["list-commands"]="list-commands" \
["list-keys"]="-t key-table" \
["list-panes"]="-as -t target" \
["list-sessions"]="list-sessions" \
["list-windows"]="-a -t target-session" \
["load-buffer"]="-b buffer-index path" \
["lock-client"]="-t target-client" \
["lock-server"]="lock-server" \
["lock-session"]="-t target-session" \
["move-window"]="-dk -s src-window -t dst-window" \
["new-session"]="-d -n window-name -s session-name -t target-session -x width -y height command" \
["new-window"]="-adk -n window-name -t target-window command" \
["next-layout"]="-t target-window" \
["next-window"]="-a -t target-session" \
["paste-buffer"]="-dr -s separator -b buffer-index -t target-pane" \
["pipe-pane"]="-t target-pane-o command" \
["previous-layout"]="-t target-window" \
["previous-window"]="-a -t target-session" \
["refresh-client"]="-t target-client" \
["rename-session"]="-t target-session new-name" \
["rename-window"]="-t target-window new-name" \
["resize-pane"]="-DLRU -t target-pane adjustment" \
["respawn-pane"]="-k -t target-pane command" \
["respawn-window"]="-k -t target-window command" \
["rotate-window"]="-DU -t target-window" \
["run-shell"]="command" \
["save-buffer"]="-a -b buffer-index" \
["select-layout"]="-np -t target-window layout-name" \
["select-pane"]="-lDLRU -t target-pane" \
["select-window"]="-lnp -t target-window" \
["send-keys"]="-t target-pane key " \
["send-prefix"]="-t target-pane" \
["server-info"]="server-info" \
["set-buffer"]="-b buffer-index data" \
["set-environment"]="-gru -t target-session name value" \
["set-option"]="-agsuw -t target-session|target-window option value" \
["set-window-option"]="-agu -t target-window option value" \
["show-buffer"]="-b buffer-index" \
["show-environment"]="-g -t target-session" \
["show-messages"]="-t target-client" \
["show-options"]="-gsw -t target-session|target-window" \
["show-window-options"]="-g -t target-window" \
["source-file"]="path" \
["split-window"]="-dhvP -p percentage|-l size -t target-pane command" \
["start-server"]="start-server" \
["suspend-client"]="-t target-client" \
["swap-pane"]="-dDU -s src-pane -t dst-pane" \
["swap-window"]="-d -s src-window -t dst-window" \
["switch-client"]="-lnp -c target-client -t target-session" \
["unbind-key"]="-acn -t key-table key" \
["unlink-window"]="-k -t target-window" )
declare -A tmux_alias_map
tmux_alias_map=( ["attach"]="attach-session" \
["detach"]="detach-client" \
["has"]="has-session" \
["lsc"]="list-clients" \
["lscm"]="list-commands" \
["ls"]="list-sessions" \
["lockc"]="lock-client" \
["locks"]="lock-session" \
["new"]="new-session" \
["refresh"]="refresh-client" \
["rename"]="rename-session" \
["showmsgs"]="show-messages" \
["source"]="source-file" \
["start"]="start-server" \
["suspendc"]="suspend-client" \
["switchc"]="switch-client" \
["breakp"]="break-pane" \
["capturep"]="target-pane]" \
["displayp"]="display-panes" \
["findw"]="find-window" \
["joinp"]="join-pane" \
["killp"]="kill-pane" \
["killw"]="kill-window" \
["lastp"]="last-pane" \
["last"]="last-window" \
["linkw"]="link-window" \
["lsp"]="list-panes" \
["lsw"]="list-windows" \
["movew"]="move-window" \
["neww"]="new-window" \
["nextl"]="next-layout" \
["next"]="next-window" \
["pipep"]="pipe-pane" \
["prevl"]="previous-layout" \
["prev"]="previous-window" \
["renamew"]="rename-window" \
["resizep"]="resize-pane" \
["respawnp"]="respawn-pane" \
["respawnw"]="respawn-window" \
["rotatew"]="rotate-window" \
["selectl"]="select-layout" \
["selectp"]="select-pane" \
["selectw"]="select-window" \
["splitw"]="[shell-command]" \
["swapp"]="swap-pane" \
["swapw"]="swap-window" \
["unlinkw"]="unlink-window" \
["bind"]="bind-key" \
["lsk"]="list-keys" \
["send"]="send-keys" \
["unbind"]="unbind-key" \
["set"]="set-option" \
["setw"]="set-window-option" \
["show"]="show-options" \
["showw"]="show-window-options" \
["setenv"]="set-environment" \
["showenv"]="show-environment" \
["confirm"]="confirm-before" \
["display"]="display-message" \
["clearhist"]="clear-history" \
["deleteb"]="delete-buffer" \
["lsb"]="list-buffers" \
["loadb"]="load-buffer" \
["pasteb"]="paste-buffer" \
["saveb"]="save-buffer" \
["setb"]="set-buffer" \
["showb"]="show-buffer" \
["if"]="if-shell" \
["lock"]="lock-server" \
["run"]="run-shell" \
["info"]="server-info" )
local cur="${COMP_WORDS[COMP_CWORD]}"
local prev="${COMP_WORDS[COMP_CWORD-1]}"
COMPREPLY=()
# completing an option
if [[ "$cur" == -* ]]; then
#tmux options
if [[ "$prev" == "tmux" ]]; then
COMPREPLY=( $( compgen -W "-2 -8 -c -f -L -l -q -S -u -v -V" -- $cur ) )
else
#find the tmux command so that we can complete the options
local cmd="$prev"
local i=$COMP_CWORD
while [[ "$cmd" == -* ]]
do
cmd="${COMP_WORDS[i]}"
((i--))
done
#if it is an alias, look up what the alias maps to
local alias_cmd=${tmux_alias_map[$cmd]}
if [[ -n ${alias_cmd} ]]
then
cmd=${alias_cmd}
fi
#now work out the options to this command
local opts=""
for opt in ${tmux_cmd_map[$cmd]}
do
if [[ "$opt" == -* ]]; then
len=${#opt}
i=1
while [ $i -lt $len ]; do
opts="$opts -${opt:$i:1}"
((i++))
done
fi
done
COMPREPLY=($(compgen -W "$opts" -- ${cur}))
fi
else
COMPREPLY=($(compgen -W "$(echo ${!tmux_cmd_map[@]} ${!tmux_alias_map[@]})" -- ${cur}))
fi
return 0
}
complete -F _tmux tmux
Related posts:
Managing Multiple Terminals with Tmux
Writing your own Bash Completion Function