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:
parent
15921306ce
commit
7f79eb4579
6 changed files with 284 additions and 170 deletions
14
modules/emacs/eshell/autoload/commands.el
Normal file
14
modules/emacs/eshell/autoload/commands.el
Normal 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))
|
|
@ -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))))))
|
||||||
|
|
||||||
|
|
|
@ -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."
|
||||||
|
|
31
modules/emacs/eshell/autoload/prompts.el
Normal file
31
modules/emacs/eshell/autoload/prompts.el
Normal 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))
|
||||||
|
" "))
|
16
modules/emacs/eshell/autoload/settings.el
Normal file
16
modules/emacs/eshell/autoload/settings.el
Normal 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)))))
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue