Just published a short video on Emacs shell interactions, which you can view here.
The following content is the video notes showcased in the video.
- Emacs offers an enhanced experience for interacting with shell tools & may be the most extensible terminal emulator available.
- Provides seamless integration between shell tools & editing capabilities.
Using shell commands from within a buffer
shell-command
M-! CMD <RET>
- Run the shell command CMD and display the output.
async-shell-command
M-& CMD <RET>
- Run the shell command CMD asynchronously, and display the output
shell-command-on-region
M-| CMD <RET>
- Run the shell command CMD with region contents as input; optionally replace the region with the output
Emacs as a Terminal Emulator
Shell
M-x shell
- A subshell with input and output through an Emacs buffer. You can then give commands interactively.
My configuration
(use-package shell
:defer t
:config
(defun thanos/shell (n)
"Create or switch to a shell buffer."
(interactive "P")
(let* ((num (if n (prefix-numeric-value n) nil))
(buf-name (if num (format "*shell<%d>*" num) "*shell*")))
(shell buf-name)))
:bind (("C-c v" . thanos/shell)
:map shell-mode-map
("C-l" . 'comint-clear-buffer))
:hook ((shell-mode . (lambda () (display-line-numbers-mode -1)))))
Eshell
M-x eshell
- Shell implemented entirely in Emacs Lisp
My configuration
(use-package esh-mode
:defer t
:config
;; Prompt
(defun eshell-git-info ()
"Return a string with git info."
(when (eq (call-process "git" nil nil nil "rev-parse" "--is-inside-work-tree") 0)
(let* ((branch-raw (shell-command-to-string "git rev-parse --abbrev-ref HEAD"))
(branch (if (or (string-match-p "^fatal" branch-raw)
(string-match-p "^error" branch-raw))
"Unknown"
(string-trim branch-raw)))
(dirty (not
(string= "" (string-trim (shell-command-to-string "git status --porcelain")))))
(dirty-info (if dirty " ✎" " ✔")))
(concat (propertize "⎇ " 'face 'modus-themes-fg-green-warmer)
(propertize branch 'face 'modus-themes-fg-magenta-warmer)
(propertize dirty-info 'face
(if dirty 'modus-themes-fg-red 'modus-themes-fg-green))))))
(defun eshell-prompt-multiline ()
"Eshell Multiline Git prompt."
(let ((separator (propertize " | " 'face 'font-lock-comment-face))
(hr (propertize (concat "\n" (make-string (/ (window-total-width) 2) ?─) "\n") 'face 'font-lock-comment-face))
(dir (propertize (format "%s" (abbreviate-file-name (eshell/pwd))) 'face 'modus-themes-fg-yellow-warmer))
(git-info (eshell-git-info))
(time (propertize (format-time-string "%H:%M:%S") 'face 'font-lock-comment-face))
(sign (if (= (user-uid) 0)
(propertize "\n#" 'face 'modus-themes-fg-blue-intense)
(propertize "\nλ" 'face 'modus-themes-fg-red-warmer))))
(concat hr dir separator git-info separator time sign " ")))
(setf eshell-prompt-function 'eshell-prompt-multiline
eshell-highlight-prompt nil)
;; Aliases
(defun eshell/o (file)
"Open FILE."
(find-file file))
(defvar thanos/aliases
'((ll . "ls -lah")
(clear . clear-scrollback)))
(defun thanos/set-eshell-aliases (aliases)
"Set ALIASES as eshell aliases."
;; Remove aliases file
(when (and eshell-aliases-file
(file-exists-p eshell-aliases-file))
(delete-file eshell-aliases-file))
(mapc (lambda (alias)
(let ((name (symbol-name (car alias)))
(command (cdr alias)))
(eshell/alias name
(cond
((stringp command) command)
((symbolp command) (symbol-name command))
(t (error "Unsupported alias command type"))))))
aliases))
;; Rebinds
(defun thanos/eshell-clear ()
"Interactive call for clear-scrollback."
(interactive)
(eshell/clear-scrollback))
(defun thanos/eshell-preview-insert ()
(interactive)
(completion-preview-insert)
;; This funciton just deletes the extra space inserted after
;; completion.
(delete-char -1))
:bind (("C-c e" . eshell)
:map eshell-mode-map
("C-l" . 'thanos/eshell-clear)
("<tab>" . 'thanos/eshell-preview-insert)
("C-M-i" . 'completion-at-point))
:hook ((eshell-mode . (lambda ()
(thanos/set-eshell-aliases thanos/aliases)
(display-line-numbers-mode -1)
(eshell-cmpl-mode -1)))))
Eat
- xterm-like emulator, written in Emacs Lisp.
- Although it’s a standalone terminal for Emacs, similar to
term
, I’ve mostly used this package to enhanceeshell
.
My configuration
(use-package eat
:ensure t
:config
(setf eshell-visual-commands nil
eat-term-name "xterm-256color")
:bind (("C-c V" . eat))
:hook ((eshell-mode . eat-eshell-mode)
(eshell-mode . eat-eshell-visual-command-mode)
(eat-mode . (lambda () (visual-line-mode -1)))))
Term & Ansi-Term
M-x term
|M-x ansi-term
- ansi-term is the same as term, except that it always creates a
new buffer and
C-x
is being marked as an escape-char.
- ansi-term is the same as term, except that it always creates a
new buffer and
- Runs a subshell with input and output through an Emacs buffer.
How to use
- While in
term-mode
C-c CHAR
is equivalent toC-x CHAR
.- Example
C-c o
is the global bindingC-x o
other-window
- Example
C-c C-j
switches toterm-line-mode
which allows navigation similar to shellC-c C-k
switches back toterm-char-mode