diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-19 12:31:17 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-19 12:31:17 -0500 |
| commit | 924fec1f00e7ef5e497575488701e8c9eb2606f0 (patch) | |
| tree | 9c0df313352ab01bd608fd408871ef7de418a39c /dotfiles/common | |
| parent | 5d8d9df7d1b95c1a6a7bf25ddf57652c86f110b3 (diff) | |
| download | archsetup-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/common')
| -rwxr-xr-x | dotfiles/common/.local/bin/tmux-util | 54 |
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 ;; |
