Major redesign of emacs/eshell

+ :sh can now be fed commands to run immediately, e.g. :sh cd %:P to
  start from the current project root.
+ Eshell will spawn a new eshell on every split. This can be controlled
  via `+eshell-enable-new-shell-on-split'
+ Eshell can be configured to kill the window when you kill the eshell
  process. This is disabled by default. See
  `+eshell-kill-window-on-exit'. Some commands ignore this, like the
  quit-and-close command (I alias this to "q").
+ eshell-directory-name has been moved to doom-etc-dir/eshell. It will
  seem like eshell has forgotten all your history, but you can move
  ~/.eshell (or ~/.doom.d/eshell) to ~/.emacs.d/.local/etc/eshell and
  you'll be fine.
+ eshell-aliases-file has been moved to ~/.doom.d/eshell_aliases by
  default.
+ Automatic writing to eshell-aliases-file has been disabled. No shell
  so aggressively persists aliases. You may maintain it yourself, or use
  the new +eshell-aliases variable to customize eshell from Doom.
+ C-s now invokes a history search with ivy/helm.
+ C-c s and C-c v split horizontally and vertically. Inspired by tmux.
+ C-c x kill the current eshell and its window. Inspired by tmux.j
+ New set-eshell-alias! autodef for defining your own aliases.
+ +eshell/open-workspace has been replaced with +eshell/open-fullscreen.
+ Added the "cd-to-project" command. I suggest you alias it.
This commit is contained in:
Henrik Lissner 2018-06-18 22:31:27 +02:00
parent 15921306ce
commit 7f79eb4579
No known key found for this signature in database
GPG key ID: 5F6C0EA160557395
6 changed files with 284 additions and 170 deletions

View file

