2019-05-18 23:41:18 -04:00
|
|
|
;;; term/eshell/config.el -*- lexical-binding: t; -*-
|
2017-02-19 18:53:38 -05:00
|
|
|
|
|
|
|
;; see:
|
2019-06-11 07:51:16 +02:00
|
|
|
;; + `+eshell/here': open eshell in the current window
|
|
|
|
;; + `+eshell/toggle': toggles an eshell popup
|
|
|
|
;; + `+eshell/frame': converts the current frame into an eshell-dedicated
|
|
|
|
;; frame. Once the last eshell process is killed, the old frame configuration
|
|
|
|
;; is restored.
|
2017-02-19 18:53:38 -05:00
|
|
|
|
2018-06-28 18:34:02 +02:00
|
|
|
(defvar +eshell-config-dir
|
2022-08-13 21:27:11 +02:00
|
|
|
(expand-file-name "eshell/" doom-user-dir)
|
2018-06-28 18:34:02 +02:00
|
|
|
"Where to store eshell configuration files, as opposed to
|
|
|
|
`eshell-directory-name', which is where Doom will store temporary/data files.")
|
2018-06-18 22:31:27 +02:00
|
|
|
|
2022-08-14 18:10:01 +02:00
|
|
|
(defvar eshell-directory-name (concat doom-data-dir "eshell")
|
2020-04-28 16:54:34 -04:00
|
|
|
"Where to store temporary/data files, as opposed to `eshell-config-dir',
|
|
|
|
which is where Doom will store eshell configuration files.")
|
|
|
|
|
2018-06-18 22:31:27 +02:00
|
|
|
(defvar +eshell-enable-new-shell-on-split t
|
|
|
|
"If non-nil, spawn a new eshell session after splitting from an eshell
|
|
|
|
buffer.")
|
|
|
|
|
|
|
|
(defvar +eshell-kill-window-on-exit nil
|
|
|
|
"If non-nil, eshell will close windows along with its eshell buffers.")
|
|
|
|
|
|
|
|
(defvar +eshell-aliases
|
|
|
|
'(("q" "exit") ; built-in
|
2018-06-30 13:20:24 +02:00
|
|
|
("f" "find-file $1")
|
2021-07-06 02:30:06 -04:00
|
|
|
("ff" "find-file-other-window $1")
|
2019-11-18 14:19:10 -05:00
|
|
|
("d" "dired $1")
|
2019-06-11 07:57:26 +02:00
|
|
|
("bd" "eshell-up $1")
|
2019-01-22 14:56:38 -05:00
|
|
|
("rg" "rg --color=always $*")
|
2020-01-24 21:22:06 +00:00
|
|
|
("l" "ls -lh $*")
|
|
|
|
("ll" "ls -lah $*")
|
2021-04-14 18:06:33 +07:00
|
|
|
("git" "git --no-pager $*")
|
2020-04-28 16:54:34 -04:00
|
|
|
("gg" "magit-status")
|
2021-02-24 18:27:45 -05:00
|
|
|
("cdp" "cd-to-project")
|
2018-06-28 18:46:51 +02:00
|
|
|
("clear" "clear-scrollback")) ; more sensible than default
|
2018-06-18 22:31:27 +02:00
|
|
|
"An alist of default eshell aliases, meant to emulate useful shell utilities,
|
|
|
|
like fasd and bd. Note that you may overwrite these in your
|
|
|
|
`eshell-aliases-file'. This is here to provide an alternative, elisp-centric way
|
|
|
|
to define your aliases.
|
|
|
|
|
2019-06-11 07:51:16 +02:00
|
|
|
You should use `set-eshell-alias!' to change this.")
|
2018-06-18 22:31:27 +02:00
|
|
|
|
2018-06-28 18:34:02 +02:00
|
|
|
;; These files are exceptions, because they may contain configuration
|
2019-12-13 15:40:17 -05:00
|
|
|
(defvar eshell-aliases-file (concat +eshell-config-dir "aliases"))
|
2018-06-28 18:34:02 +02:00
|
|
|
(defvar eshell-rc-script (concat +eshell-config-dir "profile"))
|
|
|
|
(defvar eshell-login-script (concat +eshell-config-dir "login"))
|
|
|
|
|
2018-06-18 22:31:27 +02:00
|
|
|
(defvar +eshell--default-aliases nil)
|
2018-06-14 23:36:42 +02:00
|
|
|
|
|
|
|
|
|
|
|
;;
|
2020-04-23 23:49:35 -04:00
|
|
|
;;; Packages
|
2018-06-14 23:36:42 +02:00
|
|
|
|
|
|
|
(after! eshell ; built-in
|
2018-06-16 16:59:33 +02:00
|
|
|
(setq eshell-banner-message
|
|
|
|
'(format "%s %s\n"
|
|
|
|
(propertize (format " %s " (string-trim (buffer-name)))
|
|
|
|
'face 'mode-line-highlight)
|
|
|
|
(propertize (current-time-string)
|
|
|
|
'face 'font-lock-keyword-face))
|
|
|
|
eshell-scroll-to-bottom-on-input 'all
|
2017-02-19 18:53:38 -05:00
|
|
|
eshell-scroll-to-bottom-on-output 'all
|
2017-05-12 12:10:04 +02:00
|
|
|
eshell-kill-processes-on-exit t
|
2018-03-23 18:17:59 -04:00
|
|
|
eshell-hist-ignoredups t
|
2018-06-28 16:58:28 +02:00
|
|
|
;; don't record command in history if prefixed with whitespace
|
2019-05-29 23:44:23 -04:00
|
|
|
;; TODO Use `eshell-input-filter-initial-space' when Emacs 25 support is dropped
|
|
|
|
eshell-input-filter (lambda (input) (not (string-match-p "\\`\\s-+" input)))
|
2017-02-19 18:53:38 -05:00
|
|
|
;; em-prompt
|
2017-07-21 16:48:34 +02:00
|
|
|
eshell-prompt-regexp "^.* λ "
|
2019-07-23 00:07:14 +02:00
|
|
|
eshell-prompt-function #'+eshell-default-prompt-fn
|
2017-02-19 18:53:38 -05:00
|
|
|
;; em-glob
|
|
|
|
eshell-glob-case-insensitive t
|
2021-05-24 11:20:34 -04:00
|
|
|
eshell-error-if-no-glob t)
|
2017-02-19 18:53:38 -05:00
|
|
|
|
2018-05-18 01:26:00 +02:00
|
|
|
;; Consider eshell buffers real
|
2019-07-18 15:27:20 +02:00
|
|
|
(add-hook 'eshell-mode-hook #'doom-mark-buffer-as-real-h)
|
2018-05-18 01:26:00 +02:00
|
|
|
|
2018-06-18 22:31:27 +02:00
|
|
|
;; Keep track of open eshell buffers
|
2019-07-23 00:07:14 +02:00
|
|
|
(add-hook 'eshell-mode-hook #'+eshell-init-h)
|
|
|
|
(add-hook 'eshell-exit-hook #'+eshell-cleanup-h)
|
2018-06-18 22:31:27 +02:00
|
|
|
|
2018-06-29 01:22:06 +02:00
|
|
|
;; Enable autopairing in eshell
|
|
|
|
(add-hook 'eshell-mode-hook #'smartparens-mode)
|
|
|
|
|
2018-07-11 00:04:24 +02:00
|
|
|
;; Persp-mode/workspaces integration
|
2022-08-12 20:29:19 +02:00
|
|
|
(when (modulep! :ui workspaces)
|
2019-07-23 00:07:14 +02:00
|
|
|
(add-hook 'persp-activated-functions #'+eshell-switch-workspace-fn)
|
|
|
|
(add-hook 'persp-before-switch-functions #'+eshell-save-workspace-fn))
|
2018-07-11 00:04:24 +02:00
|
|
|
|
2018-06-16 16:39:48 +02:00
|
|
|
;; UI enhancements
|
2019-07-28 14:52:59 +02:00
|
|
|
(add-hook! 'eshell-mode-hook
|
2019-07-23 00:07:14 +02:00
|
|
|
(defun +eshell-remove-fringes-h ()
|
|
|
|
(set-window-fringes nil 0 0)
|
2020-11-19 23:00:13 -05:00
|
|
|
(set-window-margins nil 1 nil))
|
2019-07-23 00:07:14 +02:00
|
|
|
(defun +eshell-enable-text-wrapping-h ()
|
|
|
|
(visual-line-mode +1)
|
|
|
|
(set-display-table-slot standard-display-table 0 ?\ )))
|
2018-07-01 01:19:30 +02:00
|
|
|
|
2018-06-16 16:39:48 +02:00
|
|
|
(add-hook 'eshell-mode-hook #'hide-mode-line-mode)
|
|
|
|
|
2022-03-31 01:32:32 +02:00
|
|
|
;; Remove hscroll-margin in shells, otherwise you get jumpiness when the
|
|
|
|
;; cursor comes close to the left/right edges of the window.
|
|
|
|
(setq-hook! 'eshell-mode-hook hscroll-margin 0)
|
|
|
|
|
2018-06-18 22:31:27 +02:00
|
|
|
;; Don't auto-write our aliases! Let us manage our own `eshell-aliases-file'
|
|
|
|
;; or configure `+eshell-aliases' via elisp.
|
|
|
|
(advice-add #'eshell-write-aliases-list :override #'ignore)
|
2018-06-16 16:38:39 +02:00
|
|
|
|
2023-09-02 11:44:48 -05:00
|
|
|
(add-to-list 'eshell-modules-list 'eshell-tramp)
|
2021-01-10 04:49:00 -05:00
|
|
|
|
2018-06-18 22:31:27 +02:00
|
|
|
;; Visual commands require a proper terminal. Eshell can't handle that, so
|
|
|
|
;; it delegates these commands to a term buffer.
|
2017-05-12 12:07:28 +02:00
|
|
|
(after! em-term
|
2019-06-11 07:57:26 +02:00
|
|
|
(pushnew! eshell-visual-commands "tmux" "htop" "vim" "nvim" "ncmpcpp"))
|
2018-06-18 22:31:27 +02:00
|
|
|
|
2020-11-17 12:28:25 -05:00
|
|
|
(after! em-alias
|
|
|
|
(setq +eshell--default-aliases eshell-command-aliases-list
|
|
|
|
eshell-command-aliases-list
|
|
|
|
(append eshell-command-aliases-list
|
2023-09-16 16:14:41 +02:00
|
|
|
+eshell-aliases)))
|
|
|
|
|
|
|
|
;; HACK: Fixes #3817, where eshell completion after quotes is broken on Emacs
|
|
|
|
;; 28 and older.
|
|
|
|
;; CREDIT: Extracted from `cape''s cape-wrap-silent and cape-wrap-purify.
|
|
|
|
;; REVIEW: Remove when Doom drops 28 support.
|
|
|
|
(when (< emacs-major-version 29)
|
|
|
|
(defadvice! +eshell--silent-a (capf)
|
|
|
|
"Call CAPF and silence it (no messages, no errors).
|
|
|
|
This function can be used as an advice around an existing Capf."
|
|
|
|
:around #'pcomplete-completions-at-point
|
|
|
|
(letf! ((defmacro silent (&rest body) `(quiet! (ignore-errors ,@body)))
|
|
|
|
(defmacro wrapped-table (wrap body)
|
|
|
|
`(lambda (str pred action)
|
|
|
|
(,@body
|
|
|
|
(let ((result (complete-with-action action table str pred)))
|
|
|
|
(when
|
|
|
|
(and (eq action 'completion--unquote)
|
|
|
|
(functionp (cadr result)))
|
|
|
|
(cl-callf ,wrap (cadr result)))
|
|
|
|
result))))
|
|
|
|
(defun* silent-table (table) (wrapped-table silent-table (silent))))
|
|
|
|
(pcase (silent (funcall capf))
|
|
|
|
(`(,beg ,end ,table . ,plist)
|
|
|
|
`(,beg ,end ,(silent-table table) ,@plist)))))
|
|
|
|
|
|
|
|
(defadvice! +eshell--purify-a (capf)
|
|
|
|
"Call CAPF and ensure that it does not illegally modify the buffer. This
|
|
|
|
function can be used as an advice around an existing Capf. It has been
|
|
|
|
introduced mainly to fix the broken `pcomplete-completions-at-point' function in
|
|
|
|
Emacs versions < 29."
|
|
|
|
;; bug#50470: Fix Capfs which illegally modify the buffer or which
|
|
|
|
;; illegally call `completion-in-region'. The workaround here was proposed
|
|
|
|
;; by @jakanakaevangeli and is used in his capf-autosuggest package.
|
|
|
|
:around #'pcomplete-completions-at-point
|
|
|
|
(catch 'illegal-completion-in-region
|
|
|
|
(condition-case nil
|
|
|
|
(let ((buffer-read-only t)
|
|
|
|
(inhibit-read-only nil)
|
|
|
|
(completion-in-region-function
|
|
|
|
(lambda (beg end coll pred)
|
|
|
|
(throw 'illegal-completion-in-region
|
|
|
|
(list beg end coll :predicate pred)))))
|
|
|
|
(funcall capf))
|
|
|
|
(buffer-read-only nil))))))
|
2017-05-10 05:29:56 +02:00
|
|
|
|
2020-10-29 01:54:42 -04:00
|
|
|
|
|
|
|
(after! esh-mode
|
2020-10-27 21:19:59 -04:00
|
|
|
(map! :map eshell-mode-map
|
2020-10-29 01:54:42 -04:00
|
|
|
:n "RET" #'+eshell/goto-end-of-prompt
|
|
|
|
:n [return] #'+eshell/goto-end-of-prompt
|
2020-10-27 21:19:59 -04:00
|
|
|
:ni "C-j" #'eshell-next-matching-input-from-input
|
|
|
|
:ni "C-k" #'eshell-previous-matching-input-from-input
|
|
|
|
:ig "C-d" #'+eshell/quit-or-delete-char
|
2020-10-29 01:54:42 -04:00
|
|
|
:i "C-c h" #'evil-window-left
|
|
|
|
:i "C-c j" #'evil-window-down
|
|
|
|
:i "C-c k" #'evil-window-up
|
|
|
|
:i "C-c l" #'evil-window-right
|
2020-10-27 21:19:59 -04:00
|
|
|
"C-s" #'+eshell/search-history
|
|
|
|
;; Emacs bindings
|
|
|
|
"C-e" #'end-of-line
|
|
|
|
;; Tmux-esque prefix keybinds
|
|
|
|
"C-c s" #'+eshell/split-below
|
|
|
|
"C-c v" #'+eshell/split-right
|
|
|
|
"C-c x" #'+eshell/kill-and-close
|
|
|
|
[remap split-window-below] #'+eshell/split-below
|
|
|
|
[remap split-window-right] #'+eshell/split-right
|
|
|
|
[remap doom/backward-to-bol-or-indent] #'eshell-bol
|
|
|
|
[remap doom/backward-kill-to-bol-and-indent] #'eshell-kill-input
|
|
|
|
[remap evil-delete-back-to-indentation] #'eshell-kill-input
|
|
|
|
[remap evil-window-split] #'+eshell/split-below
|
|
|
|
[remap evil-window-vsplit] #'+eshell/split-right
|
2021-02-11 21:23:19 -05:00
|
|
|
;; To emulate terminal keybinds
|
2021-11-21 13:05:18 -05:00
|
|
|
"C-l" (cmd! (eshell/clear-scrollback) (eshell-emit-prompt))
|
2020-10-27 21:19:59 -04:00
|
|
|
(:localleader
|
|
|
|
"b" #'eshell-insert-buffer-name
|
|
|
|
"e" #'eshell-insert-envvar
|
2020-10-29 05:40:24 -04:00
|
|
|
"s" #'+eshell/search-history)))
|
2017-02-19 18:53:38 -05:00
|
|
|
|
2018-06-16 16:38:39 +02:00
|
|
|
|
2019-07-23 12:44:03 +02:00
|
|
|
(use-package! eshell-up
|
2019-06-11 07:57:26 +02:00
|
|
|
:commands eshell-up eshell-up-peek)
|
2018-06-16 16:51:43 +02:00
|
|
|
|
|
|
|
|
2019-07-23 12:44:03 +02:00
|
|
|
(use-package! eshell-z
|
2018-06-28 19:23:31 +02:00
|
|
|
:after eshell
|
|
|
|
:config
|
2018-06-28 18:31:46 +02:00
|
|
|
;; Use zsh's db if it exists, otherwise, store it in `doom-cache-dir'
|
|
|
|
(unless (file-exists-p eshell-z-freq-dir-hash-table-file-name)
|
2018-06-28 19:23:31 +02:00
|
|
|
(setq eshell-z-freq-dir-hash-table-file-name
|
|
|
|
(expand-file-name "z" eshell-directory-name))))
|
2019-10-18 19:39:29 -04:00
|
|
|
|
|
|
|
|
|
|
|
(use-package! esh-help
|
|
|
|
:after eshell
|
|
|
|
:config (setup-esh-help-eldoc))
|
2020-04-14 15:33:19 -04:00
|
|
|
|
|
|
|
|
2020-05-15 22:54:50 -04:00
|
|
|
(use-package! eshell-did-you-mean
|
|
|
|
:after esh-mode ; Specifically esh-mode, not eshell
|
|
|
|
:config
|
|
|
|
(eshell-did-you-mean-setup)
|
|
|
|
;; HACK There is a known issue with `eshell-did-you-mean' where it does not
|
|
|
|
;; work on first invocation, so we invoke it once manually by setting the
|
|
|
|
;; last command and then calling the output filter.
|
|
|
|
(setq eshell-last-command-name "catt")
|
|
|
|
(eshell-did-you-mean-output-filter "catt: command not found"))
|
|
|
|
|
|
|
|
|
2020-11-18 16:18:44 -05:00
|
|
|
(use-package eshell-syntax-highlighting
|
|
|
|
:hook (eshell-mode . eshell-syntax-highlighting-mode))
|
|
|
|
|
|
|
|
|
2020-04-14 15:33:19 -04:00
|
|
|
(use-package! fish-completion
|
2020-05-15 22:53:17 -04:00
|
|
|
:unless IS-WINDOWS
|
2020-04-14 15:33:19 -04:00
|
|
|
:hook (eshell-mode . fish-completion-mode)
|
|
|
|
:init (setq fish-completion-fallback-on-bash-p t)
|
|
|
|
:config
|
2020-05-15 01:44:53 -04:00
|
|
|
;; HACK Even with `fish-completion-fallback-on-bash-p' non-nil,
|
|
|
|
;; `fish-completion--list-completions-with-desc' will throw an error if
|
|
|
|
;; fish isn't installed (and so, will fail to fall back to bash), so we
|
|
|
|
;; advise it to fail silently.
|
2020-04-14 15:33:19 -04:00
|
|
|
(defadvice! +eshell--fallback-to-bash-a (&rest _)
|
2020-05-11 05:32:51 -04:00
|
|
|
:before-until #'fish-completion--list-completions-with-desc
|
|
|
|
(unless (executable-find "fish") "")))
|