Tmux session manager for StumpWM

This is a small module which allows to connect existed tmux session, or
start a new one
This commit is contained in:
Kirill A. Korinsky 2026-01-07 20:38:24 +01:00
parent 326725802f
commit 5df5bcfd93
No known key found for this signature in database
GPG key ID: 98D8D9867759226E
5 changed files with 154 additions and 0 deletions

View file

@ -140,6 +140,7 @@ Advertise your module here, open a PR and include a org-mode link!
- [[./util/swm-emacs/README.txt][swm-emacs]] :: A set of utilities for launching the beast.
- [[./util/swm-gaps/README.org][swm-gaps]] :: Pretty (useless) gaps for StumpWM
- [[./util/swm-ssh/README.org][swm-ssh]] :: A simple menu selector for ssh to a remote host for stumpwm that parses your ssh config to get available hosts
- [[./util/swm-tmux/README.org][swm-tmux]] :: Tmux session manager for StumpWM
- [[./util/ttf-fonts/README.txt][ttf-fonts]] :: A pure lisp implementation of TTF font rendering.
- [[./util/undocumented/README.org][undocumented]] :: Look for stuff that should probably be in the manual that isn't
- [[./util/urgentwindows/README.org][urgentwindows]] :: Allows focusing application windows that need user attention

55
util/swm-tmux/README.org Normal file
View file

@ -0,0 +1,55 @@
* Requirements
- cl-ppcre
Install cl-ppcre from the REPL:
#+BEGIN_SRC lisp
(ql:quickload :cl-ppcre)
#+END_SRC
* Usage
This module provides a menu interface for managing tmux sessions. You can
attach to existing sessions or create new ones. Session names default to
the current StumpWM group name.
Put the following in your =~/.stumpwmrc=
#+BEGIN_SRC lisp
(load-module "swm-tmux")
#+END_SRC
And define a keybind in your =~/.stumpwmrc=
#+BEGIN_SRC lisp
(define-key *root-map* (kbd "t") "swm-tmux-session")
#+END_SRC
* Commands
** swm-tmux-session
Opens a menu to select an existing tmux session or create a new one.
The session name defaults to the current group name.
** swm-tmux-new-session
Quickly creates a new tmux session with an auto-generated name based
on the current group.
* Variables
** *swm-tmux-default-term*
Terminal emulator to use. Default is =xterm=.
#+BEGIN_SRC lisp
(setf swm-tmux:*swm-tmux-default-term* "urxvtc")
#+END_SRC
** *swm-tmux-default-term-title-opt*
Command line option for setting the terminal title. Default is =-T=.
Set to =NIL= if your terminal does not support a title option.
#+BEGIN_SRC lisp
(setf swm-tmux:*swm-tmux-default-term-title-opt* "-title")
#+END_SRC
** *swm-tmux-default-term-exec-opt*
Command line option for executing a command in the terminal. Default is =-e=.
#+BEGIN_SRC lisp
(setf swm-tmux:*swm-tmux-default-term-exec-opt* "-e")
#+END_SRC

View file

@ -0,0 +1,7 @@
;;;; package.lisp
(defpackage #:swm-tmux
(:use #:cl #:stumpwm)
(:export #:*swm-tmux-default-term*
#:*swm-tmux-default-term-title-opt*
#:*swm-tmux-default-term-exec-opt*))

View file

@ -0,0 +1,11 @@
;;;; swm-tmux.asd
(asdf:defsystem "swm-tmux"
:description "Tmux session manager for StumpWM"
:author "Kirill A. Korinsky <kirill@korins.ky>"
:license "GPLv3"
:version "0.1"
:serial t
:depends-on ("stumpwm" "cl-ppcre")
:components ((:file "package")
(:file "swm-tmux")))

View file

@ -0,0 +1,80 @@
;;;; swm-tmux.lisp
(in-package #:swm-tmux)
(defvar *swm-tmux-default-term* "xterm"
"Terminal emulator to use for tmux sessions.")
(defvar *swm-tmux-default-term-title-opt* "-T"
"Command line option for setting terminal title. Set to NIL if your
terminal does not support title option.")
(defvar *swm-tmux-default-term-exec-opt* "-e"
"Command line option for executing a command in the terminal.")
(defun tmux-sessions ()
"Return a list of existing tmux session names."
(let ((output (run-shell-command "tmux ls -F '#{session_name}' 2>/dev/null" t)))
(when (and output (not (string= output "")))
(cl-ppcre:split "\\n" (string-trim '(#\Newline) output)))))
(defun next-session-name ()
"Generate next session name based on current group name.
If group name is not already a session, use it directly.
Otherwise append -N where N is the next available number."
(let* ((prefix (group-name (current-group)))
(sessions (tmux-sessions)))
(if (not (member prefix sessions :test #'string=))
prefix
(let* ((pattern (format nil "^~a-(\\d+)$" prefix))
(nums (loop for s in sessions
for match = (cl-ppcre:scan-to-strings pattern s)
when match
collect (parse-integer
(aref (nth-value 1 (cl-ppcre:scan-to-strings pattern s)) 0)))))
(format nil "~a-~a" prefix (1+ (or (reduce #'max nums :initial-value 0) 0)))))))
(defun build-term-command (session-name tmux-cmd)
"Build terminal command string for running tmux.
SESSION-NAME is used for window title, TMUX-CMD is the tmux command to run."
(let ((title (format nil "tmux/~a" session-name)))
(if *swm-tmux-default-term-title-opt*
(format nil "~a ~a '~a' ~a ~a"
*swm-tmux-default-term*
*swm-tmux-default-term-title-opt*
title
*swm-tmux-default-term-exec-opt*
tmux-cmd)
(format nil "~a ~a ~a"
*swm-tmux-default-term*
*swm-tmux-default-term-exec-opt*
tmux-cmd))))
(stumpwm:defcommand swm-tmux-session () ()
"Select an existing tmux session to attach or create a new one.
Presents a menu with existing sessions and a [New session] option.
Session names default to current group name."
(let* ((sessions (tmux-sessions))
(options (cons '("[New session]") (mapcar #'list sessions)))
(choice (select-from-menu (current-screen) options "Tmux session: ")))
(when choice
(if (string= (first choice) "[New session]")
;; New session: prompt for name
(let ((session-name (read-one-line (current-screen)
"Session name: "
:initial-input (next-session-name))))
(when (and session-name (not (string= session-name "")))
(let ((tmux-cmd (if (member session-name sessions :test #'string=)
(format nil "tmux attach -t '~a'" session-name)
(format nil "tmux new-session -s '~a'" session-name))))
(run-shell-command (build-term-command session-name tmux-cmd)))))
;; Existing session: attach directly
(let* ((session-name (first choice))
(tmux-cmd (format nil "tmux attach -t '~a'" session-name)))
(run-shell-command (build-term-command session-name tmux-cmd)))))))
(stumpwm:defcommand swm-tmux-new-session () ()
"Create a new tmux session with auto-generated name based on current group."
(let* ((session-name (next-session-name))
(tmux-cmd (format nil "tmux new-session -s '~a'" session-name)))
(run-shell-command (build-term-command session-name tmux-cmd))))