Skip to content

Instantly share code, notes, and snippets.

@mikeslattery
Last active May 19, 2026 22:17
Show Gist options
  • Select an option

  • Save mikeslattery/444f4fef4a20cfe786ba323a081262f7 to your computer and use it in GitHub Desktop.

Select an option

Save mikeslattery/444f4fef4a20cfe786ba323a081262f7 to your computer and use it in GitHub Desktop.
Fuzzy find Neovim buffers globally
#!/bin/bash
# Globally fuzzy search Neovim buffer filenames,
# across all Tmux panes.
# Requires: fzf, nvim, tmux, bash
# Optional: bat, eza
# Only tested on Fedora Linux
# https://gist.github.com/mikeslattery/444f4fef4a20cfe786ba323a081262f7
set -u
SOCKETDIR="/run/user/$(id -u)"
if ! find "$SOCKETDIR" -maxdepth 1 -type s -name 'nvim.*.0' -print -quit 2>/dev/null | grep -sq .; then
# macOS/BSD/WSL1/Cygwin/MSys2 logic: Neovim usually places sockets in a subdirectory of TMPDIR named after the user.
SOCKETDIR="${TMPDIR:-/tmp}/nvim.$(id -un)"
fi
get_nvim_sockets() {
_checksocket() {
if nc -z -U "$1"; then
echo "$1"
else
rm "$1"
fi
}
# Find sockets matching the pattern nvim.PID.0 and extract the PID.
for socket in $(find "$SOCKETDIR" -maxdepth 1 -type s -name 'nvim.*.0'); do
_checksocket "$socket" &
done
wait
}
# 1=socket, 2=expression
expr() {
nvim --clean --headless --server "$1" --remote-expr "$2"
echo
}
getlist() {
_getlistline() {
socket="$1"
# Query the specific Neovim instance for the TMUX_PANE environment variable it was started in.
# Convert the unique pane ID into a human-readable Session:Window.Pane format.
pane="$(expr "$socket" 'system("echo -n \"$PPID \"; tmux display-message -t $TMUX_PANE -p \"#S:#I.#P\"")')"
# Get all buffer numbers.
# Filter for listed buffers (buflisted).
# Get the absolute path (:p) for each buffer name.
# Join with newlines and prefix with PID and Pane info for fzf.
expr "$socket" 'join(map(filter(range(1, bufnr("$")), "buflisted(v:val)"), "getftime(bufname(v:val)) . \" \" . fnamemodify(bufname(v:val), \":p\")"), "\n")' |
sed "s/$/ ${pane}/"
}
{
# Iterate through all active Neovim server sockets.
for socket in $(get_nvim_sockets); do
_getlistline "$socket" &
done
wait
} | grep -v -- '^-1' | sort -r | awk '{print $3, $4, $2}'
}
focus_buffer() {
local pane="$1"
local socket="$2"
local file="$3"
tmux select-pane -t "$pane" -Z \; select-window -t "$pane" \; switch-client -t "${pane}" &
expr "$socket" "execute('b $file')" | sed '$d' &
wait
}
main() {
# Pipe the list into fzf with a dynamic preview.
# If the selection is a directory, use eza/ls; if a file, use bat/cat.
pickline="$(getlist | fzf --preview-window 'right:50%,<80(hidden)' --preview '
if [ -d {3} ]; then
eza -lT --color=always {3} 2>/dev/null || ls -la {3}
else
bat --color=always --style=numbers {3} 2>/dev/null || cat {3}
fi
')"
if [ -n "$pickline" ]; then
# Parse the PID, Tmux pane, and File path from the fzf selection.
pid=$(echo "$pickline" | awk '{print $1}')
pane=$(echo "$pickline" | awk '{print $2}')
file=$(echo "$pickline" | awk '{print $3}')
socket="${SOCKETDIR}/nvim.${pid}.0"
# Focus the correct Tmux pane/window and zoom if necessary.
# Send a remote command to the specific Neovim instance to switch to the chosen buffer.
focus_buffer "$pane" "$socket" "$file"
fi
}
main
@mikeslattery

mikeslattery commented May 17, 2026

Copy link
Copy Markdown
Author

TODOs:

  • If buffer is in a tab+window, switch to that window instead of just blindly loading the buffer in the current window.
  • Test on Mac.
  • Gracefully handle dependencies not being installed: bat eza bash
  • Use Lua instead of vimscript (as this thing gets more complicted)
  • Other options or additional related scripts:
    • Sort buffers by most recently accessed across all neovim instances
    • Given a path as arg, go to that tmux pane + neovim buffer, with autocomplete.
    • Launch in a tmux floating window, so it can be used from inside Neovim and other TUIs
    • Search unnamed buffers
    • Output all to stdout without fzf. (for scripting)
    • Global search git ls-files across instances.
    • Global search oldfiles. (Useful if you have separate shada file per instance).
    • Fuzzy find neovim instances by working directory.
    • List duplicate buffer paths, and/or duplicate neovim working directories.
    • Do not switch sessions (in case you have two terminal apps each running a different Tmux session).
  • Vim version

I do not plan to make into a neovim plugin.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment