Want to see the full-length video right now for free?
As quick as we've been able to make it to open a pane and interact with
a process, it turns out that tmux accepts an optional shell-command
argument
to the split-window
command that can make this even more efficient. I've
been calling these interactions "quick panes" and have been using them more
and more of late. They all take advantage of the fact that tmux will close
the pane when the command provided as the shell-command
argument exits.
This makes for an extremely efficient workflow for things like accessing your
todo list or wiki, interacting with commands like irb or [gitsh][]
In addition, we can specify a starting directory for the pane in addition to
the shell-command using the -c start-directory
flag.
Some examples are:
# Quickly view system & process info in htop
bind-key h split-window -h "htop"
# Quickly edit todo list
bind-key t split-window -h "vim ~/todo.md"
# Quickly edit a file in your wiki
bind-key w split-window -h -c ~/my-wiki "reattach-to-user-namespace vim +CtrlP"
Note, you will need to specifically include reattach-to-user-namespace
on
OS X for proper clipboard integration when using these quick panes.
[gitsh]: https://github.com/thoughtbot/gitsh
Building on the workflow of quick panes and incorporating the wonderful [fzf][] "Fuzzy finder for your shell" utility, I've been able to pull together a mapping that provides a prompted fuzzy matching list of the sessions for rapid and intuitive navigation between them, without losing the context of the work in your current pane.
The mapping and shell pipeline it uses are largely based on [an example from the fzf documentation][], but is specific to session switching. The final mapping is included in the tmux conk below.
[fzf]: https://github.com/junegunn/fzf [an example from the fzf documentation]: https://github.com/junegunn/fzf#using-fzf-with-tmux-splits
Although the tmux authors have done an amazing job with defining a simple and
consistent interface, at times a command may be a bit much to remember or
type. Luckily, we can make use of the command-prompt
tmux command, which
takes a prompt string and a command template string, and can interpolate the
output of the prompt into the command by replacing the placeholder value %%
.
# Prompted join-pane
bind-key j command-prompt -p "join pane from: " "join-pane -h -s '%%'"
# Easily swap a pane (targeted by pane number) with the current pane
bind-key s display-panes\; command-prompt -p "pane #: " "swap-pane -t '%%'"
After years of using tmux, I've reached a point where I feel a bit lost if I find myself not in a tmux session. I've come to rely on the ability to arbitrarily split my screen to display and compare content, easily switch between sessions, etc. As such, I've built up a collection of configurations and mappings that allow me to always remain inside of a tmux session.
The first line of defense is initial shell startup. With the following shell
functions added to your shell rc file (~/.bashrc
or ~/.zshrc
in my case),
your shell will automatically connect to a tmux session on startup, even
creating the session as needed.
Note, this functionality relies on the availability of the [tat
script][] introduced in step 3.
# Add this to your zshrc or bzshrc file
_not_inside_tmux() { [[ -z "$TMUX" ]] }
ensure_tmux_is_running() {
if _not_inside_tmux; then
tat
fi
}
ensure_tmux_is_running
[tat
script]: https://github.com/thoughtbot/dotfiles/blob/master/bin/tat
Occasionally I will want to open a new tmux session after having navigated into a different git repo. Usually this would involve detaching from the current session as tmux will kindly prevent what seems like a nested session.
The [tat
script][] has functionality built in to be able to create a
detached session, avoiding the concern for session nesting, and then attach to
it. This allows us "break out" a session based on the current pane, even
cleaning up the pane after creating the new session. The following key binding
provides this behavior, mapping it to <prefix>C-b
for "break":
bind-key C-b send-keys 'tat && exit' 'C-m'
By default, killing a session via closing the final process of the session,
or explicitly running the kill-session
command, will disconnect us from
tmux. The following mapping of <prefix>K
will instead kill the current
session and switch us to another session, keeping us connected to tmux
throughout.
bind-key K run-shell 'tmux switch-client -n \; kill-session -t "$(tmux display-message -p "#S")" || tmux kill-session'
The .tmux.conf
as of the end of step 5:
unbind C-b
set -g prefix C-s
bind-key -r C-s send-prefix
bind-key r source-file ~/.tmux.conf \; display-message "~/.tmux.conf reloaded"
is_vim='echo "#{pane_current_command}" | grep -iqE "(^|\/)g?(view|n?vim?)(diff)?$"'
bind -n C-h if-shell "$is_vim" "send-keys C-h" "select-pane -L"
bind -n C-j if-shell "$is_vim" "send-keys C-j" "select-pane -D"
bind -n C-k if-shell "$is_vim" "send-keys C-k" "select-pane -U"
bind -n C-l if-shell "$is_vim" "send-keys C-l" "select-pane -R"
bind -n C-\ if-shell "$is_vim" "send-keys C-\\" "select-pane -l"
set-option -g default-terminal "screen-256color"
set-option -g status-keys "emacs"
set-option -g status-left-length 50
set-option -g status-right ""
bind-key - split-window -v -c '#{pane_current_path}'
bind-key \ split-window -h -c '#{pane_current_path}'
bind -n S-Left resize-pane -L 2
bind -n S-Right resize-pane -R 2
bind -n S-Down resize-pane -D 1
bind -n S-Up resize-pane -U 1
bind -n C-Left resize-pane -L 10
bind -n C-Right resize-pane -R 10
bind -n C-Down resize-pane -D 5
bind -n C-Up resize-pane -U 5
bind c new-window -c '#{pane_current_path}'
set-option -g base-index 1
set-option -g renumber-windows on
bind-key b break-pane -d
bind-key C-j choose-tree
# Use vim keybindings in copy mode
setw -g mode-keys vi
# Setup 'v' to begin selection as in Vim
bind-key -t vi-copy v begin-selection
bind-key -t vi-copy y copy-pipe "reattach-to-user-namespace pbcopy"
# Update default binding of `Enter` to also use copy-pipe
unbind -t vi-copy Enter
bind-key -t vi-copy Enter copy-pipe "reattach-to-user-namespace pbcopy"
bind-key h split-window -h "htop"
bind-key t split-window -h -c ~/ "vim todo.md"
bind-key w split-window -h -c ~/my-wiki "vim +CtrlP"
bind C-j split-window -v "tmux list-sessions | sed -E 's/:.*$//' | grep -v \"^$(tmux display-message -p '#S')\$\" | fzf --reverse | xargs tmux switch-client -t"
# Prompted join-pane
bind-key j command-prompt -p "join pane from: " "join-pane -h -s '%%'"
# Easily swap a pane (targeted by pane number) with the current pane
bind-key s display-panes\; command-prompt -p "pane #: " "swap-pane -t '%%'"
bind-key C-b send-keys 'tat && exit' 'C-m'
bind-key K run-shell 'tmux switch-client -n \; kill-session -t "$(tmux display-message -p "#S")" || tmux kill-session'