1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2025-01-09 15:50:21 +00:00

Merge from origin/emacs-28

c163fd9260 (origin/emacs-28) Minor fixes for recent changes in ELisp ...
fefada4816 Fix example in calc manual
e74e17c1f0 Rewrites of Elisp manual including tab-bar and tab-line ch...
3b138917b7 ; * INSTALL: Fix typo.
ce71446585 * lisp/tab-bar.el: Improve docstrings (bug#51247)
ace4ce16a3 * lisp/tab-bar.el (tab-bar-mouse-move-tab): Don't drag tab...
04716ca48f Add tab-bar-drag-maybe for indication of tab dragging (bug...
81e3697600 * lisp/tab-bar.el: Add a new tab on [mouse-1] instead of [...
a191d3c725 Add new and fix existing docstrings in tab-bar.el and tab-...
77dbaedadc Add tab bar support to the nextstep port
7b6fb486c2 Fix potential buffer overflow (bug#50767)
ed9f5546aa Improve doc strings in tab-line.el
686a03ee22 More documentation fixes in tab-bar.el
35920791df Improve doc strings of tab-bar commands
2d15db6e89 Fix a semantic test on some macOS machines
ac6ac76e3a Update to Org 9.5-57-g9bc3a2
This commit is contained in:
Glenn Morris 2021-10-18 07:50:26 -07:00
commit 7d12c06725
24 changed files with 928 additions and 606 deletions

View File

@ -220,7 +220,7 @@ GNU/Linux distribution that you use, and the options that you want to
configure Emacs with. On Debian-based systems, you can install all the
packages needed to build the installed version of Emacs with a command
like 'apt-get build-dep emacs' (on older systems, replace 'emacs' with
eg 'emacs25'). On Red Hat-based systems, the corresponding command is
e.g. 'emacs25'). On Red Hat-based systems, the corresponding command is
'dnf builddep emacs' (on older systems, use 'yum-builddep' instead).
On FreeBSD, the command is 'pkg install -y `pkg rquery %dn emacs-devel`'.

View File

@ -89,11 +89,12 @@ in which most editing takes place. Most of the primitives for
examining or changing text operate implicitly on the current buffer
(@pxref{Text}).
Normally, the buffer displayed in the selected window is the current
buffer, but this is not always so: a Lisp program can temporarily
designate any buffer as current in order to operate on its contents,
without changing what is displayed on the screen. The most basic
function for designating a current buffer is @code{set-buffer}.
Normally, the buffer displayed in the selected window
(@pxref{Selecting Windows}) is the current buffer, but this is not
always so: a Lisp program can temporarily designate any buffer as
current in order to operate on its contents, without changing what is
displayed on the screen. The most basic function for designating a
current buffer is @code{set-buffer}.
@defun current-buffer
This function returns the current buffer.
@ -118,12 +119,12 @@ on it.
When an editing command returns to the editor command loop, Emacs
automatically calls @code{set-buffer} on the buffer shown in the
selected window. This is to prevent confusion: it ensures that the
buffer that the cursor is in, when Emacs reads a command, is the
buffer to which that command applies (@pxref{Command Loop}). Thus,
you should not use @code{set-buffer} to switch visibly to a different
buffer; for that, use the functions described in @ref{Switching
Buffers}.
selected window (@pxref{Selecting Windows}). This is to prevent
confusion: it ensures that the buffer that the cursor is in, when Emacs
reads a command, is the buffer to which that command applies
(@pxref{Command Loop}). Thus, you should not use @code{set-buffer} to
switch visibly to a different buffer; for that, use the functions
described in @ref{Switching Buffers}.
When writing a Lisp function, do @emph{not} rely on this behavior of
the command loop to restore the current buffer after an operation.
@ -912,16 +913,17 @@ History}) provided it is shown in that window.
If @var{buffer-or-name} is @code{nil} or omitted, this means to bury the
current buffer. In addition, if the current buffer is displayed in the
selected window, this makes sure that the window is either deleted or
another buffer is shown in it. More precisely, if the selected window
is dedicated (@pxref{Dedicated Windows}) and there are other windows on
its frame, the window is deleted. If it is the only window on its frame
and that frame is not the only frame on its terminal, the frame is
dismissed by calling the function specified by
@code{frame-auto-hide-function} (@pxref{Quitting Windows}). Otherwise,
it calls @code{switch-to-prev-buffer} (@pxref{Window History}) to show
another buffer in that window. If @var{buffer-or-name} is displayed in
some other window, it remains displayed there.
selected window (@pxref{Selecting Windows}), this makes sure that the
window is either deleted or another buffer is shown in it. More
precisely, if the selected window is dedicated (@pxref{Dedicated
Windows}) and there are other windows on its frame, the window is
deleted. If it is the only window on its frame and that frame is not
the only frame on its terminal, the frame is dismissed by calling the
function specified by @code{frame-auto-hide-function} (@pxref{Quitting
Windows}). Otherwise, it calls @code{switch-to-prev-buffer}
(@pxref{Window History}) to show another buffer in that window. If
@var{buffer-or-name} is displayed in some other window, it remains
displayed there.
To replace a buffer in all the windows that display it, use
@code{replace-buffer-in-windows}, @xref{Buffers and Windows}.

View File

@ -1048,6 +1048,7 @@ Windows
* Basic Windows:: Basic information on using windows.
* Windows and Frames:: Relating windows to the frame they appear on.
* Selecting Windows:: The selected window is the one that you edit in.
* Window Sizes:: Accessing a window's size.
* Resizing Windows:: Changing the sizes of windows.
* Preserving Window Sizes:: Preserving the size of windows.
@ -1055,7 +1056,6 @@ Windows
* Deleting Windows:: Deleting a window gives its space to other windows.
* Recombining Windows:: Preserving the frame layout when splitting and
deleting windows.
* Selecting Windows:: The selected window is the one that you edit in.
* Cyclic Window Ordering:: Moving around the existing windows.
* Buffers and Windows:: Each window displays the contents of a buffer.
* Switching Buffers:: Higher-level functions for switching to a buffer.

View File

@ -151,7 +151,7 @@ the window (a.k.a.@: the @dfn{dominating} monitor).
This function itself does not make the new frame the selected frame.
@xref{Input Focus}. The previously selected frame remains selected.
On graphical terminals, however, the windowing system may select the
On graphical terminals, however, the window system may select the
new frame for its own reasons.
@end deffn
@ -494,7 +494,8 @@ a graphical terminal:
| | |_____________ Title Bar ______________| |
| | (1)_____________ Menu Bar ______________| | ^
| | (2)_____________ Tool Bar ______________| | ^
| | (3) _________ Internal Border ________ | | ^
| | (3)_____________ Tab Bar _______________| | ^
| | | _________ Internal Border ________ | | ^
| | | | ^ | | | |
| | | | | | | | |
Outer | | | Inner | | | Native
@ -640,6 +641,15 @@ GTK+, on the other hand, never wraps the tool bar but may
automatically increase the outer width of a frame in order to
accommodate an overlong tool bar.
@item Tab Bar
@cindex internal tab bar
The tab bar (@pxref{Tab Bars,,,emacs, The GNU Emacs Manual}) is always
drawn by Emacs itself. The tab bar appears above the tool bar in
Emacs built with an internal tool bar, and below the tool bar in
builds with an external tool bar.
Display of the tab bar can be suppressed by setting the
@code{tab-bar-lines} parameter (@pxref{Layout Parameters}) to zero.
@item Native Frame
@cindex native frame
@cindex native edges
@ -740,8 +750,8 @@ the internal border, one vertical scroll bar, and one left and one right
fringe if they are specified for this frame, see @ref{Layout
Parameters}. Its height can be obtained by removing from that of the
native height the widths of the internal border and the heights of the
frame's internal menu and tool bars and one horizontal scroll bar if
specified for this frame.
frame's internal menu and tool bars, the tab bar and one horizontal
scroll bar if specified for this frame.
@end table
@cindex absolute position
@ -1875,6 +1885,13 @@ The position of the tool bar when Emacs was built with GTK+. Its value
can be one of @code{top}, @code{bottom} @code{left}, @code{right}. The
default is @code{top}.
@vindex tab-bar-lines@r{, a frame parameter}
@item tab-bar-lines
The number of lines to use for the tab bar (@pxref{Tab Bars,,,emacs, The
GNU Emacs Manual}). The default is one if Tab Bar mode is enabled and
zero otherwise. This value may change whenever the tab bar wraps
(@pxref{Frame Layout}).
@vindex line-spacing@r{, a frame parameter}
@item line-spacing
Additional space to leave below each text line, in pixels (a positive
@ -2758,7 +2775,8 @@ Terminals}.
@cindex selected frame
At any time, one frame in Emacs is the @dfn{selected frame}. The
selected window always resides on the selected frame.
selected window (@pxref{Selecting Windows}) always resides on the
selected frame.
When Emacs displays its frames on several terminals (@pxref{Multiple
Terminals}), each terminal has its own selected frame. But only one
@ -2992,12 +3010,11 @@ Auto-selection}).
Note that this option does not distinguish ``sloppy'' focus (where the
frame that previously had focus retains focus as long as the mouse
pointer does not move into another window manager window) from
``strict'' focus (where a frame immediately loses focus when it's left
by the mouse pointer). Neither does it recognize whether your window
manager supports delayed focusing or auto-raising where you can
explicitly specify the time until a new frame gets focus or is
auto-raised.
pointer does not move into another window-system window) from ``strict''
focus (where a frame immediately loses focus when it's left by the mouse
pointer). Neither does it recognize whether your window manager
supports delayed focusing or auto-raising where you can explicitly
specify the time until a new frame gets focus or is auto-raised.
You can supply a ``focus follows mouse'' policy for individual Emacs
windows by customizing the variable @code{mouse-autoselect-window}

