Overview
Using Emacs in daily life, I rely on vterm
terminal emulator instead of eshell
. However, I've
noticed that there are certain limitations in terms of integration between vterm
and Emacs. While
the package supports some user-accessible functions, they are not sufficient. I've always wanted the
integration level as VSCode
, and at least it should be able to open files from the terminal
interface. Well, this is one of essential features of the terminal emulator running on editors, so I
thought that having this kind of issue was ridiculous. So I tried to find solutions by googling
about it, but none of them had a one-shot method to achieve this. So, I made up my mind to write
functions by myself.
In this article, I am going to describe the following things:
- A callback function to open files from vterm
- Functions to manage vterm session
Note that since I am using Doomemacs right now, the keymap setting could differ from yours. If you do not want to read any details about functions that I wrote, just use the following settings.
1(require 'filenotify)
2
3(defvar my:get-vterm--backup nil)
4(defun my:vterm-new ()
5 (interactive)
6 (if (not (string-match-p "vterm" (buffer-name (current-buffer))))
7 (setq my:get-vterm--backup (current-buffer)))
8 (call-interactively #'+vterm/here))
9
10(defun my:vterm-toggle ()
11 (interactive)
12 (let ((cnt (cl-remove-if #'null
13 (mapcar (lambda (x)
14 (and (string-match-p "vterm" (buffer-name x)) (buffer-name x)))
15 (buffer-list)))))
16 (if (null cnt)
17 (progn
18 (setq my:get-vterm--backup (current-buffer))
19 (call-interactively #'+vterm/here))
20 (if (and (string-match-p "vterm" (buffer-name (current-buffer)))
21 my:get-vterm--backup)
22 (my:vterm--restore)
23 (call-interactively #'my:vterm--select)))))
24
25(defun my:vterm--restore ()
26 (switch-to-buffer my:get-vterm--backup)
27 (setq my:get-vterm--backup nil))
28
29(defun my:vterm--select (choice)
30"Argument CHOICE user's selection."
31 (interactive
32 (list (completing-read "Choose: "
33 (cl-remove-if #'null
34 (mapcar (lambda (x) (and (string-match-p "vterm" (buffer-name x)) (buffer-name x)))
35 (buffer-list)))
36 nil t)))
37 (car (split-string choice " "))
38 (setq my:get-vterm--backup (current-buffer))
39 (switch-to-buffer choice))
40
41(after! vterm
42 ;; Following must be used with bash alias:
43 ;; => alias eo='echo $1 > ~/.config/emacs/.local/cache/vterm-pipe'
44 (let* ((pipe-file (expand-file-name "vterm-pipe" user-emacs-directory))
45 (func-open-file (lambda (event)
46 (find-file
47 (with-temp-buffer
48 (insert-file-contents (expand-file-name "vterm-pipe" user-emacs-directory))
49 (string-trim (buffer-string)))))))
50 (file-notify-add-watch pipe-file '(change) func-open-file))
51
52 (add-hook 'vterm-mode-hook (lambda ()
53 (evil-emacs-state))))
File open from vterm - filenotify
Since Emacs-28.1, Emacs supports the filenotify
package, which makes it possible to watch any change
from the file. It means that whenever I write any to the file, Emacs can get the triggered event
from the write. Let's register a callback function for the vterm-pipe
in user-emacs-directory
.
1(file-notify-add-watch pipe-file '(change) callback-func)
Add the following code to $HOME/.bashrc
to use the alias
eo
command. Now, using the eo
alias will
trigger the event and invoke the callback function. It's done.
1alias eo='realpath $1 > ~/.config/emacs/.local/cache/vterm-pipe'
Vterm session management
Unfortunately, vterm
does not support any functions to manage its session. And a function to toggle
it is not perfect. Let's improve it by using an interactive menu. You can toggle the vterm
session
with my:vterm-toggle
. In the code, there are many to refactor but it is sufficient to resolve the
lack of session management and inefficient UI toggle.
Wrap up
Since I started to learn how to write code in elisp
, I have been able to use Emacs efficiently.
Beyond the simple editor, now I can see why Emacs has been loved by lots of developers. I know, this
should be the same for VI/M users :P.