From 04126e9fda050fa753ddc22511e3c3f8dc275f7a Mon Sep 17 00:00:00 2001 From: Mitch Taylor Date: Sun, 22 Mar 2026 22:07:22 -0300 Subject: initial commit --- files/emacs/.emacs.d/eshell.el | 207 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 files/emacs/.emacs.d/eshell.el (limited to 'files/emacs/.emacs.d/eshell.el') diff --git a/files/emacs/.emacs.d/eshell.el b/files/emacs/.emacs.d/eshell.el new file mode 100644 index 0000000..f48142d --- /dev/null +++ b/files/emacs/.emacs.d/eshell.el @@ -0,0 +1,207 @@ +(use-package eshell + :ensure nil + :bind + (("C-c e" . eshell) + ("C-!" . eshell-here)) + :defer t + :config + (setq eshell-history-size 100000) + (setq eshell-hist-ignoredups t) + + + ;; MAKE ALL INSTANCES OF ESHELL SHARE/MERGE ITS COMMAND HISTORY + ;; + (defun emacs-solo/eshell--collect-all-history () + "Return a list of all eshell history entries from all buffers and disk." + (let ((history-from-buffers + (cl-loop for buf in (buffer-list) + when (with-current-buffer buf (derived-mode-p 'eshell-mode)) + append (with-current-buffer buf + (when (boundp 'eshell-history-ring) + (ring-elements eshell-history-ring))))) + (history-from-file + (when (file-exists-p eshell-history-file-name) + (with-temp-buffer + (insert-file-contents eshell-history-file-name) + (split-string (buffer-string) "\n" t))))) + (seq-uniq (append history-from-buffers history-from-file)))) + + (defun emacs-solo/eshell--save-merged-history () + "Save all eshell buffer histories merged into `eshell-history-file-name`." + (let ((all-history (emacs-solo/eshell--collect-all-history))) + (with-temp-file eshell-history-file-name + (insert (mapconcat #'identity all-history "\n"))))) + + (add-hook 'kill-emacs-hook #'emacs-solo/eshell--save-merged-history) + + (add-hook 'eshell-mode-hook + (lambda () + (eshell-read-history))) + + ;; MAKES C-c l GIVE AN ICOMPLETE LIKE SEARCH TO HISTORY COMMANDS + ;; + (defun emacs-solo/eshell-pick-history () + "Show a unified and unique Eshell history from all open sessions + history file. +Pre-fills the minibuffer with current Eshell input (from prompt to point)." + (interactive) + (unless (derived-mode-p 'eshell-mode) + (user-error "This command must be called from an Eshell buffer")) + (let* (;; Safely get current input from prompt to point + (bol (save-excursion (eshell-bol) (point))) + (eol (point)) + (current-input (buffer-substring-no-properties bol eol)) + + ;; Path to Eshell history file + (history-file (expand-file-name eshell-history-file-name + eshell-directory-name)) + + ;; Read from history file + (history-from-file + (when (file-exists-p history-file) + (with-temp-buffer + (insert-file-contents-literally history-file) + (split-string (buffer-string) "\n" t)))) + + ;; Read from in-memory Eshell buffers + (history-from-rings + (cl-loop for buf in (buffer-list) + when (with-current-buffer buf (derived-mode-p 'eshell-mode)) + append (with-current-buffer buf + (when (bound-and-true-p eshell-history-ring) + (ring-elements eshell-history-ring))))) + + ;; Deduplicate and sort + (all-history (reverse + (seq-uniq + (seq-filter (lambda (s) (and s (not (string-empty-p s)))) + (append history-from-rings history-from-file))))) + + ;; Prompt user with current input as initial suggestion + (selection (completing-read "Eshell History: " all-history + nil t current-input))) + + (when selection + ;; Replace current input with selected history entry + (delete-region bol eol) + (insert selection)))) + + + ;; GIVES SYNTAX HIGHLIGHTING TO CAT + ;; + (defun eshell/cat-with-syntax-highlighting (filename) + "Like cat(1) but with syntax highlighting. + Stole from aweshell" + (let ((existing-buffer (get-file-buffer filename)) + (buffer (find-file-noselect filename))) + (eshell-print + (with-current-buffer buffer + (if (fboundp 'font-lock-ensure) + (font-lock-ensure) + (with-no-warnings + (font-lock-fontify-buffer))) + (let ((contents (buffer-string))) + (remove-text-properties 0 (length contents) '(read-only nil) contents) + contents))) + (unless existing-buffer + (kill-buffer buffer)) + nil)) + (advice-add 'eshell/cat :override #'eshell/cat-with-syntax-highlighting) + + + ;; LOCAL ESHELL BINDINGS + ;; + (add-hook 'eshell-mode-hook + (lambda () + (local-set-key (kbd "C-c l") #'emacs-solo/eshell-pick-history) + (local-set-key (kbd "C-l") + (lambda () + (interactive) + (eshell/clear 1))))) + + (defun eshell-here () + "Opens up a new shell in the directory associated with the +current buffer's file. The eshell is renamed to match that +directory to make multiple eshell windows easier." + (interactive) + (let* ((parent (if (buffer-file-name) + (file-name-directory (buffer-file-name)) + default-directory)) + (height (/ (window-total-height) 3)) + (name (car (last (split-string parent "/" t))))) + (split-window-vertically (- height)) + (other-window 1) + (eshell "new") + (rename-buffer (concat "*eshell: " name "*")))) + + (defun eshell/x () + (insert "exit") + (eshell-send-input) + (delete-window)) + + (defun fish-path (path max-len) + "Return a potentially trimmed-down version of the directory PATH, replacing +parent directories with their initial characters to try to get the character +length of PATH (sans directory slashes) down to MAX-LEN." + (let* ((components (split-string (abbreviate-file-name path) "/")) + (len (+ (1- (length components)) + (cl-reduce '+ components :key 'length))) + (str "")) + (while (and (> len max-len) + (cdr components)) + (setq str (concat str + (cond ((= 0 (length (car components))) "/") + ((= 1 (length (car components))) + (concat (car components) "/")) + (t + (if (string= "." + (string (elt (car components) 0))) + (concat (substring (car components) 0 2) + "/") + (string (elt (car components) 0) ?/))))) + len (- len (1- (length (car components)))) + components (cdr components))) + (concat str (cl-reduce (lambda (a b) (concat a "/" b)) components)))) + + (defun heks-emacs-eshell-prompt () + (defun with-face (str &rest face-plist) + (propertize str 'face face-plist)) + (concat + "\n" + (with-face user-login-name :inherit 'font-lock-function-name-face) + "@" + (with-face (system-name) :inherit 'font-lock-function-name-face) + ": " + (with-face (if (string= (eshell/pwd) (getenv "HOME")) + "~" (fish-path (eshell/pwd) 36)) + :inherit 'font-lock-function-name-face) + ": " + (with-face + (or (ignore-errors (git-prompt-branch-name)) "") + :inherit 'font-lock-function-name-face) + "\n" + (if (= (user-uid) 0) + "#" + "λ") + " ")) + + (setopt eshell-prompt-regexp "^[^#λ\n]*[#λ] ") + (setopt eshell-prompt-function 'heks-emacs-eshell-prompt) + (setopt eshell-highlight-prompt nil) + + + ;; SET TERM ENV SO MOST PROGRAMS WON'T COMPLAIN + ;; + (add-hook 'eshell-mode-hook (lambda () (setenv "TERM" "xterm-256color"))) + + + (setq eshell-visual-subcommands + '(("podman" "run" "exec" "attach" "top" "logs" "stats" "compose") + ("docker" "run" "exec" "attach" "top" "logs" "stats" "compose") + ("jj" "resolve" "squash" "split"))) + + (setq eshell-visual-commands + '("vi" "screen" "top" "htop" "btm" "less" "more" "lynx" "ncftp" "pine" "tin" "trn" + "elm" "irssi" "nmtui-connect" "nethack" "vim" "alsamixer" "nvim" "w3m" "psql" + "lazygit" "lazydocker" "ncmpcpp" "newsbeuter" "nethack" "mutt" "neomutt" "tmux" + "jqp"))) + -- cgit v1.2.3