Last active
May 19, 2026 22:17
-
-
Save mikeslattery/444f4fef4a20cfe786ba323a081262f7 to your computer and use it in GitHub Desktop.
Fuzzy find Neovim buffers globally
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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 |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
TODOs:
bat eza bashgit ls-filesacross instances.I do not plan to make into a neovim plugin.