View File

@ -1625,19 +1625,18 @@ markers.
@node Window Type
@subsection Window Type
A @dfn{window} describes the portion of the terminal screen that Emacs
uses to display a buffer. Every window has one associated buffer, whose
contents appear in the window. By contrast, a given buffer may appear
in one window, no window, or several windows.
A @dfn{window} describes the portion of the screen that Emacs uses to
display buffers. Every live window (@pxref{Basic Windows}) has one
associated buffer, whose contents appear in that window. By contrast, a
given buffer may appear in one window, no window, or several windows.
Windows are grouped on the screen into frames; each window belongs to
one and only one frame. @xref{Frame Type}.
Though many windows may exist simultaneously, at any time one window
is designated the @dfn{selected window}. This is the window where the
cursor is (usually) displayed when Emacs is ready for a command. The
selected window usually displays the current buffer (@pxref{Current
Buffer}), but this is not necessarily the case.
Windows are grouped on the screen into frames; each window belongs to
one and only one frame. @xref{Frame Type}.
is designated the @dfn{selected window} (@pxref{Selecting Windows}).
This is the window where the cursor is (usually) displayed when Emacs is
ready for a command. The selected window usually displays the current
buffer (@pxref{Current Buffer}), but this is not necessarily the case.
Windows have no read syntax. They print in hash notation, giving the
window number and the name of the buffer being displayed. The window

View File

@ -179,6 +179,8 @@ copyleft
counterintuitive
cr
creatable
customization
customizations
customize
deactivate
deactivated
@ -243,6 +245,8 @@ fmakunbound
fo
fol
following'
fontification
fontified
fooba
foobaz
foox
@ -257,6 +261,7 @@ garbles
gc
getenv
gid
glyphs
gp
grep
gtr
@ -270,6 +275,8 @@ hostname
hpux
hscroll
ick
iconified
iconify
id
idiom
ii
@ -314,6 +321,7 @@ mathsurround
memq
mh
mini
minibuf
minibuffer's
minibuffers
misalignment
@ -387,6 +395,7 @@ passwd
ped
perverse
pid
pixelwise
plist
pointer'
pointm
@ -417,6 +426,10 @@ reader'
rebind
rec
rechecking
redisplay
redisplayed
redisplaying
redisplays
redo
redrawing
redraws
@ -430,6 +443,7 @@ reinitialize
reinitialized
reinstall
reinstalled
resizable
resize
resized
resizes
@ -486,6 +500,8 @@ terpri
text'
tildes
time's
tooltip
tooltips
towards
transportable
txt
@ -494,6 +510,7 @@ unbind
unbinding
unbinds
unclutters
uncustomized
undefine
undefines
underfull
@ -520,6 +537,7 @@ vconcat
vectorp
vn
voidness
whitespace
window'
windowing
windowp

File diff suppressed because it is too large Load Diff

View File

@ -2865,7 +2865,7 @@ that always equals one. Let's try to verify this identity.
@smallexample
@group
2: -64 2: -64 2: -64 2: 9.7192e54 2: 9.7192e54
1: -64 1: -3.1175e27 1: 9.7192e54 1: -64 1: 9.7192e54
1: -64 1: 3.1175e27 1: 9.7192e54 1: -64 1: 9.7192e54
. . . . .
64 n @key{RET} @key{RET} H C 2 ^ @key{TAB} H S 2 ^

View File

