eshell is the shell I’ve tried using over time, and in the end just never stick with it. Let’s try one more time with a couple of tricks. The first tricks are mostly documentation:
M-&in a tramp-aware session means you run commands in a new buffer, without a TTY. Great for things like
- for ncurses-like applications, “visual commands” is the missing
context. Applications like
topare in the default list by default, but let’s:
htopto that default list, because I occasionally use it
- and remember about
eshell-exec-visual, which runs the command as a visual command.
(require 'em-term) (add-to-list 'eshell-visual-commands "htop")
That said, I also need to automatically close the command buffer on exit, because who wants stale buffers.
(setq eshell-destroy-buffer-when-process-dies t)
One last thing, that turns out to be very annoying:
eshell-exec-visual is not tramp-aware. Let’s make it tramp-aware for
SSH at least:
(defun eshell-exec-visual (&rest args) "Run the specified PROGRAM in a terminal emulation buffer. ARGS are passed to the program. At the moment, no piping of input is allowed." (let* (eshell-interpreter-alist (original-args args) (interp (eshell-find-interpreter (car args) (cdr args))) (in-ssh-tramp (and (tramp-tramp-file-p default-directory) (equal (tramp-file-name-method (tramp-dissect-file-name default-directory)) "ssh"))) (program (if in-ssh-tramp "ssh" (car interp))) (args (if in-ssh-tramp (let ((dir-name (tramp-dissect-file-name default-directory))) (eshell-flatten-list (list "-t" (tramp-file-name-host dir-name) (format "export TERM=xterm-256color; cd %s; exec %s" (tramp-file-name-localname dir-name) (string-join (append (list (tramp-file-name-localname (tramp-dissect-file-name (car interp)))) (cdr args)) " "))))) (eshell-flatten-list (eshell-stringify-list (append (cdr interp) (cdr args)))))) (term-buf (generate-new-buffer (concat "*" (if in-ssh-tramp (format "%s %s" default-directory (string-join original-args " ")) (file-name-nondirectory program)) "*"))) (eshell-buf (current-buffer))) (save-current-buffer (switch-to-buffer term-buf) (term-mode) (set (make-local-variable 'term-term-name) eshell-term-name) (make-local-variable 'eshell-parent-buffer) (setq eshell-parent-buffer eshell-buf) (term-exec term-buf program program nil args) (let ((proc (get-buffer-process term-buf))) (if (and proc (eq 'run (process-status proc))) (set-process-sentinel proc 'eshell-term-sentinel) (error "Failed to invoke visual command"))) (term-char-mode) (if eshell-escape-control-x (term-set-escape-char ?\C-x)))) nil)
Besides that, let’s have some sane default settings.
For example, default history size is 128 items. lol.
(setq eshell-history-size 1000000)
(Side note: this is a nice trick to import all of bash history. Only
run once though:
Let’s also make tramp a bit faster:
;; cache file-name forever (setq remote-file-name-inhibit-cache nil) ;; make sure vc stuff is not making tramp slower (setq vc-ignore-dir-regexp (format "%s\\|%s" vc-ignore-dir-regexp tramp-file-name-regexp)) ;; not sure why we have this? just cargo-culting from an answer I saw ;; online. (setq tramp-verbose 1) ;; projectile has the fun side-effect of wanting to calculate the ;; project name, which makes tramp oh-so-much-slower. (setq projectile-mode-line "Projectile")
But the real performance gain is making sure that the
file has this:
Host * ControlPath ~/.ssh/master-%h:%p ControlMaster auto ControlPersist 10m
(aka: make every SSH connection use the “control master” openssh feature, which opens a single SSH connection, reuses it when you create new channels, and keeps it around for 10 minutes until after you’ve closed your last channel.)