Skip to main content
Neovim: config update

Neovim: config update

A few days ago I finally found the courage to update my setup, moving from a single vimscript file to a nice Lua config. I also took the opportunity to update my tmux config.

For at least 10 years, I’ve been using Vim inside tmux with the same prefix, C-w. When Vim is open, the prefix is forwarded to vim; otherwise, it goes to tmux. Life is good, everything works.

Migration fail
#

The curse of updates: this behavior is broken. But only partially, meaning that with the combo tmux+neovim or ssh+tmux+neovim on my laptop, everything is fine, BUT on my desktop with tmux+neovim, it isn’t.

Am I a grumpy old man now? Is this it? Is this the feeling? The world changes and I can’t adapt? Not wanting to change my habits so they work with how the world changes?

Probably. I’m a grumpy old man then. I want Ctrl-w as the prefix for tmux and Neovim. Leave me alone with your editors of the future.

Let’s check versions first, and add a third server as a witness for fun.

Host distro tmux neovim ssh nushell oh-my-posh
Desktop manjaro 3.5a 0.11.4 OpenSSH_10.0p2, OpenSSL 3.5.3 16 Sep 2025 0.109.0 28.1.0
Laptop arch 3.6 0.11.5 OpenSSH_10.2p1, OpenSSL 3.6.0 1 Oct 2025 0.109.0 28.1.0
Server ubuntu 3.4 0.10.0-dev OpenSSH_9.6p1 Ubuntu-3ubuntu13.14, OpenSSL 3.0.13 30 Jan 2024 0.79.1 na

Okay. We already have a small idea of what’s wrong. I’ll have to manually update tmux and nvim. Once I’ve got a working workflow, I’ll add the required versions to my config’s README.

Update on Manjaro
#

On AUR, we can find tmux 3.6:

$ yay -Ss tmux
extra/tmux 3.6_a-1 (485.2 KiB 1.1 MiB) (Installed)
    Terminal multiplexer
$ tmux -V
tmux 3.6a

Same for neovim:

$ yay -Ss neovim
extra/neovim 0.11.5-1 (6.8 MiB 28.8 MiB) (Installed)
    Fork of Vim aiming to improve user experience, plugins, and GUIs
$ nvim --version
NVIM v0.11.5
Build type: RelWithDebInfo
LuaJIT 2.1.1765007043
Run "nvim -V1 -v" for more info

Let’s see if I restart the tmux server now

$ tmux kill-server

Nope. Still not the expected behavior.

Update on Ubuntu
#

Let’s check that my config does NOT work on the server.

$ git clone git@github.com:proullon/conf.git

First, nu crashes on startup. Let’s update it.

$ git clone git@github.com:nushell/nushell.git
$ git checkout 0.109.0
$ cargo build --release
$ cp target/release/nu /usr/local/bin/nu
$ nu --version
$ curl -s https://ohmyposh.dev/install.sh | bash -s -- -d ~/.local/bin

(yes, I know, that’s not ideal.)

$ cd /tmp
$ curl -LO https://github.com/neovim/neovim/releases/download/v0.11.5/nvim-linux-arm64.tar.gz
$ tar xzf nvim-linux-arm64.tar.gz
$ sudo mv nvim-linux-arm64 /opt/neovim
$ sudo ln -sf /opt/neovim/bin/nvim /usr/local/bin/nvim
$ cd /tmp
$ curl -LO https://github.com/tmux/tmux/releases/download/3.6/tmux-3.6.tar.gz
$ tar xzf tmux-3.6.tar.gz
$ cd tmux-3.6
$ ./configure
$ make
$ sudo make install
$ tmux -V
tmux 3.6

Let’s recap now:

Host distro tmux neovim ssh nushell oh-my-posh
Desktop manjaro 3.6a 0.11.6 OpenSSH_10.2p1, OpenSSL 3.6.0 0.109.0 28.1.0
Laptop arch 3.6 0.11.5 OpenSSH_10.2p1, OpenSSL 3.6.0 0.109.0 28.1.0
Server ubuntu 3.6 0.11.5 OpenSSH_9.6p1 Ubuntu-3ubuntu13.14, OpenSSL 3.0.13 0.109.0 28.2.2

tmux config debug
#

So now I don’t have C-w in Neovim on both the desktop and the server. Yay. Also, C-l doesn’t clear the shell anymore. I now have to do C-w C-l.

So, to summarize:

Host C-w l C l
Desktop last_window nothing
Laptop split switch nothing
Server last_window nothing

To start, I’ll unbind C-w l last_window since I don’t use it.

unbind l
Host C-w l C l
Desktop nothing nothing
Laptop split switch nothing
Server nothing nothing

OK, time to debug. Let’s check why the test to detect whether the current pane is Vim isn’t working. Let’s add this shortcut to my config:

bind D run-shell '
cmd=$(ps -o comm= -p #{pane_pid})
tmux display-message "pane_pid=#{pane_pid} cmd=$cmd"
'

Surprise. In a Vim pane -> cmd: nu. In a pane with htop -> nu. OK.

Let’s try to display the child process

bind D run-shell '
children=$(ps --ppid #{pane_pid} -o comm= | tr "\n" " ")
tmux display-message "children=$children"
'

So, I guess, a correct is_vim would rather be:

is_vim='ps --ppid #{pane_pid} -o comm= | tr "\n" " " | grep -iq nvim'

Dumb forwarding
#

ANYWAY. That’s not really the problem since is_vim is never evaluated anyway. Let’s change strategy. I’m going back to what I had in my config before:

bind-key 'h' 'send-keys C-w h'
bind-key 'j' 'send-keys C-w j'
bind-key 'k' 'send-keys C-w k'
bind-key 'l' 'send-keys C-w l'

I simply make tmux forward the entire sequence when it receives C-w h/j/k/l. Still no idea why it works at all on my laptop. That’s it. I’ll deal with being smart later. I’ll look at vim-tmux-navigator later: https://github.com/christoomey/vim-tmux-navigator.

vim-tmux-navigator
#

OK. Let’s try to be smart and adapt.

I’ll add vim-tmux-navigator to my tmux config:

# tmux.conf
# (automatically handle C-h/j/k/l)
set -g @plugin 'christoomey/vim-tmux-navigator'

and to my Neovim config:

--- lua/plugins/tmux.conf
return {
    {
        "christoomey/vim-tmux-navigator",
        lazy = false,
        init = function()
            -- Disable default mappings if you want to control everything yourself
            -- Set to 1 ONLY if you want to define your own keymaps
            -- vim.g.tmux_navigator_no_mappings = 1
        end,
    },
}

I can now move around between nvim and tmux split seamlessly with C h/j/k/l.

It takes a month to cement a habit? Let’s see.

Related