Coder Social home page Coder Social logo

ob-tmux's Introduction

ob-tmux

Ob-tmux is an Emacs library that allows org mode to evaluate code blocks in a tmux session.

Ob-tmux is useful for keeping notes on how to perform tasks in the terminal, especially when some interactivity is required. The functionality can be used to document software installation, build instructions, and administrative tasks. The documentation can be tested and adjusted while it is written.

Installation

This package is available on from MELPA.

If you have added MELPA to your package sources, you can install ob-tmux interactively

M-x package-install [RET] ob-tmux [RET]

Alternatively, you can copy the ob-tmux.el file to a directory in your load-path.

Configuration

In your .emacs or .emacs.d/init.el file, add the following:

(require 'ob-tmux)
(setq org-babel-default-header-args:tmux
      '((:results . "silent")	;
        (:session . "default")	; The default tmux session to send code to
        (:socket  . nil)))      ; The default tmux socket to communicate with

;; The tmux sessions are prefixed with the following string.
;; You can customize this if you like.
(setq org-babel-tmux-session-prefix "ob-")

;; The terminal that will be used.
;; You can also customize the options passed to the terminal.
(setq org-babel-tmux-terminal "xterm")
(setq org-babel-tmux-terminal-opts '("-T" "ob-tmux" "-e"))
; The default terminal is "gnome-terminal" with options "--".

;; Finally, if your tmux is not in your $PATH for whatever reason, you
;; may set the path to the tmux binary as follows:
(setq org-babel-tmux-location "/usr/bin/tmux")

If you use use-package, you can also write

(use-package ob-tmux
  ;; Install package automatically (optional)
  :ensure t
  :custom
  (org-babel-default-header-args:tmux
   '((:results . "silent")	;
     (:session . "default")	; The default tmux session to send code to
     (:socket  . nil)))		; The default tmux socket to communicate with
  ;; The tmux sessions are prefixed with the following string.
  ;; You can customize this if you like.
  (org-babel-tmux-session-prefix "ob-")
  ;; The terminal that will be used.
  ;; You can also customize the options passed to the terminal.
  ;; The default terminal is "gnome-terminal" with options "--".
  (org-babel-tmux-terminal "xterm")
  (org-babel-tmux-terminal-opts '("-T" "ob-tmux" "-e"))
  ;; Finally, if your tmux is not in your $PATH for whatever reason, you
  ;; may set the path to the tmux binary as follows:
  (org-babel-tmux-location "/usr/bin/tmux"))

Usage

You can start a new terminal window with a tmux session as follows:

#+BEGIN_SRC tmux :session hello
echo hello
#+END_SRC

If you press C-c C-c with your point in the code block, a terminal window will pop up with a new tmux session named org-babel-session-hello.

You can continue work in this session with another code block.

#+BEGIN_SRC tmux :session hello
echo world
#+END_SRC

If you press C-c C-c now, no new terminal window will open, but the code will be sent to the existing tmux session.

You can also specify to which tmux window the source block should be sent. If the tmux window does not yet exist, ob-tmux will create it. To specify the window, you may use the tmux target syntax. In the following example, the :session argument has been changed to hello:new-world:

#+BEGIN_SRC tmux :session hello:new-window
echo hello world in new-window
#+END_SRC

Executing this code block will add a window, new-window, to your session.

You can parameterize scripts by using ~:var variable=”value”~. This will add a line containing variable“value”= preceding the content body.

#+begin_src tmux :var name="Ismael"
echo hello ${name}
#+end_src

You can exit your tmux session by detaching. The terminal window will close automatically. Ob-tmux will not detect that you have detached. Any commands you send will be sent to the tmux session in the background. You can reattach to your tmux session at any time and check that the commands have indeed been executed.

Tip. Ob-tmux is also very useful for restarting your tmux sessions after a reboot. Take a look at the following snippet.

** Startup tmux
Use ~C-c C-v s~ to execute subtree.
*** Jupyter
#+BEGIN_SRC tmux :session daemons:jupyter
cd ~/projects/notebooks/
jupyter notebook
#+END_SRC
*** htop
#+BEGIN_SRC tmux session daemons:htop
htop
#+END_SRC
*** dmesg
#+BEGIN_SRC tmux :session daemons:dmesg
dmesg
#+END_SRC

If your point is on the Startup tmux header, you can execute all code blocks in the subtree with C-c C-v s to restart your favorite tmux sessions.

Sockets: remoting

If you want your code to execute on a remote machine, you can use ob-tmux too. There are two ways to control a remote machine. The first is to simply SSH into the remote machine and execute code from there:

#+BEGIN_SRC tmux
ssh remote-machine
#+END_SRC
#+BEGIN_SRC tmux
echo do things...
#+END_SRC

This method has one big downside: long-running code might be interrupted when you lose connection. This method does not start a tmux session on the remote computer; it only starts a tmux session on the local computer.

The other method is to start a remote tmux session and share the remote tmux socket with your local machine. It is possible to start a remote tmux session:

ssh remote-machine -t tmux new -d

This creates a socket on the remote machine. You can forward this socket to the local machine as follows:

REMOTE_SOCKET=$(ssh remote-machine  'tmux ls -F "#{socket_path}"' | head -1)
echo $REMOTE_SOCKET
ssh remote-machine -tfN \
    -L ~/.tmux-local-socket-remote-machine:$REMOTE_SOCKET

Now you can execute code on the remote machine:

#+BEGIN_SRC tmux :socket ~/.tmux-local-socket-remote-machine :session hello
echo hello from remote machine
#+END_SRC

There are some advantages to this method, especially with long running jobs. For instance, if your local machine is rebooted the remote tmux session remains running and you can always reconnect. Furthermore, you do not have to prepend ssh remote-machine to every tmux source code block. This saves time and makes sure that you code is reexecutable: you can execute the same code block twice and it will (hopefully) work the same. It will not try to SSH into the remote machine again while it is already logged in remotely.

Known bugs and or possible issues

My tmux indexes start at 1. By default, tmux window indexes start at zero. This might lead to problems. I have not yet checked.

I will try to respond within a week to any issues raised. I cannot promise I will fix them.

Contributions

Contributions are always welcome. Please be in touch before you make sweeping changes or add large features. This may prevent disappointment and will help me help you.

ob-tmux's People

Contributors

ahendriksen avatar kaiha avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ob-tmux's Issues

Allowing options for the terminal

Hi

Can you add the possibility to pass options to the terminal spawn by ob-tmux?

Example: I use i3wm and I can put a terminal in the scratchpad which will act as a dropdown terminal. If I can set an option for the ob-tmux terminal, like window title, I can make a window rule in i3wm where this terminal will be put in the scratchpad automatically.

Thank you for your work btw :)

