2018-05-27 12:05:15 +02:00
|
|
|
;;; emacs/eshell/autoload/eshell.el -*- lexical-binding: t; -*-
|
2017-02-19 18:53:38 -05:00
|
|
|
|
2018-05-11 20:17:00 +02:00
|
|
|
;;;###autoload
|
2018-06-17 02:05:33 +02:00
|
|
|
(defface +eshell-prompt-pwd '((t :inherit font-lock-constant-face))
|
2018-05-11 20:17:00 +02:00
|
|
|
"TODO"
|
|
|
|
:group 'eshell)
|
2018-03-24 07:36:59 -04:00
|
|
|
|
2018-05-11 20:17:00 +02:00
|
|
|
;;;###autoload
|
2018-06-17 02:05:33 +02:00
|
|
|
(defface +eshell-prompt-git-branch '((t :inherit font-lock-builtin-face))
|
2018-05-11 20:17:00 +02:00
|
|
|
"TODO"
|
|
|
|
:group 'eshell)
|
2018-03-24 07:36:59 -04:00
|
|
|
|
|
|
|
|
|
|
|
(defvar +eshell-buffers (make-ring 25)
|
2017-09-27 12:42:24 +02:00
|
|
|
"List of open eshell buffers.")
|
|
|
|
|
2018-01-07 15:25:35 -05:00
|
|
|
(defvar +eshell-buffer-name "*doom eshell*"
|
2017-09-27 12:42:24 +02:00
|
|
|
"The name to use for custom eshell buffers. This only affects `+eshell/open',
|
|
|
|
`+eshell/open-popup' and `+eshell/open-workspace'.")
|
2017-02-19 18:53:38 -05:00
|
|
|
|
2018-03-24 07:36:59 -04:00
|
|
|
(defvar +eshell-last-buffer nil
|
|
|
|
"TODO")
|
|
|
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
;; Library
|
|
|
|
;;
|
|
|
|
|
2018-03-24 17:51:55 -04:00
|
|
|
(defun +eshell--add-buffer (buf)
|
|
|
|
(ring-remove+insert+extend +eshell-buffers buf))
|
|
|
|
|
|
|
|
(defun +eshell--remove-buffer (buf)
|
|
|
|
(when-let* ((idx (ring-member +eshell-buffers buf)))
|
2018-05-18 01:22:49 +02:00
|
|
|
(ring-remove +eshell-buffers idx)
|
|
|
|
t))
|
2018-03-24 17:51:55 -04:00
|
|
|
|
2018-03-24 07:36:59 -04:00
|
|
|
(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))
|
|
|
|
"")))
|
|
|
|
|
2018-03-24 23:19:14 -04:00
|
|
|
(defun +eshell--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)))
|
|
|
|
return buf))
|
2018-03-24 07:36:59 -04:00
|
|
|
(generate-new-buffer +eshell-buffer-name)))
|
|
|
|
|
2018-05-18 01:22:49 +02:00
|
|
|
(defun +eshell--set-window (window &optional flag)
|
|
|
|
(when window
|
|
|
|
(set-window-parameter window 'no-other-window flag)
|
|
|
|
(set-window-parameter window 'visible flag)))
|
|
|
|
|
2018-03-24 17:51:55 -04:00
|
|
|
;;;###autoload
|
|
|
|
(defun +eshell-prompt ()
|
|
|
|
"Generate the prompt string for eshell. Use for `eshell-prompt-function'."
|
2018-06-16 16:51:43 +02:00
|
|
|
(concat (if (bobp) "" "\n")
|
|
|
|
(propertize (abbreviate-file-name (shrink-path-file (eshell/pwd)))
|
|
|
|
'face '+eshell-prompt-pwd)
|
2018-06-17 02:05:33 +02:00
|
|
|
(propertize (+eshell--current-git-branch)
|
|
|
|
'face '+eshell-prompt-git-branch)
|
|
|
|
" λ "))
|
2018-03-24 17:51:55 -04:00
|
|
|
|
2017-09-27 14:48:05 +02:00
|
|
|
|
2018-03-24 07:36:59 -04:00
|
|
|
;;
|
|
|
|
;; Commands
|
|
|
|
;;
|
2017-09-27 14:48:05 +02:00
|
|
|
|
2017-02-19 18:53:38 -05:00
|
|
|
;;;###autoload
|
2017-09-27 14:48:05 +02:00
|
|
|
(defun +eshell/open (&optional command)
|
2017-02-19 18:53:38 -05:00
|
|
|
"Open eshell in the current buffer."
|
|
|
|
(interactive)
|
2018-03-24 23:19:14 -04:00
|
|
|
(let ((buf (+eshell--buffer (eq major-mode 'eshell-mode))))
|
2017-02-19 18:53:38 -05:00
|
|
|
(with-current-buffer buf
|
|
|
|
(unless (eq major-mode 'eshell-mode) (eshell-mode)))
|
2018-06-16 21:04:20 +02:00
|
|
|
(switch-to-buffer buf)
|
|
|
|
(+eshell--set-window (get-buffer-window buf) t)
|
2017-09-27 14:48:05 +02:00
|
|
|
(when command
|
|
|
|
(+eshell-run-command command))))
|
2017-02-19 18:53:38 -05:00
|
|
|
|
|
|
|
;;;###autoload
|
2017-09-27 14:48:05 +02:00
|
|
|
(defun +eshell/open-popup (&optional command)
|
2017-02-19 18:53:38 -05:00
|
|
|
"Open eshell in a popup window."
|
|
|
|
(interactive)
|
2018-03-24 23:19:14 -04:00
|
|
|
(let ((buf (+eshell--buffer)))
|
2017-02-19 18:53:38 -05:00
|
|
|
(with-current-buffer buf
|
|
|
|
(unless (eq major-mode 'eshell-mode) (eshell-mode)))
|
2018-01-06 03:27:23 -05:00
|
|
|
(pop-to-buffer buf)
|
2018-05-18 01:22:49 +02:00
|
|
|
(+eshell--set-window (get-buffer-window buf) t)
|
2017-09-27 14:48:05 +02:00
|
|
|
(when command
|
|
|
|
(+eshell-run-command command))))
|
2017-02-19 18:53:38 -05:00
|
|
|
|
|
|
|
;;;###autoload
|
2017-09-27 14:48:05 +02:00
|
|
|
(defun +eshell/open-workspace (&optional command)
|
2017-02-19 18:53:38 -05:00
|
|
|
"Open eshell in a separate workspace. Requires the (:feature workspaces)
|
|
|
|
module to be loaded."
|
|
|
|
(interactive)
|
2017-02-23 00:06:12 -05:00
|
|
|
(unless (featurep! :feature workspaces)
|
2017-02-19 18:53:38 -05:00
|
|
|
(user-error ":feature workspaces is required, but disabled"))
|
|
|
|
(unless (+workspace-get "eshell" t)
|
|
|
|
(+workspace/new "eshell"))
|
2018-03-24 07:36:59 -04:00
|
|
|
(if-let* ((buf (cl-find-if (lambda (buf) (eq 'eshell-mode (buffer-local-value 'major-mode buf)))
|
|
|
|
(doom-visible-windows)
|
|
|
|
:key #'window-buffer)))
|
2017-02-19 18:53:38 -05:00
|
|
|
(select-window (get-buffer-window buf))
|
2017-09-27 12:42:24 +02:00
|
|
|
(+eshell/open))
|
2017-09-27 14:48:05 +02:00
|
|
|
(when command
|
2018-03-24 07:36:59 -04:00
|
|
|
(+eshell-run-command command))
|
2018-05-18 01:22:49 +02:00
|
|
|
(+eshell--set-window (selected-window) t)
|
2018-03-24 07:36:59 -04:00
|
|
|
(doom/workspace-display))
|
2017-09-27 14:48:05 +02:00
|
|
|
|
|
|
|
(defun +eshell-run-command (command)
|
|
|
|
(unless (cl-remove-if-not #'buffer-live-p +eshell-buffers)
|
|
|
|
(user-error "No living eshell buffers available"))
|
|
|
|
(with-current-buffer (car +eshell-buffers)
|
|
|
|
(goto-char eshell-last-output-end)
|
|
|
|
(when (bound-and-true-p evil-mode)
|
|
|
|
(call-interactively #'evil-append-line))
|
|
|
|
(insert command)
|
|
|
|
(eshell-send-input nil t)))
|
2017-02-19 18:53:38 -05:00
|
|
|
|
2018-06-16 16:37:43 +02:00
|
|
|
;;;###autoload
|
|
|
|
(defun +eshell/pcomplete ()
|
|
|
|
"Use pcomplete with completion-in-region backend instead of popup window at
|
|
|
|
bottom. This ties pcomplete into ivy or helm, if they are enabled."
|
|
|
|
(interactive)
|
|
|
|
(require 'pcomplete)
|
|
|
|
(pcomplete-std-complete))
|
|
|
|
|
2017-09-27 12:42:24 +02:00
|
|
|
|
2018-03-24 07:36:59 -04:00
|
|
|
;;
|
|
|
|
;; Hooks
|
|
|
|
;;
|
2017-09-27 12:42:24 +02:00
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
(defun +eshell|init ()
|
|
|
|
"Keep track of eshell buffers."
|
2018-03-24 07:36:59 -04:00
|
|
|
(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)))
|
2017-09-27 12:42:24 +02:00
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
(defun +eshell|cleanup ()
|
|
|
|
"Close window (or workspace) on quit."
|
2018-05-18 01:22:49 +02:00
|
|
|
(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))))))
|
2017-09-27 12:42:24 +02:00
|
|
|
|
|
|
|
|
2018-03-24 07:36:59 -04:00
|
|
|
;;
|
|
|
|
;; Keybinds
|
|
|
|
;;
|
2017-09-27 12:42:24 +02:00
|
|
|
|
2017-07-21 16:50:44 +02:00
|
|
|
;;;###autoload
|
|
|
|
(defun +eshell/quit-or-delete-char (arg)
|
2018-03-24 07:36:59 -04:00
|
|
|
"Delete a character (ahead of the cursor) or quit eshell if there's nothing to
|
|
|
|
delete."
|
2017-07-21 16:50:44 +02:00
|
|
|
(interactive "p")
|
2017-07-22 00:12:04 +02:00
|
|
|
(if (and (eolp) (looking-back eshell-prompt-regexp nil))
|
2017-07-21 16:50:44 +02:00
|
|
|
(eshell-life-is-too-much)
|
2017-07-22 00:12:04 +02:00
|
|
|
(delete-char arg)))
|
2017-07-21 16:50:44 +02:00
|
|
|
|
2018-05-26 21:22:38 +02:00
|
|
|
(defsubst +eshell--bury-buffer ()
|
|
|
|
(unless (switch-to-prev-buffer nil 'bury)
|
|
|
|
(switch-to-buffer (doom-fallback-buffer))))
|
|
|
|
|
2017-02-19 18:53:38 -05:00
|
|
|
;;;###autoload
|
2018-03-24 17:51:55 -04:00
|
|
|
(defun +eshell/split-below ()
|
|
|
|
"Create a new eshell window below the current one."
|
2017-02-19 18:53:38 -05:00
|
|
|
(interactive)
|
|
|
|
(select-window (split-window-vertically))
|
2018-05-26 21:22:38 +02:00
|
|
|
(+eshell--bury-buffer))
|
2017-02-19 18:53:38 -05:00
|
|
|
|
|
|
|
;;;###autoload
|
2018-03-24 17:51:55 -04:00
|
|
|
(defun +eshell/split-right ()
|
|
|
|
"Create a new eshell window to the right of the current one."
|
2017-02-19 18:53:38 -05:00
|
|
|
(interactive)
|
|
|
|
(select-window (split-window-horizontally))
|
2018-05-26 21:22:38 +02:00
|
|
|
(+eshell--bury-buffer))
|
2017-02-19 18:53:38 -05:00
|
|
|
|
2018-03-24 07:36:59 -04:00
|
|
|
;; `make-ring'
|
|
|
|
;; `ring-ref'
|
|
|
|
;; `ring-empty-p'
|
|
|
|
;; `ring-remove'
|
|
|
|
|
2017-02-19 18:53:38 -05:00
|
|
|
;;;###autoload
|
2018-03-24 07:36:59 -04:00
|
|
|
(defun +eshell/next ()
|
|
|
|
"Switch to the next eshell buffer."
|
|
|
|
(interactive)
|
|
|
|
(when (ring-empty-p +eshell-buffers)
|
|
|
|
(user-error "No eshell buffers are available"))
|
|
|
|
(switch-to-buffer (ring-next +eshell-buffers (current-buffer))))
|
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
(defun +eshell/previous ()
|
|
|
|
"Switch to the previous eshell buffer."
|
|
|
|
(interactive)
|
|
|
|
(when (ring-empty-p +eshell-buffers)
|
|
|
|
(user-error "No eshell buffers are available"))
|
|
|
|
(switch-to-buffer (ring-previous +eshell-buffers (current-buffer))))
|
2017-02-19 18:53:38 -05:00
|
|
|
|
2018-03-24 07:36:59 -04:00
|
|
|
;;;###autoload
|
|
|
|
(defun +eshell/open-last ()
|
|
|
|
"Switch to the last eshell buffer that was open (and is still alive)."
|
|
|
|
(interactive)
|
|
|
|
(unless (buffer-live-p +eshell-last-buffer)
|
|
|
|
(setq +eshell-last-buffer nil)
|
|
|
|
(user-error "No last eshell buffer to jump to"))
|
|
|
|
(switch-to-buffer +eshell-last-buffer))
|
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
(defun +eshell/switch (buffer)
|
|
|
|
"Interactively switch to another eshell buffer."
|
|
|
|
(interactive
|
2018-06-17 02:05:33 +02:00
|
|
|
(let ((buffers (doom-buffers-in-mode
|
|
|
|
'eshell-mode (delq (current-buffer) (ring-elements +eshell-buffers)))))
|
2018-03-28 19:07:48 -04:00
|
|
|
(if (not buffers)
|
2018-03-28 17:32:35 -04:00
|
|
|
(user-error "No eshell buffers are available")
|
|
|
|
(list (completing-read
|
|
|
|
"Eshell buffers"
|
|
|
|
(mapcar #'buffer-name buffers)
|
|
|
|
#'get-buffer
|
|
|
|
'require-match
|
2018-03-28 19:07:48 -04:00
|
|
|
nil nil
|
|
|
|
(when (eq major-mode 'eshell-mode)
|
|
|
|
(buffer-name (current-buffer))))))))
|
|
|
|
(if-let* ((window (get-buffer-window buffer)))
|
|
|
|
(select-window window)
|
|
|
|
(switch-to-buffer buffer)))
|