Move eshell, term & vterm modules to :term
This commit is contained in:
parent
42ba2a22b8
commit
8c65a63b1c
18 changed files with 41 additions and 30 deletions
18
modules/term/eshell/autoload/commands.el
Normal file
18
modules/term/eshell/autoload/commands.el
Normal file
|
@ -0,0 +1,18 @@
|
|||
;;; term/eshell/autoload/commands.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defun eshell/cd-to-project ()
|
||||
"Change to the project root of the current directory."
|
||||
(eshell/cd (doom-project-root (eshell/pwd))))
|
||||
|
||||
;;;###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))
|
||||
|
||||
;;;###autoload
|
||||
(defun eshell/mkdir-and-cd (dir)
|
||||
"Create a directory then cd into it."
|
||||
(make-directory dir t)
|
||||
(eshell/cd dir))
|
297
modules/term/eshell/autoload/eshell.el
Normal file
297
modules/term/eshell/autoload/eshell.el
Normal file
|
@ -0,0 +1,297 @@
|
|||
;;; term/eshell/autoload/eshell.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar eshell-buffer-name "*doom:eshell*")
|
||||
|
||||
(defvar +eshell-buffers (make-ring 25)
|
||||
"List of open eshell buffers.")
|
||||
|
||||
|
||||
(defvar +eshell--last-buffer nil)
|
||||
|
||||
|
||||
;;
|
||||
;; Helpers
|
||||
|
||||
(defun +eshell--add-buffer (buf)
|
||||
(ring-remove+insert+extend +eshell-buffers buf 'grow))
|
||||
|
||||
(defun +eshell--remove-buffer (buf)
|
||||
(when-let* ((idx (ring-member +eshell-buffers buf)))
|
||||
(ring-remove +eshell-buffers idx)
|
||||
t))
|
||||
|
||||
(defun +eshell--bury-buffer (&optional dedicated-p)
|
||||
(unless (switch-to-prev-buffer nil 'bury)
|
||||
(switch-to-buffer (doom-fallback-buffer)))
|
||||
(when (eq major-mode 'eshell-mode)
|
||||
(switch-to-buffer (doom-fallback-buffer)))
|
||||
(when +eshell-enable-new-shell-on-split
|
||||
(when-let* ((win (get-buffer-window (+eshell/open t))))
|
||||
(set-window-dedicated-p win dedicated-p))))
|
||||
|
||||
(defun +eshell--setup-window (window &optional flag)
|
||||
(when (window-live-p window)
|
||||
(set-window-parameter window 'no-other-window flag)
|
||||
(set-window-parameter window 'visible flag)))
|
||||
|
||||
(defun +eshell--unused-buffer (&optional new-p)
|
||||
(or (unless new-p
|
||||
(cl-loop for buf in (+eshell-buffers)
|
||||
if (and (buffer-live-p buf)
|
||||
(not (get-buffer-window buf t)))
|
||||
return buf))
|
||||
(generate-new-buffer eshell-buffer-name)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +eshell-last-buffer (&optional noerror)
|
||||
"Return the last opened eshell buffer."
|
||||
(let ((buffer (cl-find-if #'buffer-live-p (+eshell-buffers))))
|
||||
(cond (buffer)
|
||||
(noerror nil)
|
||||
((user-error "No live eshell buffers remaining")))))
|
||||
|
||||
;;;###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 (+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))))
|
||||
|
||||
|
||||
;;
|
||||
;; Commands
|
||||
|
||||
;;;###autoload
|
||||
(defun +eshell/open (arg &optional command)
|
||||
"Open eshell in the current buffer."
|
||||
(interactive "P")
|
||||
(when (eq major-mode 'eshell-mode)
|
||||
(user-error "Already in an eshell buffer"))
|
||||
(let* ((default-directory (or (if arg default-directory (doom-project-root))
|
||||
default-directory))
|
||||
(buf (+eshell--unused-buffer)))
|
||||
(with-current-buffer (switch-to-buffer buf)
|
||||
(if (eq major-mode 'eshell-mode)
|
||||
(run-hooks 'eshell-mode-hook)
|
||||
(eshell-mode))
|
||||
(if command (+eshell-run-command command buf)))
|
||||
buf))
|
||||
|
||||
;;;###autoload
|
||||
(defun +eshell/open-popup (arg &optional command)
|
||||
"Open eshell in a popup window."
|
||||
(interactive "P")
|
||||
(let* ((default-directory (or (if arg default-directory (doom-project-root))
|
||||
default-directory))
|
||||
(buf (+eshell--unused-buffer)))
|
||||
(with-current-buffer (pop-to-buffer buf)
|
||||
(if (eq major-mode 'eshell-mode)
|
||||
(run-hooks 'eshell-mode-hook)
|
||||
(eshell-mode))
|
||||
(if command (+eshell-run-command command buf)))
|
||||
buf))
|
||||
|
||||
;;;###autoload
|
||||
(defun +eshell/open-fullscreen (arg &optional command)
|
||||
"Open eshell in a separate workspace. Requires the (:ui workspaces)
|
||||
module to be loaded."
|
||||
(interactive "P")
|
||||
(let ((default-directory (or (if arg default-directory (doom-project-root))
|
||||
default-directory))
|
||||
(buf (+eshell--unused-buffer 'new)))
|
||||
(set-frame-parameter nil 'saved-wconf (current-window-configuration))
|
||||
(delete-other-windows)
|
||||
(with-current-buffer (switch-to-buffer buf)
|
||||
(eshell-mode)
|
||||
(if command (+eshell-run-command command buf)))
|
||||
buf))
|
||||
|
||||
|
||||
;;
|
||||
;; Keybinds
|
||||
|
||||
;;;###autoload
|
||||
(defun +eshell/search-history ()
|
||||
"Search the eshell command history with helm, ivy or `eshell-list-history'."
|
||||
(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
|
||||
(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)
|
||||
(ignore-errors (pcomplete-std-complete)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +eshell/quit-or-delete-char (arg)
|
||||
"Delete a character (ahead of the cursor) or quit eshell if there's nothing to
|
||||
delete."
|
||||
(interactive "p")
|
||||
(if (and (eolp) (looking-back eshell-prompt-regexp nil))
|
||||
(eshell-life-is-too-much)
|
||||
(delete-char arg)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +eshell/split-below ()
|
||||
"Create a new eshell window below the current one."
|
||||
(interactive)
|
||||
(let ((ignore-window-parameters t)
|
||||
(dedicated-p (window-dedicated-p))
|
||||
(+eshell-enable-new-shell-on-split
|
||||
(or +eshell-enable-new-shell-on-split (frame-parameter nil 'saved-wconf))))
|
||||
(select-window (split-window-vertically))
|
||||
(+eshell--bury-buffer dedicated-p)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +eshell/split-right ()
|
||||
"Create a new eshell window to the right of the current one."
|
||||
(interactive)
|
||||
(let* ((ignore-window-parameters t)
|
||||
(dedicated-p (window-dedicated-p))
|
||||
(+eshell-enable-new-shell-on-split
|
||||
(or +eshell-enable-new-shell-on-split (frame-parameter nil 'saved-wconf))))
|
||||
(select-window (split-window-horizontally))
|
||||
(+eshell--bury-buffer dedicated-p)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +eshell/switch-to-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/switch-to-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))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +eshell/switch-to-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-to (buffer)
|
||||
"Interactively switch to another eshell buffer."
|
||||
(interactive
|
||||
(let ((buffers (doom-buffers-in-mode
|
||||
'eshell-mode (delq (current-buffer) (+eshell-buffers)))))
|
||||
(if (not buffers)
|
||||
(user-error "No eshell buffers are available")
|
||||
(list
|
||||
(completing-read "Eshell buffers"
|
||||
(mapcar #'buffer-name buffers)
|
||||
#'get-buffer
|
||||
'require-match
|
||||
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)))
|
||||
|
||||
;;;###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 ((current-buffer (current-buffer)))
|
||||
(dolist (buf (+eshell-buffers))
|
||||
(unless (buffer-live-p buf)
|
||||
(+eshell--remove-buffer buf)))
|
||||
(+eshell--setup-window (get-buffer-window current-buffer))
|
||||
(+eshell--add-buffer current-buffer)
|
||||
(setq +eshell--last-buffer current-buffer)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +eshell|cleanup ()
|
||||
"Close window (or workspace) on quit."
|
||||
(let ((buf (current-buffer)))
|
||||
(when (+eshell--remove-buffer buf)
|
||||
(when-let* ((win (get-buffer-window buf)))
|
||||
(+eshell--setup-window win nil)
|
||||
(cond ((and (one-window-p t)
|
||||
(window-configuration-p (frame-parameter nil 'saved-wconf)))
|
||||
(set-window-configuration (frame-parameter nil 'saved-wconf))
|
||||
(set-frame-parameter win 'saved-wconf nil))
|
||||
((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 (window-dedicated-p win)
|
||||
+eshell-kill-window-on-exit)
|
||||
(let ((ignore-window-parameters t)
|
||||
(popup-p (window-dedicated-p win)))
|
||||
(delete-window win)
|
||||
(when popup-p
|
||||
(cl-loop for win in (window-list)
|
||||
for buf = (window-buffer win)
|
||||
for mode = (buffer-local-value 'major-mode buf)
|
||||
if (eq mode 'eshell-mode)
|
||||
return (select-window win))))))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +eshell|switch-workspace (type)
|
||||
(when (eq type 'frame)
|
||||
(setq +eshell-buffers
|
||||
(or (persp-parameter 'eshell-buffers)
|
||||
(make-ring 25)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +eshell|save-workspace (_workspace target)
|
||||
(when (framep target)
|
||||
(set-persp-parameter 'eshell-buffers +eshell-buffers)))
|
76
modules/term/eshell/autoload/evil.el
Normal file
76
modules/term/eshell/autoload/evil.el
Normal file
|
@ -0,0 +1,76 @@
|
|||
;;; term/eshell/autoload/evil.el -*- lexical-binding: t; -*-
|
||||
;;;###if (featurep! :editor 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 "term/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
|
||||
(defun +eshell|goto-prompt-on-insert ()
|
||||
"Move cursor to the prompt when switching to insert mode (if point isn't
|
||||
already there)."
|
||||
(when (< (point) eshell-last-output-end)
|
||||
(goto-char
|
||||
(if (memq this-command '(evil-append evil-append-line))
|
||||
(point-max)
|
||||
eshell-last-output-end))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +eshell/goto-end-of-prompt ()
|
||||
"Move cursor to the prompt when switching to insert mode (if point isn't
|
||||
already there)."
|
||||
(interactive)
|
||||
(goto-char (point-max))
|
||||
(evil-append 1))
|
||||
|
||||
;;;###autoload (autoload '+eshell/evil-change "term/eshell/autoload/evil" nil t)
|
||||
(evil-define-operator +eshell/evil-change (beg end type register yank-handler delete-func)
|
||||
"Like `evil-change' but will not delete/copy the prompt."
|
||||
(interactive "<R><x><y>")
|
||||
(save-restriction
|
||||
(narrow-to-region eshell-last-output-end (point-max))
|
||||
(evil-change (max beg (point-min))
|
||||
(if (eq type 'line) (point-max) (min (or end (point-max)) (point-max)))
|
||||
type register yank-handler delete-func)))
|
||||
|
||||
;;;###autoload (autoload '+eshell/evil-change-line "term/eshell/autoload/evil" nil t)
|
||||
(evil-define-operator +eshell/evil-change-line (beg end type register yank-handler)
|
||||
"Change to end of line."
|
||||
:motion evil-end-of-line
|
||||
(interactive "<R><x><y>")
|
||||
(+eshell/evil-change beg end type register yank-handler #'evil-delete-line))
|
||||
|
||||
;;;###autoload (autoload '+eshell/evil-delete "term/eshell/autoload/evil" nil t)
|
||||
(evil-define-operator +eshell/evil-delete (beg end type register yank-handler)
|
||||
"Like `evil-delete' but will not delete/copy the prompt."
|
||||
(interactive "<R><x><y>")
|
||||
(save-restriction
|
||||
(narrow-to-region eshell-last-output-end (point-max))
|
||||
(evil-delete (if beg (max beg (point-min)) (point-min))
|
||||
(if (eq type 'line) (point-max) (min (or end (point-max)) (point-max)))
|
||||
type register yank-handler)))
|
||||
|
||||
;;;###autoload (autoload '+eshell/evil-delete-line "term/eshell/autoload/evil" nil t)
|
||||
(evil-define-operator +eshell/evil-delete-line (_beg end type register yank-handler)
|
||||
"Change to end of line."
|
||||
:motion nil
|
||||
:keep-visual t
|
||||
(interactive "<R><x>")
|
||||
(+eshell/evil-delete (point) end type register yank-handler))
|
34
modules/term/eshell/autoload/prompts.el
Normal file
34
modules/term/eshell/autoload/prompts.el
Normal file
|
@ -0,0 +1,34 @@
|
|||
;;; term/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")
|
||||
(let ((pwd (eshell/pwd)))
|
||||
(propertize (if (equal pwd "~")
|
||||
pwd
|
||||
(abbreviate-file-name (shrink-path-file 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))
|
||||
" "))
|
26
modules/term/eshell/autoload/settings.el
Normal file
26
modules/term/eshell/autoload/settings.el
Normal file
|
@ -0,0 +1,26 @@
|
|||
;;; term/eshell/autoload/settings.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autodef
|
||||
(defun set-eshell-alias! (&rest aliases)
|
||||
"Define aliases for eshell.
|
||||
|
||||
ALIASES is a flat list of alias -> command pairs. e.g.
|
||||
|
||||
(set-eshell-alias!
|
||||
\"hi\" \"echo hello world\"
|
||||
\"bye\" \"echo goodbye world\")"
|
||||
(or (cl-evenp (length aliases))
|
||||
(signal 'wrong-number-of-arguments (list 'even (length aliases))))
|
||||
(after! eshell
|
||||
(while aliases
|
||||
(let ((alias (pop aliases))
|
||||
(command (pop aliases)))
|
||||
(if-let* ((oldval (assoc alias +eshell-aliases)))
|
||||
(setcdr oldval (list command))
|
||||
(push (list alias command) +eshell-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)))))
|
165
modules/term/eshell/config.el
Normal file
165
modules/term/eshell/config.el
Normal file
|
@ -0,0 +1,165 @@
|
|||
;;; term/eshell/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; see:
|
||||
;; + `+eshell/open': open in current buffer
|
||||
;; + `+eshell/open-popup': open in a popup
|
||||
;; + `+eshell/open-fullscreen': open eshell fullscreen (will restore window
|
||||
;; config when quitting the last eshell buffer)
|
||||
|
||||
(defvar +eshell-config-dir
|
||||
(expand-file-name "eshell/" doom-private-dir)
|
||||
"Where to store eshell configuration files, as opposed to
|
||||
`eshell-directory-name', which is where Doom will store temporary/data files.")
|
||||
|
||||
(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
|
||||
("f" "find-file $1")
|
||||
("bd" "eshell-up $1") ; `eshell-up'
|
||||
("rg" "rg --color=always $*")
|
||||
("ag" "ag --color=always $*")
|
||||
("l" "ls -lh")
|
||||
("ll" "ls -lah")
|
||||
("clear" "clear-scrollback")) ; more sensible than default
|
||||
"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-directory-name (concat doom-etc-dir "eshell"))
|
||||
|
||||
;; These files are exceptions, because they may contain configuration
|
||||
(defvar eshell-aliases-file (concat +eshell-config-dir "alias"))
|
||||
(defvar eshell-rc-script (concat +eshell-config-dir "profile"))
|
||||
(defvar eshell-login-script (concat +eshell-config-dir "login"))
|
||||
|
||||
|
||||
(defvar +eshell--default-aliases nil)
|
||||
|
||||
|
||||
;;
|
||||
;; Packages
|
||||
|
||||
(after! eshell ; built-in
|
||||
(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
|
||||
eshell-scroll-to-bottom-on-output 'all
|
||||
eshell-buffer-shorthand t
|
||||
eshell-kill-processes-on-exit t
|
||||
eshell-hist-ignoredups t
|
||||
;; don't record command in history if prefixed with whitespace
|
||||
eshell-input-filter #'eshell-input-filter-initial-space
|
||||
;; em-prompt
|
||||
eshell-prompt-regexp "^.* λ "
|
||||
eshell-prompt-function #'+eshell-default-prompt
|
||||
;; em-glob
|
||||
eshell-glob-case-insensitive t
|
||||
eshell-error-if-no-glob t)
|
||||
|
||||
;; Consider eshell buffers 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)
|
||||
|
||||
;; Enable autopairing in eshell
|
||||
(add-hook 'eshell-mode-hook #'smartparens-mode)
|
||||
|
||||
;; Persp-mode/workspaces integration
|
||||
(when (featurep! :ui workspaces)
|
||||
(add-hook 'persp-activated-functions #'+eshell|switch-workspace)
|
||||
(add-hook 'persp-before-switch-functions #'+eshell|save-workspace))
|
||||
|
||||
;; UI enhancements
|
||||
(defun +eshell|remove-fringes ()
|
||||
(set-window-fringes nil 0 0)
|
||||
(set-window-margins nil 1 nil))
|
||||
(add-hook 'eshell-mode-hook #'+eshell|remove-fringes)
|
||||
|
||||
(defun +eshell|enable-text-wrapping ()
|
||||
(visual-line-mode +1)
|
||||
(set-display-table-slot standard-display-table 0 ?\ ))
|
||||
(add-hook 'eshell-mode-hook #'+eshell|enable-text-wrapping)
|
||||
|
||||
(add-hook 'eshell-mode-hook #'hide-mode-line-mode)
|
||||
|
||||
;; 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)
|
||||
|
||||
;; Visual commands require a proper terminal. Eshell can't handle that, so
|
||||
;; it delegates these commands to a term buffer.
|
||||
(after! em-term
|
||||
(dolist (cmd '("tmux" "htop" "vim" "nvim" "ncmpcpp"))
|
||||
(add-to-list 'eshell-visual-commands cmd)))
|
||||
|
||||
(defun +eshell|init-aliases ()
|
||||
(setq +eshell--default-aliases eshell-command-aliases-list
|
||||
eshell-command-aliases-list
|
||||
(append eshell-command-aliases-list
|
||||
+eshell-aliases)))
|
||||
(add-hook 'eshell-alias-load-hook #'+eshell|init-aliases)
|
||||
|
||||
(when (featurep! :editor evil +everywhere)
|
||||
(add-hook 'eshell-mode-hook #'+eshell|init-evil))
|
||||
|
||||
(defun +eshell|init-keymap ()
|
||||
"Setup eshell keybindings. This must be done in a hook because eshell-mode
|
||||
redefines its keys every time `eshell-mode' is enabled."
|
||||
(map! :map eshell-mode-map
|
||||
:n [return] #'+eshell/goto-end-of-prompt
|
||||
:n "c" #'+eshell/evil-change
|
||||
:n "C" #'+eshell/evil-change-line
|
||||
:n "d" #'+eshell/evil-delete
|
||||
:n "D" #'+eshell/evil-delete-line
|
||||
:i [tab] #'+eshell/pcomplete
|
||||
:i "C-j" #'evil-window-down
|
||||
:i "C-k" #'evil-window-up
|
||||
:i "C-h" #'evil-window-left
|
||||
:i "C-l" #'evil-window-right
|
||||
:i "C-d" #'+eshell/quit-or-delete-char
|
||||
:i "C-p" #'eshell-previous-input
|
||||
:i "C-n" #'eshell-next-input
|
||||
"C-s" #'+eshell/search-history
|
||||
"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-window-split] #'+eshell/split-below
|
||||
[remap evil-window-vsplit] #'+eshell/split-right))
|
||||
(add-hook 'eshell-first-time-mode-hook #'+eshell|init-keymap))
|
||||
|
||||
|
||||
(def-package! eshell-up
|
||||
:commands (eshell-up eshell-up-peek))
|
||||
|
||||
|
||||
(def-package! shrink-path
|
||||
:commands shrink-path-file)
|
||||
|
||||
|
||||
(def-package! eshell-z
|
||||
:after eshell
|
||||
:config
|
||||
;; 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)
|
||||
(setq eshell-z-freq-dir-hash-table-file-name
|
||||
(expand-file-name "z" eshell-directory-name))))
|
6
modules/term/eshell/packages.el
Normal file
6
modules/term/eshell/packages.el
Normal file
|
@ -0,0 +1,6 @@
|
|||
;; -*- no-byte-compile: t; -*-
|
||||
;;; term/eshell/packages.el
|
||||
|
||||
(package! eshell-up)
|
||||
(package! eshell-z)
|
||||
(package! shrink-path)
|
33
modules/term/term/autoload.el
Normal file
33
modules/term/term/autoload.el
Normal file
|
@ -0,0 +1,33 @@
|
|||
;;; term/term/autoload.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defun +term/open (arg)
|
||||
"Open a terminal buffer in the current window. If ARG (universal argument) is
|
||||
non-nil, cd into the current project's root."
|
||||
(interactive "P")
|
||||
(let ((default-directory
|
||||
(if arg
|
||||
(or (doom-project-root) default-directory)
|
||||
default-directory)))
|
||||
;; Doom's switch-buffer hooks prevent themselves from triggering when
|
||||
;; switching from buffer A back to A. Because `multi-term' uses `set-buffer'
|
||||
;; before `switch-to-buffer', the hooks don't trigger, so we use this
|
||||
;; roundabout way to trigger them properly.
|
||||
(switch-to-buffer (save-window-excursion (multi-term)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +term/open-popup (arg)
|
||||
"Open a terminal popup window. If ARG (universal argument) is
|
||||
non-nil, cd into the current project's root."
|
||||
(interactive "P")
|
||||
(let ((default-directory
|
||||
(if arg
|
||||
(or (doom-project-root) default-directory)
|
||||
default-directory)))
|
||||
(pop-to-buffer (save-window-excursion (multi-term)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +term/open-popup-in-project ()
|
||||
"Open a terminal popup window in the root of the current project."
|
||||
(interactive)
|
||||
(+term/open-popup t))
|
8
modules/term/term/config.el
Normal file
8
modules/term/term/config.el
Normal file
|
@ -0,0 +1,8 @@
|
|||
;;; term/term/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###package multi-term
|
||||
(setq multi-term-dedicated-window-height 20
|
||||
multi-term-switch-after-close 'PREVIOUS)
|
||||
|
||||
;;;###package term
|
||||
(add-hook 'term-mode-hook #'doom|mark-buffer-as-real)
|
5
modules/term/term/packages.el
Normal file
5
modules/term/term/packages.el
Normal file
|
@ -0,0 +1,5 @@
|
|||
;; -*- no-byte-compile: t; -*-
|
||||
;;; term/term/packages.el
|
||||
|
||||
(package! term :built-in t)
|
||||
(package! multi-term)
|
91
modules/term/vterm/README.org
Normal file
91
modules/term/vterm/README.org
Normal file
|
@ -0,0 +1,91 @@
|
|||
#+TITLE: term/vterm
|
||||
#+DATE: January 16, 2019
|
||||
#+SINCE: 2.1
|
||||
#+STARTUP: inlineimages
|
||||
|
||||
* Table of Contents :TOC_3:noexport:
|
||||
- [[#description][Description]]
|
||||
- [[#module-flags][Module Flags]]
|
||||
- [[#plugins][Plugins]]
|
||||
- [[#prerequisites][Prerequisites]]
|
||||
- [[#dynamic-module-support][Dynamic Module support]]
|
||||
- [[#libvterm][libvterm]]
|
||||
- [[#compilation-tools-for-vterm-moduleso][Compilation tools for vterm-module.so]]
|
||||
|
||||
* Description
|
||||
This module provides a terminal emulator powered by libvterm. It is still in
|
||||
alpha and requires a component be compiled (=vterm-module.sh=).
|
||||
|
||||
The following commands are available to open it:
|
||||
|
||||
+ ~+vterm/open~ (=SPC o t=): Opens vterm in the current window.
|
||||
+ ~+vterm/open-popup~ (no keybind): Opens vterm in a pop up window.
|
||||
+ ~+vterm/open-popup-in-project~ (=SPC o T=): Opens vterm from the project root
|
||||
in a pop up window.
|
||||
|
||||
** Module Flags
|
||||
This module provides no flags.
|
||||
|
||||
** Plugins
|
||||
+ [[https://github.com/akermu/emacs-libvterm][vterm]]
|
||||
|
||||
* Prerequisites
|
||||
+ Emacs must be built with dynamic module support, i.e. compiled with the
|
||||
=--with-modules= option.
|
||||
+ You need =libvterm= installed on your system.
|
||||
+ You need =make=, =cmake= and a C compiler such as =gcc= so that vterm can
|
||||
build =vterm-module.so=.
|
||||
|
||||
** Dynamic Module support
|
||||
To check if your build of Emacs was built with dynamic module support, check
|
||||
~bin/doom info~ for ~MODULES~ next to "System features". If it's there, you're
|
||||
good to go.
|
||||
|
||||
You can also check for =--with-modules= in the ~system-configuration-options~
|
||||
variable (=SPC h v system-configuration-options=).
|
||||
|
||||
- Archlinux or Manjaro users who installed Emacs through pacman will have
|
||||
support baked in.
|
||||
- MacOS users:
|
||||
- If you use [[https://emacsformacosx.com/][Emacs For Mac OS X]], this option is enabled.
|
||||
- If you use [[https://github.com/d12frosted/homebrew-emacs-plus][emacs-plus]], this option is enabled by default.
|
||||
- If you use [[https://github.com/railwaycat/homebrew-emacsmacport][emacs-mac]], this options is *not* enabled by default. You may have
|
||||
to reinstall emacs with the option: ~brew install emacs-mac --with-modules~
|
||||
|
||||
** libvterm
|
||||
+ Ubuntu or Debian users: ~apt-get install libvterm-dev~
|
||||
+ ArchLinux or Manjaro: ~pacman -S libvterm~
|
||||
+ MacOS: ~libvterm~
|
||||
|
||||
** Compilation tools for vterm-module.so
|
||||
When you first load vterm, it will compile =vterm-module.so= for you. For this
|
||||
to succeed, you need the following:
|
||||
|
||||
+ =make=
|
||||
+ =cmake=
|
||||
+ A C compiler like =gcc=
|
||||
+ An internet connection (=cmake= will download needed libraries)
|
||||
|
||||
There are several ways to manually install the module:
|
||||
|
||||
1. You can use =M-x vterm-module-compile= to let emacs automatically compile and
|
||||
install the module.
|
||||
|
||||
*WARNING*: Emacs will hang during the compilation. It may take a while.
|
||||
|
||||
2. You can compile and install the module yourself. Go to the vterm installation
|
||||
directory (usually =~/.emacs.d/.local/packages/elpa/vterm-<version>=) and run
|
||||
the following:
|
||||
|
||||
#+BEGIN_SRC sh
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
|
||||
make
|
||||
#+END_SRC
|
||||
|
||||
3. You can also compile =vterm-module.sh= elsewhere, but the module must be
|
||||
moved/symlinked to
|
||||
=~/.emacs.d/.local/packages/elpa/vterm-<version>/vterm-module.so=
|
||||
=vterm-module.so=. Keep in mind that this folder will be deleted whenever the
|
||||
vterm package is updated.
|
37
modules/term/vterm/autoload.el
Normal file
37
modules/term/vterm/autoload.el
Normal file
|
@ -0,0 +1,37 @@
|
|||
;;; term/vterm/autoload.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defun +vterm/open (arg)
|
||||
"Open a terminal buffer in the current window. If ARG (universal argument) is
|
||||
non-nil, cd into the current project's root."
|
||||
(interactive "P")
|
||||
(unless (fboundp 'module-load)
|
||||
(user-error "Your build of Emacs lacks dynamic modules support and cannot load vterm"))
|
||||
;; This hack forces vterm to redraw, fixing strange artefacting in the tty.
|
||||
;; Don't ask me why it works.
|
||||
(save-window-excursion
|
||||
(pop-to-buffer "*scratch*"))
|
||||
(let ((default-directory
|
||||
(if arg
|
||||
(or (doom-project-root) default-directory)
|
||||
default-directory)))
|
||||
(vterm)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +vterm/open-popup (arg)
|
||||
"Open a terminal popup window. If ARG (universal argument) is
|
||||
non-nil, cd into the current project's root."
|
||||
(interactive "P")
|
||||
(unless (fboundp 'module-load)
|
||||
(user-error "Your build of Emacs lacks dynamic modules support and cannot load vterm"))
|
||||
(let ((default-directory
|
||||
(if arg
|
||||
(or (doom-project-root) default-directory)
|
||||
default-directory)))
|
||||
(vterm-other-window)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +vterm/open-popup-in-project ()
|
||||
"Open a terminal popup window in the root of the current project."
|
||||
(interactive)
|
||||
(+vterm/open-popup t))
|
44
modules/term/vterm/config.el
Normal file
44
modules/term/vterm/config.el
Normal file
|
@ -0,0 +1,44 @@
|
|||
;;; term/vterm/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(def-package! vterm
|
||||
:when (fboundp 'module-load)
|
||||
:defer t
|
||||
:preface (setq vterm-install t)
|
||||
:config
|
||||
(set-popup-rule! "^vterm" :size 0.25 :vslot -4 :select t :quit nil :ttl 0)
|
||||
|
||||
(add-hook 'vterm-mode-hook #'doom|mark-buffer-as-real)
|
||||
;; Automatically kill buffer when vterm exits.
|
||||
(add-to-list 'vterm-exit-functions (lambda (buffer) (if buffer (kill-buffer buffer))))
|
||||
;; Modeline serves no purpose in vterm
|
||||
(add-hook 'vterm-mode-hook #'hide-mode-line-mode)
|
||||
;; Don't prompt about processes when killing vterm
|
||||
(setq-hook! 'vterm-mode-hook confirm-kill-processes nil)
|
||||
|
||||
(when (featurep! :editor evil)
|
||||
(evil-set-initial-state 'vterm-mode 'insert)
|
||||
;; Go back to normal state but don't move cursor backwards. Moving cursor
|
||||
;; backwards is the default Vim behavior but it is not appropriate in some
|
||||
;; cases like terminals.
|
||||
(setq-hook! 'vterm-mode-hook evil-move-cursor-back nil)
|
||||
;; Those keys are commonly needed by terminals.
|
||||
(evil-define-key* 'insert vterm-mode-map
|
||||
(kbd "C-a") #'vterm--self-insert
|
||||
(kbd "C-b") #'vterm--self-insert ; Should not be necessary.
|
||||
(kbd "C-d") #'vterm--self-insert
|
||||
(kbd "C-e") #'vterm--self-insert
|
||||
(kbd "C-f") #'vterm--self-insert ; Should not be necessary.
|
||||
(kbd "C-k") #'vterm--self-insert
|
||||
(kbd "C-l") #'vterm--self-insert ; Should not be necessary.
|
||||
(kbd "C-n") #'vterm--self-insert
|
||||
(kbd "C-o") #'vterm--self-insert
|
||||
(kbd "C-p") #'vterm--self-insert
|
||||
(kbd "C-q") #'vterm--self-insert ; Should not be necessary.
|
||||
(kbd "C-r") #'vterm--self-insert
|
||||
(kbd "C-s") #'vterm--self-insert ; Should not be necessary.
|
||||
(kbd "C-t") #'vterm--self-insert
|
||||
(kbd "C-u") #'vterm--self-insert ; Should not be necessary.
|
||||
(kbd "C-v") #'vterm--self-insert ; Should not be necessary.
|
||||
(kbd "C-w") #'vterm--self-insert
|
||||
(kbd "C-y") #'vterm--self-insert
|
||||
(kbd "C-z") #'vterm--self-insert)))
|
13
modules/term/vterm/doctor.el
Normal file
13
modules/term/vterm/doctor.el
Normal file
|
@ -0,0 +1,13 @@
|
|||
;;; term/vterm/doctor.el -*- lexical-binding: t; -*-
|
||||
|
||||
(unless (executable-find "vterm-ctrl")
|
||||
(warn! "Couldn't find libvterm. Vterm module won't compile"))
|
||||
|
||||
(unless (executable-find "make")
|
||||
(warn! "Couldn't find make command. Vterm module won't compile"))
|
||||
|
||||
(unless (executable-find "cmake")
|
||||
(warn! "Couldn't find cmake command. Vterm module won't compile"))
|
||||
|
||||
(unless (fboundp 'module-load)
|
||||
(warn! "Your emacs doesn't have MODULES support. Vterm module won't work"))
|
4
modules/term/vterm/packages.el
Normal file
4
modules/term/vterm/packages.el
Normal file
|
@ -0,0 +1,4 @@
|
|||
;; -*- no-byte-compile: t; -*-
|
||||
;;; term/vterm/packages.el
|
||||
|
||||
(package! vterm)
|
Loading…
Add table
Add a link
Reference in a new issue