Any way to get output back to emacs ?

Thank you very much for writing this very nice package.

Is there a way to get kind of screenshot of the latest state as seen in the tmux window back to org-mode ?
I could not find any such option in tmux manual, anyone knows ?, but it would be helpful to make this even more interactive.

Idea: support for :var header argument

Sorry for opening so many issues - I don't want to spam, but I just stumbled upon these things :)

Short backstory: In my workflow I start tmux on a HPC, log in to a compute node, and run a jupyter kernel there, which I tunnel to my local emacs. That means there are code snippets I reuse often, e.g. this one:

#+BEGIN_SRC tmux :socket ~/.tmux-local-socket-remote-machine :session tmux
jupyter notebook --no-browser --port=8888
#+END_SRC

Feature idea: implement the :var header argument like in other org source blocks so that this would be possible:

#+NAME: jpt-tmux
#+BEGIN_SRC tmux :socket ~/.tmux-local-socket-remote-machine :session tmux :var port="8888"
jupyter notebook --no-browser --port=$port
#+END_SRC

#+CALL: jpt-tmux(port=8888)

Current behaviour: in the tmux session we just get jupyter notebook --no-browser --port=$port

Amazing! yet on linux cant get the term to pop?

This is extremely cool!

i maybe wrong but when i have this in the conf

   (:terminal . "gnome-terminal")))

