;;; my-eshell.el --- Configure eshell -*- lexical-binding: t -*- ;;; Commentary: ;;; Code: (require 'cl-seq) (require 'vc) (require 'eshell) (require 'esh-mode) (require 'esh-module) (setq eshell-modules-list '(eshell-alias eshell-basic eshell-cmpl eshell-dirs eshell-glob eshell-hist eshell-ls eshell-pred eshell-prompt eshell-script eshell-term eshell-tramp eshell-unix)) (require 'em-alias) (require 'em-basic) (require 'em-dirs) (require 'em-glob) (require 'em-hist) (require 'em-term) (require 'em-tramp) (require 'em-prompt) (defun my/eshell-mode-setup () "Configures various aliases for eshell." (eshell/alias "e" "find-file $1") (eshell/alias "emacs" "find-file $1") (eshell/alias "ee" "find-file-other-window $1") (eshell/alias "ll" "ls -l") (eshell/alias "d" "dired $1") (eshell/alias "gs" "vc-diff") (eshell/alias "cal" "calendar") (eshell/alias "agenda" "org-agenda")) (defvar-local my/eshell-output-buffer "*Exported eshell output*" "Name of buffer with the last output of Eshell command.") (defvar-local my/eshell-output-delimiter "---" "Delimiter for successive `prot-eshell-export' outputs.") (defun my/eshell--command-prompt-output () "Capture last command prompt and its output." (let ((beg (save-excursion (goto-char (eshell-beginning-of-input)) (goto-char (point-at-bol))))) (when (derived-mode-p 'eshell-mode) (buffer-substring-no-properties beg (eshell-end-of-output))))) ;; https://gitlab.com/protesilaos/dotfiles/-/blob/master/emacs/.emacs.d/prot-lisp/prot-eshell.el#L114 (defun my/eshell-export () "Produce a buffer with output of the last Eshell command. If `my/eshell-output-buffer' does not exist, create it. Else append to it, while separating multiple outputs with `my/eshell-output-delimiter'." (interactive) (let ((eshell-output (my/eshell--command-prompt-output))) (with-current-buffer (get-buffer-create my/eshell-output-buffer) (goto-char (point-max)) (unless (eq (point-min) (point-max)) (insert (format "\n%s\n\n" my/eshell-output-delimiter))) (goto-char (point-at-bol)) (insert eshell-output) (switch-to-buffer-other-window (current-buffer))))) (defun my/short-pwd (path) "Turn a PATH of the form /foo/bar/baz into /f/b/baz, like fish shell." (let* ((home-path (replace-regexp-in-string (expand-file-name "~") "~" path)) (current-dir (split-string home-path "/")) (cdir (last current-dir)) (head (butlast current-dir))) (concat (mapconcat (lambda (s) (if (string= "" s) nil (substring s 0 1))) head "/") (if head "/" nil) (car cdir)))) (defmacro with-face (str &rest properties) "Set the PROPERTIES for the given STR." `(propertize ,str 'face (list ,@properties))) (defun my/prompt () "EShell prompt displaying VC info and such." (concat (with-face (concat (my/short-pwd (eshell/pwd)) " ") :foreground "#070707") (if (= 0 (user-uid)) (with-face "#" :foreground "#f43841") (with-face "λ" :foreground "#63c904")) (with-face " " :foreground "#000000"))) (define-key eshell-mode-map (kbd "C-c e e") 'my/eshell-export) (customize-set-variable 'eshell-scroll-to-bottom-on-input 'all) (customize-set-variable 'eshell-error-if-no-glob t) (customize-set-variable 'eshell-hist-ignoredups t) (customize-set-variable 'eshell-save-history-on-exit t) (customize-set-variable 'eshell-cd-on-directory t) (customize-set-variable 'eshell-prefer-lisp-functions nil) (customize-set-variable 'eshell-prompt-function 'my/prompt) (customize-set-variable 'eshell-highlight-prompt nil) (customize-set-variable 'eshell-where-to-jump 'begin) (customize-set-variable 'eshell-review-quick-commands nil) (customize-set-variable 'tramp-shell-prompt-pattern "^[^$>\n]*[#$%>] *\\(customize-set-variable '\[[0-9;]*[a-zA-Z] *\\)*") (customize-set-variable 'eshell-destroy-buffer-when-process-dies t) (add-hook 'eshell-mode-hook 'my/eshell-mode-setup) (provide 'my-eshell) ;;; my-eshell.el ends here