Add support for tmux windows

It is now possible to create multiple windows in the same
session. One can write, for example,

echo boom

echo done

This will open up a terminal window with one tmux session, named
'hello', and two windows, named 'boom' and 'done'.
hello-test
Allard Hendriksen 2018-01-09 09:56:18 +01:00
parent d5deb53751
commit beacdb5ffc
1 changed files with 61 additions and 30 deletions

View File

@ -35,6 +35,7 @@
;;; Code: ;;; Code:
(require 'ob) (require 'ob)
(require 'seq)
(defvar org-babel-tmux-location "tmux" (defvar org-babel-tmux-location "tmux"
"The command location for tmux. "The command location for tmux.
@ -53,8 +54,10 @@ In case you want to use a different tmux than one selected by your $PATH")
(message "Sending source code block to interactive terminal session...") (message "Sending source code block to interactive terminal session...")
(save-window-excursion (save-window-excursion
(let* ((session (cdr (assq :session params))) (let* ((session (cdr (assq :session params)))
(socket (org-babel-tmux-session-socketname session))) (session-alive (org-babel-tmux-session-alive-p session))
(unless socket (org-babel-prep-session:tmux session params)) (window-alive (org-babel-tmux-window-alive-p session)))
(unless session-alive (org-babel-prep-session:tmux session params))
(unless window-alive (org-babel-tmux-create-window session))
(org-babel-tmux-session-execute-string (org-babel-tmux-session-execute-string
session (org-babel-expand-body:generic body params))))) session (org-babel-expand-body:generic body params)))))
@ -67,57 +70,85 @@ In case you want to use a different tmux than one selected by your $PATH")
(apply 'start-process process-name "*Messages*" (apply 'start-process process-name "*Messages*"
terminal terminal
`("--" `("--"
,org-babel-tmux-location ,org-babel-tmux-location "new-session" "-A"
"new-session" "-A" "-s" "-s" ,(org-babel-tmux-session session)
,(concat org-babel-tmux-session-prefix session))) "-n" ,(org-babel-tmux-window-default session)))
;; XXX: Is there a better way than the following? ;; XXX: Is there a better way than the following?
(while (not (org-babel-tmux-session-socketname session)) (while (not (org-babel-tmux-session-alive-p session))
;; wait until tmux session is available before returning ;; wait until tmux session is available before returning
))) )))
;; helper functions ;; helper functions
(defun org-babel-tmux-create-window (session)
"Creates a tmux window in session if it does not yet exist."
(unless (org-babel-tmux-window-alive-p session)
(start-process "tmux-create-window" "*Messages*"
"tmux" "new-window"
"-c" (expand-file-name "~/")
"-n" (org-babel-tmux-window-default session)
"-t" (org-babel-tmux-session session))))
(defun org-babel-tmux-send-keys (session line) (defun org-babel-tmux-send-keys (session line)
"If SESSION exists, send a line of text to it." "If SESSION exists, send a line of text to it."
(let ((socket (org-babel-tmux-session-socketname session))) (let ((alive (org-babel-tmux-session-alive-p session)))
(when socket (when alive
(start-process "tmux-send-keys" (start-process "tmux-send-keys"
"*Messages*" "*Messages*"
"tmux" "tmux"
"send-keys" "send-keys"
"-t" "-t"
(concat org-babel-tmux-session-prefix session ":1") (concat (org-babel-tmux-session session)
":"
(org-babel-tmux-window-default session))
line line
"Enter")))) "Enter"))))
(defun org-babel-tmux-session-execute-string (session body) (defun org-babel-tmux-session-execute-string (session body)
"If SESSION exists, send BODY to it." "If SESSION exists, send BODY to it."
(let ((socket (org-babel-tmux-session-socketname session))) (let ((alive (org-babel-tmux-session-alive-p session)))
(when socket (when alive
(let ((lines (split-string body "[\n\r]+"))) (let ((lines (split-string body "[\n\r]+")))
(mapc (lambda (l) (org-babel-tmux-send-keys session l)) (mapc (lambda (l) (org-babel-tmux-send-keys session l))
lines))))) lines)))))
(defun org-babel-tmux-session-socketname (session) (defun org-babel-tmux-session (org-session)
"Extracts the tmux session from the org session string."
(concat org-babel-tmux-session-prefix
(car (split-string org-session ":"))))
(defun org-babel-tmux-window (org-session)
"Extracts the tmux window from the org session string.
Can return nil if no windows specified"
(cadr (split-string org-session ":")))
(defun org-babel-tmux-window-default (org-session)
"Extracts the tmux window from the org session string.
Can return nil if no windows specified"
(let* ((tmux-window (cadr (split-string org-session ":"))))
(if tmux-window tmux-window "1")))
(defun org-babel-tmux-session-alive-p (session)
"Check if SESSION exists by parsing output of \"tmux ls\"." "Check if SESSION exists by parsing output of \"tmux ls\"."
(let* ((tmux-ls (shell-command-to-string "tmux ls")) (let* ((tmux-ls (shell-command-to-string "tmux ls -F '#S'"))
(sockets (delq (tmux-session (org-babel-tmux-session session)))
nil (car
(mapcar (seq-filter (lambda (x) (string-equal tmux-session x))
(lambda (x) (split-string tmux-ls "\n")))))
(when (string-match (rx "windows") x)
x)) (defun org-babel-tmux-window-alive-p (session)
(split-string tmux-ls "\n")))) "Check if WINDOW exists in tmux session."
(match-socket (car (let* ((tmux-session (org-babel-tmux-session session))
(delq (tmux-window (org-babel-tmux-window session))
nil (tmux-lws (shell-command-to-string
(mapcar (concat "tmux list-windows -F '#W' -t '"
(lambda (x) tmux-session "'"))))
(when (string-match (if tmux-window
(concat org-babel-tmux-session-prefix session) x) (car
x)) (seq-filter (lambda(x) (string-equal tmux-window x))
sockets))))) (split-string tmux-lws "\n")))
(when match-socket (car (split-string match-socket ":"))))) 't)))
(defun org-babel-tmux-open-file (path) (defun org-babel-tmux-open-file (path)
(with-temp-buffer (with-temp-buffer