tonybtw.com

tonybtw.com

https://git.tonybtw.com/tonybtw.com.git git://git.tonybtw.com/tonybtw.com.git
12,722 bytes raw
1
#+TITLE: Tmux with Zero Plugins
2
#+AUTHOR: Tony, btw
3
#+date: 2025-11-13
4
#+HUGO_TITLE: Tmux with Zero Plugins
5
#+HUGO_FRONT_MATTER_FORMAT: yaml
6
#+HUGO_CUSTOM_FRONT_MATTER: :image "/img/tmux.png" :showTableOfContents true
7
#+HUGO_BASE_DIR: ~/repos/tonybtw.com
8
#+HUGO_SECTION: tutorial/tmux
9
#+EXPORT_FILE_NAME: index
10
#+OPTIONS: toc:nil broken-links:mark
11
#+HUGO_AUTO_SET_HEADLINE_SECTION: nil
12
#+DESCRIPTION: This is a quick and painless guide on how to configure tmux with zero plugins. Heavily inspired by Henry Misc's via negativa philosophy on removing things to solve problems, rather than adding them.
13
14
* Intro
15
What's up guys, my name is Tony, and today I'm gonna give you a quick and painless guide on configuring tmux with ZERO plugins.
16
17
Tmux is probably the most essential tool in my development workflow. It's a terminal multiplexer that allows you to split your terminal into multiple panes, create multiple windows, and detach/reattach sessions.
18
19
In the past, I relied on TPM as a plugin manager, but taking inspiration from Henry Misc, I decided to debloat my entire config into a plugin-less config. This means I don't need to rely on any plugins, and can just use the native Tmux settings.
20
21
Let's jump into it.
22
23
* What is Tmux?
24
Tmux stands for "Terminal Multiplexer". Here's what that means:
25
26
- *Sessions*: A tmux session is like a workspace. You can detach from it, close your terminal, and reattach later - everything is still there.
27
- *Windows*: Think of these like browser tabs. Each window is a full terminal view.
28
- *Panes*: These are splits within a window. You can have multiple terminals visible at once.
29
30
This is crucial if you SSH into servers, work on multiple projects, or just want to keep your terminal organized without using a tiling window manager.
31
32
* Installation
33
34
Alright so I'm on arch linux, btw, but this is going to work on literally any distro. Tmux is in every package manager.
35
36
For arch:
37
#+begin_src sh
38
sudo pacman -S tmux
39
#+end_src
40
41
For Ubuntu/Debian:
42
#+begin_src sh
43
sudo apt install tmux
44
#+end_src
45
46
NixOS... just add `tmux` to wherever you install your nixpkgs.
47
48
That's it. No plugins, no plugin managers, nothing. Just tmux.
49
50
* Key Pivotal Binds
51
52
** Prefix Key
53
The most important concept in tmux is the *prefix key*. By default, it's =Ctrl-b=, but we're gonna change it to =Ctrl-a= because it's way easier to reach.
54
55
Every tmux command starts with the prefix. So when I say "prefix + c", that means:
56
1. Press =Ctrl-a=
57
2. Release
58
3. Press =c=
59
60
** Sessions, Windows & Panes
61
62
Here's the hierarchy:
63
- A *session* contains multiple *windows*
64
- A *window* contains multiple *panes*
65
66
Think of it like this:
67
- Session = Project
68
- Window = Task within that project
69
- Pane = Terminal view for that task
70
71
** Pane Navigation
72
73
These are the binds you'll use 1000 times a day:
74
75
| Bind                | Action                    |
76
|---------------------+---------------------------|
77
| =prefix + \vert=    | Split vertically          |
78
| =prefix + -=        | Split horizontally        |
79
| =prefix + h/j/k/l=  | Navigate panes (vim-like) |
80
| =Alt + h/j/k/l=     | Navigate without prefix   |
81
82
** Window Management
83
84
| Bind                      | Action                |
85
|---------------------------+-----------------------|
86
| =prefix + c=              | Create new window     |
87
| =prefix + n=              | Next window           |
88
| =prefix + p=              | Previous window       |
89
| =Alt + 1-9=               | Jump to window 1-9    |
90
91
** Copy Mode
92
93
Copy mode lets you scroll through terminal history and copy text:
94
95
| Bind                 | Action                      |
96
|----------------------+-----------------------------|
97
| =prefix + [=         | Enter copy mode             |
98
| =v=                  | Start selection (vim-like)  |
99
| =Ctrl-v=             | Rectangle selection         |
100
| =y=                  | Copy selection              |
101
| =q=                  | Exit copy mode              |
102
103
* Configuration
104
105
Let's build a clean, readable config with zero plugins.
106
107
** Basic Settings
108
109
Create =~/.config/tmux/tmux.conf=:
110
111
#+begin_src conf
112
# Enable 256 color support
113
set -g default-terminal "tmux-256color"
114
set -ga terminal-overrides ",*:RGB"
115
116
# Enable mouse support
117
set -g mouse on
118
119
# Enable clipboard
120
set -g set-clipboard on
121
#+end_src
122
123
Let me break these down:
124
125
- =default-terminal "tmux-256color"= tells tmux to advertise itself as a 256-color terminal, which is essential for proper color rendering in modern terminal applications like Neovim.
126
- =terminal-overrides ",*:RGB"= enables true color (24-bit RGB) support, giving you access to millions of colors instead of just 256. This is what makes your color schemes look properly vibrant.
127
- =mouse on= is controversial in the terminal purist community, but it's genuinely useful for quickly clicking between panes or dragging borders to resize them. You can always disable it later if you go full keyboard-only.
128
- =set-clipboard on= allows tmux to integrate with your system clipboard, so when you copy text in tmux copy-mode, it actually goes to your system clipboard.
129
130
** Better Keybinds
131
132
#+begin_src conf
133
# Change prefix from Ctrl-b to Ctrl-a
134
unbind C-b
135
set -g prefix C-a
136
bind-key C-a send-prefix
137
138
# Vim-style pane navigation
139
bind h select-pane -L
140
bind j select-pane -D
141
bind k select-pane -U
142
bind l select-pane -R
143
144
# Split windows (opens in same directory)
145
unbind %
146
bind | split-window -h -c "#{pane_current_path}"
147
148
unbind '"'
149
bind - split-window -v -c "#{pane_current_path}"
150
151
# Reload config
152
unbind r
153
bind r source-file $HOME/.config/tmux/tmux.conf
154
155
# Alt+hjkl to switch panes without prefix
156
bind -n M-h select-pane -L
157
bind -n M-j select-pane -D
158
bind -n M-k select-pane -U
159
bind -n M-l select-pane -R
160
161
# Alt+number to select window
162
bind -n M-1 select-window -t 1
163
bind -n M-2 select-window -t 2
164
bind -n M-3 select-window -t 3
165
bind -n M-4 select-window -t 4
166
bind -n M-5 select-window -t 5
167
bind -n M-6 select-window -t 6
168
bind -n M-7 select-window -t 7
169
bind -n M-8 select-window -t 8
170
bind -n M-9 select-window -t 9
171
#+end_src
172
173
Let me explain the key concepts here:
174
175
- =unbind C-b= removes the default Ctrl-b prefix because it's awkward to reach. =set -g prefix C-a= changes it to Ctrl-a, which is way more ergonomic since your pinky is already on Ctrl.
176
- =bind-key C-a send-prefix= allows you to send the actual Ctrl-a to the terminal (useful in nested tmux sessions or when an app needs Ctrl-a).
177
- The vim-style =hjkl= binds are essential if you're a vim user - they let you navigate panes with prefix+h/j/k/l instead of the default arrow keys.
178
- =split-window -h -c "#{pane_current_path}"= is crucial - the =-c= flag makes new panes open in the same directory as your current pane. Without this, splits would open in your home directory, which is super annoying.
179
- =unbind %= and =unbind '"'= remove the default split bindings so we can use =|= and =-= instead, which are way more intuitive (vertical bar for vertical split, dash for horizontal split).
180
- =bind -n= means "bind without prefix". So =bind -n M-h= lets you use Alt+h to switch panes instantly, without hitting prefix first. This is a MASSIVE quality of life improvement once you get used to it.
181
- The Alt+number binds (M-1 through M-9) let you jump directly to windows without prefix, similar to how browser tabs work with Ctrl+1-9.
182
183
** Theme Colors
184
185
Now here's where we make it look good. I'm using Tokyo Night Moon colors, but you can swap these out for any color scheme.
186
187
#+begin_src conf
188
# Tokyo Night Moon theme colors
189
thm_bg="#222436"
190
thm_fg="#c8d3f5"
191
thm_cyan="#86e1fc"
192
thm_black="#1b1d2b"
193
thm_gray="#3a3f5a"
194
thm_magenta="#c099ff"
195
thm_pink="#ff757f"
196
thm_red="#ff757f"
197
thm_green="#c3e88d"
198
thm_yellow="#ffc777"
199
thm_blue="#82aaff"
200
thm_orange="#ff9e64"
201
thm_black4="#444a73"
202
203
# Status bar settings
204
set -g status "on"
205
set -g status-bg "${thm_bg}"
206
set -g status-justify "left"
207
set -g status-left-length "100"
208
set -g status-right-length "100"
209
210
# Messages
211
set -g message-style "fg=${thm_cyan},bg=${thm_gray},align=centre"
212
set -g message-command-style "fg=${thm_cyan},bg=${thm_gray},align=centre"
213
214
# Panes
215
set -g pane-border-style "fg=${thm_gray}"
216
set -g pane-active-border-style "fg=${thm_blue}"
217
218
# Windows
219
set -g window-status-activity-style "fg=${thm_fg},bg=${thm_bg},none"
220
set -g window-status-separator ""
221
set -g window-status-style "fg=${thm_fg},bg=${thm_bg},none"
222
#+end_src
223
224
** Status Bar Customization
225
226
This is where it gets interesting. The status bar shows your current windows and session info.
227
228
#+begin_src conf
229
# Statusline - current window
230
set -g window-status-current-format "#[fg=${thm_blue},bg=${thm_bg}] #I: #[fg=${thm_magenta},bg=${thm_bg}](✓) #[fg=${thm_cyan},bg=${thm_bg}]#(echo '#{pane_current_path}' | rev | cut -d'/' -f-2 | rev) #[fg=${thm_magenta},bg=${thm_bg}]"
231
232
# Statusline - other windows
233
set -g window-status-format "#[fg=${thm_blue},bg=${thm_bg}] #I: #[fg=${thm_fg},bg=${thm_bg}]#W"
234
235
# Statusline - right side
236
set -g status-right "#[fg=${thm_blue},bg=${thm_bg},nobold,nounderscore,noitalics]#[fg=${thm_bg},bg=${thm_blue},nobold,nounderscore,noitalics] #[fg=${thm_fg},bg=${thm_gray}] #W #{?client_prefix,#[fg=${thm_magenta}],#[fg=${thm_cyan}]}#[bg=${thm_gray}]#{?client_prefix,#[bg=${thm_magenta}],#[bg=${thm_cyan}]}#[fg=${thm_bg}] #[fg=${thm_fg},bg=${thm_gray}] #S "
237
238
# Statusline - left side (empty)
239
set -g status-left ""
240
241
# Modes
242
set -g clock-mode-colour "${thm_blue}"
243
set -g mode-style "fg=${thm_blue} bg=${thm_black4} bold"
244
#+end_src
245
246
This is where things get interesting. Let me break down what's happening:
247
248
- =window-status-current-format= defines how the active window looks in the status bar. It shows the window index (=#I=), a checkmark, and the last two parts of the current path.
249
- The =#(echo '#{pane_current_path}' | rev | cut -d'/' -f-2 | rev)= command runs a shell command every time the status bar updates. It reverses the path, takes the last 2 parts, then reverses again. So =/home/tony/projects/dotfiles= becomes =projects/dotfiles=.
250
- =window-status-format= is for inactive windows - just shows the index and window name.
251
- =status-right= shows the window name (=#W=), a visual indicator that changes from cyan to magenta when prefix is pressed using =#{?client_prefix,...}= conditional, and the session name (=#S=).
252
- =#I= is the window index (number), =#W= is the window name, =#S= is the session name - these are tmux's format variables.
253
254
The =#{?client_prefix,...}= syntax is tmux's conditional - it means "if prefix is pressed, use magenta, otherwise use cyan". This gives you a visual indicator when you're in prefix mode.
255
256
* Extra Binds & Tweaks
257
258
Here are some nice-to-haves that should be placed earlier in the config (after the basic settings):
259
260
#+begin_src conf
261
# Change from 0 based to 1 based because keyboard layout
262
set -g base-index 1
263
set -g pane-base-index 1
264
set-window-option -g pane-base-index 1
265
set-option -g renumber-windows on
266
267
# Vim-like copy/paste
268
set-window-option -g mode-keys vi
269
bind-key -T copy-mode-vi v send-keys -X begin-selection
270
bind-key -T copy-mode-vi C-v send-keys -X rectangle-toggle
271
bind-key -T copy-mode-vi y send-keys -X copy-selection-and-cancel
272
unbind -T copy-mode-vi MouseDragEnd1Pane
273
#+end_src
274
275
Here's what these do:
276
277
- =base-index 1= makes windows start counting from 1 instead of 0. This is way more ergonomic because window 1 is on the left of your keyboard (the 1 key), not the right (0 is to the right of 9). It's a small thing but it makes a huge difference.
278
- =pane-base-index 1= does the same for panes.
279
- =renumber-windows on= automatically renumbers your windows when you close one. So if you have windows 1, 2, 3, 4 and you close window 2, the remaining windows become 1, 2, 3. Without this, you'd have gaps like 1, 3, 4.
280
- =mode-keys vi= enables vim keybindings in copy mode. This is essential if you're a vim user - it means you can use j/k to navigate, v to start visual selection, etc.
281
- The =copy-mode-vi= bindings make =v= start a selection (like visual mode in vim) and =y= yank (copy) the selection.
282
- =C-v= lets you do rectangle selection (block visual mode in vim).
283
- =unbind -T copy-mode-vi MouseDragEnd1Pane= prevents mouse selection from automatically exiting copy mode, so you can still use =y= to copy after selecting with the mouse.
284
- You enter copy mode with =prefix + [=, navigate with vim keys, =v= to select, =y= to copy.
285
286
* Final Thoughts
287
288
You're now ready to use Tmux as a minimal, fast, and efficient terminal multiplexer.
289
290
Thanks so much for checking out this tutorial. If you got value from it, and you want to find more tutorials like this, check out
291
my youtube channel here: [[https://youtube.com/@tony-btw][YouTube]], or my website here: [[https://www.tonybtw.com][tony,btw]]
292
293
You can support me here: [[https://ko-fi.com/tonybtw][kofi]]