Integrating the Helix editor and Tmux

In a previous article, I shared my configuration for Helix and Zellij. This time, I’d like to share a similar setup, but focused on integrating the Helix editor with tmux.

I decided to switch from Zellij to tmux for two main reasons: to resolve keybindings conflicts between applications, and because I found Zellij’s configuration to be too rigid for my workflow, ultimately causing more trouble than it was worth.

Tmux Configuration

I use a few different terminal emulators on my Linux distribution, partly to experiment with new ones like Ghostty, and partly due to my Wayland setup. I have configured my system to automatically launch a new tmux session whenever I open a new instance of my terminal.

To achieve this, I added the following rule to my ~/.bashrc file:

# Automatically start tmux
if [ -z "$TMUX" ] && [ "$TERM" = "xterm-kitty" ] || [ "$TERM" = "xterm-ghostty" ]; then
  tmux attach || tmux new-session
fi

This script checks if the $TMUX variable is set. If it is, which indicates a tmux session is already active, the terminal attaches to it. Otherwise, it creates a new session. This rule is applied specifically to Kitty and Ghostty terminals.

Next, I've modified my ~/.tmux.conf to ensure that new windows and panes open in the same directory as the currently active pane:

# Open new windows and panes in the current working directory
bind c new-window -c "#{pane_current_path}"
bind '"' split-window -h -c "#{pane_current_path}"
bind % split-window -v -c "#{pane_current_path}"

Helix Configuration

First things first, here are the contents of my config.toml file:

theme = "catppuccin_mocha"

[editor]
# show currently open buffers, only when more than one exists.
bufferline = "multiple"
# Highlight all lines with a cursor
cursorline = true
# Use relative line numbers
line-number = "relative"
# Show a ruler at column 120
rulers = [120]
# Forse the theme to show colors
true-color = true
# Enable mouse usage
mouse = true
# Change color for modes
color-modes = true

[editor.cursor-shape]
insert = "bar"
normal = "block"
select = "underline"

[editor.lsp]
# Disable automatically popups of signature parameter help
auto-signature-help = false
# Show LSP messages in the status line
display-messages = true

[editor.file-picker]
git-global = false
hidden = false

[editor.statusline]
left = ["mode", "spinner"]
center = ["file-name"]
right = ["version-control", "diagnostics", "selections", "position", "file-encoding", "file-line-ending", "file-type"]
separator = ""
mode.normal = "NORMAL"
mode.insert = "INSERT"
mode.select = "SELECT"

[editor.indent-guides]
render = true
character = "" # Some characters that work well: "", "", "", ""
skip-levels = 1

[editor.whitespace]
render = "all"
# or control each character
#[editor.whitespace.render]
space = "all"
tab = "all"
nbsp = "all"
nnbsp = "all"
newline = "all"

[editor.whitespace.characters]
space = "·"
nbsp = ""
nnbsp = ""
tab = ""
newline = ""
tabpad = "·" # Tabs will look like "→···" (depending on tab width)

[keys.normal]
"A-," = "goto_previous_buffer"
"A-." = "goto_next_buffer"
"A-w" = ":buffer-close"
"A-|" = "repeat_last_motion"
"A-x" = "extend_to_line_bounds"
"X" = ["extend_line_up", "extend_to_line_bounds"]
"C-r" = ":config-reload"
"C-s" = ":w"
"C-j" = ["extend_to_line_bounds", "delete_selection", "paste_after"]
"C-k" = ["extend_to_line_bounds", "delete_selection", "move_line_up", "paste_before"]
"C-g" = ":sh tmux popup -d \"#{pane_current_path}\" -xC -yC -w80%% -h80%% -E /home/linuxbrew/.linuxbrew/bin/lazygit"
"C-t" = ":sh tmux split-window -v -l '35%%'"

[keys.normal."A-r"]
# Rust compile and run shortcuts
"b" = ":sh cargo build"
"r" = ":sh cargo run"
"t" = ":sh cargo test"

# Golang compile and run shortcuts
[keys.normal."A-g"]
"b" = ":sh go build ."
"r" = ":sh go run ."
"t" = ":sh go test ."

# Insert secure complex password of 36 chars
[keys.normal."A-i"]
"p" = ":append-output pwgen -snycB1 36"

# tmux pane settings
[keys.normal."A-t"]
"v" = ":sh tmux split-window -h"
"h" = ":sh tmux split-window -v"

[keys.select]
"A-x" = "extend_to_line_bounds"
"X" = ["extend_line_up", "extend_to_line_bounds"]

In the Helix configuration file, you can see several keybindings designed to integrate with tmux.

For example, in the [keys.normal."A-t"] section, I have set up bindings that use tmux to manage panes. Pressing Alt+t in normal mode provides two options:

  • v: Opens a new vertical tmux pane.
  • h: Opens a new horizontal tmux pane.

Additionally, the Ctrl+t binding is configured to create a new horizontal pane that occupies 35% of the window's height.

Note that movement between these tmux panes must be handled by your standard tmux keybindings, not by Helix.


You'll only receive email when they publish something new.

More from Pietrangelo Masala
All posts