From 6c9213d532a960b9e98db21f8e2f0932178748be Mon Sep 17 00:00:00 2001 From: Madeleine Sydney Date: Sun, 16 Feb 2025 18:50:00 -0700 Subject: [PATCH] feat(emacs): Eshell stuff - Fancify prompt - Shows success of last command. - TRAMP prefix is made distinct. - CWD is abbreviated. - cd to project root (`cdp`). - Imitate using `C-d` / send-EOF to exit. - Opening popup shell puts user in insert state. - Fixes TRAMP customisation. Nicely done! }:3 --- users/crumb/programs/emacs/eshell/alias | 33 +++++ users/crumb/programs/emacs/eshell/history | 3 - users/crumb/programs/emacs/lib/syd-file.el | 11 ++ users/crumb/programs/emacs/lib/syd-project.el | 4 + .../programs/emacs/modules/syd-eshell.el | 130 ++++++++++++++---- .../crumb/programs/emacs/modules/syd-evil.el | 7 +- .../crumb/programs/emacs/modules/syd-tramp.el | 11 +- users/crumb/programs/emacs/modules/syd-ui.el | 27 ++-- 8 files changed, 182 insertions(+), 44 deletions(-) create mode 100644 users/crumb/programs/emacs/eshell/alias delete mode 100644 users/crumb/programs/emacs/eshell/history diff --git a/users/crumb/programs/emacs/eshell/alias b/users/crumb/programs/emacs/eshell/alias new file mode 100644 index 0000000..00661f0 --- /dev/null +++ b/users/crumb/programs/emacs/eshell/alias @@ -0,0 +1,33 @@ +alias ga git add $* +alias gb git branch $* +alias gc git commit $* +alias gcl git clone $* +alias gco git checkout $* +alias gd git diff $* +alias gl git log $* +alias glo git log --pretty=oneline $* +alias glol git log --graph --oneline --decorate $* +alias gp git push $* +alias gr git remote $* +alias grs git remote show $* +alias gs git status $* +alias gtd git tag --delete $* + +alias jb jj bookmark $* +alias jd jj describe $* +alias jdi jj diff $* +alias je jj edit $* +alias jgcl jj git clone $* +alias jgp jj git push $* +alias jgr jj git remote $* +alias jl jj log $* +alias jn jj new $* +alias js jj status --no-pager $* +alias jsp jj split $* +alias l ls -alh $* +alias ll ls -l $* +alias ls ls --color=tty $* + +alias pass /nix/store/hqhi6dgl7p16v49ymg2hwkgl844092fb-passage-1.7.4a2/bin/passage $* + +alias cdp syd-cd-project \ No newline at end of file diff --git a/users/crumb/programs/emacs/eshell/history b/users/crumb/programs/emacs/eshell/history deleted file mode 100644 index 46f13fc..0000000 --- a/users/crumb/programs/emacs/eshell/history +++ /dev/null @@ -1,3 +0,0 @@ -doge -soge -grep -r xref diff --git a/users/crumb/programs/emacs/lib/syd-file.el b/users/crumb/programs/emacs/lib/syd-file.el index abb2bbd..6f93bac 100644 --- a/users/crumb/programs/emacs/lib/syd-file.el +++ b/users/crumb/programs/emacs/lib/syd-file.el @@ -135,4 +135,15 @@ If FORCE-P, delete without confirmation." base-file conflict-file))) +(defun syd-split-tramp-file-name (file-name) + "Split FILE-NAME into (TRAMP-PREFIX . LOCAL-NAME). Returns (nil . FILE-NAME) +if FILE-NAME has no TRAMP prefix." + (if (tramp-tramp-file-p file-name) + (let* ((dissected (tramp-dissect-file-name file-name t)) + (localname (tramp-file-name-localname dissected))) + (setf (tramp-file-name-localname dissected) nil) + (cons (tramp-make-tramp-file-name dissected) + localname)) + (cons nil file-name))) + (provide 'syd-file) diff --git a/users/crumb/programs/emacs/lib/syd-project.el b/users/crumb/programs/emacs/lib/syd-project.el index d77ed49..8712e05 100644 --- a/users/crumb/programs/emacs/lib/syd-project.el +++ b/users/crumb/programs/emacs/lib/syd-project.el @@ -8,5 +8,9 @@ (when-let* ((project (project-current nil dir))) (project-root project))) +(defun syd-cd-project () + "Change the working directory to the root of the current project." + (cd (syd-project-root))) + (provide 'syd-project) ;;; syd-project.el ends here diff --git a/users/crumb/programs/emacs/modules/syd-eshell.el b/users/crumb/programs/emacs/modules/syd-eshell.el index d81dc71..b892961 100644 --- a/users/crumb/programs/emacs/modules/syd-eshell.el +++ b/users/crumb/programs/emacs/modules/syd-eshell.el @@ -60,9 +60,103 @@ (eshell-mode)) (when command (syd-eshell-run-command command eshell-buffer))) - (pop-to-buffer eshell-buffer)))) + (pop-to-buffer eshell-buffer) + (when (bound-and-true-p evil-mode) + (call-interactively #'evil-append-line))))) + +(defun syd-eshell-adapt-bash-aliases () + "Very sloppily convert aliases defined in Bash to an Eshell alias file." + (interactive) + (save-window-excursion + (let ((err-buf (generate-new-buffer "*adapt-bash-aliases-err*")) + (result-buf (generate-new-buffer "*adapted-bash-aliases*"))) + (with-current-buffer result-buf + (insert "# Automatically generated by syd-eshell-adapt-bash-aliases\n")) + (with-temp-buffer + ;; Aliases are only loaded when bash is in interactive mode. + (shell-command "bash -ic alias" (current-buffer) err-buf) + (goto-char (point-min)) + (while (re-search-forward + (rx bol "alias " (group (+ alphanumeric)) "='" + (group (* (not ?\'))) "'") + nil t) + (let ((eshell-alias (format "alias %s %s $*\n" + (match-string 1) + (match-string 2)))) + (with-current-buffer result-buf + (insert eshell-alias))))) + (unless (= 0 (buffer-size err-buf)) + (message "Some errors occured whilst fetching Bash's aliases:") + (message (with-current-buffer err-buf (buffer-string)))) + (kill-buffer err-buf) + result-buf))) + +(defun syd-eshell-C-d () + "Imitate the typical 'C-d' behaviour in other shells. Quits Eshell when the input is empty." + (interactive) + (when (and (eolp) (looking-back eshell-prompt-regexp nil)) + (eshell-life-is-too-much))) + +(defun syd-eshell--init-ui-hacks () + (defun syd-eshell-remove-fringes-h () + (set-window-fringes nil 0 0) + (set-window-margins nil 1 nil)) + (defun syd-eshell-enable-text-wrapping-h () + (visual-line-mode +1) + (set-display-table-slot standard-display-table 0 ?\ )) + (add-hook 'eshell-mode-hook #'syd-eshell-remove-fringes-h) + (add-hook 'eshell-mode-hook #'syd-eshell-enable-text-wrapping-h) + + (with-eval-after-load 'hide-mode-line + (add-hook 'eshell-mode-hook #'hide-mode-line-mode)) + + ;; Remove hscroll-margin in shells, otherwise you get jumpiness when the + ;; cursor comes close to the left/right edges of the window. + (defun syd-eshell-disable-hscroll-margin () + (setq hscroll-margin 0)) + (add-hook 'eshell-mode-hook #'syd-eshell-disable-hscroll-margin)) + +(use-package shrink-path + :defer t) + +(defface syd-eshell-local-name '((t (:inherit font-lock-constant-face))) + "Face used by the Eshell prompt for the CWD's non-TRAMP part. See +`syd-eshell--prompt-fn'" + :group 'eshell) + +(defface syd-eshell-tramp-prefix '((t (:inherit font-lock-comment-face))) + "Face used by the Eshell prompt for the CWD's TRAMP prefix. See +`syd-eshell--prompt-fn'." + :group 'eshell) + +(defun syd-eshell--prompt-fn () + "See `eshell-prompt-function'." + (require 'shrink-path) + (require 'syd-file) + (-let (((tramp-prefix . local-name) (syd-split-tramp-file-name (eshell/pwd)))) + (concat (unless (bobp) "\n") + (when tramp-prefix + (propertize tramp-prefix 'face 'syd-eshell-tramp-prefix)) + (propertize (if (equal local-name "~") + local-name + (abbreviate-file-name (shrink-path-file local-name))) + 'face 'syd-eshell-local-name) + (propertize " $" + 'face (if (zerop eshell-last-command-status) + 'success + 'error)) + " "))) + +(defvar syd-eshell--prompt-regexp (rx bol (* (not (any "\n$"))) " $ ")) + +(set-popup-rule! "^\\*eshell-popup" + :vslot -5 :size 13 :select t :modeline nil :quit nil :ttl nil) (use-package eshell + :init + (defvar syd-eshell-data-dir (file-name-concat syd-data-dir + "eshell")) + (make-directory syd-eshell-data-dir t) :custom ((eshell-banner-message '(format "🦌 %s %s }:3\n" @@ -77,42 +171,32 @@ (eshell-glob-case-insensitive t) (eshell-error-if-no-glob t) (eshell-history-file-name (file-name-concat - syd-data-dir "eshell" "history")) + syd-eshell-data-dir "history")) (eshell-last-dir-ring-file-name (file-name-concat - syd-data-dir "eshell" "lastdir"))) + syd-eshell-data-dir "lastdir")) + (eshell-prompt-function #'syd-eshell--prompt-fn) + (eshell-prompt-regexp syd-eshell--prompt-regexp)) :general (:keymaps 'syd-leader-open-map "e" #'syd-eshell/toggle) + (:keymaps 'eshell-mode-map + :states 'insert + "C-d" #'syd-eshell-C-d) (:keymaps 'eshell-mode-map :states '(normal insert) "C-j" #'eshell-next-matching-input-from-input "C-k" #'eshell-previous-matching-input-from-input) :config + ;; When cd'd into a TRAMP remote, automatically expand '/' to the TRAMP + ;; notation referring to the remote's root. + (add-to-list 'eshell-modules-list 'eshell-elecslash) + (require 'syd-buffers) (add-hook 'eshell-mode-hook #'syd-mark-buffer-as-real) ;; UI enhancements. - (defun syd-eshell-remove-fringes-h () - (set-window-fringes nil 0 0) - (set-window-margins nil 1 nil)) - (defun syd-eshell-enable-text-wrapping-h () - (visual-line-mode +1) - (set-display-table-slot standard-display-table 0 ?\ )) - (add-hook 'eshell-mode-hook #'syd-eshell-remove-fringes-h) - (add-hook 'eshell-mode-hook #'syd-eshell-enable-text-wrapping-h) - - (with-eval-after-load 'hide-mode-line - (add-hook 'eshell-mode-hook #'hide-mode-line-mode)) - - ;; Remove hscroll-margin in shells, otherwise you get jumpiness when the - ;; cursor comes close to the left/right edges of the window. - (defun syd-eshell-disable-hscroll-margin () - (setq hscroll-margin 0)) - (add-hook 'eshell-mode-hook #'syd-eshell-disable-hscroll-margin)) - -(set-popup-rule! "^\\*eshell-popup" - :vslot -5 :size 0.35 :select t :modeline nil :quit nil :ttl nil) + (syd-eshell--init-ui-hacks)) (provide 'syd-eshell) diff --git a/users/crumb/programs/emacs/modules/syd-evil.el b/users/crumb/programs/emacs/modules/syd-evil.el index e111436..4e45ef3 100755 --- a/users/crumb/programs/emacs/modules/syd-evil.el +++ b/users/crumb/programs/emacs/modules/syd-evil.el @@ -52,7 +52,12 @@ ;; In imitation of Vim's :mes[sages] command, define an Evil analogue to show ;; the echo area. - (evil-ex-define-cmd "mes[sages]" #'view-echo-area-messages) + (defun syd-evil-messages () + (interactive) + (view-echo-area-messages) + (with-current-buffer messages-buffer-name + (evil-motion-state 1))) + (evil-ex-define-cmd "mes[sages]" #'syd-evil-messages) ;; On ESC, remove highlighted search results. (defun syd-evil-nohl-h () diff --git a/users/crumb/programs/emacs/modules/syd-tramp.el b/users/crumb/programs/emacs/modules/syd-tramp.el index d8cf692..36c3103 100644 --- a/users/crumb/programs/emacs/modules/syd-tramp.el +++ b/users/crumb/programs/emacs/modules/syd-tramp.el @@ -1,10 +1,9 @@ ;;; syd-tramp.el -*- lexical-binding: t; -*- -(use-package tramp - :defer t - :custom ((tramp-persistency-file-name (file-name-concat syd-cache-dir - "tramp")) - (tramp-auto-save-directory - (file-name-concat syd-cache-dir "tramp-autosave/")))) +(with-eval-after-load 'tramp + (setq tramp-persistency-file-name + (file-name-concat syd-cache-dir "tramp")) + (setq tramp-auto-save-directory + (file-name-concat syd-cache-dir "tramp-autosave/"))) (provide 'syd-tramp) diff --git a/users/crumb/programs/emacs/modules/syd-ui.el b/users/crumb/programs/emacs/modules/syd-ui.el index 3d9fc90..5a3da14 100755 --- a/users/crumb/programs/emacs/modules/syd-ui.el +++ b/users/crumb/programs/emacs/modules/syd-ui.el @@ -64,7 +64,11 @@ (native-comp-async-report-warnings-errors 'silent) ;; Don't recenter the view unless >10 lines are scrolled off-screen ;; in a single movement. - (scroll-conservatively 10)) + (scroll-conservatively 10) + ;; In modes making use of `recenter-top-bottom' (e.g. Comint, + ;; Eshell), this will make the command behave more like a plain old + ;; `clear` invocation. + (recenter-positions '(top))) :config ;; Disable the menu bar, scroll bar, and tool bar. (menu-bar-mode -1) @@ -75,7 +79,7 @@ :disabled :unless noninteractive :commands persp-switch-to-buffer - :hook (on-init-ui . persp-mode) + :hook (on-init-ui-hook . persp-mode) :config (setq persp-autokill-buffer-on-remove 'kill-weak persp-reset-windows-on-nil-window-conf nil @@ -89,14 +93,15 @@ persp-auto-resume-time -1 ; Don't auto-load on startup persp-auto-save-opt (if noninteractive 0 1))) -(defun syd-init-ui-hacks () - (set-popup-rule! "*Backtrace*" - :size #'doom-popup-shrink-to-fit) - (set-popup-rule! "*Messages*" - :ttl nil - :quit t) - (evil-set-initial-state 'debugger-mode 'normal)) - -(add-hook 'on-init-ui-hook #'syd-init-ui-hacks) +(syd-add-hook 'on-init-ui-hook + (defun syd-init-ui-hacks () + (set-popup-rule! "*Backtrace*" + :size #'doom-popup-shrink-to-fit) + (set-popup-rule! "*Messages*" + :ttl nil + :quit t) + ;; Required for :quit t to do anything. + (evil-set-initial-state 'messages-buffer-mode 'motion) + (evil-set-initial-state 'debugger-mode 'normal))) (provide 'syd-ui)