reddit / emacs
org-mode + vterm + tmux == ❤️❤️❤️
dnquark · 2022-10-08 09:09
I often find myself switching between Emacs and terminal (e.g. xterm). A typical example is to run a test suite after editing some code. For years, I've been looking for a clean way to send code directly to a terminal without copy-pasting, and I think I finally found it. Best hack I've come up with in 12 years of using this editor. Here it is:
1. Install the absolutely excellent vterm package:[https://github.com/akermu/emacs-libvterm](https://github.com/akermu/emacs-libvterm)
2. Create the following script, put it somewhere reasonable:`#!/bin/bashemacsclient -e "(progn (vterm) (vterm-send-string \"$*\") (vterm-send-return))"`
3. Install ob-tmux and configure:[https://github.com/ahendriksen/ob-tmux](https://github.com/ahendriksen/ob-tmux)`(setq org-babel-tmux-terminal "<PATH TO THE BASH SCRIPT ABOVE>")(setq org-babel-tmux-terminal-opts nil)`
4. Enjoy!
(e.t.a: with `(setq vterm-enable-manipulate-selection-data-by-osc52 t)` you also get integration between tmux visual mode and the kill-ring, which depending on your habits may be a more ergonomic way to copy/paste between terminal and emacs)
​
https://i.redd.it/twkilcoqsjs91.gif
ArjaSpellan · 2022-10-08 09:41
I suggest checking out stuff like `projectile-test-project` and friends
NoisyFrequency · 2022-10-08 09:53
Yeah if your project is setup correctly, it's just one command away
stuudente · 2022-10-08 12:01
I found vterm hard to use because I am an evil user (doom actually), and for some reason the default key bindings aren't so great.. Now I see I can use emacs buffers instead of the repl.. I'm sold!
HumanBrainMapper · 2022-10-08 13:38
That's neat. This is however also possible with the built in (ansi) term.
dnquark · 2022-10-08 19:27
I also use doom/evil! In addition, I use vi bindings in bash/inputrc. I find that \`evil-collection-vterm\` works pretty well. I use the following tweaks:
;; better evil integration
(map! :leader "ESC" #'evil-force-normal-state)
(defun lva/vterm-mode-hook ()
(unless evil-collection-vterm-send-escape-to-vterm-p
(evil-collection-vterm-toggle-send-escape))
(after! (vterm evil-collection)
(add-hook 'vterm-mode-hook 'lva/vterm-mode-hook))
;; better tmux integration
(after! vterm
(setq vterm-enable-manipulate-selection-data-by-osc52 t)
(map! :map vterm-mode-map :i "<M-up>" 'vterm--self-insert))
​
With the first line, you can use a binding like \`M-SPC ESC\` (\`M-SPC\` being the default alt-leader key) to switch the vterm buffer to evil normal state. Most of the time I don't use it, and simply interact with the vterm the same exact way I do with any other terminal.
frozenzeta · 2022-10-08 20:22
That’s neat! I have been using similar approach, but simply sending tmux commands to terminal by executing an org shell code block.
mattaccount · 2022-10-08 21:06
Thanks, that looks useful!
I have a similar function in my init that I use to execute a line in a shellscript within vterm. I've found it useful for writing and debugging scripts. Can't remember where I found it, maybe here?
(defun my/vterm-execute-current-line ()
"Insert text of current line in vterm and execute."
(interactive)
(require 'vterm)
(eval-when-compile (require 'subr-x))
(let ((command (string-trim (buffer-substring
(save-excursion
(beginning-of-line)
(point))
(save-excursion
(end-of-line)
(point))))))
(let ((buf (current-buffer)))
(unless (get-buffer vterm-buffer-name)
(vterm))
(display-buffer vterm-buffer-name t)
(switch-to-buffer-other-window vterm-buffer-name)
(vterm--goto-line -1)
(message command)
(vterm-send-string command)
(vterm-send-return)
(switch-to-buffer-other-window buf)
)))
Thaodan · 2022-10-08 21:19
Try multi-vterm next.
ExistingProgram3883 · 2022-10-09 03:34
Would you mind to share your workflow with term?
arthurno1 · 2022-10-09 20:19
Yes, as you say, running stuff directly from Emacs can save a lot of time. However instead of running your tests from terminal, have you tried !-:? It runs a shell command. You can give your command same arguments as on command line in the terminal and you will get a buffer with results which you can edit like any other text buffer so you don'thave to copy-paste text from terminal.
Also you don't need libvterm either, ansi-term or just term will go long way. I don't say you should not use it, just that there is a good-enough built-in solution that works in many cases for readers that maybe prefer not to download extra software if they don't need it.
But it is probably even better to create a makefile and use compile command to run it. Make is an automation tool and is good to run other stuff too, not just for compiling software.
HumanBrainMapper · 2022-10-10 14:27
I wrote the following snippet to do it:
`(defun hbm-ansi-select-buffer ()`
`(interactive)`
`(setq hbm-ansi-output-buffer (completing-read "" (mapcar (function buffer-name) (buffer-list)))))`
`(defun hbm-ansi-command-to-term ()`
`;; Send line or region to term`
`(interactive)`
`;; Set input buffer`
`(setq hbm-ansi-input-buffer (buffer-name))`
`;; Set output buffer`
`(if (boundp 'hbm-ansi-output-buffer)`
`(message "ansi output buffer already selected")`
`(hbm-ansi-select-buffer)`
`;; Then rerun this command`
`(hbm-ansi-command-to-term)`
`)`
`;; If a region is selected:`
`(if (use-region-p)`
`;; Grab region`
`(setq mystring (buffer-substring-no-properties (region-beginning) (region-end)))`
`;; Else, select the current line`
`(setq mystring (buffer-substring-no-properties (point-at-bol) (point-at-eol)))`
`)`
`;; Send the selection to the output buffer`
`(comint-send-string hbm-ansi-output-buffer mystring)`
`;; Go to the output buffer`
`(switch-to-buffer hbm-ansi-output-buffer)`
`;; Go to the end of the buffer to make sure the cursor is after the last`
`;; pasted command`
`(end-of-buffer)`
`;; Press enter (sort of)`
`(term-send-input)`
`;; Go to previous frame, deselect anything that was selected and go`
`;; to the next line`
`(switch-to-buffer hbm-ansi-input-buffer)`
`(next-line)`
`(deactivate-mark)`
`)`
`;; Key binding`
`;; To be able to run shell lines directly from an org file`
`(define-key org-mode-map (kbd "C-c m x") 'hbm-ansi-command-to-term)`
`;; To use this in a shell mode buffer`
`(defun my-sh-mode-hook ()`
`(define-key sh-mode-map (kbd "C-<return>") 'hbm-ansi-command-to-term)`
`(define-key sh-mode-map (kbd "C-c m x") 'hbm-ansi-command-to-term)`
`)`
`(add-hook 'sh-mode-hook 'my-sh-mode-hook)`
tomatoaway · 2022-11-17 10:10
I've been looking for documentation on this function, and all I've found is this link:
https://docs.projectile.mx/projectile/configuration.html#project-specific-compilation-buffers
How does this enable one to spawn a detached session, tmux-style?
ArjaSpellan · 2022-11-17 15:57
I think you'd use detached if you need to: https://sr.ht/\~niklaseklund/detached.el/