shouldnt gnome-term pop up the first time i evaluate a tmux block?

i also tried other terms such as xterm and terminator but they never pop up

i can however manually open a term and then tmux attach to the session

what am i missing :)

thx!

Z

Can not pass a variable to a tmux block

First of all, thanks for publishing and maintaining this piece of org-babel awesomeness :)

I have a pretty simple question - does ob-tmux support variable passing?
Basically I was trying do the following:

#+BEGIN_SRC tmux :session main :var fooId="1"
echo ${fooId}
#+END_SRC

ob-sh and many other packages seem to have no issues with var passing. Not sure if this feature exists in ob-tmux or this is something wrong with my local setup/how I attempt to use it?

Thanks

No syntax highlight in tmux source block

ob-tmux is great but it does not highlight the code in the source block. Can we add a :src variable to specify the source type, then tmux can use ob-src to highlight the code in the block? Not sure how hard it is to implement it.

Confirming this works with iterm

I'm using ob-tmux on a Mac with iTerm2 Build 3.1.5 and using the following configuration worked fine for me:

(setq org-babel-default-header-args:tmux '((:terminal . "iterm")))

Lines starting with '-' are not correctly sent

The following does not work:

#+BEGIN_SRC tmux
- hello
#+END_SRC

Tmux responds with

tmux: unknown option --  
usage: send-keys [-lXRM] [-N repeat-count] [-t target-pane] key ...

Process ob-tmux finished

Tmux interprets the hyphen as a (possible) option.

The fix is to send hyphens as separate command-line arguments. Will fix this soon.

Remote tmux session hangs

I'm on a Mac, using the latest tmux version (3.2a). The remote machine is also a Mac, same version of tmux installed via homebrew. Emacs v27.2, with org 9.4.6.

I can use ob-tmux to control local tmux without any issue. On a remote machine, I started tmux session ob-tmux, and set up the socket.

==> ssh sedona.local /usr/local/bin/tmux ls
ob-tmux: 3 windows (created Sat Jun 26 15:02:22 2021) (attached)

I can issue the following from a shell locally and see the vim pop-up, so it seems the socket setup is correct:

==> tmux -S ~/.tmux-local-socket-sedona.local new-window vim ~/.tmux.conf

But, with ob-tmux, it just hangs:

#+BEGIN_SRC tmux :socket ~/.tmux-local-socket-sedona.local :session tmux
vim ~/.tmux.conf
#+END_SRC

I see the following in Messages:
Sending source code block to interactive terminal session...
Waiting for process to die...done

Happy to provide any more details you may require to solve this issue.

How do I execute multiple commands?

#+BEGIN_SRC tmux :socket ~/.tmux-local-socket-remote-machine :session test-vm 
sudo snap install charmcraft --classic &&
sudo snap install juju --classic &&
sudo snap install charmcraft --classic
#+END_SRC

I can append && but wonder if there's a better way.

Sockets: remoting questions

Hi there, first of all, thanks for making such a great package! It's hugely useful, it's a major improvement over searching through shell history and juggling shell scripts in multiple locations.

I'm trying to get the steps in the "Sockets: remoting" section working but haven't had much luck. After creating a new tmux session on my remote machine, when I run tmux ls -F "#{socket_path}" on the remote machine, I get blank output. It seems that the -F flag takes a format, but "socket_path" doesn't seem to be one of them. Here is explainshell's list of the formats.

Is there a way I can get the correct socket manually? That way I can manually set $REMOTE_SOCKET for the next step.

Also, in the next step, I'm a little confused about ~/.tmux-local-socket-remote-machine. Is this local socket supposed to have been created in an earlier step?

Many thanks!

Remote tmux session using :socket leads to wrong tmux path inside session

To check the output of my tmux session, I have to attach to the session in a terminal (output directly to org is not yet supported). I noticed that I can not "tmux detach" or "tmux ls" because of tmux version issues. Using C-b d to detach still works. So I can work around it, but I noticed this inconsistency and wanted to report it.
Edit: I found out the reason for this behaviour - it is that the tmux session I attach to itself is created by tmux 3.0a, but the tmux path inside the session is different and so the tmux version is different as well (1.8). Therefore they are not compatible and the active tmux session can not be controlled via shell commands. This only happens with ob-tmux and not with a manually created session - this is what I wanted to report with this issue.

On my local machine I've got (works as expected)

which tmux
tmux -V

#+RESULTS:
| /bin/tmux |      |
| tmux      | 3.0a |

On the remote machine I've got (works as expected):

which tmux
tmux -V

#+RESULTS:
| /usr/local/bin/tmux |      |
| tmux                | 3.0a |

If I open a tmux session from my terminal and start a new session with tmux new -d and then attach to it I get (works as expected):

[user@remote ~]$ which tmux
/usr/local/bin/tmux
[user@remote ~]$ tmux -V
tmux 3.0a

If I use ob-tmux to open a tmux session following the README where in the end I have a code block somewhat like this #+BEGIN_SRC tmux :socket ~/.tmux-local-socket-remote-machine :session tmuxtest and then attach to it from my terminal I get (does not work as expected):

[user@remote ~]$ which tmux
/bin/tmux
[user@remote ~]$ tmux -V
tmux 1.8

I already tried to specify the desired path /usr/local/bin/tmux in org-babel-tmux-location (and soft- and hardlinked tmux on my own machine to this place, since otherwise ob-tmux did not create a session. The result was still the one you see above.

Here are some details on my setup, please tell me if you need more: GNU Emacs 26.3

Org mode version 9.1.9 (release_9.1.9-65-g5e4542 @ /usr/share/emacs/26.3/lisp/org/)

(use-package ob-tmux
 ;; Install package automatically (optional)
 :ensure t
 :custom
 (org-babel-default-header-args:tmux
  '((:results . "silent")	;
    (:session . "default")	; The default tmux session to send code to
    (:socket  . nil)))		; The default tmux socket to communicate with
 ;; The tmux sessions are prefixed with the following string.
 ;; You can customize this if you like.
 (org-babel-tmux-session-prefix "ob-")
 ;; The terminal that will be used.
 ;; You can also customize the options passed to the terminal.
 ;; The default terminal is "gnome-terminal" with options "--".
 (org-babel-tmux-terminal "xterm")
 (org-babel-tmux-terminal-opts '("-T" "ob-tmux" "-e"))
 ;; Finally, if your tmux is not in your $PATH for whatever reason, you
 ;; may set the path to the tmux binary as follows:
 (org-babel-tmux-location "/usr/local/bin/tmux"))

ob-tmux bind key?

I do as the readme described, but the error msg: C-c C-c is undefined .
But the ob-tmux--test works.
I wonder if I can bind other key to ob-tmux?

Set working directory with :dir

I just noticed another possible improvement. Using the header :dir in a source block usually allows to set the working directory, e.g.:

#+BEGIN_SRC sh :dir ~/my/path :session local
  pwd
#+END_SRC

#+RESULTS:
|                               |
| /home/user/my/path |

Doing this in ob-tmux on the other hand does not seem to work:

#+BEGIN_SRC tmux :dir ~/my/path :session local2
  pwd
#+END_SRC

#+RESULTS:
#+begin_example
  (base) [user@host ~]$ pwd
  /home/user
#+end_example

I think that would be a good functionality, especially since remote tmux sessions using :socket is possible. Would implementing this be feasible?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.