From: Juri Linkov Date: Sat, 6 Jun 2020 23:42:24 +0000 (+0300) Subject: The key prefix 'C-x t t' displays next command buffer in a new tab (bug#41691) X-Git-Tag: emacs-28.0.90~7202 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=788cd6d8b98c0e7750e478ae84e580f29576b5ff;p=emacs.git The key prefix 'C-x t t' displays next command buffer in a new tab (bug#41691) * lisp/tab-bar.el (other-tab-prefix): New command. (tab-prefix-map): Bind key 'C-x t t' to other-tab-prefix. * lisp/windmove.el (windmove-display-in-direction): Use display-buffer-override-next-command. * lisp/window.el (display-buffer-override-next-command): New function refactored from windmove-display-in-direction. --- diff --git a/etc/NEWS b/etc/NEWS index edad5b37d6c..6e94d4a91ba 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -109,6 +109,10 @@ setting the variable 'auto-save-visited-mode' buffer-locally to nil. * Changes in Specialized Modes and Packages in Emacs 28.1 +** Tab Bars + +*** The key prefix 'C-x t t' displays next command buffer in a new tab. + ** New bindings in occur-mode, 'next-error-no-select' bound to 'n' and 'previous-error-no-select' bound to 'p'. diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el index 76e7f8c33a2..eb3ad72db43 100644 --- a/lisp/tab-bar.el +++ b/lisp/tab-bar.el @@ -1575,6 +1575,25 @@ Like \\[find-file-other-frame] (which see), but creates a new tab." value) (switch-to-buffer-other-tab value)))) +(defun other-tab-prefix () + "Display the buffer of the next command in a new tab. +The next buffer is the buffer displayed by the next command invoked +immediately after this command (ignoring reading from the minibuffer). +Creates a new tab before displaying the buffer, or switches to the tab +that already contains that buffer. +When `switch-to-buffer-obey-display-actions' is non-nil, +`switch-to-buffer' commands are also supported." + (interactive) + (display-buffer-override-next-command + (lambda (buffer alist) + (cons (progn + (display-buffer-in-tab + buffer (append alist '((inhibit-same-window . nil) + (reusable-frames . t)))) + (selected-window)) + 'tab))) + (message "Display next command buffer in a new tab...")) + (define-key tab-prefix-map "2" 'tab-new) (define-key tab-prefix-map "1" 'tab-close-other) (define-key tab-prefix-map "0" 'tab-close) @@ -1585,6 +1604,7 @@ Like \\[find-file-other-frame] (which see), but creates a new tab." (define-key tab-prefix-map "b" 'switch-to-buffer-other-tab) (define-key tab-prefix-map "f" 'find-file-other-tab) (define-key tab-prefix-map "\C-f" 'find-file-other-tab) +(define-key tab-prefix-map "t" 'other-tab-prefix) (provide 'tab-bar) diff --git a/lisp/windmove.el b/lisp/windmove.el index f96383197bd..341c739d924 100644 --- a/lisp/windmove.el +++ b/lisp/windmove.el @@ -461,60 +461,38 @@ select the window with a displayed buffer, and the meaning of the prefix argument is reversed. When `switch-to-buffer-obey-display-actions' is non-nil, `switch-to-buffer' commands are also supported." - (let* ((no-select (xor (consp arg) windmove-display-no-select)) - (old-window (or (minibuffer-selected-window) (selected-window))) - (new-window) - (minibuffer-depth (minibuffer-depth)) - (action (lambda (buffer alist) - (unless (> (minibuffer-depth) minibuffer-depth) - (let* ((type 'reuse) - (window (cond - ((eq dir 'new-tab) - (let ((tab-bar-new-tab-choice t)) - (tab-bar-new-tab)) - (setq type 'tab) - (selected-window)) - ((eq dir 'new-frame) - (let* ((params (cdr (assq 'pop-up-frame-parameters alist))) - (pop-up-frame-alist (append params pop-up-frame-alist)) - (frame (make-frame-on-current-monitor - pop-up-frame-alist))) - (unless (cdr (assq 'inhibit-switch-frame alist)) - (window--maybe-raise-frame frame)) - (setq type 'frame) - (frame-selected-window frame))) - ((eq dir 'same-window) - (selected-window)) - (t (window-in-direction - dir nil nil - (and arg (prefix-numeric-value arg)) - windmove-wrap-around))))) - (unless window - (setq window (split-window nil nil dir) type 'window)) - (setq new-window (window--display-buffer buffer window - type alist)))))) - (command this-command) - (clearfun (make-symbol "clear-display-buffer-overriding-action")) - (exitfun - (lambda () - (setq display-buffer-overriding-action - (delq action display-buffer-overriding-action)) - (when (window-live-p (if no-select old-window new-window)) - (select-window (if no-select old-window new-window))) - (remove-hook 'post-command-hook clearfun)))) - (fset clearfun - (lambda () - (unless (or - ;; Remove the hook immediately - ;; after exiting the minibuffer. - (> (minibuffer-depth) minibuffer-depth) - ;; But don't remove immediately after - ;; adding the hook by the same command below. - (eq this-command command)) - (funcall exitfun)))) - (add-hook 'post-command-hook clearfun) - (push action display-buffer-overriding-action) - (message "[display-%s]" dir))) + (let ((no-select (xor (consp arg) windmove-display-no-select))) + (display-buffer-override-next-command + (lambda (_buffer alist) + (let* ((type 'reuse) + (window (cond + ((eq dir 'new-tab) + (let ((tab-bar-new-tab-choice t)) + (tab-bar-new-tab)) + (setq type 'tab) + (selected-window)) + ((eq dir 'new-frame) + (let* ((params (cdr (assq 'pop-up-frame-parameters alist))) + (pop-up-frame-alist (append params pop-up-frame-alist)) + (frame (make-frame-on-current-monitor + pop-up-frame-alist))) + (unless (cdr (assq 'inhibit-switch-frame alist)) + (window--maybe-raise-frame frame)) + (setq type 'frame) + (frame-selected-window frame))) + ((eq dir 'same-window) + (selected-window)) + (t (window-in-direction + dir nil nil + (and arg (prefix-numeric-value arg)) + windmove-wrap-around))))) + (unless window + (setq window (split-window nil nil dir) type 'window)) + (cons window type))) + (lambda (old-window new-window) + (when (window-live-p (if no-select old-window new-window)) + (select-window (if no-select old-window new-window)))))) + (message "[display-%s]" dir)) ;;;###autoload (defun windmove-display-left (&optional arg) diff --git a/lisp/window.el b/lisp/window.el index d658cb81f65..998568e7b82 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -8578,6 +8578,47 @@ documentation for additional customization information." (interactive (list (read-buffer-to-switch "Switch to buffer in other frame: "))) (pop-to-buffer buffer-or-name display-buffer--other-frame-action norecord)) + +(defun display-buffer-override-next-command (pre-function &optional post-function) + "Set `display-buffer-overriding-action' for the next command. +`pre-function' is called to prepare the window where the buffer should be +displayed. This function takes two arguments `buffer' and `alist', and +should return a cons with the displayed window and its type. See the +meaning of these values in `window--display-buffer'. +Optional `post-function' is called after the buffer is displayed in the +window; the function takes two arguments: an old and new window." + (let* ((old-window (or (minibuffer-selected-window) (selected-window))) + (new-window nil) + (minibuffer-depth (minibuffer-depth)) + (action (lambda (buffer alist) + (unless (> (minibuffer-depth) minibuffer-depth) + (let* ((ret (funcall pre-function buffer alist)) + (window (car ret)) + (type (cdr ret))) + (setq new-window (window--display-buffer buffer window + type alist)))))) + (command this-command) + (clearfun (make-symbol "clear-display-buffer-overriding-action")) + (exitfun + (lambda () + (setq display-buffer-overriding-action + (delq action display-buffer-overriding-action)) + (remove-hook 'post-command-hook clearfun) + (when (functionp post-function) + (funcall post-function old-window new-window))))) + (fset clearfun + (lambda () + (unless (or + ;; Remove the hook immediately + ;; after exiting the minibuffer. + (> (minibuffer-depth) minibuffer-depth) + ;; But don't remove immediately after + ;; adding the hook by the same command below. + (eq this-command command)) + (funcall exitfun)))) + (add-hook 'post-command-hook clearfun) + (push action display-buffer-overriding-action))) + (defun set-window-text-height (window height) "Set the height in lines of the text display area of WINDOW to HEIGHT.