aboutsummaryrefslogtreecommitdiff
path: root/dotfiles
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-19 12:31:17 -0500
committerCraig Jennings <c@cjennings.net>2026-05-19 12:31:17 -0500
commit924fec1f00e7ef5e497575488701e8c9eb2606f0 (patch)
tree9c0df313352ab01bd608fd408871ef7de418a39c /dotfiles
parent5d8d9df7d1b95c1a6a7bf25ddf57652c86f110b3 (diff)
downloadarchsetup-924fec1f00e7ef5e497575488701e8c9eb2606f0.tar.gz
archsetup-924fec1f00e7ef5e497575488701e8c9eb2606f0.zip
feat(tmux-util): add ls subcommand
tmux-util ls is an opinionated replacement for `tmux ls` with columns for state (attached/detached), name, idle time (humanized), window count, and the current pane's cwd (tilde-fied if it sits under $HOME). The cwd query goes through `tmux display -p -t <session> '#{pane_current_path}'`, which returns the cwd of the active pane of the active window. That's close enough to "what the session is about" for a one-line summary. Idle calculation reads `date +%s` by default and accepts an override via the TMUX_UTIL_NOW env var so tests can pin "now" to a known epoch. 12 new tests cover Normal cases (attached / detached, multiple sessions) and Boundary cases (no sessions, idle exactly at minute / hour / day boundaries, $HOME tilde). One existing dispatch test got reworked because the original stub target (`ls`) is no longer unimplemented. Total suite is 26 tests, all green. The fake-tmux harness picked up two things along the way: real format-string parsing for `list-sessions -F` and a new handler for `display -p`. The state file format extended to include activity epoch, window count, and cwd, with sensible defaults for older 3-tuple test inputs so the reap tests keep passing untouched.
Diffstat (limited to 'dotfiles')
-rwxr-xr-xdotfiles/common/.local/bin/tmux-util54
1 files changed, 53 insertions, 1 deletions
diff --git a/dotfiles/common/.local/bin/tmux-util b/dotfiles/common/.local/bin/tmux-util
index 10c6fbb..2fa861d 100755
--- a/dotfiles/common/.local/bin/tmux-util
+++ b/dotfiles/common/.local/bin/tmux-util
@@ -36,6 +36,55 @@ EOF
}
# -----------------------------------------------------------------------------
+# ls
+# -----------------------------------------------------------------------------
+
+# Render seconds as a short human duration (e.g. "5s", "12m", "3h", "2d").
+format_idle() {
+ local s="$1"
+ if [ "$s" -lt 60 ]; then
+ echo "${s}s"
+ elif [ "$s" -lt 3600 ]; then
+ echo "$((s / 60))m"
+ elif [ "$s" -lt 86400 ]; then
+ echo "$((s / 3600))h"
+ else
+ echo "$((s / 86400))d"
+ fi
+}
+
+cmd_ls() {
+ local sessions
+ sessions=$(tmux list-sessions \
+ -F '#{session_attached} #{session_name} #{session_activity} #{session_windows}' \
+ 2>/dev/null || true)
+
+ if [ -z "$sessions" ]; then
+ echo "No tmux sessions."
+ return 0
+ fi
+
+ local now="${TMUX_UTIL_NOW:-$(date +%s)}"
+
+ {
+ printf 'STATE\tNAME\tIDLE\tWINDOWS\tCWD\n'
+ local attached name activity windows state idle_str cwd
+ while IFS=' ' read -r attached name activity windows; do
+ [ -n "$name" ] || continue
+ state="detached"
+ [ "$attached" -gt 0 ] && state="attached"
+ idle_str=$(format_idle "$((now - activity))")
+ cwd=$(tmux display -p -t "$name" '#{pane_current_path}' 2>/dev/null || echo "?")
+ # Replace leading $HOME with ~ for display.
+ if [ -n "${HOME:-}" ] && [ "${cwd#$HOME}" != "$cwd" ]; then
+ cwd="~${cwd#$HOME}"
+ fi
+ printf '%s\t%s\t%s\t%s\t%s\n' "$state" "$name" "$idle_str" "$windows" "$cwd"
+ done <<<"$sessions"
+ } | column -t -s $'\t'
+}
+
+# -----------------------------------------------------------------------------
# Reap
# -----------------------------------------------------------------------------
@@ -92,7 +141,10 @@ main() {
reap)
cmd_reap "$@"
;;
- go|pick|ls|find|rename)
+ ls)
+ cmd_ls "$@"
+ ;;
+ go|pick|find|rename)
echo "tmux-util: subcommand '$sub' is not implemented yet" >&2
return 2
;;