From 09de712152e2a07a64530f4e5af769323431d23d Mon Sep 17 00:00:00 2001 From: Prad Nukala Date: Fri, 16 Oct 2026 11:50:45 -0400 Subject: [PATCH] feat(cli): add tmux-sessions script for tmux session switching via palette --- dot_local/bin/executable_tmux-sessions | 95 ++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100755 dot_local/bin/executable_tmux-sessions diff --git a/dot_local/bin/executable_tmux-sessions b/dot_local/bin/executable_tmux-sessions new file mode 100755 index 0000000..d2f8f4d --- /dev/null +++ b/dot_local/bin/executable_tmux-sessions @@ -0,0 +1,95 @@ +#!/usr/bin/env bash +# tmux-sessions — tmux session switcher as a tmux-palette source (the +# "sessions" palette, ~/.config/tmux-palette/palettes/sessions.json). +# +# tmux-sessions print palette items (JSON): the other sessions +# (last one first), every window of every session, +# zoxide's directories, ~/.config's directories, +# and a Rename and a Kill item per session +# tmux-sessions --new QUERY the palette's query item (what was typed): switch +# to session QUERY, or start it in QUERY if that is +# a directory, else in zoxide's best match for it +# tmux-sessions --dir DIR switch to, or start in DIR, the session named +# after DIR's basename without dots +# +# pj-palette's background task sessions (@pj_task) are left out. Sessions are +# targeted by id since names may contain ':'. + +set -uo pipefail +self=$(readlink -f "$0") + +session_id() { # name + local id name + while IFS=$'\t' read -r id name; do + [ "$name" = "$1" ] && { printf '%s' "$id"; return 0; } + done < <(tmux list-sessions -F $'#{session_id}\t#{session_name}' 2>/dev/null) + return 1 +} + +# Switch to session NAME, first starting it in DIR (when given) if missing. +open() { # name [dir] + local id + id=$(session_id "$1") || + id=$(tmux new-session -d -P -F '#{session_id}' -s "$1" ${2:+-c "$2"}) || exit 1 + tmux switch-client -t "$id" +} + +case ${1-} in +--dir) + dir=${2%/} + name=${dir##*/} + open "${name//./}" "$2" + exit + ;; +--new) + query=$2 + [ -d "${query/#\~/$HOME}" ] && exec "$self" --dir "${query/#\~/$HOME}" + dir= + if ! session_id "$query" >/dev/null; then + read -ra words <<<"$query" + dir=$(zoxide query -- "${words[@]}" 2>/dev/null) + fi + open "$query" "$dir" + exit + ;; +esac + +{ + tmux list-sessions -F $'S\t#{session_id}\t#{session_name}\t#{@pj_task}\t#{session_attached}\t#{session_windows}\t#{session_path}' + tmux list-windows -a -F $'W\t#{session_id}\t#{session_name}\t#{@pj_task}\t#{window_id}\t#{window_index}\t#{window_name}\t#{pane_current_path}' + zoxide query -l 2>/dev/null | sed 's/^/Z\t/' + find -L "$HOME/.config" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sort | sed 's/^/C\t/' +} | jq -Rn --arg self "$self" --arg home "$HOME" \ + --arg cur "$(tmux display -p '#{session_id}')" --arg last "$(tmux display -p '#{client_last_session}')" ' + def tilde: if startswith($home) then "~" + .[($home | length):] else . end; + def session_name: rtrimstr("/") | split("/") | last | gsub("\\."; ""); + [inputs | split("\t")] as $rows + | ($rows | map(select(.[0] == "S" and .[3] == ""))) as $sessions + | ($rows | map(select(.[0] == "S") | .[2])) as $names + | ($rows | map(select(.[0] == "Z") | .[1])) as $zoxide + | ($sessions | map(select(.[1] != $cur))) as $others + | def dir($category; $icon): + (.[1] | session_name) as $name + | {category: $category, icon: $icon, title: (.[1] | tilde), + description: (if $names | any(. == $name) then "switch to \($name)" else "new session \($name)" end), + action: {shell: "\($self | @sh) --dir \(.[1] | @sh)"}}; + [ + (($others | map(select(.[2] == $last)) + map(select(.[2] != $last)))[] + | {category: "Sessions", icon: "󱂬", title: .[2], + description: "\(.[5]) window\(if .[5] == "1" then "" else "s" end)\(if .[4] != "0" then " · attached" else "" end) · \(.[6] | tilde)", + action: {tmux: "switch-client -t \(.[1] | @sh)"}} + + (if .[4] != "0" then {iconColor: "#5eff6c"} else {} end)), + ($rows[] | select(.[0] == "W" and .[3] == "") + | (.[6] | capture("^(?[^\\x00-\\x7f]) (?.*)$") // {icon: "", title: .}) as $w + | {category: "Windows", icon: $w.icon, title: $w.title, + description: "\(.[2]):\(.[5]) · \(.[7] | tilde)", + action: {tmux: "switch-client -t \("\(.[1]):\(.[4])" | @sh)"}}), + ($rows[] | select(.[0] == "Z") | dir("Zoxide"; "")), + ($rows[] | select(.[0] == "C" and (.[1] as $d | $zoxide | any(. == $d) | not)) | dir("Config"; "󱃖")), + ($sessions[] + | {category: "Rename", icon: "󰑕", title: "Rename \(.[2])", description: "rename the session", + action: {tmux: "command-prompt -I \(.[2] | @sh) -p \("Rename \(.[2]):" | @sh) \("rename-session -t \(.[1] | @sh) -- \"%%%\"" | @sh)"}}), + ($others[] + | {category: "Kill", icon: "󱂧", title: "Kill \(.[2])", description: "kill the session", + action: {tmux: "kill-session -t \(.[1] | @sh)"}}) + ]'