From 3e511319706d357c523889b6620eb87c9f8abe65 Mon Sep 17 00:00:00 2001 From: Trevor Arjeski Date: Sun, 14 Jan 2024 23:46:31 +0300 Subject: [PATCH] refactor: fully rewrite opening logic - Iterate over all nvim sockets and find their associated panes. Traversing from sockets -> ppid (nvim client) -> ppid (shell/pane), instead of iterating through all panes - If there is one instance of nvim in the current window open there, otherwise display a menu that allows the user to select a pane containing nvim and open the file there. The menu can be styled with options in tmux conf. - If no nvim is found, the logic is the same and will just open in the current pane. --- README.md | 7 +++- scripts/ton | 89 ++++++++++++++++++++------------------------ scripts/variables.sh | 3 ++ tmux_open_nvim.tmux | 12 ++++++ 4 files changed, 61 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 60ab01a..ab5af6c 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,8 @@ Available configuration options to put in your `.tmux.conf` |Config |Description | Example |--- |--- |--- |`set -g @ton-open-strategy ":e"` | Command for opening a file | `:e` or `:tabnew` - +|`set -g @ton-menu-style` | Set style of display-menu for picking a pane | See `man tmux` STYLES +|`set -g @ton-menu-selected-style` | Set style of display-menu selection for picking a pane | See `man tmux` STYLES ## Usage @@ -50,6 +51,10 @@ $ ton file.txt # optionally add :[line]:[col] to the end, i.e file.txt:40:5 # Opens file.txt in nvim pane ``` +If you have more than one Neovim instance running in a tmux window, you will be +prompted with a tmux display-menu that will allow you to select where to open +the file. + #### Caveat Upon launch of a fresh tmux session, the script will not be in the first pane diff --git a/scripts/ton b/scripts/ton index 460ed33..5f1bd2a 100755 --- a/scripts/ton +++ b/scripts/ton @@ -8,6 +8,8 @@ source "$CURRENT_DIR/variables.sh" source "$CURRENT_DIR/helpers.sh" OPEN_STRATEGY="$(get_tmux_option "$open_strategy" ":e")" +MENU_STYLE="$(get_tmux_option "$menu_style")" +MENU_SELECTED_STYLE="$(get_tmux_option "$menu_selected_style")" # Check pipe from stdin or parameter FPATH=${STDIN:-$1} @@ -30,60 +32,49 @@ LINE=${a[1]:-0} COLUMN=${a[2]:-0} # Get all nvim listening sockets (default location) -IFS=':' read -r -a LISTEN_SOCKS <<<"$(ls "${XDG_RUNTIME_DIR:-${TMPDIR}nvim.${USER}}"/**/nvim.*.0 2>/dev/null | tr '\n' ':')" -IFS=$OIFS - -# Match child process with nvim sock, since process is within -# e.g `/run/user/1000/nvim.1624238.0` -- nvim process is 1624238 -IFS=':' read -r -a panes <<<"$(tmux list-panes -a -F '#{window_index} #{pane_index} #{pane_pid}' | tr '\n' ':')" -IFS=$OIFS +readarray -t LISTEN_SOCKS < <(ls "${XDG_RUNTIME_DIR:-${TMPDIR}nvim.${USER}}"/**/nvim.*.0 2>/dev/null) -CURRENT_WINDOW_ID=$(tmux display-message -p '#{window_index}') - -# args: -# socket -# win_id -# pane_id -remote_open() { - nvim --server "$1" --remote-send "$OPEN_STRATEGY $FILE" - nvim --server "$1" --remote-send ":call cursor($LINE, $COLUMN)" - tmux selectw -t "$2" && tmux selectp -t "$3" - exit 0 -} +CURRENT_WINDOW_INDEX=$(tmux display-message -p '#{window_index}') -for pane in "${panes[@]}"; do - IFS=' ' pane_ids=($pane) - IFS=$OIFS +MENU_ARGS=() +SOCK_COUNT=${#LISTEN_SOCKS[@]} +SOCK_INDEX=1 +for sock in "${LISTEN_SOCKS[@]}"; do + # extract pid from socket path + server_pid=$(echo "$sock" | cut -d'.' -f2) + # process id of server's parent, which is the nvim client + client_pid=$(ps -o ppid= -p "$server_pid" | tr -d ' ') + # process id of tmux pane that contains the nvim client + pane_pid=$(ps -o ppid= -p "$client_pid" | tr -d ' ') - win_id=${pane_ids[0]} - pane_id=${pane_ids[1]} - pid=${pane_ids[2]} + # tmux ids for the nvim client pane + readarray -d ' ' -t ids < <(tmux list-panes -a -f "#{==:#{pane_pid},$pane_pid}" -F "#{window_index} #{window_name} #{pane_index}") + window_index=${ids[0]} + window_name=${ids[1]} + pane_index=${ids[2]} - # Get pid of nvim process - cpid=$(pgrep -P "$pid" nvim) - ppid=0 - if [ $cpid ]; then - # Get pid of nvim parent RPC process (--embed) - ppid=$(pgrep -P "$cpid" nvim) + c1="nvim --server $sock --remote-send \"$OPEN_STRATEGY $FILE\"" + c2="nvim --server $sock --remote-send \":call cursor($LINE, $COLUMN)\"" + c3="tmux selectw -t $window_index && tmux selectp -t $pane_index" + remote_open="$c1 && $c2 && $c3" + if [[ $window_index == "$CURRENT_WINDOW_INDEX" ]] && [[ $SOCK_COUNT == 1 ]]; then + # we found a nvim running in our window, escape hatch + eval $remote_open + exit 0 + else + # store this nvim instance for selection + MENU_ARGS+=("$window_name: pane $pane_index" "$SOCK_INDEX" "run '$remote_open'") fi - - for sock in "${LISTEN_SOCKS[@]}"; do - # Check if the nvim process associated with the socket is the parent id - # Prioritize instances running in the current window, but fallback to first found instance - if [[ $sock == *nvim.$ppid.* ]] && [[ $win_id == $CURRENT_WINDOW_ID ]]; then - remote_open $sock $win_id $pane_id - elif [[ $sock == *nvim.$ppid.* ]] && [[ ! $SOCK ]]; then - SOCK=$sock - WIN_ID=$win_id - PANE_ID=$pane_id - fi - done + SOCK_INDEX=$(($SOCK_INDEX + 1)) done -if [[ $SOCK ]]; then - remote_open $SOCK $WIN_ID $PANE_ID +if [[ ${MENU_ARGS[0]} ]]; then + # open menu for selection + tmux menu -s "$MENU_STYLE" -H "$MENU_SELECTED_STYLE" -T "tmux-open-nvim: $FILE" "${MENU_ARGS[@]}" + exit 0 +else + # No remote nvim, so just open in current pane + tmux send-keys "nvim -c \"call cursor($LINE, $COLUMN)\" $FILE" + tmux send-keys "C-m" + exit 0 fi - -# No remote nvim, so just open in current pane -tmux send-keys "nvim -c \"call cursor($LINE, $COLUMN)\" $FILE" -tmux send-keys "C-m" diff --git a/scripts/variables.sh b/scripts/variables.sh index 2877412..8d32129 100644 --- a/scripts/variables.sh +++ b/scripts/variables.sh @@ -2,3 +2,6 @@ # ex. :e or :tabnew open_strategy="@ton-open-strategy" open_strategy_default=":e" + +menu_style="@ton-menu-style" +menu_selected_style="@ton-menu-selected-style" diff --git a/tmux_open_nvim.tmux b/tmux_open_nvim.tmux index 5e63cda..3e30aaa 100755 --- a/tmux_open_nvim.tmux +++ b/tmux_open_nvim.tmux @@ -17,8 +17,20 @@ set_open_strategy() { tmux set-option -gq "$open_strategy" "$strategy" } +set_menu_style() { + local style=$(get_tmux_option "$menu_style") + tmux set-option -gq "$open_strategy" "$style" +} + +set_menu_selected_style() { + local style=$(get_tmux_option "$menu_selected_style") + tmux set-option -gq "$menu_selected_style" "$style" +} + main() { set_open_strategy + set_menu_style + set_menu_selected_style path_add "$SCRIPT_DIR" } main