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.
This commit is contained in:
Juri Linkov 2020-06-07 02:42:24 +03:00
parent 7ac79872ae
commit 788cd6d8b9
4 changed files with 97 additions and 54 deletions

View file

@ -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'.

View file

@ -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)

View file

@ -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)

View file

@ -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.