diff --git a/modules/config/default/+emacs-bindings.el b/modules/config/default/+emacs-bindings.el index e2a5ef333..00bbdd83c 100644 --- a/modules/config/default/+emacs-bindings.el +++ b/modules/config/default/+emacs-bindings.el @@ -26,14 +26,14 @@ :desc "Open project scratch buffer" "X" #'doom/switch-to-scratch-buffer (:when (featurep! :term term) - :desc "Terminal" "`" #'+term/open - :desc "Terminal in popup" "~" #'+term/open-popup-in-project) + :desc "Toggle term popup" "`" #'+term/toggle + :desc "Open term here" "~" #'+term/here) (:when (featurep! :term vterm) - :desc "Terminal" "`" #'+vterm/open - :desc "Terminal in popup" "~" #'+vterm/open-popup-in-project) + :desc "Toggle vterm popup" "`" #'+vterm/toggle + :desc "Open vterm here" "~" #'+vterm/here) (:when (featurep! :term eshell) - :desc "Eshell" "`" #'+eshell/open - :desc "Eshell in popup" "~" #'+eshell/open-popup) + :desc "Toggle eshell popup" "`" #'+eshell/toggle + :desc "Open eshell here" "~" #'+eshell/here) (:prefix ("l" . "")) ; bound locally (:prefix ("!" . "checkers")) ; bound by flycheck diff --git a/modules/config/default/+evil-bindings.el b/modules/config/default/+evil-bindings.el index 813f4bf46..fd439b291 100644 --- a/modules/config/default/+evil-bindings.el +++ b/modules/config/default/+evil-bindings.el @@ -694,14 +694,14 @@ :desc "Project sidebar" "p" #'+treemacs/toggle :desc "Find file in project sidebar" "P" #'+treemacs/find-file) (:when (featurep! :term term) - :desc "Terminal" "t" #'+term/open - :desc "Terminal in popup" "T" #'+term/open-popup-in-project) + :desc "Toggle terminal popup" "t" #'+term/toggle + :desc "Open terminal here" "T" #'+term/here) (:when (featurep! :term vterm) - :desc "Terminal" "t" #'+vterm/open - :desc "Terminal in popup" "T" #'+vterm/open-popup-in-project) + :desc "Toggle vterm popup" "t" #'+vterm/toggle + :desc "Open vterm here" "T" #'+vterm/here) (:when (featurep! :term eshell) - :desc "Eshell" "e" #'+eshell/open - :desc "Eshell in popup" "E" #'+eshell/open-popup) + :desc "Toggle eshell popup" "e" #'+eshell/toggle + :desc "Open eshell here" "E" #'+eshell/here) (:when (featurep! :collab floobits) (:prefix ("f" . "floobits") "c" #'floobits-clear-highlights diff --git a/modules/term/eshell/autoload/eshell.el b/modules/term/eshell/autoload/eshell.el index f83750540..9ea06d987 100644 --- a/modules/term/eshell/autoload/eshell.el +++ b/modules/term/eshell/autoload/eshell.el @@ -78,48 +78,79 @@ ;; Commands ;;;###autoload -(defun +eshell/open (arg &optional command) +(defun +eshell/toggle (arg &optional command) + "Toggle eshell popup window at project's root. + +Changes the PWD to the PWD of the buffer this command is executed from a new +project (or if prefix ARG was present)." + (interactive "P") + (let ((eshell-buffer (get-buffer-create "*doom:eshell-popup*")) + (target-project (or (doom-project-root) default-directory)) + confirm-kill-processes + current-prefix-arg) + (when arg + (when-let (win (get-buffer-window eshell-buffer)) + (delete-window win)) + (when (buffer-live-p eshell-buffer) + (kill-buffer eshell-buffer))) + (if-let (win (get-buffer-window eshell-buffer)) + (if (eq (selected-window) win) + (let (confirm-kill-processes) + (delete-window win) + (ignore-errors (kill-buffer eshell-buffer))) + (select-window win)) + (with-current-buffer (pop-to-buffer eshell-buffer) + (if (eq major-mode 'eshell-mode) + (run-hooks 'eshell-mode-hook) + (eshell-mode)) + (let ((old-project (doom-project-root))) + (when (and old-project + target-project + (not (file-equal-p old-project target-project))) + (setq default-directory target-project) + (with-silent-modifications + (goto-char (point-max)) + (when (re-search-backward eshell-prompt-regexp) + (delete-region (match-end 0) (point-max))) + (eshell-send-input)))) + (when command + (+eshell-run-command command buf)))))) + +;;;###autoload +(defun +eshell/here (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)) + (let* ((default-directory + (if arg + default-directory + (or (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))) + (when 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)) +(defun +eshell/frame (arg &optional command) + "Open a frame dedicated to eshell. -;;;###autoload -(defun +eshell/open-fullscreen (arg &optional command) - "Open eshell in a separate workspace. Requires the (:ui workspaces) -module to be loaded." +Once the eshell process is killed, the previous frame layout is restored." (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)) + (unless (frame-parameter nil 'saved-wconf) + (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))) + (when command + (+eshell-run-command command buf))) buf)) @@ -267,7 +298,7 @@ delete." (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)) + (set-frame-parameter nil 'saved-wconf nil)) ((one-window-p) (let ((prev (save-window-excursion (previous-buffer)))) (unless (and prev (doom-real-buffer-p prev)) diff --git a/modules/term/eshell/config.el b/modules/term/eshell/config.el index 8739067e5..20eba0986 100644 --- a/modules/term/eshell/config.el +++ b/modules/term/eshell/config.el @@ -1,10 +1,11 @@ ;;; 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) +;; + `+eshell/here': open eshell in the current window +;; + `+eshell/toggle': toggles an eshell popup +;; + `+eshell/frame': converts the current frame into an eshell-dedicated +;; frame. Once the last eshell process is killed, the old frame configuration +;; is restored. (defvar +eshell-config-dir (expand-file-name "eshell/" doom-private-dir) @@ -32,7 +33,7 @@ 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.") +You should use `set-eshell-alias!' to change this.") ;; (defvar eshell-directory-name (concat doom-etc-dir "eshell")) diff --git a/modules/term/term/autoload.el b/modules/term/term/autoload.el index 3fce6a005..6a3bac645 100644 --- a/modules/term/term/autoload.el +++ b/modules/term/term/autoload.el @@ -1,33 +1,50 @@ ;;; 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." +(defun +term/toggle (arg) + "Toggle a persistent terminal popup window at project's root. + +If popup is visible but unselected, select it. + +If prefix ARG, recreate term buffer in the current project's root." + (interactive "P") + (require 'multi-term) + (let ((default-directory (or (doom-project-root) default-directory)) + (multi-term-dedicated-buffer-name "doom:term-popup") + (multi-term-dedicated-select-after-open-p t) + confirm-kill-processes + current-prefix-arg) + (cl-letf (((symbol-function #'multi-term-dedicated-get-window) + (lambda () (setq multi-term-dedicated-window + (display-buffer-in-side-window + multi-term-dedicated-buffer + `((window-height . ,multi-term-dedicated-window-height))))))) + (when arg + (when (multi-term-window-exist-p multi-term-dedicated-window) + (delete-window multi-term-dedicated-window)) + (when (multi-term-buffer-exist-p multi-term-dedicated-buffer) + (when-let (process (get-buffer-process multi-term-dedicated-buffer)) + (kill-process process)) + (kill-buffer multi-term-dedicated-buffer))) + (if (multi-term-dedicated-exist-p) + (if (eq (selected-window) multi-term-dedicated-window) + (multi-term-dedicated-close) + (select-window multi-term-dedicated-window)) + (multi-term-dedicated-open))))) + +;;;###autoload +(defun +term/here (arg) + "Open a terminal buffer in the current window at project's root. + +If prefix ARG is non-nil, cd into `default-directory' instead of the project +root." (interactive "P") (let ((default-directory (if arg - (or (doom-project-root) default-directory) - default-directory))) + default-directory + (or (doom-project-root) 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)) diff --git a/modules/term/term/config.el b/modules/term/term/config.el index 419b7f226..12adbd62a 100644 --- a/modules/term/term/config.el +++ b/modules/term/term/config.el @@ -6,3 +6,4 @@ ;;;###package term (add-hook 'term-mode-hook #'doom|mark-buffer-as-real) +(add-hook 'term-mode-hook #'hide-mode-line-mode) diff --git a/modules/term/vterm/README.org b/modules/term/vterm/README.org index 444285ee4..3fecdfe15 100644 --- a/modules/term/vterm/README.org +++ b/modules/term/vterm/README.org @@ -18,10 +18,8 @@ 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. ++ ~+vterm/toggle~ (=SPC o t=): Toggle vterm pop up window in the current project ++ ~+vterm/here~ (=SPC o T=): Opens vterm in the current window ** Module Flags This module provides no flags. diff --git a/modules/term/vterm/autoload.el b/modules/term/vterm/autoload.el index 56ff395e1..bfe502a7f 100644 --- a/modules/term/vterm/autoload.el +++ b/modules/term/vterm/autoload.el @@ -1,37 +1,48 @@ ;;; 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." +(defun +vterm/toggle (arg) + "Toggles a terminal popup window at project root. + +If prefix ARG is non-nil, recreate vterm buffer in 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 ((buffer-name "*doom:vterm-popup*") + confirm-kill-processes + current-prefix-arg) + (when arg + (let ((buffer (get-buffer buffer-name)) + (window (get-buffer-window buffer-name))) + (when (buffer-live-p buffer) + (kill-buffer buffer)) + (when (window-live-p window) + (delete-window window)))) + (if-let (win (get-buffer-window buffer-name)) + (if (eq (selected-window) win) + (delete-window win) + (select-window win)) + (let* ((default-directory (or (doom-project-root) default-directory)) + (buffer (get-buffer-create buffer-name))) + (with-current-buffer buffer + (vterm-mode)) + (pop-to-buffer buffer))))) + +;;;###autoload +(defun +vterm/here (arg) + "Open a terminal buffer in the current window at project root. + +If prefix ARG is non-nil, cd into `default-directory' instead of project root." + (interactive "P") + (unless (fboundp 'module-load) + (user-error "Your build of Emacs lacks dynamic modules support and cannot load vterm")) + (when (eq major-mode 'vterm-mode) + (user-error "Already in a vterm buffer")) ;; 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))) + default-directory + (or (doom-project-root) 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))