From: Andreas Gerler Date: Sat, 25 Nov 2023 10:43:39 +0000 (+0100) Subject: update ob-tmux X-Git-Url: http://git.bundesbrandschatzamt.de/?a=commitdiff_plain;h=165f17dec26d3e7d79881fbba01604e24c9db41d;p=emacsconfig.git update ob-tmux Signed-off-by: Andreas Gerler --- diff --git a/elpa/ob-tmux-20190708.1202/ob-tmux-autoloads.el b/elpa/ob-tmux-20190708.1202/ob-tmux-autoloads.el deleted file mode 100644 index c9e622d1..00000000 --- a/elpa/ob-tmux-20190708.1202/ob-tmux-autoloads.el +++ /dev/null @@ -1,15 +0,0 @@ -;;; ob-tmux-autoloads.el --- automatically extracted autoloads -;; -;;; Code: -(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path)))) - -;;;### (autoloads nil nil ("ob-tmux.el") (23994 46441 855796 628000)) - -;;;*** - -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; End: -;;; ob-tmux-autoloads.el ends here diff --git a/elpa/ob-tmux-20190708.1202/ob-tmux-pkg.el b/elpa/ob-tmux-20190708.1202/ob-tmux-pkg.el deleted file mode 100644 index a62dff3b..00000000 --- a/elpa/ob-tmux-20190708.1202/ob-tmux-pkg.el +++ /dev/null @@ -1,2 +0,0 @@ -;;; -*- no-byte-compile: t -*- -(define-package "ob-tmux" "20190708.1202" "Babel Support for Interactive Terminal" '((emacs "25.1") (seq "2.3") (s "1.9.0")) :commit "3687ed7b874bdfe14617f5d14492887cb0836a85" :keywords '("literate programming" "interactive shell" "tmux") :authors '(("Allard Hendriksen")) :maintainer '("Allard Hendriksen") :url "https://github.com/ahendriksen/ob-tmux") diff --git a/elpa/ob-tmux-20190708.1202/ob-tmux.el b/elpa/ob-tmux-20190708.1202/ob-tmux.el deleted file mode 100644 index fbfb5b27..00000000 --- a/elpa/ob-tmux-20190708.1202/ob-tmux.el +++ /dev/null @@ -1,392 +0,0 @@ -;;; ob-tmux.el --- Babel Support for Interactive Terminal -*- lexical-binding: t; -*- - -;; Copyright (C) 2009-2017 Free Software Foundation, Inc. -;; Copyright (C) 2017 Allard Hendriksen - -;; Author: Allard Hendriksen -;; Keywords: literate programming, interactive shell, tmux -;; URL: https://github.com/ahendriksen/ob-tmux -;; Version: 0.1.5 -;; Package-Version: 20190708.1202 -;; Package-X-Original-version: 0.1.5 -;; Package-Requires: ((emacs "25.1") (seq "2.3") (s "1.9.0")) - -;; This file is NOT part of GNU Emacs. - -;; This program is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see . - -;;; Commentary: - -;; Org-Babel support for tmux. -;; -;; Heavily inspired by 'eev' from Eduardo Ochs and ob-screen.el from -;; Benjamin Andresen. -;; -;; See documentation on https://github.com/ahendriksen/ob-tmux -;; -;; You can test the default setup with -;; M-x org-babel-tmux-test RET - -;;; Code: - -(require 'ob) -(require 'seq) -(require 's) - - -(defcustom org-babel-tmux-location "tmux" - "The command location for tmux. -Change in case you want to use a different tmux than the one in your $PATH." - :group 'org-babel - :type 'string) - -(defcustom org-babel-tmux-session-prefix "org-babel-session-" - "The string that will be prefixed to tmux session names started by ob-tmux." - :group 'org-babel - :type 'string) - -(defcustom org-babel-tmux-default-window-name "ob1" - "This is the default tmux window name used for windows that are not explicitly named in an org session." - :group 'org-babel - :type 'string) - -(defcustom org-babel-tmux-terminal "gnome-terminal" - "This is the terminal that will be spawned." - :group 'org-babel - :type 'string) - -(defcustom org-babel-tmux-terminal-opts '("--") - "The list of options that will be passed to the terminal." - :group 'org-babel - :type 'list) - -(defvar org-babel-default-header-args:tmux - '((:results . "silent") - (:session . "default") - (:socket . nil)) - "Default arguments to use when running tmux source blocks.") - -(add-to-list 'org-src-lang-modes '("tmux" . sh)) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; org-babel interface -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun org-babel-execute:tmux (body params) - "Send a block of code via tmux to a terminal using Babel. -\"default\" session is used when none is specified. -Argument BODY the body of the tmux code block. -Argument PARAMS the org parameters of the code block." - (message "Sending source code block to interactive terminal session...") - (save-window-excursion - (let* ((org-session (cdr (assq :session params))) - (org-header-terminal (cdr (assq :terminal params))) - (terminal (or org-header-terminal org-babel-tmux-terminal)) - (socket (cdr (assq :socket params))) - (socket (when socket (expand-file-name socket))) - (ob-session (ob-tmux--from-org-session org-session socket)) - (session-alive (ob-tmux--session-alive-p ob-session)) - (window-alive (ob-tmux--window-alive-p ob-session))) - ;; Create tmux session and window if they do not yet exist - (unless session-alive (ob-tmux--create-session ob-session)) - (unless window-alive (ob-tmux--create-window ob-session)) - ;; Start terminal window if the session does not yet exist - (unless session-alive - (ob-tmux--start-terminal-window ob-session terminal)) - ;; Wait until tmux window is available - (while (not (ob-tmux--window-alive-p ob-session))) - ;; Disable window renaming from within tmux - (ob-tmux--disable-renaming ob-session) - (ob-tmux--send-body - ob-session (org-babel-expand-body:generic body params)) - ;; Warn that setting the terminal from the org source block - ;; header arguments is going to be deprecated. - (message "ob-tmux terminal: %s" org-header-terminal) - (when org-header-terminal - (ob-tmux--deprecation-warning org-header-terminal))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ob-tmux object -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(cl-defstruct (ob-tmux- (:constructor ob-tmux--create) - (:copier ob-tmux--copy)) - session - window - socket) - -(defun ob-tmux--tmux-session (org-session) - "Extract tmux session from ORG-SESSION string." - (let* ((session (car (split-string org-session ":")))) - (concat org-babel-tmux-session-prefix - (if (string-equal "" session) "default" session)))) -(defun ob-tmux--tmux-window (org-session) - "Extract tmux window from ORG-SESSION string." - (let* ((window (cadr (split-string org-session ":")))) - (if (string-equal "" window) nil window))) - -(defun ob-tmux--from-org-session (org-session &optional socket) - "Create a new ob-tmux-session object from ORG-SESSION specification. -Optional argument SOCKET: the location of the tmux socket (only use if non-standard)." - - (ob-tmux--create - :session (ob-tmux--tmux-session org-session) - :window (ob-tmux--tmux-window org-session) - :socket socket)) - -(defun ob-tmux--window-default (ob-session) - "Extracts the tmux window from the ob-tmux- object. -Returns `org-babel-tmux-default-window-name' if no window specified. - -Argument OB-SESSION: the current ob-tmux session." - (if (ob-tmux--window ob-session) - (ob-tmux--window ob-session) - org-babel-tmux-default-window-name)) - -(defun ob-tmux--target (ob-session) - "Constructs a tmux target from the `ob-tmux-' object. - -If no window is specified, use first window. - -Argument OB-SESSION: the current ob-tmux session." - (let* ((target-session (ob-tmux--session ob-session)) - (window (ob-tmux--window ob-session)) - (target-window (if window (concat "=" window) "^"))) - (concat target-session ":" target-window))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Process execution functions -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun ob-tmux--execute (ob-session &rest args) - "Execute a tmux command with arguments as given. - -Argument OB-SESSION: the current ob-tmux session. -Optional command-line arguments can be passed in ARGS." - (if (ob-tmux--socket ob-session) - (apply 'start-process "ob-tmux" "*Messages*" - org-babel-tmux-location - "-S" (ob-tmux--socket ob-session) - args) - (apply 'start-process - "ob-tmux" "*Messages*" org-babel-tmux-location args))) - -(defun ob-tmux--execute-string (ob-session &rest args) - "Execute a tmux command with arguments as given. -Returns stdout as a string. - -Argument OB-SESSION: the current ob-tmux session. Optional -command-line arguments can be passed in ARGS and are -automatically space separated." - (let* ((socket (ob-tmux--socket ob-session)) - (args (if socket (cons "-S" (cons socket args)) args))) - (shell-command-to-string - (concat org-babel-tmux-location " " - (s-join " " args))))) - -(defun ob-tmux--start-terminal-window (ob-session terminal) - "Start a TERMINAL window with tmux attached to session. - - Argument OB-SESSION: the current ob-tmux session." - (let ((start-process-mandatory-args `("org-babel: terminal" - "*Messages*" - ,terminal)) - (tmux-cmd `(,org-babel-tmux-location - "attach-session" - "-t" ,(ob-tmux--target ob-session)))) - (unless (ob-tmux--socket ob-session) - (apply 'start-process (append start-process-mandatory-args - org-babel-tmux-terminal-opts - tmux-cmd))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Tmux interaction -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun ob-tmux--create-session (ob-session) - "Create a tmux session if it does not yet exist. - -Argument OB-SESSION: the current ob-tmux session." - (unless (ob-tmux--session-alive-p ob-session) - (ob-tmux--execute ob-session - "new-session" - "-d" ;; just create the session, don't attach. - "-c" (expand-file-name "~") ;; start in home directory - "-s" (ob-tmux--session ob-session) - "-n" (ob-tmux--window-default ob-session)))) - -(defun ob-tmux--create-window (ob-session) - "Create a tmux window in session if it does not yet exist. - -Argument OB-SESSION: the current ob-tmux session." - (unless (ob-tmux--window-alive-p ob-session) - (ob-tmux--execute ob-session - "new-window" - "-c" (expand-file-name "~") ;; start in home directory - "-n" (ob-tmux--window-default ob-session) - "-t" (ob-tmux--session ob-session)))) - -(defun ob-tmux--set-window-option (ob-session option value) - "If window exists, set OPTION for window. - -Argument OB-SESSION: the current ob-tmux session." - (when (ob-tmux--window-alive-p ob-session) - (ob-tmux--execute ob-session - "set-window-option" - "-t" (ob-tmux--target ob-session) - option value))) - -(defun ob-tmux--disable-renaming (ob-session) - "Disable renaming features for tmux window. - -Disabling renaming improves the chances that ob-tmux will be able -to find the window again later. - -Argument OB-SESSION: the current ob-tmux session." - (progn - (ob-tmux--set-window-option ob-session "allow-rename" "off") - (ob-tmux--set-window-option ob-session "automatic-rename" "off"))) - - -(defun ob-tmux--format-keys (string) - "Format STRING as a sequence of hexadecimal numbers, to be sent via the `send-keys' command." - (mapcar (lambda (c) (format "0x%x" c)) - string)) - -(defun ob-tmux--send-keys (ob-session line) - "If tmux window exists, send a LINE of text to it. - -Argument OB-SESSION: the current ob-tmux session." - (when (ob-tmux--window-alive-p ob-session) - (let* ((hex-line (ob-tmux--format-keys line))) - (apply 'ob-tmux--execute - ob-session - "send-keys" - "-t" (ob-tmux--target ob-session) - hex-line)))) - -(defun ob-tmux--send-body (ob-session body) - "If tmux window (passed in OB-SESSION) exists, send BODY to it. - -Argument OB-SESSION: the current ob-tmux session." - (let ((lines (split-string body "[\n\r]+"))) - (when (ob-tmux--window-alive-p ob-session) - (mapc (lambda (l) - (ob-tmux--send-keys ob-session (concat l "\n"))) - lines)))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Tmux interrogation -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun ob-tmux--session-alive-p (ob-session) - "Check if SESSION exists by parsing output of \"tmux ls\". - -Argument OB-SESSION: the current ob-tmux session." - (let* ((tmux-ls (ob-tmux--execute-string ob-session "ls -F '#S'")) - (tmux-session (ob-tmux--session ob-session))) - (car - (seq-filter (lambda (x) (string-equal tmux-session x)) - (split-string tmux-ls "\n"))))) - -(defun ob-tmux--window-alive-p (ob-session) - "Check if WINDOW exists in tmux session. - -If no window is specified in OB-SESSION, returns 't." - (let* ((window (ob-tmux--window ob-session)) - (target (ob-tmux--target ob-session)) - (output (ob-tmux--execute-string ob-session - "list-panes" - "-F 'yes_exists'" - "-t" (concat "'" target "'")))) - (cond (window - (string-equal "yes_exists\n" output)) - ((null window) - 't)))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Warnings -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defun ob-tmux--deprecation-warning (org-header-terminal) - (let* ((message (format "DEPRECATION WARNING: Setting `:terminal` using org source block header arguments is deprecated. - -Consider changing your ob-tmux configuration as follows: - -(setq org-babel-default-header-args:tmux - '((:results . \"\") - (:session . \"\") - (:terminal. \"%s\") ; <--- REMOVE THIS LINE - (:socket . nil))) - -;; You can now customize the terminal and its options as follows: -(setq org-babel-tmux-terminal \"%s\") -(setq org-babel-tmux-terminal-opts '(\"-T\" \"ob-tmux\" \"-e\")) -; The default terminal is \"gnome-terminal\" with options \"--\". - -If you have any source blocks containing `:terminal`, please consider removing them: - - #+begin_src tmux :session test :terminal %s - echo hello - #+end_src - -Becomes: - - #+begin_src tmux :session test - echo hello - #+end_src - -End of warning. (See *Warnings* buffer for full message) -" org-header-terminal org-header-terminal org-header-terminal))) - (display-warning 'deprecation-warning message :warning) - message)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Test functions -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun ob-tmux--open-file (path) - "Open file as string. - -Argument PATH: the location of the file." -(with-temp-buffer - (insert-file-contents-literally path) - (buffer-substring (point-min) (point-max)))) - -(defun ob-tmux--test () - "Test if the default setup works. The terminal should shortly flicker." - (interactive) - (let* ((random-string (format "%s" (random 99999))) - (tmpfile (org-babel-temp-file "ob-tmux-test-")) - (body (concat "echo '" random-string "' > " tmpfile)) - tmp-string) - (org-babel-execute:tmux body org-babel-default-header-args:tmux) - ;; XXX: need to find a better way to do the following - (while (or (not (file-readable-p tmpfile)) - (= 0 (length (ob-tmux--open-file tmpfile)))) - ;; do something, otherwise this will be optimized away - (format "org-babel-tmux: File not readable yet.")) - (setq tmp-string (ob-tmux--open-file tmpfile)) - (delete-file tmpfile) - (message (concat "org-babel-tmux: Setup " - (if (string-match random-string tmp-string) - "WORKS." - "DOESN'T work."))))) - -(provide 'ob-tmux) - - - -;;; ob-tmux.el ends here diff --git a/elpa/ob-tmux-20221005.2025/ob-tmux-autoloads.el b/elpa/ob-tmux-20221005.2025/ob-tmux-autoloads.el new file mode 100644 index 00000000..be62edaa --- /dev/null +++ b/elpa/ob-tmux-20221005.2025/ob-tmux-autoloads.el @@ -0,0 +1,26 @@ +;;; ob-tmux-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*- +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "ob-tmux" "ob-tmux.el" (0 0 0 0)) +;;; Generated autoloads from ob-tmux.el + +(register-definition-prefixes "ob-tmux" '("ob-tmux--" "org-babel-")) + +;;;*** + +;;;### (autoloads nil nil ("ob-tmux-pkg.el") (0 0 0 0)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; ob-tmux-autoloads.el ends here diff --git a/elpa/ob-tmux-20221005.2025/ob-tmux-pkg.el b/elpa/ob-tmux-20221005.2025/ob-tmux-pkg.el new file mode 100644 index 00000000..607edf18 --- /dev/null +++ b/elpa/ob-tmux-20221005.2025/ob-tmux-pkg.el @@ -0,0 +1,16 @@ +(define-package "ob-tmux" "20221005.2025" "Babel Support for Interactive Terminal" + '((emacs "25.1") + (seq "2.3") + (s "1.9.0")) + :commit "e672ca5a9534b9f33ed7aa5cd21b88189ccc5697" :authors + '(("Allard Hendriksen")) + :maintainers + '(("Allard Hendriksen")) + :maintainer + '("Allard Hendriksen") + :keywords + '("literate programming" "interactive shell" "tmux") + :url "https://github.com/ahendriksen/ob-tmux") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/elpa/ob-tmux-20221005.2025/ob-tmux.el b/elpa/ob-tmux-20221005.2025/ob-tmux.el new file mode 100644 index 00000000..4c52124c --- /dev/null +++ b/elpa/ob-tmux-20221005.2025/ob-tmux.el @@ -0,0 +1,394 @@ +;;; ob-tmux.el --- Babel Support for Interactive Terminal -*- lexical-binding: t; -*- + +;; Copyright (C) 2009-2017 Free Software Foundation, Inc. +;; Copyright (C) 2017 Allard Hendriksen + +;; Author: Allard Hendriksen +;; Keywords: literate programming, interactive shell, tmux +;; URL: https://github.com/ahendriksen/ob-tmux +;; Version: 0.1.5 +;; Package-version: 0.1.5 +;; Package-Requires: ((emacs "25.1") (seq "2.3") (s "1.9.0")) + +;; This file is NOT part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; Org-Babel support for tmux. +;; +;; Heavily inspired by 'eev' from Eduardo Ochs and ob-screen.el from +;; Benjamin Andresen. +;; +;; See documentation on https://github.com/ahendriksen/ob-tmux +;; +;; You can test the default setup with +;; M-x org-babel-tmux-test RET + +;;; Code: + +(require 'ob) +(require 'seq) +(require 's) + + +(defcustom org-babel-tmux-location "tmux" + "The command location for tmux. +Change in case you want to use a different tmux than the one in your $PATH." + :group 'org-babel + :type 'string) + +(defcustom org-babel-tmux-session-prefix "org-babel-session-" + "The string that will be prefixed to tmux session names started by ob-tmux." + :group 'org-babel + :type 'string) + +(defcustom org-babel-tmux-default-window-name "ob1" + "This is the default tmux window name used for windows that are not explicitly named in an org session." + :group 'org-babel + :type 'string) + +(defcustom org-babel-tmux-terminal "gnome-terminal" + "This is the terminal that will be spawned." + :group 'org-babel + :type 'string) + +(defcustom org-babel-tmux-terminal-opts '("--") + "The list of options that will be passed to the terminal." + :group 'org-babel + :type 'list) + +(defvar org-babel-default-header-args:tmux + '((:results . "silent") + (:session . "default") + (:socket . nil)) + "Default arguments to use when running tmux source blocks.") + +(add-to-list 'org-src-lang-modes '("tmux" . sh)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; org-babel interface +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun org-babel-execute:tmux (body params) + "Send a block of code via tmux to a terminal using Babel. +\"default\" session is used when none is specified. +Argument BODY the body of the tmux code block. +Argument PARAMS the org parameters of the code block." + (message "Sending source code block to interactive terminal session...") + (save-window-excursion + (let* ((org-session (cdr (assq :session params))) + (org-header-terminal (cdr (assq :terminal params))) + (vars (mapcar + (lambda (y) (format "%s=\"%s\"" (cadr y) (cddr y))) + (seq-filter (lambda (x) (eq :var (car x))) params))) + (terminal (or org-header-terminal org-babel-tmux-terminal)) + (socket (cdr (assq :socket params))) + (socket (when socket (expand-file-name socket))) + (ob-session (ob-tmux--from-org-session org-session socket)) + (session-alive (ob-tmux--session-alive-p ob-session)) + (window-alive (ob-tmux--window-alive-p ob-session))) + ;; Create tmux session and window if they do not yet exist + (unless session-alive (ob-tmux--create-session ob-session)) + (unless window-alive (ob-tmux--create-window ob-session)) + ;; Start terminal window if the session does not yet exist + (unless session-alive + (ob-tmux--start-terminal-window ob-session terminal)) + ;; Wait until tmux window is available + (while (not (ob-tmux--window-alive-p ob-session))) + ;; Disable window renaming from within tmux + (ob-tmux--disable-renaming ob-session) + (ob-tmux--send-body + ob-session (org-babel-expand-body:generic body params vars)) + ;; Warn that setting the terminal from the org source block + ;; header arguments is going to be deprecated. + (message "ob-tmux terminal: %s" org-header-terminal) + (when org-header-terminal + (ob-tmux--deprecation-warning org-header-terminal))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ob-tmux object +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(cl-defstruct (ob-tmux- (:constructor ob-tmux--create) + (:copier ob-tmux--copy)) + session + window + socket) + +(defun ob-tmux--tmux-session (org-session) + "Extract tmux session from ORG-SESSION string." + (let* ((session (car (split-string org-session ":")))) + (concat org-babel-tmux-session-prefix + (if (string-equal "" session) "default" session)))) +(defun ob-tmux--tmux-window (org-session) + "Extract tmux window from ORG-SESSION string." + (let* ((window (cadr (split-string org-session ":")))) + (if (string-equal "" window) nil window))) + +(defun ob-tmux--from-org-session (org-session &optional socket) + "Create a new ob-tmux-session object from ORG-SESSION specification. +Optional argument SOCKET: the location of the tmux socket (only use if non-standard)." + + (ob-tmux--create + :session (ob-tmux--tmux-session org-session) + :window (ob-tmux--tmux-window org-session) + :socket socket)) + +(defun ob-tmux--window-default (ob-session) + "Extracts the tmux window from the ob-tmux- object. +Returns `org-babel-tmux-default-window-name' if no window specified. + +Argument OB-SESSION: the current ob-tmux session." + (if (ob-tmux--window ob-session) + (ob-tmux--window ob-session) + org-babel-tmux-default-window-name)) + +(defun ob-tmux--target (ob-session) + "Constructs a tmux target from the `ob-tmux-' object. + +If no window is specified, use first window. + +Argument OB-SESSION: the current ob-tmux session." + (let* ((target-session (ob-tmux--session ob-session)) + (window (ob-tmux--window ob-session)) + (target-window (if window (concat "=" window) "^"))) + (concat target-session ":" target-window))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Process execution functions +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun ob-tmux--execute (ob-session &rest args) + "Execute a tmux command with arguments as given. + +Argument OB-SESSION: the current ob-tmux session. +Optional command-line arguments can be passed in ARGS." + (if (ob-tmux--socket ob-session) + (apply 'start-process "ob-tmux" "*Messages*" + org-babel-tmux-location + "-S" (ob-tmux--socket ob-session) + args) + (apply 'start-process + "ob-tmux" "*Messages*" org-babel-tmux-location args))) + +(defun ob-tmux--execute-string (ob-session &rest args) + "Execute a tmux command with arguments as given. +Returns stdout as a string. + +Argument OB-SESSION: the current ob-tmux session. Optional +command-line arguments can be passed in ARGS and are +automatically space separated." + (let* ((socket (ob-tmux--socket ob-session)) + (args (if socket (cons "-S" (cons socket args)) args))) + (shell-command-to-string + (concat org-babel-tmux-location " " + (s-join " " args))))) + +(defun ob-tmux--start-terminal-window (ob-session terminal) + "Start a TERMINAL window with tmux attached to session. + + Argument OB-SESSION: the current ob-tmux session." + (let ((start-process-mandatory-args `("org-babel: terminal" + "*Messages*" + ,terminal)) + (tmux-cmd `(,org-babel-tmux-location + "attach-session" + "-t" ,(ob-tmux--target ob-session)))) + (unless (ob-tmux--socket ob-session) + (apply 'start-process (append start-process-mandatory-args + org-babel-tmux-terminal-opts + tmux-cmd))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Tmux interaction +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun ob-tmux--create-session (ob-session) + "Create a tmux session if it does not yet exist. + +Argument OB-SESSION: the current ob-tmux session." + (unless (ob-tmux--session-alive-p ob-session) + (ob-tmux--execute ob-session + "new-session" + "-d" ;; just create the session, don't attach. + "-c" (expand-file-name "~") ;; start in home directory + "-s" (ob-tmux--session ob-session) + "-n" (ob-tmux--window-default ob-session)))) + +(defun ob-tmux--create-window (ob-session) + "Create a tmux window in session if it does not yet exist. + +Argument OB-SESSION: the current ob-tmux session." + (unless (ob-tmux--window-alive-p ob-session) + (ob-tmux--execute ob-session + "new-window" + "-c" (expand-file-name "~") ;; start in home directory + "-n" (ob-tmux--window-default ob-session) + "-t" (ob-tmux--session ob-session)))) + +(defun ob-tmux--set-window-option (ob-session option value) + "If window exists, set OPTION for window. + +Argument OB-SESSION: the current ob-tmux session." + (when (ob-tmux--window-alive-p ob-session) + (ob-tmux--execute ob-session + "set-window-option" + "-t" (ob-tmux--target ob-session) + option value))) + +(defun ob-tmux--disable-renaming (ob-session) + "Disable renaming features for tmux window. + +Disabling renaming improves the chances that ob-tmux will be able +to find the window again later. + +Argument OB-SESSION: the current ob-tmux session." + (progn + (ob-tmux--set-window-option ob-session "allow-rename" "off") + (ob-tmux--set-window-option ob-session "automatic-rename" "off"))) + + +(defun ob-tmux--format-keys (string) + "Format STRING as a sequence of hexadecimal numbers, to be sent via the `send-keys' command." + (mapcar (lambda (c) (format "0x%x" c)) + string)) + +(defun ob-tmux--send-keys (ob-session line) + "If tmux window exists, send a LINE of text to it. + +Argument OB-SESSION: the current ob-tmux session." + (when (ob-tmux--window-alive-p ob-session) + (let* ((hex-line (ob-tmux--format-keys line))) + (apply 'ob-tmux--execute + ob-session + "send-keys" + "-t" (ob-tmux--target ob-session) + hex-line)))) + +(defun ob-tmux--send-body (ob-session body) + "If tmux window (passed in OB-SESSION) exists, send BODY to it. + +Argument OB-SESSION: the current ob-tmux session." + (let ((lines (split-string body "[\n\r]+"))) + (when (ob-tmux--window-alive-p ob-session) + (mapc (lambda (l) + (ob-tmux--send-keys ob-session (concat l "\n"))) + lines)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Tmux interrogation +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun ob-tmux--session-alive-p (ob-session) + "Check if SESSION exists by parsing output of \"tmux ls\". + +Argument OB-SESSION: the current ob-tmux session." + (let* ((tmux-ls (ob-tmux--execute-string ob-session "ls -F '#S'")) + (tmux-session (ob-tmux--session ob-session))) + (car + (seq-filter (lambda (x) (string-equal tmux-session x)) + (split-string tmux-ls "\n"))))) + +(defun ob-tmux--window-alive-p (ob-session) + "Check if WINDOW exists in tmux session. + +If no window is specified in OB-SESSION, returns 't." + (let* ((window (ob-tmux--window ob-session)) + (target (ob-tmux--target ob-session)) + (output (ob-tmux--execute-string ob-session + "list-panes" + "-F 'yes_exists'" + "-t" (concat "'" target "'")))) + (cond (window + (string-equal "yes_exists\n" output)) + ((null window) + 't)))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Warnings +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun ob-tmux--deprecation-warning (org-header-terminal) + (let* ((message (format "DEPRECATION WARNING: Setting `:terminal` using org source block header arguments is deprecated. + +Consider changing your ob-tmux configuration as follows: + +(setq org-babel-default-header-args:tmux + '((:results . \"\") + (:session . \"\") + (:terminal. \"%s\") ; <--- REMOVE THIS LINE + (:socket . nil))) + +;; You can now customize the terminal and its options as follows: +(setq org-babel-tmux-terminal \"%s\") +(setq org-babel-tmux-terminal-opts '(\"-T\" \"ob-tmux\" \"-e\")) +; The default terminal is \"gnome-terminal\" with options \"--\". + +If you have any source blocks containing `:terminal`, please consider removing them: + + #+begin_src tmux :session test :terminal %s + echo hello + #+end_src + +Becomes: + + #+begin_src tmux :session test + echo hello + #+end_src + +End of warning. (See *Warnings* buffer for full message) +" org-header-terminal org-header-terminal org-header-terminal))) + (display-warning 'deprecation-warning message :warning) + message)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Test functions +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun ob-tmux--open-file (path) + "Open file as string. + +Argument PATH: the location of the file." +(with-temp-buffer + (insert-file-contents-literally path) + (buffer-substring (point-min) (point-max)))) + +(defun ob-tmux--test () + "Test if the default setup works. The terminal should shortly flicker." + (interactive) + (let* ((random-string (format "%s" (random 99999))) + (tmpfile (org-babel-temp-file "ob-tmux-test-")) + (body (concat "echo '" random-string "' > " tmpfile)) + tmp-string) + (org-babel-execute:tmux body org-babel-default-header-args:tmux) + ;; XXX: need to find a better way to do the following + (while (or (not (file-readable-p tmpfile)) + (= 0 (length (ob-tmux--open-file tmpfile)))) + ;; do something, otherwise this will be optimized away + (format "org-babel-tmux: File not readable yet.")) + (setq tmp-string (ob-tmux--open-file tmpfile)) + (delete-file tmpfile) + (message (concat "org-babel-tmux: Setup " + (if (string-match random-string tmp-string) + "WORKS." + "DOESN'T work."))))) + +(provide 'ob-tmux) + + + +;;; ob-tmux.el ends here