@ -0,0 +1,14 @@
;;; emacs/eshell/autoload/commands.el -*- lexical-binding: t; -*-
;;;###autoload
(defun eshell/cd-to-project ()
"Change to the project root of the current directory."
(let* ((default-directory (eshell/pwd))
(project-root (doom-project-root 'nocache)))
(eshell/cd project-root)))
;;;###autoload
(defun eshell/quit-and-close (&rest _)
"Quit the current eshell buffer and close the window it's in."
(setq-local +eshell-kill-window-on-exit t)
(throw 'eshell-terminal t))

View file

@ -1,29 +1,17 @@
;;; emacs/eshell/autoload/eshell.el -*- lexical-binding: t; -*- ;;; emacs/eshell/autoload/eshell.el -*- lexical-binding: t; -*-
;;;###autoload (defvar eshell-buffer-name "*doom eshell*")
(defface +eshell-prompt-pwd '((t :inherit font-lock-constant-face))
"TODO"
:group 'eshell)
;;;###autoload
(defface +eshell-prompt-git-branch '((t :inherit font-lock-builtin-face))
"TODO"
:group 'eshell)
(defvar +eshell-buffers (make-ring 25) (defvar +eshell-buffers (make-ring 25)
"List of open eshell buffers.") "List of open eshell buffers.")
(defvar +eshell-buffer-name "*doom eshell*"
"The name to use for custom eshell buffers. This only affects `+eshell/open',
`+eshell/open-popup' and `+eshell/open-workspace'.")
(defvar +eshell-last-buffer nil (defvar +eshell--last-buffer nil)
"TODO") (defvar-local +eshell--wconf nil)
;; ;;
;; Library ;; Helpers
;; ;;
(defun +eshell--add-buffer (buf) (defun +eshell--add-buffer (buf)
@ -34,37 +22,55 @@
(ring-remove +eshell-buffers idx) (ring-remove +eshell-buffers idx)
t)) t))
(defun +eshell--current-git-branch () (defun +eshell--bury-buffer ()
(let ((branch (car (cl-loop for match in (split-string (shell-command-to-string "git branch") "\n") (unless (switch-to-prev-buffer nil 'bury)
if (string-match-p "^\*" match) (switch-to-buffer (doom-fallback-buffer))
collect match)))) (when +eshell-enable-new-shell-on-split
(if (not (eq branch nil)) (+eshell/open t))))
(format " [%s]" (substring branch 2))
"")))
(defun +eshell--buffer (&optional new-p) (defun +eshell--setup-window (window &optional flag)
(or (unless new-p (when (window-live-p window)
(cl-loop for buf in (ring-elements +eshell-buffers)
if (and (buffer-live-p buf)
(not (get-buffer-window buf)))
return buf))
(generate-new-buffer +eshell-buffer-name)))
(defun +eshell--set-window (window &optional flag)
(when window
(set-window-parameter window 'no-other-window flag) (set-window-parameter window 'no-other-window flag)
(set-window-parameter window 'visible flag))) (set-window-parameter window 'visible flag)))
(defun +eshell--unused-buffer (&optional new-p)
(or (unless new-p
(cl-loop for buf in (ring-elements +eshell-buffers)
if (and (buffer-live-p buf)
(not (get-buffer-window buf t)))
return buf))
(generate-new-buffer eshell-buffer-name)))
;;;###autoload ;;;###autoload
(defun +eshell-prompt () (defun +eshell-last-buffer (&optional noerror)
"Generate the prompt string for eshell. Use for `eshell-prompt-function'." "Return the last opened eshell buffer."
(concat (if (bobp) "" "\n") (let ((buffer (cl-find-if #'buffer-live-p (ring-elements +eshell-buffers))))
(propertize (abbreviate-file-name (shrink-path-file (eshell/pwd))) (cond ((buffer-live-p buffer) buffer)
'face '+eshell-prompt-pwd) (noerror nil)
(propertize (+eshell--current-git-branch) ((user-error "No live eshell buffers remaining")))))
'face '+eshell-prompt-git-branch)
(propertize " λ" 'face (if (zerop eshell-last-command-status) 'success 'error)) ;;;###autoload
" ")) (defun +eshell-buffers ()
"TODO"
(ring-elements +eshell-buffers))
;;;###autoload
(defun +eshell-run-command (command &optional buffer)
"TODO"
(let ((buffer
(or buffer
(if (eq major-mode 'eshell-mode)
(current-buffer)
(cl-find-if #'buffer-live-p (ring-elements +eshell-buffers))))))
(unless buffer
(user-error "No living eshell buffers available"))
(unless (buffer-live-p buffer)
(user-error "Cannot operate on a dead buffer"))
(with-current-buffer buffer
(goto-char eshell-last-output-end)
(goto-char (line-end-position))
(insert command)
(eshell-send-input nil t))))
;; ;;
@ -75,57 +81,64 @@
(defun +eshell/open (arg &optional command) (defun +eshell/open (arg &optional command)
"Open eshell in the current buffer." "Open eshell in the current buffer."
(interactive "P") (interactive "P")
(when (eq major-mode 'eshell-mode)
(user-error "Already in an eshell buffer"))
(let* ((default-directory (if arg default-directory (doom-project-root))) (let* ((default-directory (if arg default-directory (doom-project-root)))
(buf (+eshell--buffer (eq major-mode 'eshell-mode)))) (buf (+eshell--unused-buffer)))
(with-current-buffer buf (with-current-buffer (switch-to-buffer buf)
(unless (eq major-mode 'eshell-mode) (eshell-mode))) (eshell-mode)
(switch-to-buffer buf) (if command (+eshell-run-command command buf)))
(+eshell--set-window (get-buffer-window buf) t) buf))
(when command
(+eshell-run-command command))))
;;;###autoload ;;;###autoload
(defun +eshell/open-popup (arg &optional command) (defun +eshell/open-popup (arg &optional command)
"Open eshell in a popup window." "Open eshell in a popup window."
(interactive "P") (interactive "P")
(let* ((default-directory (if arg default-directory (doom-project-root))) (let* ((default-directory (if arg default-directory (doom-project-root)))
(buf (+eshell--buffer))) (buf (+eshell--unused-buffer)))
(with-current-buffer buf (with-current-buffer (pop-to-buffer buf)
(unless (eq major-mode 'eshell-mode) (eshell-mode))) (eshell-mode)
(pop-to-buffer buf) (if command (+eshell-run-command command buf)))
(+eshell--set-window (get-buffer-window buf) t) buf))
(when command
(+eshell-run-command command))))
;;;###autoload ;;;###autoload
(defun +eshell/open-workspace (arg &optional command) (defun +eshell/open-fullscreen (arg &optional command)
"Open eshell in a separate workspace. Requires the (:feature workspaces) "Open eshell in a separate workspace. Requires the (:feature workspaces)
module to be loaded." module to be loaded."
(interactive "P") (interactive "P")
(let ((default-directory (if arg default-directory (doom-project-root)))) (let ((default-directory (if arg default-directory (doom-project-root))))
(unless (featurep! :feature workspaces) (setq +eshell--wconf (current-window-configuration))
(user-error ":feature workspaces is required, but disabled")) (delete-other-windows)
(unless (+workspace-get "eshell" t) (with-current-buffer (+eshell/open arg command)
(+workspace/new "eshell")) (setq-local +eshell--wconf (current-window-configuration)))))
(if-let* ((buf (cl-find-if (lambda (buf) (eq 'eshell-mode (buffer-local-value 'major-mode buf)))
(doom-visible-windows)
:key #'window-buffer)))
(select-window (get-buffer-window buf))
(+eshell/open arg))
(when command
(+eshell-run-command command))
(+eshell--set-window (selected-window) t)
(doom/workspace-display)))
(defun +eshell-run-command (command)
(unless (cl-remove-if-not #'buffer-live-p +eshell-buffers) ;;
(user-error "No living eshell buffers available")) ;; Keybinds
(with-current-buffer (car +eshell-buffers) ;;
(goto-char eshell-last-output-end)
(when (bound-and-true-p evil-mode) ;;;###autoload
(call-interactively #'evil-append-line)) (defun +eshell/search-history ()
(insert command) "Search the eshell command history with helm, ivy or `eshell-list-history'."
(eshell-send-input nil t))) (interactive)
(cond ((featurep! :completion ivy)
(require 'em-hist)
(let* ((ivy-completion-beg (eshell-bol))
(ivy-completion-end (point-at-eol))
(input (buffer-substring-no-properties
ivy-completion-beg
ivy-completion-end)))
;; Better than `counsel-esh-history' because that doesn't
;; pre-populate the initial input or selection.
(ivy-read "Command: "
(delete-dups
(when (> (ring-size eshell-history-ring) 0)
(ring-elements eshell-history-ring)))
:initial-input input
:action #'ivy-completion-in-region-action)))
((featurep! :completion helm)
(helm-eshell-history))
((eshell-list-history))))
;;;###autoload ;;;###autoload
(defun +eshell/pcomplete () (defun +eshell/pcomplete ()
@ -135,41 +148,6 @@ bottom. This ties pcomplete into ivy or helm, if they are enabled."
(require 'pcomplete) (require 'pcomplete)
(pcomplete-std-complete)) (pcomplete-std-complete))
;;
;; Hooks
;;
;;;###autoload
(defun +eshell|init ()
"Keep track of eshell buffers."
(let ((buf (current-buffer)))
(dolist (buf (ring-elements +eshell-buffers))
(unless (buffer-live-p buf)
(+eshell--remove-buffer buf)))
(+eshell--add-buffer buf)
(setq +eshell-last-buffer buf)))
;;;###autoload
(defun +eshell|cleanup ()
"Close window (or workspace) on quit."
(let ((buf (current-buffer)))
(when (+eshell--remove-buffer buf)
(+eshell--set-window (get-buffer-window buf) nil)
(cond ((and (featurep! :feature workspaces)
(string= "eshell" (+workspace-current-name)))
(+workspace/delete "eshell"))
((one-window-p)
(unless (doom-real-buffer-p (progn (previous-buffer) (current-buffer)))
(switch-to-buffer (doom-fallback-buffer))))
((and (fboundp '+popup-window-p) (+popup-window-p))
(delete-window))))))
;;
;; Keybinds
;;
;;;###autoload ;;;###autoload
(defun +eshell/quit-or-delete-char (arg) (defun +eshell/quit-or-delete-char (arg)
"Delete a character (ahead of the cursor) or quit eshell if there's nothing to "Delete a character (ahead of the cursor) or quit eshell if there's nothing to
@ -179,10 +157,6 @@ delete."
(eshell-life-is-too-much) (eshell-life-is-too-much)
(delete-char arg))) (delete-char arg)))
(defsubst +eshell--bury-buffer ()
(unless (switch-to-prev-buffer nil 'bury)
(switch-to-buffer (doom-fallback-buffer))))
;;;###autoload ;;;###autoload
(defun +eshell/split-below () (defun +eshell/split-below ()
"Create a new eshell window below the current one." "Create a new eshell window below the current one."
@ -197,13 +171,8 @@ delete."
(select-window (split-window-horizontally)) (select-window (split-window-horizontally))
(+eshell--bury-buffer)) (+eshell--bury-buffer))
;; `make-ring'
;; `ring-ref'
;; `ring-empty-p'
;; `ring-remove'
;;;###autoload ;;;###autoload
(defun +eshell/next () (defun +eshell/switch-to-next ()
"Switch to the next eshell buffer." "Switch to the next eshell buffer."
(interactive) (interactive)
(when (ring-empty-p +eshell-buffers) (when (ring-empty-p +eshell-buffers)
@ -211,7 +180,7 @@ delete."
(switch-to-buffer (ring-next +eshell-buffers (current-buffer)))) (switch-to-buffer (ring-next +eshell-buffers (current-buffer))))
;;;###autoload ;;;###autoload
(defun +eshell/previous () (defun +eshell/switch-to-previous ()
"Switch to the previous eshell buffer." "Switch to the previous eshell buffer."
(interactive) (interactive)
(when (ring-empty-p +eshell-buffers) (when (ring-empty-p +eshell-buffers)
@ -219,30 +188,72 @@ delete."
(switch-to-buffer (ring-previous +eshell-buffers (current-buffer)))) (switch-to-buffer (ring-previous +eshell-buffers (current-buffer))))
;;;###autoload ;;;###autoload
(defun +eshell/open-last () (defun +eshell/switch-to-last ()
"Switch to the last eshell buffer that was open (and is still alive)." "Switch to the last eshell buffer that was open (and is still alive)."
(interactive) (interactive)
(unless (buffer-live-p +eshell-last-buffer) (unless (buffer-live-p +eshell--last-buffer)
(setq +eshell-last-buffer nil) (setq +eshell--last-buffer nil)
(user-error "No last eshell buffer to jump to")) (user-error "No last eshell buffer to jump to"))
(switch-to-buffer +eshell-last-buffer)) (switch-to-buffer +eshell--last-buffer))
;;;###autoload ;;;###autoload
(defun +eshell/switch (buffer) (defun +eshell/switch-to (buffer)
"Interactively switch to another eshell buffer." "Interactively switch to another eshell buffer."
(interactive (interactive
(let ((buffers (doom-buffers-in-mode (let ((buffers (doom-buffers-in-mode
'eshell-mode (delq (current-buffer) (ring-elements +eshell-buffers))))) 'eshell-mode (delq (current-buffer) (ring-elements +eshell-buffers)))))
(if (not buffers) (if (not buffers)
(user-error "No eshell buffers are available") (user-error "No eshell buffers are available")
(list (completing-read (list
"Eshell buffers" (completing-read "Eshell buffers"
(mapcar #'buffer-name buffers) (mapcar #'buffer-name buffers)
#'get-buffer #'get-buffer
'require-match 'require-match
nil nil nil nil
(when (eq major-mode 'eshell-mode) (when (eq major-mode 'eshell-mode)
(buffer-name (current-buffer)))))))) (buffer-name (current-buffer))))))))
(if-let* ((window (get-buffer-window buffer))) (if-let* ((window (get-buffer-window buffer)))
(select-window window) (select-window window)
(switch-to-buffer buffer))) (switch-to-buffer buffer)))
;;;###autoload
(defun +eshell/kill-and-close ()
"Kill the current eshell buffer and close its window."
(interactive)
(unless (eq major-mode 'eshell-mode)
(user-error "Not in an eshell buffer"))
(let ((+eshell-kill-window-on-exit t))
(kill-this-buffer)))
;;
;; Hooks
;;
;;;###autoload
(defun +eshell|init ()
"Initialize and track this eshell buffer in `+eshell-buffers'."
(let ((buf (current-buffer)))
(dolist (buf (ring-elements +eshell-buffers))
(unless (buffer-live-p buf)
(+eshell--remove-buffer buf)))
(+eshell--setup-window (get-buffer-window buf))
(+eshell--add-buffer buf)
(setq +eshell--last-buffer buf)))
;;;###autoload
(defun +eshell|cleanup ()
"Close window (or workspace) on quit."
(let ((buf (current-buffer)))
(when (+eshell--remove-buffer buf)
(+eshell--setup-window (get-buffer-window buf) nil)
(cond (+eshell--wconf
(set-window-configuration +eshell--wconf))
((one-window-p)
(let ((prev (save-window-excursion (previous-buffer))))
(unless (and prev (doom-real-buffer-p prev))
(switch-to-buffer (doom-fallback-buffer)))))
((or (and (fboundp '+popup-window-p) (+popup-window-p))
+eshell-kill-window-on-exit)
(delete-window))))))

View file

@ -1,6 +1,27 @@
;;; emacs/eshell/autoload/evil.el -*- lexical-binding: t; -*- ;;; emacs/eshell/autoload/evil.el -*- lexical-binding: t; -*-
;;;###if (featurep! :feature evil) ;;;###if (featurep! :feature evil)
;;;###autoload
(defun +eshell|init-evil ()
"Replace `evil-collection-eshell-next-prompt-on-insert' with
`+eshell|goto-prompt-on-insert', which ensures the point is on the prompt when
changing to insert mode."
(dolist (hook '(evil-replace-state-entry-hook evil-insert-state-entry-hook))
(remove-hook hook 'evil-collection-eshell-next-prompt-on-insert t)
(add-hook hook '+eshell|goto-prompt-on-insert nil t)))
;;;###autoload (autoload '+eshell:run "emacs/eshell/autoload/evil" nil t)
(evil-define-command +eshell:run (command bang)
"TODO"
(interactive "<fsh><!>")
(let ((buffer (+eshell-last-buffer))
(command (+evil*resolve-vim-path command)))
(cond (buffer
(select-window (get-buffer-window buffer))
(+eshell-run-command command buffer))
(bang (+eshell/open nil command))
((+eshell/open-popup nil command)))))
;;;###autoload ;;;###autoload
(defun +eshell|goto-prompt-on-insert () (defun +eshell|goto-prompt-on-insert ()
"Move cursor to the prompt when switching to insert mode (if point isn't "Move cursor to the prompt when switching to insert mode (if point isn't
@ -19,14 +40,6 @@ already there)."
(goto-char (point-max)) (goto-char (point-max))
(evil-append 1)) (evil-append 1))
;;;###autoload (autoload '+eshell:run "emacs/eshell/autoload/evil" nil t)
(evil-define-command +eshell:run (command bang)
"TODO"
(interactive "<fsh><!>")
(if bang
(+eshell/open nil command)
(+eshell/open-popup nil command)))
;;;###autoload (autoload '+eshell/evil-change "emacs/eshell/autoload/evil" nil t) ;;;###autoload (autoload '+eshell/evil-change "emacs/eshell/autoload/evil" nil t)
(evil-define-operator +eshell/evil-change (beg end type register yank-handler delete-func) (evil-define-operator +eshell/evil-change (beg end type register yank-handler delete-func)
"Like `evil-change' but will not delete/copy the prompt." "Like `evil-change' but will not delete/copy the prompt."

View file

@ -0,0 +1,31 @@
;;; emacs/eshell/autoload/prompts.el -*- lexical-binding: t; -*-
;;;###autoload
(defface +eshell-prompt-pwd '((t :inherit font-lock-constant-face))
"TODO"
:group 'eshell)
;;;###autoload
(defface +eshell-prompt-git-branch '((t :inherit font-lock-builtin-face))
"TODO"
:group 'eshell)
(defun +eshell--current-git-branch ()
(let ((branch (car (cl-loop for match in (split-string (shell-command-to-string "git branch") "\n")
if (string-match-p "^\*" match)
collect match))))
(if (not (eq branch nil))
(format " [%s]" (substring branch 2))
"")))
;;;###autoload
(defun +eshell-default-prompt ()
"Generate the prompt string for eshell. Use for `eshell-prompt-function'."
(concat (if (bobp) "" "\n")
(propertize (abbreviate-file-name (shrink-path-file (eshell/pwd)))
'face '+eshell-prompt-pwd)
(propertize (+eshell--current-git-branch)
'face '+eshell-prompt-git-branch)
(propertize " λ" 'face (if (zerop eshell-last-command-status) 'success 'error))
" "))

View file

@ -0,0 +1,16 @@
;;; emacs/eshell/autoload/settings.el -*- lexical-binding: t; -*-
;;;###autodef
(defun set-eshell-alias! (&rest aliases)
"Define aliases for eshell."
(or (cl-evenp (length aliases))
(signal 'wrong-number-of-arguments (list 'even (length aliases))))
(after! eshell
(while aliases
(map-put +eshell-aliases (pop aliases) (list (pop aliases))))
(when (boundp 'eshell-command-aliases-list)
(if +eshell--default-aliases
(setq eshell-command-aliases-list
(append +eshell--default-aliases
+eshell-aliases))
(setq eshell-command-aliases-list +eshell-aliases)))))

View file

@ -6,11 +6,35 @@
;; + `+eshell/open-workspace': open in separate tab (requires :feature ;; + `+eshell/open-workspace': open in separate tab (requires :feature
;; workspaces) ;; workspaces)
(defvar eshell-directory-name (defvar eshell-directory-name (concat doom-etc-dir "eshell"))
(let ((dir (expand-file-name "eshell" doom-private-dir)))
(if (file-directory-p dir) (defvar eshell-aliases-file
dir (expand-file-name "eshell_aliases" doom-private-dir)
"~/.eshell"))) "The path to your eshell aliases file, where you may declare alises. This is
here as an alternative to `set-eshell-alias!'.")
;;
(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
("z" "cd =$1") ; built-in
("bd" "eshell-up $1") ; `eshell-up'
("rg" "rg --color=always")
("ag" "ag --color=always"))
"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.
You should use `det-eshell-alias!' to change this.")
(defvar +eshell--default-aliases nil)
;; ;;
@ -31,7 +55,7 @@
eshell-hist-ignoredups t eshell-hist-ignoredups t
;; em-prompt ;; em-prompt
eshell-prompt-regexp "^.* λ " eshell-prompt-regexp "^.* λ "
eshell-prompt-function #'+eshell-prompt eshell-prompt-function #'+eshell-default-prompt
;; em-glob ;; em-glob
eshell-glob-case-insensitive t eshell-glob-case-insensitive t
eshell-error-if-no-glob t) eshell-error-if-no-glob t)
@ -39,6 +63,10 @@
;; Consider eshell buffers real ;; Consider eshell buffers real
(add-hook 'eshell-mode-hook #'doom|mark-buffer-as-real) (add-hook 'eshell-mode-hook #'doom|mark-buffer-as-real)
;; Keep track of open eshell buffers
(add-hook 'eshell-mode-hook #'+eshell|init)
(add-hook 'eshell-exit-hook #'+eshell|cleanup)
;; UI enhancements ;; UI enhancements
(defun +eshell|replace-fringes-with-margins () (defun +eshell|replace-fringes-with-margins ()
"Remove eshell's fringes and give it a margin of 1." "Remove eshell's fringes and give it a margin of 1."
@ -47,28 +75,25 @@
(add-hook 'eshell-mode-hook #'+eshell|replace-fringes-with-margins) (add-hook 'eshell-mode-hook #'+eshell|replace-fringes-with-margins)
(add-hook 'eshell-mode-hook #'hide-mode-line-mode) (add-hook 'eshell-mode-hook #'hide-mode-line-mode)
;; Keep track of open eshell buffers ;; Don't auto-write our aliases! Let us manage our own `eshell-aliases-file'
(add-hook 'eshell-mode-hook #'+eshell|init) ;; or configure `+eshell-aliases' via elisp.
(add-hook 'eshell-exit-hook #'+eshell|cleanup) (advice-add #'eshell-write-aliases-list :override #'ignore)
(after! em-alias
;; Emulates popular shell utilities
(map-put eshell-command-aliases-list "z" '("cd =$1"))
(map-put eshell-command-aliases-list "bd" '("eshell-up $1")))
;; Visual commands require a proper terminal. Eshell can't handle that, so
;; it delegates these commands to a term buffer.
(after! em-term (after! em-term
;; Visual commands require a proper terminal. Eshell can't handle that, so
;; it delegates these commands to a term buffer.
(dolist (cmd '("tmux" "htop" "bash" "zsh" "fish" "vim" "nvim" "ncmpcpp")) (dolist (cmd '("tmux" "htop" "bash" "zsh" "fish" "vim" "nvim" "ncmpcpp"))
(cl-pushnew cmd eshell-visual-commands))) (add-to-list 'eshell-visual-commands cmd)))
(defun +eshell|init-evil () (defun +eshell|init-aliases ()
"Replace `evil-collection-eshell-next-prompt-on-insert' with (setq +eshell--default-aliases eshell-command-aliases-list
`+eshell|goto-prompt-on-insert'." eshell-command-aliases-list
(dolist (hook '(evil-replace-state-entry-hook evil-insert-state-entry-hook)) (append eshell-command-aliases-list
(remove-hook hook 'evil-collection-eshell-next-prompt-on-insert t) +eshell-aliases)))
(add-hook hook '+eshell|goto-prompt-on-insert nil t))) (add-hook 'eshell-alias-load-hook #'+eshell|init-aliases)
(add-hook 'eshell-mode-hook #'+eshell|init-evil)
(when (featurep! :feature evil +everywhere)
(add-hook 'eshell-mode-hook #'+eshell|init-evil))
(defun +eshell|init-keymap () (defun +eshell|init-keymap ()
"Setup eshell keybindings. This must be done in a hook because eshell-mode "Setup eshell keybindings. This must be done in a hook because eshell-mode
@ -90,6 +115,10 @@ redefines its keys every time `eshell-mode' is enabled."
"\C-p" #'eshell-previous-input "\C-p" #'eshell-previous-input
"\C-n" #'eshell-next-input)) "\C-n" #'eshell-next-input))
(define-key! eshell-mode-map (define-key! eshell-mode-map
(kbd "C-s") #'+eshell/search-history
(kbd "C-c s") #'+eshell/split-below
(kbd "C-c v") #'+eshell/split-right
(kbd "C-c x") #'+eshell/kill-and-close
[remap split-window-below] #'+eshell/split-below [remap split-window-below] #'+eshell/split-below
[remap split-window-right] #'+eshell/split-right [remap split-window-right] #'+eshell/split-right
[remap doom/backward-to-bol-or-indent] #'eshell-bol [remap doom/backward-to-bol-or-indent] #'eshell-bol