Summary

I demonstrate how to use YASnippet while in the terminal in emacs. I don’t mean merely in shell mode.

It works for any program running in vterm or term or ansi-term.

The trick is to expand the snippet in a temporary buffer and then insert the contents of that buffer into the terminal using whatever is the insert function for that terminal. A last resort could be to use tmux send-keys to do the insertion if you had an emacs terminal emulator that did not have an insert function.

Demo

elisp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
(defun my-yas-insert-snippet ()
  (interactive)
  (cond
   ((major-mode-p 'term-mode)
    (yas-insert-snippet-term))
   ((major-mode-p 'vterm-mode)
    (yas-insert-snippet-vterm))
   (t
    (yas-insert-snippet))))

(defun yas-insert-snippet-term ()
  (interactive)
  ;; Firstly, get off the current term window. It will go haywire with fz
  (let ((s))
    (save-window-excursion
      (switch-to-buffer "*scratch*")
      (let ((b (new-buffer-from-string "" "yastemp" (str2sym (fz (chomp (sn "find /home/shane/source/git/mullikine/yas-snippets -maxdepth 1 -mindepth 1 -type d | sed '/\\.git/d' | sed 's=^.*/=='"))
                                                                 nil nil "yas-insert-snippet-term: ")))))
        (save-window-excursion
          (save-excursion
            (with-current-buffer b
              (switch-to-buffer b)
              (yas-insert-snippet))))
        (setq s (buffer-to-string b))
        (kill-buffer b)))
    (term-send-raw-string s)))

(defun yas-insert-snippet-vterm ()
  (interactive)
  ;; Firstly, get off the current term window. It will go haywire with fz
  (let ((s))
    (save-window-excursion
      (switch-to-buffer "*scratch*")
      (let ((b (new-buffer-from-string "" "yastemp" (str2sym (fz (chomp (sn "find /home/shane/source/git/mullikine/yas-snippets -maxdepth 1 -mindepth 1 -type d | sed '/\\.git/d' | sed 's=^.*/=='"))
                                                                 nil nil "yas-insert-snippet-term: ")))))
        (save-window-excursion
          (save-excursion
            (with-current-buffer b
              (switch-to-buffer b)
              (yas-insert-snippet))))
        (setq s (buffer-to-string b))
        (kill-buffer b)))
    (vterm-insert s)))

Supporting functions

fz is similar to the completing-read function.

sn is a function which runs a shell command, similar to sh-notty here.

Creating fz and sn, I leave up to you.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
(defun sh-notty (&optional cmd stdin dir)
    "Runs command in shell and return the result.
This appears to strip ansi codes."
    (interactive)
    (if (not cmd)
        (setq cmd "false"))

    (if (not dir)
        (setq dir (get-dir)))

    (setq tf (make-temp-file "elispbash"))

    (setq final_cmd (concat "( cd " (e/q dir) "; " cmd ") > " tf))

    (if (not stdin)
        (progn
          (shell-command final_cmd))
      (with-temp-buffer
        (insert stdin)
        (shell-command-on-region (point-min) (point-max) final_cmd)))
    (setq output (with-temp-buffer
                   (insert-file-contents tf)
                   (buffer-string)))

    output)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(defalias 'str2sym 'intern)

(defun my-new-buffer-frame (&optional contents bufname mode nodisplay)
  "Create a new frame with a new empty buffer."
  (interactive)
  (if (not bufname)
      (setq bufname "*untitled*"))
  (let ((buffer (generate-new-buffer bufname)))
    (set-buffer-major-mode buffer)
    ;; (display-buffer buffer '(display-buffer-pop-up-frame . nil))
    (if (not nodisplay)
        (display-buffer buffer '(display-buffer-same-window . nil)))
    (with-current-buffer buffer
      (if contents (insert (str contents)))
      (company-mode 1)
      (beginning-of-buffer)
      ;; A hack to get the modeline to not display -- though this makes huge delays if there is docker, aws, etc.
      (ignore-errors (toggle-chrome))
      (ignore-errors (toggle-chrome))
      (if mode (call-function mode))
      (run-hooks 'new-buffer-hooks))
    buffer))
(defalias 'new-buffer-from-string 'my-new-buffer-frame)

Then create a keybinding

kb f
M-' M-s M-i my-yas-insert-snippet my-mode-map