Hi Max, Reply-to does not include you in my mail client, only the list. I assume that's intentional?
On 2025-07-25 at 03:28 -07, Max Nikulin <maniku...@gmail.com> wrote... > make single > ob-screen.el:78:8:Warning: ‘mapcar’ called for effect; use ‘mapc’ or > ‘dolist’ instead > > I hope, there is no this kind of warnings for the latest patch set. I forgot about this test warning. It remained. I've now fixed it. >> +(defun org-babel-variable-assignments:screen (params) >> + "Return variable assignments for a screen source block. >> +Dispatches to the appropriate shell-specific assignment function >> +based on the :cmd header argument." >> + (let* ((cmd (cdr (assq :cmd params))) >> + (shell (or (and cmd (if (listp cmd) (car cmd) cmd)) "sh")) >> + (var-helper >> + (and shell >> + (intern-soft >> + (format "org-babel--variable-assignments:%s" shell))))) > > My naive expectation is that it should be possible to just do > (intern-soft (format "org-babel-variable-assignments:%s" shell)) > with single dash and > (funcall var-helper params) This works for bash and sh, but I've also been testing with fish shell where 'x="42"' is an error and the shell says "Please use 'set x 42'". The current version, using internal org-babel--variable-assignments:%s works in fish shell. I've added a comment. See attached patch. > Finally an idea for further improvements after these patches will be > committed. > > On 16/03/2023 11:12, Ken Mankoff wrote: >> #+BEGIN_SRC bash >> ssh somewhere >> python > > It would be nice to be able to have something like > > #+begin_src screen :cmd ssh somewhere python :var a="test" > > An obvious obstacle is complications with determining language for > org-babel-variable-assignments:... Perhaps it can be solved by > introducing new :lang header argument to explicitly specify language > with fallback to current heuristics with :cmd and sh. I have been working on a new patch (see attachment 0004) that implements what you suggest here, sort-of. My personal flow uses screen to ssh to a remote host, and I wanted my variables there, not on localhost. Earlier I figured out that I can inject PROPERTIES anywhere - on remote host, in an R session using "x <- 42" syntax, etc. with custom noweb functions. But I wanted to access *header vars* not just *properties* on remote hosts, so patch 0004 injects :prologue before :var. Now you can do what you show above but with :prologue instead of :cmd: #+BEGIN_SRC screen :var x="42" y="24" :prologue "ssh foo -t \"python3\"" print(x) print(y) #+END_SRC Because the default variable assignment is "%s=%s", it works in most places and languages. Python. Fortran, etc. It fails in fish (set x 42) and R (x <- 42) and languages that do not match (x=42). Injecting :prologue before :var is also not something that should only benefit screen, if it is even a benefit, but for some reason this already works in 'normal' bash babel blocks. I would be grateful for your (and others) comments on the WIP 0004 patch, in addition to the other three that have been seen before and here have only the suggested small improvements. Note: Just for completeness in case someone is interested in injecting properties as variables: *** Foo :PROPERTIES: :message: hello world :END: #+NAME: get_property #+BEGIN_SRC emacs-lisp :var prop_name="" :results silent ;; Put this in library of babel so it becomes universal (org-with-point-at org-babel-current-src-block-location (org-entry-get nil prop_name t)) #+END_SRC #+BEGIN_SRC screen # or any other language ssh host python3 m="<<get_property("message")>>" print(m) #+END_SRC And because you control the syntax (m=""), it works in any language you want (R: m <- <<get_property...>>). And because you control when the injection occurs, it can be nested e.g. multiple remote hosts, multiple shells or languages, even in TUI environments. TUI environments means you can run top or midnight-commander in screen and control it by sending keys. I just haven't figured out how to send anything but a-zA-Z. No ctrl, shift, etc. > In addition it should allow non-standard executable names > :cmd /home/user/src/bash-9.99/bash-9.99 I just tried this and it is already supported. > #+begin_src screen :cmd ssh somewhere python :lang python :var a="test" This more complicated :cmd is not supported. But can be achieved with :prologue as shown above. > Ideally wrappers like ssh or screen should be available in a > TRAMP-like way for any babel language, but I do not have vision how to > properly implement it. With ob-screen it is not really convenient, but > should be easy to implement. It's not clear yet what your vision is. Is this for REPL languages, or compiled languages too (I've just set myself as maintainer for ob-fortran). Would Babel need to know about the final environment the way Tramp knows about the remote host and dir and can inject and compile files there, or is this closer to 'screen' where Babel is just 'dumbly' injecting one character at a time locally. Even though I don't have a clear vision yet, your mention of TRAMP-like suggests an implementation to me. :dir is handled by most (all?) languages. Maybe :cmd or :env needs to be handled at the top babel level so it's universal, and a syntax like :env foo|something else here|other" Then each string between || pairs is a command that's run in whatever language of the current babel block, or in the shell before that language is loaded. Also, we have :var but could add a universal :varsyntax that defaults to "%s=%s", but could be controlled by the user (e.g., "%s <- %s"). By offloading this to the user, it saves Babel from having to know about all the possible environments and syntax. -k.
>From 2c11f6f39b04dca75138f6e3eb1c58c545fcc833 Mon Sep 17 00:00:00 2001 From: Ken Mankoff <mank...@gmail.com> Date: Wed, 23 Jul 2025 08:41:57 -0400 Subject: [PATCH 1/4] lisp/ob-screen.el (org-babel-screen-test): Test now passes --- lisp/ob-screen.el | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lisp/ob-screen.el b/lisp/ob-screen.el index 554a01406..60a473f39 100644 --- a/lisp/ob-screen.el +++ b/lisp/ob-screen.el @@ -128,16 +128,15 @@ The terminal should shortly flicker." (body (concat "echo '" random-string "' > " tmpfile "\nexit\n")) tmp-string) (org-babel-execute:screen body org-babel-default-header-args:screen) - ;; XXX: need to find a better way to do the following - (while (not (file-readable-p tmpfile)) - ;; do something, otherwise this will be optimized away - (message "org-babel-screen: File not readable yet.")) + (while (= (file-attribute-size (file-attributes tmpfile)) 0) + (progn (message "org-babel-screen: Still executing...") + (sleep-for 0.1))) (setq tmp-string (with-temp-buffer (insert-file-contents-literally tmpfile) (buffer-substring (point-min) (point-max)))) (delete-file tmpfile) (message (concat "org-babel-screen: Setup " - (if (string-match random-string tmp-string) + (if (string-match-p random-string tmp-string) "WORKS." "DOESN'T work."))))) -- 2.47.2
>From d1222c4416413536cf1b6affb37bafd741984591 Mon Sep 17 00:00:00 2001 From: Ken Mankoff <mank...@gmail.com> Date: Wed, 23 Jul 2025 08:45:30 -0400 Subject: [PATCH 2/4] lisp/ob-screen.el: Support custom location for 'screen' command * lisp/ob-screen.el: All direct calls to 'screen' now use `org-babel-screen-location`. Also supports custom screen locations including paths with spaces. --- lisp/ob-screen.el | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lisp/ob-screen.el b/lisp/ob-screen.el index 60a473f39..024669a39 100644 --- a/lisp/ob-screen.el +++ b/lisp/ob-screen.el @@ -67,8 +67,11 @@ In case you want to use a different screen than one selected by your $PATH") (screenrc (cdr (assq :screenrc params))) (process-name (concat "org-babel: terminal (" session ")"))) (apply 'start-process process-name "*Messages*" - terminal `("-T" ,(concat "org-babel: " session) "-e" ,org-babel-screen-location - "-c" ,screenrc "-mS" ,session ,cmd)) + (append (list terminal "-T" (concat "org-babel: " session) "-e") + (list org-babel-screen-location + "-c" screenrc + "-mS" session + cmd))) ;; XXX: Is there a better way than the following? (while (not (org-babel-screen-session-socketname session)) ;; wait until screen session is available before returning @@ -83,13 +86,14 @@ In case you want to use a different screen than one selected by your $PATH") (let ((tmpfile (org-babel-screen-session-write-temp-file session body))) (apply 'start-process (concat "org-babel: screen (" session ")") "*Messages*" org-babel-screen-location - `("-S" ,socket "-X" "eval" "msgwait 0" - ,(concat "readreg z " tmpfile) - "paste z")))))) + (list "-S" socket "-X" "eval" "msgwait 0" + (concat "readreg z " tmpfile) + "paste z")))))) (defun org-babel-screen-session-socketname (session) "Check if SESSION exists by parsing output of \"screen -ls\"." - (let* ((screen-ls (shell-command-to-string "screen -ls")) + (let* ((screen-cmd (format "%S -ls" org-babel-screen-location)) + (screen-ls (shell-command-to-string screen-cmd)) (sockets (delq nil (mapcar -- 2.47.2
>From ebafd63cab714ef562e952ed964ca7b129e99d73 Mon Sep 17 00:00:00 2001 From: Ken Mankoff <mank...@gmail.com> Date: Wed, 23 Jul 2025 08:51:33 -0400 Subject: [PATCH 3/4] lisp/ob-screen.el: Support :var header argument * lisp/ob-screen.el: Support :var header argument similar to org babel shell code blocks. * etc/ORG-NEWS (ob-screen now supports :var header arguments): Document new feature. --- etc/ORG-NEWS | 10 ++++++++++ lisp/ob-screen.el | 27 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 4cb7561a8..951c3f290 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -224,6 +224,16 @@ appropriate major mode is unavailable. When editing Dot source blocks, Org now uses Graphviz Dot mode, if installed. +*** ob-screen now supports :var header arguments + +The ~:var~ header arg is now supported. + +#+BEGIN_src org +,#+BEGIN_SRC screen :var x=42 +,echo $x +,#+END_SRC +#+END_src + ** New and changed options # Changes dealing with changing default values of customizations, diff --git a/lisp/ob-screen.el b/lisp/ob-screen.el index 024669a39..34297a406 100644 --- a/lisp/ob-screen.el +++ b/lisp/ob-screen.el @@ -39,6 +39,7 @@ (org-assert-version) (require 'ob) +(require 'ob-shell) (defvar org-babel-screen-location "screen" "The command location for screen. @@ -54,8 +55,12 @@ In case you want to use a different screen than one selected by your $PATH") \"default\" session is used when none is specified in the PARAMS." (save-window-excursion (let* ((session (cdr (assq :session params))) + (var-lines (org-babel-variable-assignments:screen params)) (socket (org-babel-screen-session-socketname session))) (unless socket (org-babel-prep-session:screen session params)) + (mapc (lambda (var) + (org-babel-screen-session-execute-string session var)) + var-lines) (org-babel-screen-session-execute-string session (org-babel-expand-body:generic body params))))) @@ -123,6 +128,28 @@ In case you want to use a different screen than one selected by your $PATH") (delete-matching-lines "^ +$")) tmpfile)) +(defun org-babel-variable-assignments:screen (params) + "Return variable assignments for a screen source block. +Dispatches to the appropriate shell-specific assignment function +based on the :cmd header argument." + (let* ((cmd (cdr (assq :cmd params))) + (shell (or (and cmd (if (listp cmd) (car cmd) cmd)) "sh")) + (var-helper + (and shell + (intern-soft + (format "org-babel-variable-assignments:%s" shell))))) + (mapcar ;; Use `mapcar` to apply per-variable formatting because + ;; most shell assignment helpers expect one variable at a + ;; time. Avoid cleaner `funcall` unless the callee can handle the + ;; entire `params` list." + (lambda (pair) + (let ((varname (symbol-name (car pair))) + (val (cdr pair))) + (if (and var-helper (fboundp var-helper)) + (funcall var-helper varname val) + (format "%s=%s" varname (org-babel-sh-var-to-sh val))))) + (org-babel--get-vars params)))) + (defun org-babel-screen-test () "Test if the default setup works. The terminal should shortly flicker." -- 2.47.2
>From 386a8b3ea85bda672a0ce09047868019fb59ecf9 Mon Sep 17 00:00:00 2001 From: Ken Mankoff <k...@kenmankoff.com> Date: Fri, 25 Jul 2025 06:46:40 -0700 Subject: [PATCH 4/4] WIP: lisp/ob-screen.el inject :prologue before :var * lisp/ob-screen.el (org-babel-execute:screen): Inject :prologue before :var assigment. This allows variables in header blocks to ssh to a remote host or load a different program (e.g., Python) before the variable assignment. --- lisp/ob-screen.el | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lisp/ob-screen.el b/lisp/ob-screen.el index 34297a406..662a98f63 100644 --- a/lisp/ob-screen.el +++ b/lisp/ob-screen.el @@ -56,13 +56,18 @@ In case you want to use a different screen than one selected by your $PATH") (save-window-excursion (let* ((session (cdr (assq :session params))) (var-lines (org-babel-variable-assignments:screen params)) - (socket (org-babel-screen-session-socketname session))) + (socket (org-babel-screen-session-socketname session)) + (prologue (cdr (assoc :prologue params))) + (body-no-prologue (if (and prologue (string-prefix-p prologue body)) + (string-trim-left body prologue) + body))) (unless socket (org-babel-prep-session:screen session params)) - (mapc (lambda (var) + (when prologue ; Send :prologue first, if any + (org-babel-screen-session-execute-string session prologue)) + (mapc (lambda (var) ; Send variable assignments (org-babel-screen-session-execute-string session var)) - var-lines) - (org-babel-screen-session-execute-string - session (org-babel-expand-body:generic body params))))) + var-lines) ; Send the rest of the body without :prologue + (org-babel-screen-session-execute-string session body-no-prologue)))) (defun org-babel-prep-session:screen (_session params) "Prepare SESSION according to the header arguments specified in PARAMS." -- 2.47.2