@ -98,6 +98,15 @@ latest stable version of Org should be compatible with Emacs 28.x,
See [[https://orgmode.org/worg/org-maintenance.html#emacs-compatibility][this note on Worg]] and [[git::519947e508e081e71bf67db99e27b1c171ba4dfe][this commit]].
*** The keybinding for ~org-table-blank-field~ has been removed
If you prefer to keep the keybinding, you can add it back to
~org-mode-map~ like so:
#+begin_src emacs-lisp
(define-key org-mode-map (kbd "C-c SPC") #'org-table-blank-field)
#+end_src
** New features
*** New citation engine

View File

@ -69,7 +69,6 @@
(require 'bibtex)
(require 'json)
(require 'oc)
(require 'org)
(require 'seq)
(declare-function org-open-at-point "org" (&optional arg))

View File

@ -213,8 +213,8 @@ PROPS is the local properties of the bibliography, as a property list."
(defun org-cite-biblatex-export-citation (citation style _ info)
"Export CITATION object.
STYLE is the citation style, as a string or nil. INFO is the export state, as
a property list."
STYLE is the citation style, as a pair of either strings or nil.
INFO is the export state, as a property list."
(apply
#'org-cite-biblatex--command citation info
(pcase style

View File

@ -248,11 +248,11 @@ If nil then the Chicago author-date style is used as a fallback.")
("paras." . "paragraph")
("" . "paragraph")
("¶¶" . "paragraph")
("§" . "paragraph")
("§§" . "paragraph")
("part" . "part")
("pt." . "part")
("pts." . "part")
("§" . "section")
("§§" . "section")
("section" . "section")
("sec." . "section")
("secs." . "section")
@ -270,11 +270,12 @@ If nil then the Chicago author-date style is used as a fallback.")
(defconst org-cite-csl--label-regexp
;; Prior to Emacs-27.1 argument of `regexp' form must be a string literal.
;; It is the reason why `rx' is avoided here.
(rx-to-string `(seq word-start
(regexp ,(regexp-opt (mapcar #'car org-cite-csl--label-alist) t))
(0+ digit)
(or word-start line-end (any ?\s ?\t)))
t)
(rx-to-string
`(seq (or line-start space)
(regexp ,(regexp-opt (mapcar #'car org-cite-csl--label-alist) t))
(0+ digit)
(or word-end line-end space " "))
t)
"Regexp matching a label in a citation reference suffix.
Label is in match group 1.")
@ -371,7 +372,7 @@ or raise an error if the variable is unset."
((and (guard org-cite-csl-styles-dir) file)
(expand-file-name file org-cite-csl-styles-dir))
(other
(user-error "Cannot handle relative style file name" other))))
(user-error "Cannot handle relative style file name: %S" other))))
(defun org-cite-csl--locale-getter ()
"Return a locale getter.
@ -425,7 +426,9 @@ The result is a association list. Keys are: `id', `prefix',`suffix',
((re-search-forward org-cite-csl--label-regexp nil t)
(setq location-start (match-beginning 0))
(setq label (cdr (assoc (match-string 1) org-cite-csl--label-alist)))
(setq locator-start (match-end 1)))
(goto-char (match-end 1))
(skip-chars-forward "[:space:] ")
(setq locator-start (point)))
((re-search-forward (rx digit) nil t)
(setq location-start (match-beginning 0))
(setq label "page")

View File

@ -789,6 +789,20 @@ Citations are ordered by appearance in the document, when following footnotes.
INFO is the export communication channel, as a property list."
(or (plist-get info :citations)
(letrec ((cites nil)
(tree (plist-get info :parse-tree))
(find-definition
;; Find definition for standard reference LABEL. At
;; this point, it is impossible to rely on
;; `org-export-get-footnote-definition' because the
;; function caches results that could contain
;; un-processed citation objects. So we use
;; a simplified version of the function above.
(lambda (label)
(org-element-map tree 'footnote-definition
(lambda (d)
(and (equal label (org-element-property :label d))
(or (org-element-contents d) "")))
info t)))
(search-cites
(lambda (data)
(org-element-map data '(citation footnote-reference)
@ -798,22 +812,13 @@ INFO is the export communication channel, as a property list."
;; Do not force entering inline definitions, since
;; `org-element-map' is going to enter it anyway.
((guard (eq 'inline (org-element-property :type datum))))
;; Find definition for current standard
;; footnote reference. Unlike to
;; `org-export-get-footnote-definition', do
;; not cache results as they would contain
;; un-processed citation objects.
;; Walk footnote definition.
(_
(let ((label (org-element-property :label datum)))
(funcall
search-cites
(org-element-map data 'footnote-definition
(lambda (d)
(and
(equal label (org-element-property :label d))
(or (org-element-contents d) "")))))))))
(funcall search-cites
(funcall find-definition label))))))
info nil 'footnote-definition t))))
(funcall search-cites (plist-get info :parse-tree))
(funcall search-cites tree)
(let ((result (nreverse cites)))
(plist-put info :citations result)
result))))
@ -1593,8 +1598,9 @@ The generated function inserts or edit a citation at point. More specifically,
(concat "/" style)
""))
"")
(mapconcat (lambda (k) (concat "@" k)) keys ";"))))))))
(mapconcat (lambda (k) (concat "@" k)) keys "; "))))))))
;;;###autoload
(defun org-cite-insert (arg)
"Insert a citation at point.
Insertion is done according to the processor set in `org-cite-insert-processor'.
@ -1603,7 +1609,7 @@ ARG is the prefix argument received when calling interactively the function."
(let ((name org-cite-insert-processor))
(cond
((null name)
(user-error "No processor set to follow citations"))
(user-error "No processor set to insert citations"))
((not (org-cite--get-processor name))
(user-error "Unknown processor %S" name))
((not (org-cite-processor-has-capability-p name 'insert))

View File

@ -11,7 +11,7 @@ Inserted by installing Org mode or when a release is made."
(defun org-git-version ()
"The Git version of Org mode.
Inserted by installing Org or when a release is made."
(let ((org-git-version "release_9.5-46-gb71474"))
(let ((org-git-version "release_9.5-57-g9bc3a2"))
org-git-version))
(provide 'org-version)

View File

@ -95,6 +95,7 @@
(require 'org-keys)
(require 'ol)
(require 'oc)
(require 'oc-basic)
(require 'org-table)
;; `org-outline-regexp' ought to be a defconst but is let-bound in

View File

@ -227,6 +227,10 @@ a list of frames to update."
;;; Key bindings
(defun tab-bar--key-to-number (key)
"Return the tab number represented by KEY.
If KEY is a symbol 'tab-N', where N is a tab number, the value is N.
If KEY is \\='current-tab, the value is nil.
For any other value of KEY, the value is t."
(cond
((null key) t)
((eq key 'current-tab) nil)
@ -235,7 +239,16 @@ a list of frames to update."
(string-to-number (string-replace "tab-" "" key-name)))))
(t t)))
(defvar tab-bar-drag-maybe)
(defun tab-bar--event-to-item (posn)
"This function extracts extra info from the mouse event at position POSN.
It returns a list of the form (KEY KEY-BINDING CLOSE-P), where:
KEY is a symbol representing a tab, such as \\='tab-1 or \\='current-tab;
KEY-BINDING is the binding of KEY;
CLOSE-P is non-nil if the mouse event was a click on the close button \"x\",
nil otherwise."
(setq tab-bar-drag-maybe nil)
(if (posn-window posn)
(let ((caption (car (posn-string posn))))
(when caption
@ -259,31 +272,40 @@ a list of frames to update."
(setq column (+ column (length (nth 1 binding))))))
keymap))))))
(defun tab-bar-mouse-select-tab (event)
(defun tab-bar-mouse-down-1 (event)
"Select the tab at mouse click, or add a new tab on the tab bar.
Whether this command adds a new tab or selects an existing tab
depends on whether the click is on the \"+\" button or on an
existing tab."
(interactive "e")
(let* ((item (tab-bar--event-to-item (event-start event)))
(tab-number (tab-bar--key-to-number (nth 0 item))))
;; Don't close the tab when clicked on the close button.
;; Let `tab-bar-mouse-close-tab-from-button' do this.
(unless (nth 2 item)
(setq tab-bar-drag-maybe t)
;; Don't close the tab when clicked on the close button. Also
;; don't add new tab on down-mouse. Let `tab-bar-mouse-1' do this.
(unless (or (eq (car item) 'add-tab) (nth 2 item))
(if (functionp (nth 1 item))
(call-interactively (nth 1 item))
(unless (eq tab-number t)
(tab-bar-select-tab tab-number))))))
(defun tab-bar-mouse-close-tab-from-button (event)
"Close the tab only when clicked on the close button."
(defun tab-bar-mouse-1 (event)
"Close the tab whose \"x\" close button you click.
See also `tab-bar-mouse-close-tab', which closes the tab
regardless of where you click on it. Also add a new tab."
(interactive "e")
(let* ((item (tab-bar--event-to-item (event-start event)))
(tab-number (tab-bar--key-to-number (nth 0 item))))
(when (nth 2 item)
(unless (eq tab-number t)
(tab-bar-close-tab tab-number)))))
(cond
((and (eq (car item) 'add-tab) (functionp (nth 1 item)))
(call-interactively (nth 1 item)))
((and (nth 2 item) (not (eq tab-number t)))
(tab-bar-close-tab tab-number)))))
(defun tab-bar-mouse-close-tab (event)
"Close the tab when clicked anywhere on the tab.
This is in contrast with `tab-bar-mouse-close-tab-from-button'
that closes only when clicked on the close button."
"Close the tab you click on.
This is in contrast with `tab-bar-mouse-1' that closes a tab
only when you click on its \"x\" close button."
(interactive "e")
(let* ((item (tab-bar--event-to-item (event-start event)))
(tab-number (tab-bar--key-to-number (nth 0 item))))
@ -291,6 +313,7 @@ that closes only when clicked on the close button."
(tab-bar-close-tab tab-number))))
(defun tab-bar-mouse-context-menu (event)
"Pop up the context menu for the tab on which you click."
(interactive "e")
(let* ((item (tab-bar--event-to-item (event-start event)))
(tab-number (tab-bar--key-to-number (nth 0 item)))
@ -330,23 +353,28 @@ that closes only when clicked on the close button."
(popup-menu menu event)))
(defun tab-bar-mouse-move-tab (event)
"Move a tab to a different position on the tab bar.
This command should be bound to a drag event. It moves the tab
at the mouse-down event to the position at mouse-up event."
(interactive "e")
(setq tab-bar-drag-maybe nil)
(let ((from (tab-bar--key-to-number
(nth 0 (tab-bar--event-to-item
(event-start event)))))
(to (tab-bar--key-to-number
(nth 0 (tab-bar--event-to-item
(event-end event))))))
(unless (or (eq from t) (eq to t))
(tab-bar-move-tab-to to from))))
(unless (or (eq from to) (eq from t) (eq to t))
(tab-bar-move-tab-to
(if (null to) (1+ (tab-bar--current-tab-index)) to) from))))
(defvar tab-bar-map
(let ((map (make-sparse-keymap)))
(define-key map [down-mouse-1] 'tab-bar-mouse-select-tab)
(define-key map [down-mouse-1] 'tab-bar-mouse-down-1)
(define-key map [drag-mouse-1] 'tab-bar-mouse-move-tab)
(define-key map [mouse-1] 'tab-bar-mouse-close-tab-from-button)
(define-key map [mouse-1] 'tab-bar-mouse-1)
(define-key map [down-mouse-2] 'tab-bar-mouse-close-tab)
(define-key map [mouse-2] 'ignore)
(define-key map [mouse-2] 'ignore)
(define-key map [down-mouse-3] 'tab-bar-mouse-context-menu)
(define-key map [mouse-4] 'tab-previous)
@ -677,11 +705,14 @@ the formatted tab name to display in the tab bar."
"Template for displaying tab bar items.
Every item in the list is a function that returns
a string, or a list of menu-item elements, or nil.
When you add more items `tab-bar-format-align-right' and
`tab-bar-format-global' to the end, then after enabling
`display-time-mode' (or any other mode that uses `global-mode-string')
it will display time aligned to the right on the tab bar instead of
the mode line. Replacing `tab-bar-format-tabs' with
Adding a function to the list causes the tab bar to show
that string, or display a menu with those menu items when
you click on the tab bar.
If the list ends with `tab-bar-format-align-right' and
`tab-bar-format-global', then after enabling `display-time-mode'
(or any other mode that uses `global-mode-string'),
it will display time aligned to the right on the tab bar instead
of the mode line. Replacing `tab-bar-format-tabs' with
`tab-bar-format-tabs-groups' will group tabs on the tab bar."
:type 'hook
:options '(tab-bar-format-menu-global
@ -700,7 +731,7 @@ the mode line. Replacing `tab-bar-format-tabs' with
:version "28.1")
(defun tab-bar-format-menu-global ()
"Show global menu on clicking the Menu button."
"Produce the Menu button for the tab bar that shows a global menu."
`((add-tab menu-item (propertize "Menu" 'face 'tab-bar-tab-inactive)
(lambda (event) (interactive "e")
(let ((menu (make-sparse-keymap
@ -717,7 +748,8 @@ the mode line. Replacing `tab-bar-format-tabs' with
:help "Global Menu")))
(defun tab-bar-format-history ()
"Show back and forward buttons when `tab-bar-history-mode' is enabled.
"Produce back and forward buttons for the tab bar.
These buttons will be shown when `tab-bar-history-mode' is enabled.
You can hide these buttons by customizing `tab-bar-format' and removing
`tab-bar-format-history' from it."
(when tab-bar-history-mode
@ -731,7 +763,7 @@ You can hide these buttons by customizing `tab-bar-format' and removing
:help "Click to go forward in tab history"))))
(defun tab-bar--format-tab (tab i)
"Format TAB using its index I and return the result as a string."
"Format TAB using its index I and return the result as a keymap."
(append
`((,(intern (format "sep-%i" i)) menu-item ,(tab-bar-separator) ignore))
(cond
@ -753,7 +785,7 @@ You can hide these buttons by customizing `tab-bar-format' and removing
,(alist-get 'close-binding tab))))))
(defun tab-bar-format-tabs ()
"Show all tabs."
"Produce all the tabs for the tab bar."
(let ((i 0))
(mapcan
(lambda (tab)
@ -807,6 +839,9 @@ Function gets one argument: a tab."
(tab-bar-tab-face-default tab)))
(defun tab-bar--format-tab-group (tab i &optional current-p)
"Format TAB as a tab that represents a group of tabs.
The argument I is the tab index, and CURRENT-P is non-nil
when the tab is current. Return the result as a keymap."
(append
`((,(intern (format "sep-%i" i)) menu-item ,(tab-bar-separator) ignore))
`((,(intern (format "group-%i" i))
@ -824,7 +859,7 @@ Function gets one argument: a tab."
:help "Click to visit group"))))
(defun tab-bar-format-tabs-groups ()
"Show tabs with their groups."
"Produce tabs for the tab bar grouped according to their groups."
(let* ((tabs (funcall tab-bar-tabs-function))
(current-group (funcall tab-bar-tab-group-function
(tab-bar--current-tab-find tabs)))
@ -868,7 +903,7 @@ Function gets one argument: a tab."
`((align-right menu-item ,str ignore))))
(defun tab-bar-format-global ()
"Format `global-mode-string' to display it in the tab bar.
"Produce display of `global-mode-string' in the tab bar.
When `tab-bar-format-global' is added to `tab-bar-format'
(possibly appended after `tab-bar-format-align-right'),
then modes that display information on the mode line
@ -917,6 +952,7 @@ on the tab bar instead."
(push '(tabs . frameset-filter-tabs) frameset-filter-alist)
(defun tab-bar--tab (&optional frame)
"Make a new tab data structure that can be added to tabs on the FRAME."
(let* ((tab (tab-bar--current-tab-find nil frame))
(tab-explicit-name (alist-get 'explicit-name tab))
(tab-group (alist-get 'group tab))
@ -951,12 +987,15 @@ on the tab bar instead."
(cdr tab)))))
(defun tab-bar--current-tab (&optional tab frame)
"Make the current tab data structure from TAB on FRAME."
(tab-bar--current-tab-make (or tab (tab-bar--current-tab-find nil frame))))
(defun tab-bar--current-tab-make (&optional tab)
;; `tab' here is an argument meaning "use tab as template". This is
;; necessary when switching tabs, otherwise the destination tab
;; inherits the current tab's `explicit-name' parameter.
"Make the current tab data structure from TAB.
TAB here is an argument meaning \"use tab as template\",
i.e. the tab is created using data from TAB. This is
necessary when switching tabs, otherwise the destination tab
inherits the current tab's `explicit-name' parameter."
(let* ((tab-explicit-name (alist-get 'explicit-name tab))
(tab-group (if tab
(alist-get 'group tab)
@ -979,27 +1018,33 @@ on the tab bar instead."
(cdr tab)))))
(defun tab-bar--current-tab-find (&optional tabs frame)
;; Find the current tab as a pointer to its data structure.
(assq 'current-tab (or tabs (funcall tab-bar-tabs-function frame))))
(defun tab-bar--current-tab-index (&optional tabs frame)
;; Return the index of the current tab.
(seq-position (or tabs (funcall tab-bar-tabs-function frame))
'current-tab (lambda (a b) (eq (car a) b))))
(defun tab-bar--tab-index (tab &optional tabs frame)
;; Return the index of TAB.
(seq-position (or tabs (funcall tab-bar-tabs-function frame))
tab #'eq))
(defun tab-bar--tab-index-by-name (name &optional tabs frame)
;; Return the index of TAB by the its NAME.
(seq-position (or tabs (funcall tab-bar-tabs-function frame))
name (lambda (a b) (equal (alist-get 'name a) b))))
(defun tab-bar--tab-index-recent (nth &optional tabs frame)
;; Return the index of NTH recent tab.
(let* ((tabs (or tabs (funcall tab-bar-tabs-function frame)))
(sorted-tabs (tab-bar--tabs-recent tabs frame))
(tab (nth (1- nth) sorted-tabs)))
(tab-bar--tab-index tab tabs)))
(defun tab-bar--tabs-recent (&optional tabs frame)
;; Return the list of tabs sorted by recency.
(let* ((tabs (or tabs (funcall tab-bar-tabs-function frame))))
(seq-sort-by (lambda (tab) (alist-get 'time tab)) #'>
(seq-remove (lambda (tab)
@ -1089,7 +1134,8 @@ the tab bar."
(force-mode-line-update))))
(defun tab-bar-switch-to-next-tab (&optional arg)
"Switch to ARGth next tab."
"Switch to ARGth next tab.
Interactively, ARG is the prefix numeric argument and defaults to 1."
(interactive "p")
(unless (integerp arg)
(setq arg 1))
@ -1099,20 +1145,24 @@ the tab bar."
(tab-bar-select-tab (1+ to-index))))
(defun tab-bar-switch-to-prev-tab (&optional arg)
"Switch to ARGth previous tab."
"Switch to ARGth previous tab.
Interactively, ARG is the prefix numeric argument and defaults to 1."
(interactive "p")
(unless (integerp arg)
(setq arg 1))
(tab-bar-switch-to-next-tab (- arg)))
(defun tab-bar-switch-to-last-tab (&optional arg)
"Switch to the last tab or ARGth tab from the end of the tab bar."
"Switch to the last tab or ARGth tab from the end of the tab bar.
Interactively, ARG is the prefix numeric argument; it defaults to 1,
which means the last tab on the tab bar."
(interactive "p")
(tab-bar-select-tab (- (length (funcall tab-bar-tabs-function))
(1- (or arg 1)))))
(defun tab-bar-switch-to-recent-tab (&optional arg)
"Switch to ARGth most recently visited tab."
"Switch to ARGth most recently visited tab.
Interactively, ARG is the prefix numeric argument and defaults to 1."
(interactive "p")
(unless (integerp arg)
(setq arg 1))
@ -1160,8 +1210,9 @@ where argument addressing is relative."
(defun tab-bar-move-tab (&optional arg)
"Move the current tab ARG positions to the right.
If a negative ARG, move the current tab ARG positions to the left.
Argument addressing is relative in contrast to `tab-bar-move-tab-to'
Interactively, ARG is the prefix numeric argument and defaults to 1.
If ARG is negative, move the current tab ARG positions to the left.
Argument addressing is relative in contrast to `tab-bar-move-tab-to',
where argument addressing is absolute."
(interactive "p")
(let* ((tabs (funcall tab-bar-tabs-function))
@ -1171,6 +1222,7 @@ where argument addressing is absolute."
(defun tab-bar-move-tab-backward (&optional arg)
"Move the current tab ARG positions to the left.
Interactively, ARG is the prefix numeric argument and defaults to 1.
Like `tab-bar-move-tab', but moves in the opposite direction."
(interactive "p")
(tab-bar-move-tab (- (or arg 1))))
@ -1181,7 +1233,8 @@ FROM-NUMBER defaults to the current tab number.
FROM-NUMBER and TO-NUMBER count from 1.
FROM-FRAME specifies the source frame and defaults to the selected frame.
TO-FRAME specifies the target frame and defaults the next frame.
Interactively, ARG selects the ARGth different frame to move to."
Interactively, ARG selects the ARGth next frame on the same terminal,
to which to move the tab; ARG defaults to 1."
(interactive "P")
(unless from-frame
(setq from-frame (selected-frame)))
@ -1209,7 +1262,7 @@ Interactively, ARG selects the ARGth different frame to move to."
(defun tab-bar-detach-tab (&optional from-number)
"Move tab number FROM-NUMBER to a new frame.
Interactively or without argument, move the current tab."
FROM-NUMBER defaults to the current tab (which happens interactively)."
(interactive (list (1+ (tab-bar--current-tab-index))))
(let* ((tabs (funcall tab-bar-tabs-function))
(tab-index (1- (or from-number (1+ (tab-bar--current-tab-index tabs)))))
@ -1223,7 +1276,10 @@ Interactively or without argument, move the current tab."
(tab-bar-close-tab))))
(defun tab-bar-move-window-to-tab ()
"Detach the selected window to a new tab."
"Move the selected window to a new tab.
This command removes the selected window from the configuration stored
on the current tab, and makes a new tab with that window in its
configuration."
(interactive)
(let ((tab-bar-new-tab-choice 'window))
(tab-bar-new-tab))
@ -1233,17 +1289,17 @@ Interactively or without argument, move the current tab."
(defcustom tab-bar-new-tab-to 'right
"Defines where to create a new tab.
"Where to create a new tab.
If `leftmost', create as the first tab.
If `left', create to the left from the current tab.
If `right', create to the right from the current tab.
If `left', create to the left of the current tab.
If `right', create to the right of the current tab.
If `rightmost', create as the last tab.
If the value is a function, it should return a number as a position
on the tab bar specifying where to insert a new tab."
:type '(choice (const :tag "First tab" leftmost)
(const :tag "To the left" left)
(const :tag "To the right" right)
(const :tag "Last tab" rightmost)
on the tab bar specifying where to add a new tab."
:type '(choice (const :tag "Add as First" leftmost)
(const :tag "Add to Left" left)
(const :tag "Add to Right" right)
(const :tag "Add as Last" rightmost)
(function :tag "Function"))
:group 'tab-bar
:version "27.1")
@ -1262,7 +1318,7 @@ TAB-NUMBER counts from 1. If no TAB-NUMBER is specified, then add
a new tab at the position specified by `tab-bar-new-tab-to'.
Negative TAB-NUMBER counts tabs from the end of the tab bar,
and -1 means the new tab will become the last one.
Argument addressing is absolute in contrast to `tab-bar-new-tab'
Argument addressing is absolute in contrast to `tab-bar-new-tab',
where argument addressing is relative.
After the tab is created, the hooks in
`tab-bar-tab-post-open-functions' are run."
@ -1335,7 +1391,7 @@ If a negative ARG, create a new tab ARG positions to the left.
If ARG is zero, create a new tab in place of the current tab.
If no ARG is specified, then add a new tab at the position
specified by `tab-bar-new-tab-to'.
Argument addressing is relative in contrast to `tab-bar-new-tab-to'
Argument addressing is relative in contrast to `tab-bar-new-tab-to',
where argument addressing is absolute.
If FROM-NUMBER is a tab number, a new tab is created from that tab."
(interactive "P")
@ -1362,7 +1418,7 @@ ARG and FROM-NUMBER have the same meaning as in `tab-bar-new-tab'."
"A list of closed tabs to be able to undo their closing.")
(defcustom tab-bar-close-tab-select 'recent
"Defines what tab to select after closing the specified tab.
"Which tab to make current after closing the specified tab.
If `left', select the adjacent left tab.
If `right', select the adjacent right tab.
If `recent', select the most recently visited tab."
@ -1373,7 +1429,7 @@ If `recent', select the most recently visited tab."
:version "27.1")
(defcustom tab-bar-close-last-tab-choice nil
"Defines what to do when the last tab is closed.
"What to do when the last tab is closed.
If nil, do nothing and show a message, like closing the last window or frame.
If `delete-frame', delete the containing frame, as a web browser would do.
If `tab-bar-mode-disable', disable `tab-bar-mode' so that tabs no longer show
@ -1398,9 +1454,8 @@ function returns a non-nil value, the tab will not be closed."
(defcustom tab-bar-tab-pre-close-functions nil
"List of functions to call before closing a tab.
The tab to be closed and a boolean indicating whether or not it
is the only tab in the frame are supplied as arguments,
respectively."
Each function is called with two arguments: the tab to be closed
and a boolean indicating whether or not it is the only tab on its frame."
:type '(repeat function)
:group 'tab-bar
:version "27.1")
@ -1409,6 +1464,7 @@ respectively."
"Close the tab specified by its absolute position TAB-NUMBER.
If no TAB-NUMBER is specified, then close the current tab and switch
to the tab specified by `tab-bar-close-tab-select'.
Interactively, TAB-NUMBER is the prefix numeric argument, and defaults to 1.
TAB-NUMBER counts from 1.
Optional TO-NUMBER could be specified to override the value of
`tab-bar-close-tab-select' programmatically with a position
@ -1482,7 +1538,8 @@ for the last tab on a frame is determined by
(message "Deleted tab and switched to %s" tab-bar-close-tab-select))))))
(defun tab-bar-close-tab-by-name (name)
"Close the tab by NAME."
"Close the tab given its NAME.
Interactively, prompt for NAME."
(interactive
(list (completing-read "Close tab by name: "
(mapcar (lambda (tab)
@ -1491,8 +1548,9 @@ for the last tab on a frame is determined by
(tab-bar-close-tab (1+ (tab-bar--tab-index-by-name name))))
(defun tab-bar-close-other-tabs (&optional tab-number)
"Close all tabs on the selected frame, except TAB-NUMBER.
TAB-NUMBER counts from 1 and defaults to the current tab."
"Close all tabs on the selected frame, except the tab TAB-NUMBER.
TAB-NUMBER counts from 1 and defaults to the current tab (which
happens interactively)."
(interactive)
(let* ((tabs (funcall tab-bar-tabs-function))
(current-index (tab-bar--current-tab-index tabs))
@ -1558,9 +1616,12 @@ TAB-NUMBER counts from 1 and defaults to the current tab."
(defun tab-bar-rename-tab (name &optional tab-number)
"Rename the tab specified by its absolute position TAB-NUMBER.
"Give the tab specified by its absolute position TAB-NUMBER a new NAME.
If no TAB-NUMBER is specified, then rename the current tab.
Interactively, TAB-NUMBER is the prefix numeric argument, and defaults
to the current tab.
TAB-NUMBER counts from 1.
Interactively, prompt for the new NAME.
If NAME is the empty string, then use the automatic name
function `tab-bar-tab-name-function'."
(interactive
@ -1588,7 +1649,8 @@ function `tab-bar-tab-name-function'."
(message "Renamed tab to '%s'" tab-new-name))))
(defun tab-bar-rename-tab-by-name (tab-name new-name)
"Rename the tab named TAB-NAME.
"Rename the tab named TAB-NAME to NEW-NAME.
Interactively, prompt for TAB-NAME and NEW-NAME.
If NEW-NAME is the empty string, then use the automatic name
function `tab-bar-tab-name-function'."
(interactive
@ -1605,7 +1667,7 @@ function `tab-bar-tab-name-function'."
;;; Tab groups
(defun tab-bar-move-tab-to-group (&optional tab)
"Relocate TAB (or the current tab) closer to its group."
"Relocate TAB (by default, the current tab) closer to its group."
(interactive)
(let* ((tabs (funcall tab-bar-tabs-function))
(tab (or tab (tab-bar--current-tab-find tabs)))
@ -1643,6 +1705,8 @@ The current tab is supplied as an argument."
(defun tab-bar-change-tab-group (group-name &optional tab-number)
"Add the tab specified by its absolute position TAB-NUMBER to GROUP-NAME.
If no TAB-NUMBER is specified, then set the GROUP-NAME for the current tab.
Interactively, TAB-NUMBER is the prefix numeric argument, and the command
prompts for GROUP-NAME.
TAB-NUMBER counts from 1.
If GROUP-NAME is the empty string, then remove the tab from any group.
While using this command, you might also want to replace
@ -1680,7 +1744,8 @@ While using this command, you might also want to replace
(message "Set tab group to '%s'" group-new-name))))
(defun tab-bar-close-group-tabs (group-name)
"Close all tabs that belong to GROUP-NAME on the selected frame."
"Close all tabs that belong to GROUP-NAME on the selected frame.
Interactively, prompt for GROUP-NAME."
(interactive
(let ((group-name (funcall tab-bar-tab-group-function
(tab-bar--current-tab-find))))
@ -1727,7 +1792,7 @@ While using this command, you might also want to replace
(defun tab-bar--history-pre-change ()
(setq tab-bar-history-old-minibuffer-depth (minibuffer-depth))
;; Store wc before possibly entering the minibuffer
;; Store window-configuration before possibly entering the minibuffer.
(when (zerop tab-bar-history-old-minibuffer-depth)
(setq tab-bar-history-old
`((wc . ,(current-window-configuration))
@ -1736,7 +1801,8 @@ While using this command, you might also want to replace
(defun tab-bar--history-change ()
(when (and (not tab-bar-history-omit)
tab-bar-history-old
;; Store wc before possibly entering the minibuffer
;; Store window-configuration before possibly entering
;; the minibuffer.
(zerop tab-bar-history-old-minibuffer-depth))
(puthash (selected-frame)
(seq-take (cons tab-bar-history-old
@ -1928,12 +1994,16 @@ Letters do not insert themselves; instead, they are commands.
nil))))
(defun tab-switcher-next-line (&optional arg)
"Move to ARGth next line in the list of tabs.
Interactively, ARG is the prefix numeric argument and defaults to 1."
(interactive "p")
(forward-line arg)
(beginning-of-line)
(move-to-column tab-switcher-column))
(defun tab-switcher-prev-line (&optional arg)
"Move to ARGth previous line in the list of tabs.
Interactively, ARG is the prefix numeric argument and defaults to 1."
(interactive "p")
(forward-line (- arg))
(beginning-of-line)
@ -1941,7 +2011,7 @@ Letters do not insert themselves; instead, they are commands.
(defun tab-switcher-unmark (&optional backup)
"Cancel requested operations on window configuration on this line and move down.
Optional prefix arg means move up."
With prefix arg, move up instead."
(interactive "P")
(beginning-of-line)
(move-to-column tab-switcher-column)
@ -1961,7 +2031,7 @@ Optional prefix arg means move up."
(defun tab-switcher-delete (&optional arg)
"Mark window configuration on this line to be deleted by \\<tab-switcher-mode-map>\\[tab-switcher-execute] command.
Prefix arg is how many window configurations to delete.
Prefix arg says how many window configurations to delete.
Negative arg means delete backwards."
(interactive "p")
(let ((buffer-read-only nil))
@ -1986,7 +2056,7 @@ Then move up one line. Prefix arg means move that many lines."
(tab-switcher-delete (- (or arg 1))))
(defun tab-switcher-delete-from-list (tab)
"Delete the window configuration from both lists."
"Delete the window configuration from the list of tabs."
(push `((frame . ,(selected-frame))
(index . ,(tab-bar--tab-index tab))
(tab . ,tab))
@ -2014,8 +2084,8 @@ Then move up one line. Prefix arg means move that many lines."
(defun tab-switcher-select ()
"Select this line's window configuration.
This command deletes and replaces all the previously existing windows
in the selected frame."
This command replaces all the existing windows in the selected frame
with those specified by the selected window configuration."
(interactive)
(let* ((to-tab (tab-switcher-current-tab t)))
(kill-buffer (current-buffer))
@ -2041,8 +2111,8 @@ in the selected frame."
(t (list (selected-frame)))))
(defun tab-bar-get-buffer-tab (buffer-or-name &optional all-frames ignore-current-tab)
"Return a tab owning a window whose buffer is BUFFER-OR-NAME.
BUFFER-OR-NAME may be a buffer or a buffer name and defaults to
"Return the tab that owns the window whose buffer is BUFFER-OR-NAME.
BUFFER-OR-NAME may be a buffer or a buffer name, and defaults to
the current buffer.
The optional argument ALL-FRAMES specifies the frames to consider:
@ -2090,7 +2160,7 @@ Otherwise, prefer buffers of the current tab."
(tab-bar--reusable-frames all-frames)))))
(defun display-buffer-in-tab (buffer alist)
"Display BUFFER in a tab.
"Display BUFFER in a tab using display actions in ALIST.
ALIST is an association list of action symbols and values. See
Info node `(elisp) Buffer Display Action Alists' for details of
such alists.
@ -2098,8 +2168,8 @@ such alists.
If ALIST contains a `tab-name' entry, it creates a new tab with that name and
displays BUFFER in a new tab. If a tab with this name already exists, it
switches to that tab before displaying BUFFER. The `tab-name' entry can be
a function, then it is called with two arguments: BUFFER and ALIST, and
should return the tab name. When a `tab-name' entry is omitted, create
a function, in which case it is called with two arguments: BUFFER and ALIST,
and should return the tab name. When a `tab-name' entry is omitted, create
a new tab without an explicit name.
The ALIST entry `tab-group' (string or function) defines the tab group.
@ -2149,7 +2219,7 @@ indirectly called by the latter."
(display-buffer-in-new-tab buffer alist))))))
(defun display-buffer-in-new-tab (buffer alist)
"Display BUFFER in a new tab.
"Display BUFFER in a new tab using display actions in ALIST.
ALIST is an association list of action symbols and values. See
Info node `(elisp) Buffer Display Action Alists' for details of
such alists.
@ -2159,9 +2229,9 @@ without checking if a suitable tab already exists.
If ALIST contains a `tab-name' entry, it creates a new tab with that name
and displays BUFFER in a new tab. The `tab-name' entry can be a function,
then it is called with two arguments: BUFFER and ALIST, and should return
the tab name. When a `tab-name' entry is omitted, create a new tab without
an explicit name.
in which case it is called with two arguments: BUFFER and ALIST, and should
return the tab name. When a `tab-name' entry is omitted, create a new tab
without an explicit name.
The ALIST entry `tab-group' (string or function) defines the tab group.
@ -2183,19 +2253,23 @@ indirectly called by the latter."
(tab-bar-change-tab-group tab-group)))
(window--display-buffer buffer (selected-window) 'tab alist)))
(defun switch-to-buffer-other-tab (buffer-or-name &optional norecord)
(defun switch-to-buffer-other-tab (buffer-or-name &optional _norecord)
"Switch to buffer BUFFER-OR-NAME in another tab.
Like \\[switch-to-buffer-other-frame] (which see), but creates a new tab."
Like \\[switch-to-buffer-other-frame] (which see), but creates a new tab.
Interactively, prompt for the buffer to switch to."
(declare (advertised-calling-convention (buffer-or-name) "28.1"))
(interactive
(list (read-buffer-to-switch "Switch to buffer in other tab: ")))
(display-buffer (window-normalize-buffer-to-switch-to buffer-or-name)
'((display-buffer-in-tab)
(inhibit-same-window . nil))
norecord))
(inhibit-same-window . nil))))
(defun find-file-other-tab (filename &optional wildcards)
"Edit file FILENAME, in another tab.
Like \\[find-file-other-frame] (which see), but creates a new tab."
Like \\[find-file-other-frame] (which see), but creates a new tab.
Interactively, prompt for FILENAME.
If WILDCARDS is non-nil, FILENAME can include widcards, and all matching
files will be visited."
(interactive
(find-file-read-args "Find file in other tab: "
(confirm-nonexistent-file-or-buffer)))
@ -2212,7 +2286,10 @@ Like \\[find-file-other-frame] (which see), but creates a new tab."
"Edit file FILENAME, in another tab, but don't allow changes.
Like \\[find-file-other-frame] (which see), but creates a new tab.
Like \\[find-file-other-tab], but marks buffer as read-only.
Use \\[read-only-mode] to permit editing."
Use \\[read-only-mode] to permit editing.
Interactively, prompt for FILENAME.
If WILDCARDS is non-nil, FILENAME can include widcards, and all matching
files will be visited."
(interactive
(find-file-read-args "Find file read-only in other tab: "
(confirm-nonexistent-file-or-buffer)))

View File

@ -262,13 +262,14 @@ If nil, don't show it at all."
(defcustom tab-line-tab-name-function #'tab-line-tab-name-buffer
"Function to get a tab name.
Function gets two arguments: tab to get name for and a list of tabs
to display. By default, use function `tab-line-tab-name'."
The function is called with one or two arguments: the buffer or
another object whose tab's name is requested, and, optionally,
the list of all tabs."
:type '(choice (const :tag "Buffer name"
tab-line-tab-name-buffer)
(const :tag "Truncated buffer name"
tab-line-tab-name-truncated-buffer)
(function :tag "Function"))
(function :tag "Function"))
:initialize 'custom-initialize-default
:set (lambda (sym val)
(set-default sym val)
@ -294,9 +295,9 @@ to `tab-line-tab-name-truncated-buffer'."
(defvar tab-line-tab-name-ellipsis t)
(defun tab-line-tab-name-truncated-buffer (buffer &optional _buffers)
"Generate tab name from BUFFER.
"Generate tab name from BUFFER, truncating it as needed.
Truncate it to the length specified by `tab-line-tab-name-truncated-max'.
Append ellipsis `tab-line-tab-name-ellipsis' in this case."
If truncated, append ellipsis per `tab-line-tab-name-ellipsis'."
(let ((tab-name (buffer-name buffer)))
(if (< (length tab-name) tab-line-tab-name-truncated-max)
tab-name
@ -343,7 +344,7 @@ Used only for `tab-line-tabs-mode-buffers' and `tab-line-tabs-buffer-groups'.")
(buffer-list)))))
(defun tab-line-tabs-mode-buffers ()
"Return a list of buffers with the same major mode with current buffer."
"Return a list of buffers with the same major mode as the current buffer."
(let ((mode major-mode))
(seq-sort-by #'buffer-name #'string<
(seq-filter (lambda (b) (with-current-buffer b
@ -351,12 +352,12 @@ Used only for `tab-line-tabs-mode-buffers' and `tab-line-tabs-buffer-groups'.")
(funcall tab-line-tabs-buffer-list-function)))))
(defvar tab-line-tabs-buffer-group-function nil
"Function to put a buffer to the group.
Takes a buffer as arg and should return a group name as string.
When the return value is nil, filter out the buffer.")
"Function to add a buffer to the appropriate group of tabs.
Takes a buffer as arg and should return a group name as a string.
If the return value is nil, the buffer should be filtered out.")
(defvar tab-line-tabs-buffer-group-sort-function nil
"Function to sort buffers in group.")
"Function to sort buffers in a group.")
(defvar tab-line-tabs-buffer-groups-sort-function #'string<
"Function to sort group names.")
@ -364,7 +365,9 @@ When the return value is nil, filter out the buffer.")
(defvar tab-line-tabs-buffer-groups mouse-buffer-menu-mode-groups
"How to group various major modes together in the tab line.
Each element has the form (REGEXP . GROUPNAME).
If the major mode's name string matches REGEXP, use GROUPNAME instead.")
If the major mode's name matches REGEXP, it belongs to GROUPNAME.
The default is for each major mode to have a separate group
named the same as the mode.")
(defun tab-line-tabs-buffer-group-name (&optional buffer)
(if (functionp tab-line-tabs-buffer-group-function)
@ -460,8 +463,11 @@ variable `tab-line-tabs-function'."
(defcustom tab-line-tab-name-format-function #'tab-line-tab-name-format-default
"Function to format a tab name.
Function gets two arguments: the tab and a list of all tabs, and
should return the formatted tab name to display in the tab line."
The function will be called two arguments: the tab whose name to format,
and the list of all the tabs; it should return the formatted tab name
to display in the tab line.
The first argument could also be a different object, for example the buffer
which the tab will represent."
:type 'function
:initialize 'custom-initialize-default
:set (lambda (sym val)
@ -471,6 +477,7 @@ should return the formatted tab name to display in the tab line."
:version "28.1")
(defun tab-line-tab-name-format-default (tab tabs)
"Default function to use as `tab-line-tab-name-format-function', which see."
(let* ((buffer-p (bufferp tab))
(selected-p (if buffer-p
(eq tab (window-buffer))
@ -503,7 +510,8 @@ should return the formatted tab name to display in the tab line."
mouse-face tab-line-highlight))))
(defun tab-line-format-template (tabs)
"Template for displaying tab line for selected window."
"Template of the format for displaying tab line for selected window.
This is used by `tab-line-format'."
(let* ((separator (or tab-line-separator (if window-system " " "|")))
(hscroll (window-parameter nil 'tab-line-hscroll))
(strings
@ -535,7 +543,8 @@ should return the formatted tab name to display in the tab line."
(defun tab-line-tab-face-inactive-alternating (tab tabs face _buffer-p selected-p)
"Return FACE for TAB in TABS with alternation.
When TAB is an inactive buffer and is even-numbered, make FACE
SELECTED-P nil means TAB is not the selected tab.
When TAB is not selected and is even-numbered, make FACE
inherit from `tab-line-tab-inactive-alternate'. For use in
`tab-line-tab-face-functions'."
(when (and (not selected-p) (cl-evenp (cl-position tab tabs)))
@ -543,8 +552,8 @@ inherit from `tab-line-tab-inactive-alternate'. For use in
face)
(defun tab-line-tab-face-special (tab _tabs face buffer-p _selected-p)
"Return FACE for TAB according to whether it's special.
When TAB is a non-file-backed buffer, make FACE inherit from
"Return FACE for TAB according to whether its buffer is special.
When TAB is a non-file-visiting buffer, make FACE inherit from
`tab-line-tab-special'. For use in
`tab-line-tab-face-functions'."
(when (and buffer-p (not (buffer-file-name tab)))
@ -552,7 +561,7 @@ When TAB is a non-file-backed buffer, make FACE inherit from
face)
(defun tab-line-tab-face-modified (tab _tabs face buffer-p _selected-p)
"Return FACE for TAB according to whether it's modified.
"Return FACE for TAB according to whether its buffer is modified.
When TAB is a modified, file-backed buffer, make FACE inherit
from `tab-line-tab-modified'. For use in
`tab-line-tab-face-functions'."
@ -570,7 +579,7 @@ For use in `tab-line-tab-face-functions'."
(defvar tab-line-auto-hscroll)
(defun tab-line-format ()
"Template for displaying tab line for selected window."
"Format for displaying the tab line of the selected window."
(let* ((tabs (funcall tab-line-tabs-function))
(cache-key (list tabs
;; handle buffer renames
@ -598,7 +607,7 @@ For use in `tab-line-tab-face-functions'."
(defcustom tab-line-auto-hscroll t
"Allow or disallow automatic horizontal scrolling of the tab line.
Non-nil means the tab line are automatically scrolled horizontally to make
Non-nil means the tab lines are automatically scrolled horizontally to make
the selected tab visible."
:type 'boolean
:group 'tab-line
@ -694,12 +703,16 @@ the selected tab visible."
(force-mode-line-update t))))
(defun tab-line-hscroll-right (&optional arg event)
"Scroll the tab line ARG positions to the right.
Interactively, ARG is the prefix numeric argument and defaults to 1."
(interactive (list current-prefix-arg last-nonmenu-event))
(let ((window (and (listp event) (posn-window (event-start event)))))
(tab-line-hscroll arg window)
(force-mode-line-update window)))
(defun tab-line-hscroll-left (&optional arg event)
"Scroll the tab line ARG positions to the left.
Interactively, ARG is the prefix numeric argument and defaults to 1."
(interactive (list current-prefix-arg last-nonmenu-event))
(let ((window (and (listp event) (posn-window (event-start event)))))
(tab-line-hscroll (- (or arg 1)) window)
@ -707,10 +720,10 @@ the selected tab visible."
(defun tab-line-new-tab (&optional event)
"Add a new tab to the tab line.
Usually is invoked by clicking on the plus-shaped button.
But any switching to other buffer also adds a new tab
corresponding to the switched buffer."
"Add a new tab to the selected-window's tab line.
This command is usually invoked by clicking on the plus-shaped button
on the tab line. Switching to another buffer also adds a new tab
corresponding to the new buffer shown in the window."
(interactive (list last-nonmenu-event))
(if (functionp tab-line-new-tab-choice)
(funcall tab-line-new-tab-choice)
@ -723,9 +736,9 @@ corresponding to the switched buffer."
(tmm-prompt (mouse-buffer-menu-keymap))))))
(defun tab-line-select-tab (&optional event)
"Switch to the selected tab.
"Switch to the buffer specified by the tab on which you click.
This command maintains the original order of prev/next buffers.
So for example, switching to a previous tab is equivalent to
So, for example, switching to a previous tab is equivalent to
using the `previous-buffer' command."
(interactive "e")
(let* ((posnp (event-start event))
@ -771,7 +784,7 @@ when `tab-line-tabs-function' is `tab-line-tabs-window-buffers'."
:version "28.1")
(defun tab-line-switch-to-prev-tab (&optional event)
"Switch to the previous tab.
"Switch to the previous tab's buffer.
Its effect is the same as using the `previous-buffer' command
(\\[previous-buffer])."
(interactive (list last-nonmenu-event))
@ -795,7 +808,7 @@ Its effect is the same as using the `previous-buffer' command
(switch-to-buffer buffer)))))))
(defun tab-line-switch-to-next-tab (&optional event)
"Switch to the next tab.
"Switch to the next tab's buffer.
Its effect is the same as using the `next-buffer' command
(\\[next-buffer])."
(interactive (list last-nonmenu-event))
@ -820,9 +833,9 @@ Its effect is the same as using the `next-buffer' command
(defcustom tab-line-close-tab-function 'bury-buffer
"Defines what to do on closing the tab.
"What to do upon closing a tab on the tab line.
If `bury-buffer', put the tab's buffer at the end of the list of all
buffers that effectively hides the buffer's tab from the tab line.
buffers, which effectively hides the buffer's tab from the tab line.
If `kill-buffer', kills the tab's buffer.
When a function, it is called with the tab as its argument.
This option is useful when `tab-line-tabs-function' has the value
@ -835,9 +848,9 @@ This option is useful when `tab-line-tabs-function' has the value
(defun tab-line-close-tab (&optional event)
"Close the selected tab.
Usually is invoked by clicking on the close button on the right side
of the tab. This command buries the buffer, so it goes out of sight
from the tab line."
This command is usually invoked by clicking on the close button on the
right side of the tab. This command buries the buffer, so it goes out of
sight of the tab line."
(interactive (list last-nonmenu-event))
(let* ((posnp (and (listp event) (event-start event)))
(window (and posnp (posn-window posnp)))
@ -860,7 +873,7 @@ from the tab line."
(force-mode-line-update))))
(defun tab-line-tab-context-menu (&optional event)
"Pop up context menu for the tab."
"Pop up the context menu for a tab-line tab."
(interactive "e")
(let ((menu (make-sparse-keymap (propertize "Context Menu" 'hide t))))
(define-key-after menu [close]
@ -868,7 +881,7 @@ from the tab line."
(popup-menu menu event)))
(defun tab-line-context-menu (&optional event)
"Pop up context menu for the tab line."
"Pop up the context menu for the tab line."
(interactive "e")
(let ((menu (make-sparse-keymap (propertize "Context Menu" 'hide t))))
(define-key-after menu [close]
@ -878,13 +891,15 @@ from the tab line."
;;;###autoload
(define-minor-mode tab-line-mode
"Toggle display of window tab line in the buffer."
"Toggle display of tab line in the windows displaying the current buffer."
:lighter nil
(setq tab-line-format (when tab-line-mode '(:eval (tab-line-format)))))
(defcustom tab-line-exclude-modes
'(completion-list-mode)
"List of major modes in which the tab line is not enabled."
"List of major modes for which the tab-line display is not enabled.
Buffers under any of these major modes will not show the tab line in
their windows, even if `global-tab-line-mode' is enabled."
:type '(repeat symbol)
:group 'tab-line
:version "27.1")
@ -893,7 +908,12 @@ from the tab line."
(defvar-local tab-line-exclude nil)
(defun tab-line-mode--turn-on ()
"Turn on `tab-line-mode'."
"Turn on `tab-line-mode' in all pertinent buffers.
Temporary buffers, buffers whose names begin with a space, buffers
under major modes that are either mentioned in `tab-line-exclude-mode'
or have a non-nil `tab-line-exclude' property on their symbol,
and buffers that have a non-nil buffer-local value
of `tab-line-exclude', are exempt from `tab-line-mode'."
(unless (or (minibufferp)
(string-match-p "\\` " (buffer-name))
(memq major-mode tab-line-exclude-modes)

View File

@ -9995,10 +9995,16 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
if (!STRINGP (lcss))
{
/* Generate the CSS for the SVG image. */
const char *css_spec = "svg{font-family:\"%s\";font-size:%4dpx}";
int css_len = strlen (css_spec) + strlen (img->face_font_family);
/* FIXME: The below calculations leave enough space for a font
size up to 9999, if it overflows we just throw an error but
should probably increase the buffer size. */
const char *css_spec = "svg{font-family:\"%s\";font-size:%dpx}";
int css_len = strlen (css_spec) + strlen (img->face_font_family) + 1;
css = xmalloc (css_len);
snprintf (css, css_len, css_spec, img->face_font_family, img->face_font_size);
if (css_len <= snprintf (css, css_len, css_spec,
img->face_font_family, img->face_font_size))
goto rsvg_error;
rsvg_handle_set_stylesheet (rsvg_handle, (guint8 *)css, strlen (css), NULL);
}
else
@ -10156,12 +10162,11 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
wrapped_contents = xmalloc (buffer_size);
if (!wrapped_contents
|| buffer_size <= snprintf (wrapped_contents, buffer_size, wrapper,
foreground & 0xFFFFFF, width, height,
viewbox_width, viewbox_height,
background & 0xFFFFFF,
SSDATA (encoded_contents)))
if (buffer_size <= snprintf (wrapped_contents, buffer_size, wrapper,
foreground & 0xFFFFFF, width, height,
viewbox_width, viewbox_height,
background & 0xFFFFFF,
SSDATA (encoded_contents)))
goto rsvg_error;
wrapped_size = strlen (wrapped_contents);

View File

@ -609,13 +609,72 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side.
}
}
void
ns_change_tab_bar_height (struct frame *f, int height)
{
int unit = FRAME_LINE_HEIGHT (f);
int old_height = FRAME_TAB_BAR_HEIGHT (f);
int lines = (height + unit - 1) / unit;
Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
/* Make sure we redisplay all windows in this frame. */
fset_redisplay (f);
/* Recalculate tab bar and frame text sizes. */
FRAME_TAB_BAR_HEIGHT (f) = height;
FRAME_TAB_BAR_LINES (f) = lines;
store_frame_param (f, Qtab_bar_lines, make_fixnum (lines));
if (FRAME_NS_WINDOW (f) && FRAME_TAB_BAR_HEIGHT (f) == 0)
{
clear_frame (f);
clear_current_matrices (f);
}
if ((height < old_height) && WINDOWP (f->tab_bar_window))
clear_glyph_matrix (XWINDOW (f->tab_bar_window)->current_matrix);
if (!f->tab_bar_resized)
{
/* As long as tab_bar_resized is false, effectively try to change
F's native height. */
if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth))
adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
1, false, Qtab_bar_lines);
else
adjust_frame_size (f, -1, -1, 4, false, Qtab_bar_lines);
f->tab_bar_resized = f->tab_bar_redisplayed;
}
else
/* Any other change may leave the native size of F alone. */
adjust_frame_size (f, -1, -1, 3, false, Qtab_bar_lines);
/* adjust_frame_size might not have done anything, garbage frame
here. */
adjust_frame_glyphs (f);
SET_FRAME_GARBAGED (f);
}
/* tabbar support */
static void
ns_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
{
/* Currently unimplemented. */
NSTRACE ("ns_set_tab_bar_lines");
int olines = FRAME_TAB_BAR_LINES (f);
int nlines;
/* Treat tab bars like menu bars. */
if (FRAME_MINIBUF_ONLY_P (f))
return;
/* Use VALUE only if an int >= 0. */
if (RANGED_FIXNUMP (0, value, INT_MAX))
nlines = XFIXNAT (value);
else
nlines = 0;
if (nlines != olines && (olines == 0 || nlines == 0))
ns_change_tab_bar_height (f, nlines * FRAME_LINE_HEIGHT (f));
}

View File

@ -1136,6 +1136,7 @@ extern void ns_implicitly_set_name (struct frame *f, Lisp_Object arg,
Lisp_Object oldval);
extern void ns_set_scroll_bar_default_width (struct frame *f);
extern void ns_set_scroll_bar_default_height (struct frame *f);
extern void ns_change_tab_bar_height (struct frame *f, int height);
extern const char *ns_get_string_resource (void *_rdb,
const char *name,
const char *class);

View File

@ -2721,11 +2721,10 @@ Hide the window (X11 semantics)
if (FRAME_LIVE_P (f) && FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
{
int border_width = FRAME_INTERNAL_BORDER_WIDTH (f);
NSView *view = FRAME_NS_VIEW (f);
NSRect edge_rect, frame_rect = [view bounds];
NSRectEdge edge[] = {NSMinXEdge, NSMinYEdge, NSMaxXEdge, NSMaxYEdge};
int border = FRAME_INTERNAL_BORDER_WIDTH (f);
int width = FRAME_PIXEL_WIDTH (f);
int height = FRAME_PIXEL_HEIGHT (f);
int margin = FRAME_TOP_MARGIN_HEIGHT (f);
int face_id =
(FRAME_PARENT_FRAME (f)
? (!NILP (Vface_remapping_alist)
@ -2747,12 +2746,12 @@ Hide the window (X11 semantics)
ns_focus (f, NULL, 1);
[ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
for (int i = 0; i < 4 ; i++)
{
NSDivideRect (frame_rect, &edge_rect, &frame_rect, border_width, edge[i]);
NSRectFill (edge_rect);
}
NSRectFill (NSMakeRect (0, margin, width, border));
NSRectFill (NSMakeRect (0, 0, border, height));
NSRectFill (NSMakeRect (0, margin, width, border));
NSRectFill (NSMakeRect (width - border, 0, border, height));
NSRectFill (NSMakeRect (0, height - border, width, border));
ns_unfocus (f);
}
}
@ -5066,6 +5065,7 @@ static Lisp_Object ns_new_font (struct frame *f, Lisp_Object font_object,
terminal->free_pixmap = ns_free_pixmap;
terminal->delete_frame_hook = ns_destroy_window;
terminal->delete_terminal_hook = ns_delete_terminal;
terminal->change_tab_bar_height_hook = ns_change_tab_bar_height;
/* Other hooks are NULL by default. */
return terminal;
@ -6675,7 +6675,27 @@ - (void)mouseDown: (NSEvent *)theEvent
}
else
{
emacs_event->kind = MOUSE_CLICK_EVENT;
Lisp_Object tab_bar_arg = Qnil;
bool tab_bar_p = false;
if (WINDOWP (emacsframe->tab_bar_window)
&& WINDOW_TOTAL_LINES (XWINDOW (emacsframe->tab_bar_window)))
{
Lisp_Object window;
int x = lrint (p.x);
int y = lrint (p.y);
window = window_from_coordinates (emacsframe, x, y, 0, true, true);
tab_bar_p = EQ (window, emacsframe->tab_bar_window);
if (tab_bar_p)
tab_bar_arg = handle_tab_bar_click (emacsframe, x, y, EV_UDMODIFIERS (theEvent) & down_modifier,
EV_MODIFIERS (theEvent) | EV_UDMODIFIERS (theEvent));
}
if (!(tab_bar_p && NILP (tab_bar_arg)))
emacs_event->kind = MOUSE_CLICK_EVENT;
emacs_event->arg = tab_bar_arg;
emacs_event->code = EV_BUTTON (theEvent);
emacs_event->modifiers = EV_MODIFIERS (theEvent)
| EV_UDMODIFIERS (theEvent);

View File

@ -765,6 +765,19 @@ selected one. */)
{
return make_fixnum (decode_live_window (window)->use_time);
}
DEFUN ("window-bump-use-time", Fwindow_bump_use_time,
Swindow_bump_use_time, 0, 1, 0,
doc: /* Mark WINDOW as having been most recently used.
WINDOW must be a live window and defaults to the selected one. */)
(Lisp_Object window)
{
struct window *w = decode_live_window (window);
w->use_time = ++window_select_count;
return Qnil;
}
DEFUN ("window-pixel-width", Fwindow_pixel_width, Swindow_pixel_width, 0, 1, 0,
doc: /* Return the width of window WINDOW in pixels.
@ -8122,18 +8135,6 @@ and scrolling positions. */)
return Qt;
return Qnil;
}
DEFUN ("window-bump-use-time", Fwindow_bump_use_time,
Swindow_bump_use_time, 1, 1, 0,
doc: /* Mark WINDOW as having been recently used. */)
(Lisp_Object window)
{
struct window *w = decode_valid_window (window);
w->use_time = ++window_select_count;
return Qnil;
}
static void init_window_once_for_pdumper (void);

View File

@ -33780,7 +33780,13 @@ note_mouse_highlight (struct frame *f, int x, int y)
if (EQ (window, f->tab_bar_window))
{
note_tab_bar_highlight (f, x, y);
return;
if (tab_bar_drag_maybe)
{
cursor = FRAME_OUTPUT_DATA (f)->hand_cursor;
goto set_cursor;
}
else
return;
}
#endif
@ -35910,6 +35916,10 @@ When nil, mouse-movement events will not be generated as long as the
mouse stays within the extent of a single glyph (except for images). */);
mouse_fine_grained_tracking = false;
DEFVAR_BOOL ("tab-bar-drag-maybe", tab_bar_drag_maybe,
doc: /* Non-nil when maybe dragging tab bar item. */);
tab_bar_drag_maybe = false;
DEFVAR_BOOL ("redisplay-skip-initial-frame", redisplay_skip_initial_frame,
doc: /* Non-nil to skip redisplay in initial frame.
The initial frame is not displayed anywhere, so skipping it is

View File

@ -124,6 +124,11 @@ gcc version 2.95.2 19991024 (release)"
"Test the output parser against the machine currently running Emacs."
(skip-unless (executable-find "gcc"))
(let ((semantic-gcc-test-strings (list (semantic-gcc-query "gcc" "-v"))))
(semantic-gcc-test-output-parser)))
;; Some macOS machines run llvm when you type gcc. (!)
;; We can't even check if it's a symlink; it's a binary placed in
;; "/usr/bin/gcc". So check the output and just skip this test if
;; it says "Apple LLVM".
(unless (string-match "Apple LLVM" (car semantic-gcc-test-strings))
(semantic-gcc-test-output-parser))))
;;; gcc-tests.el ends here