Merge from origin/emacs-30

d509a35699 Fix regression in widget-move (bug#72995)
ef0276de82 ; * lisp/cus-edit.el (setopt): Doc fix.  (Bug#73098)
b115c2d5eb ; * lisp/minibuffer.el (completion-pcm--merge-completions...
3cda1fdc3b Correctly include fixed strings before a prefix wildcard ...
57d93d0259 ; * lisp/treesit.el (treesit-major-mode-setup): Doc fix.
ad289f364e ; Improve documentation of 'easy-menu-define'
3cad7cc8dc Set treesit-primary-parser for c and elixir ts mode
2f243fb91d ; Minor doc fix in treesit.el
6a6d7925c9 Fix range handling so it works for multibyte buffer (bug#...
76faf7e609 Revert "Read more on each call to treesit's buffer reader"
c70bd0e3fe Fix tree-sitter indent preset prev-adaptive-prefix
272df33fb8 ; * CONTRIBUTE: Minor copyedits.
8e1187e336 Improve NEWS entries
ca3932121a Don't fail uniquify-tests in non-version-controlled sourc...
79f68597ab ; * etc/ORG-NEWS: Fix typo.
d66b70f360 * doc/misc/auth.texi: Minor copy edits.
2c6b7b2da9 ; * admin/MAINTAINERS: Remove some entries for Artur Mala...
11e7ae3964 Fix bug#72254

# Conflicts:
#	etc/NEWS
This commit is contained in:
Eli Zaretskii 2024-09-14 07:55:01 -04:00
commit 0cf9886cdf
20 changed files with 317 additions and 174 deletions

View file

@ -208,8 +208,9 @@ formatting them:
- Unindented ChangeLog entries normally come next. However, if the
commit couldn't be properly summarized in the brief summary line,
you can put a paragraph (after the empty line and before the
individual ChangeLog entries) that further describes the commit.
you can put one or more paragraphs (after the empty line and before
the individual ChangeLog entries) that further describe(s) the
commit.
- Lines in ChangeLog entries should preferably be not longer than 63
characters, and must not exceed 78 characters, unless they consist

View file

@ -58,9 +58,7 @@ Bastien Guerry
doc/misc/org.texi
Artur Malabarba
lisp/emacs-lisp/package.el
lisp/emacs-lisp/let-alist.el
lisp/character-fold.el
Michael Albinus
Tramp
@ -295,9 +293,6 @@ Stefan Monnier
lisp/progmodes/tcl.el
lisp/emacs-lisp/easymenu.el
Artur Malabarba
lisp/isearch.el
Paul Eggert
.dir-locals.el
.gitattributes

View file

@ -3243,7 +3243,8 @@ contents are given by @var{menu}.
If @var{symbol} is non-@code{nil}, it should be a symbol; then this
macro defines @var{symbol} as a function for popping up the menu
(@pxref{Pop-Up Menus}), with @var{doc} as its documentation string.
(@pxref{Pop-Up Menus}), with @var{doc} as its documentation string. It
also defines @var{symbol} as a variable whose value is the menu.
@var{symbol} should not be quoted.
Regardless of the value of @var{symbol}, if @var{maps} is a keymap,

View file

@ -73,7 +73,7 @@ It is a way for multiple applications to share a single configuration
@chapter Overview
The auth-source library is simply a way for Emacs and Gnus, among
others, to answer the old burning question ``What are my user name and
others, to answer the old burning question ``What is my user name and
password?''
(This is different from the old question about burning ``Where is the
@ -82,11 +82,11 @@ fire extinguisher, please?''.)
The auth-source library supports more than just the user name or the
password (known as the secret).
Similarly, the auth-source library supports multiple storage backend,
Similarly, the auth-source library supports multiple storage backends,
currently either the classic ``netrc'' backend, examples of which you
can see later in this document, JSON files, the Secret Service API, and pass, the
standard unix password manager. This is done with EIEIO-based
backends and you can write your own if you want.
can see later in this document, JSON files, the Secret Service API, and
@samp{pass}, the standard unix password manager. This is done with
EIEIO-based backends, and you can write your own if you want.
@node Help for users
@chapter Help for users
@ -363,7 +363,7 @@ collections such as @code{"login"}.
With GNOME Keyring, there exists a special collection called
@code{"session"}, which has the lifetime of the user being logged in.
Its data are not stored on disk and go away when the user logs out.
Its data is not stored on disk and goes away when the user logs out.
Therefore, it can be used to store and retrieve secret items
temporarily. The @code{"session"} collection is better than a
persistent collection when the secret items should not live
@ -372,7 +372,7 @@ by the string @code{"session"}, or by @code{nil}, whenever a
collection parameter is needed.
However, other Secret Service provider don't create this temporary
@code{"session"} collection. You shall check first that this
@code{"session"} collection. You must check first that this
collection exists, before you use it.
@defun secrets-list-items collection
@ -474,13 +474,13 @@ functions.
@chapter The Unix password store
@uref{https://www.passwordstore.org,,The standard unix password
manager} (or just @code{pass}) stores your passwords in
manager} (or just @samp{pass}) stores your passwords in
@code{gpg}-protected files following the Unix philosophy. The store
location (any directory) must be specified in the
@code{auth-source-pass-filename} variable which defaults to
@file{~/.password-store}.
Emacs integration of @code{pass} follows the approach suggested by the
Emacs integration of @samp{pass} follows the approach suggested by the
pass project itself for data organization to find data. In
particular, to store a password for the user @code{rms} on the host
@code{gnu.org} and port @code{22}, you should use one of the following
@ -531,12 +531,13 @@ while searching for an entry matching the @code{rms} user on host
However, such processing is not applied when the option
@code{auth-source-pass-extra-query-keywords} is set to @code{t}.
Users of @code{pass} may also be interested in functionality provided
Users of @samp{pass} may also be interested in functionality provided
by other Emacs packages:
@itemize
@item
@uref{https://git.zx2c4.com/password-store/tree/contrib/emacs/password-store.el,,password-store}: library wrapping @code{pass};
@uref{https://git.zx2c4.com/password-store/tree/contrib/emacs/password-store.el,,password-store}:
library wrapping @samp{pass};
@item
@uref{https://github.com/NicolasPetton/pass,,pass}: major mode to manipulate the store and edit entries;
@item
@ -585,7 +586,7 @@ The auth-source library only has a few functions for external use.
@defun auth-source-search &rest spec &key type max host user port secret require create delete &allow-other-keys
This function searches (or modifies) authentication backends according
to @var{spec}. See the function's doc-string for details.
to @var{spec}. See the function's docstring for details.
@c TODO more details.
@end defun
@ -635,8 +636,6 @@ authentication information we just used, if it was newly created.''
After the first time it's called, the @code{:save-function} will not
run again (but it will log something if you have set
@code{auth-source-debug} to @code{'trivia}). This is so it won't ask
the same question again, which is annoying. This is so it won't ask
the same question again, which is annoying. This is so it won't ask
the same question again, which is annoying.
So the responsibility of the API user that specified @code{:create t}

View file

@ -150,7 +150,7 @@ number has been bumped to 2048 bits.
+++
** URL now never sends user email addresses in HTTP requests.
Emacs never sent email addresses by default, but it used to be
possible to customize 'url-privacy-level' so that the users email
possible to customize 'url-privacy-level' so that the user's email
address was sent along in HTTP requests. This feature has now been
removed, as it was considered more dangerous than useful. RFC 9110
(§ 10.1.2) also recommends against it. The user option
@ -670,15 +670,15 @@ that shows as diffs replacements in the marked files in Dired.
+++
** New mode of prompting for register names and showing preview.
The new user option 'register-use-preview' can be customized to the
value t or insist to request a different user interface of prompting for
value t or 'insist' to request a different user interface of prompting for
register names and previewing the registers: Emacs will require
confirmation for overwriting the value of a register, and will show
the preview of registers without delay. You can also customize this
new option to disable the preview completely.
The default value of 'register-use-preview' preserves the behavior of
Emacs 29 and before. See the Info node "(emacs) Registers" for more
details about the new UI and its variants.
The default value of 'register-use-preview' ('traditional') preserves the
behavior of Emacs 29 and before. See the Info node "(emacs) Registers"
for more details about the new UI and its variants.
+++
** New advanced macro counter commands.
@ -1464,8 +1464,8 @@ bookmark URIs.
*** New command 'eww-copy-alternate-url'.
It copies an alternate link on the page currently visited in EWW into
the kill ring. Alternate links are optional metadata that HTML pages
use for linking to their alternative representations, such as
translated versions or associated RSS feeds.
use for linking to their alternative representations, such as translated
versions or associated RSS feeds. It is bound to 'A' by default.
+++
*** 'eww-open-in-new-buffer' supports the prefix argument.
@ -1565,9 +1565,10 @@ following to your init file:
---
*** New user option 'package-vc-register-as-project'.
When non-nil, it will automatically register every package as a
project, that you can quickly select using 'project-switch-project'
('C-x p p').
When non-nil, 'package-vc-install' and 'package-vc-checkout' will
automatically register every package they install as a project, that you
can quickly select using 'project-switch-project' ('C-x p p'). Default
is t.
---
*** New user option 'package-vc-allow-build-commands'.
@ -1592,9 +1593,9 @@ in a clean environment.
+++
*** New user option 'flymake-indicator-type'.
This user option controls which error indicator type Flymake should use
in current buffer. Depending on your preference, this can either use
fringes or margins for indicating errors.
This controls which error indicator type Flymake should use in the
current buffer. Depending on your preference, this can either use
fringes or margins for indicating errors, the default is 'margins'.
+++
*** New user option 'flymake-margin-indicators-string'.
@ -1603,14 +1604,14 @@ the margin indicator.
+++
*** New user option 'flymake-autoresize-margins'.
If non-nil, Flymake will resize the margins when 'flymake-mode' is
turned on or off.
If non-nil (the default), Flymake will resize the margins when
'flymake-mode' is turned on or off.
Only relevant if 'flymake-indicator-type' is set to 'margins'.
+++
*** New user option 'flymake-margin-indicator-position'.
It controls which margin (left or right) is used for margin
indicators.
It controls whether to use margins for margin indicators, and which
margin (left or right) to use. Default is to use the left margin.
+++
*** New user option 'flymake-show-diagnostics-at-end-of-line'.
@ -1618,7 +1619,7 @@ When non-nil, Flymake shows summarized descriptions of diagnostics at
the end of the line. Depending on your preference, this can either be
distracting and easily confused with actual code, or a significant
early aid that relieves you from moving the buffer or reaching for the
mouse to consult an error message.
mouse to consult an error message. Default is nil.
** Flyspell
@ -1626,6 +1627,7 @@ mouse to consult an error message.
*** New user option 'flyspell-check-changes'.
When non-nil, Flyspell mode spell-checks only words that you edited; it
does not check unedited words just because you move point across them.
Default is nil.
---
** JS mode.
@ -1647,7 +1649,7 @@ buffers contain Javascript code.
*** New user option 'python-indent-block-paren-deeper'.
If non-nil, increase the indentation of the lines inside parens in a
header of a block when they are indented to the same level as the body
of the block:
of the block, producing:
if (some_expression
and another_expression):
@ -1659,6 +1661,8 @@ instead of:
and another_expression):
do_something()
Default is nil.
---
*** New user option 'python-interpreter-args'.
This allows the user to specify command line arguments to the non
@ -1699,8 +1703,8 @@ This keyword enables the user to install packages using package-vc.el.
+++
*** New user option 'use-package-vc-prefer-newest'.
This allows the user to always install the newest commit of a package
when using the ':vc' keyword.
If non-nil, always install the newest commit of a package when using the
':vc' keyword rather than its stable release. Default is nil.
** Gnus
@ -1749,6 +1753,7 @@ Controls how the 'dictionary-search' command prompts for and displays
dictionary definitions. Customize this user option to 'help' to have
'dictionary-search' display definitions in a "*Help*" buffer and
provide dictionary-based minibuffer completion for word selection.
Default is nil, which means to use a "*Dictionary*" buffer.
---
*** New user option 'dictionary-read-word-prompt'.
@ -1971,11 +1976,11 @@ If non-nil, moving point forward or backward between widgets by typing
*** New user option 'ruby-rubocop-use-bundler'.
By default it retains the previous behavior: read the contents of
Gemfile and act accordingly. But you can also set it to t or nil to
skip the check.
skip checking the Gemfile.
*** New user option 'ruby-bracketed-args-indent'.
When it is set to nil, multiple consecutive open braces/brackets/parens
result in only one additional indentation level.
result in only one additional indentation level. Default is t.
** Thingatpt
@ -2003,7 +2008,8 @@ will return the URL for that bug.
*** New user option 'Buffer-menu-group-by'.
It controls how buffers are divided into groups that are displayed with
headings using Outline minor mode. Using commands that mark buffers
on the outline heading line will mark all buffers in the outline.
on the outline heading line will mark all buffers in the outline. By
default, no grouping is performed.
+++
*** New command 'Buffer-menu-toggle-internal'.
@ -2025,9 +2031,9 @@ Previously, it was set to t, but this broke remote file name detection.
---
*** More control on automatic update of Proced buffers.
The user option 'proced-auto-update-flag' can now be set to two
additional values, which control automatic updates of Proced buffers
that are not displayed in some window.
The user option 'proced-auto-update-flag' can now be set to an
additional value 'visible', which controls automatic updates of Proced
buffers that are displayed in some window.
---
*** nXML Mode now comes with schemas for Mono/.NET development.
@ -2165,7 +2171,8 @@ This is a minor mode for editing regular expressions in the minibuffer,
for example in 'query-replace-regexp'. It correctly highlights parens
via 'show-paren-mode' and 'blink-matching-paren' in a user-friendly way,
avoids reporting alleged paren mismatches and makes sexp navigation more
intuitive.
intuitive. It is enabled by default, 'minibuffer-regexp-prompts' can be
used to tune when it takes effect.
---
** The highly accessible Modus themes collection has eight items.
@ -2291,7 +2298,7 @@ unibyte string.
buffer-local value from the minibuffer.
+++
** 'minibuffer-allow-text-properties' also affects completions.
** 'minibuffer-allow-text-properties' now also affects completions.
When it has a non-nil value, then completion functions like
'completing-read' don't discard text properties from the returned
completion candidate.
@ -2321,7 +2328,7 @@ values.
---
** User option 'tramp-completion-reread-directory-timeout' has been removed.
This user option has been obsoleted in Emacs 27, use
This user option was obsoleted in Emacs 27, use
'remote-file-name-inhibit-cache' instead.
+++
@ -2497,7 +2504,7 @@ where arguments after the first are keyword/value pairs, all optional:
':key' specifies a function that produces the sorting key from an element,
':lessp' specifies the ordering predicate, defaulting to 'value<',
':reverse' is used to reverse the sorting order,
':in-place is used for in-place sorting, as the default is now to
':in-place' is used for in-place sorting, as the default is now to
sort a copy of the input.
The new signature is less error-prone and reduces the need to write
@ -2574,7 +2581,8 @@ analogous to 'w32-notification-notify'.
** New Haiku specific variable 'haiku-pass-control-tab-to-system'.
This sets whether Emacs should pass 'C-TAB' on to the system instead of
handling it, fixing a problem where window switching would not activate
if an Emacs frame had focus on the Haiku operating system.
if an Emacs frame had focus on the Haiku operating system. Default
value is t.
+++
** New value 'if-regular' for the REPLACE argument to 'insert-file-contents'.
@ -2956,9 +2964,9 @@ default to use 'LANGUAGE'.
---
** New optional argument to 'modify-dir-local-variable'.
A 5th argument, optional, has been added to
'modify-dir-local-variable'. It can be used to specify which
dir-locals file to modify.
An optional 5th argument FILE has been added to
'modify-dir-local-variable'. It can be used to specify which file to
modify instead of the default ".dir-locals.el".
** Connection local variables
@ -3012,13 +3020,13 @@ They pertained to the internal storage size which is now irrelevant.
** 'treesit-install-language-grammar' can handle local directory instead of URL.
It is now possible to pass a directory of a local repository as URL
inside 'treesit-language-source-alist', so that calling
'treesit-install-language-grammar' would avoid cloning the repository.
'treesit-install-language-grammar' will avoid cloning the repository.
It may be useful, for example, for the purposes of bisecting a
treesitter grammar.
+++
** New buffer-local variable 'tabulated-list-groups'.
It controls display and separate sorting of groups of entries.
It controls display and separate sorting of groups of entries. By
default no grouping or sorting is done.
+++
** New variable 'revert-buffer-restore-functions'.

View file

@ -286,7 +286,7 @@ when ~org-yank-dnd-method~ is =attach=.
*** Alignment of image previews can be customized
Previously, all the image previews where always left-aligned.
Previously, all the image previews were always left-aligned.
Now, you can customize image previews to be left-aligned, centered, or right-aligned.

View file

@ -1053,6 +1053,11 @@ This is like `setq', but is meant for user options instead of
plain variables. This means that `setopt' will execute any
`custom-set' form associated with VARIABLE.
Note that `setopt' will emit a warning if the type of a VALUE
does not match the type of the corresponding VARIABLE as
declared by `defcustom'. (VARIABLE will be assigned the value
even if it doesn't match the type.)
\(fn [VARIABLE VALUE]...)"
(declare (debug setq))
(unless (zerop (mod (length pairs) 2))

View file

@ -38,7 +38,8 @@
(defmacro easy-menu-define (symbol maps doc menu)
"Define a pop-up menu and/or menu bar menu specified by MENU.
If SYMBOL is non-nil, define SYMBOL as a function to pop up the
submenu defined by MENU, with DOC as its doc string.
submenu defined by MENU, with DOC as its doc string. Also define
SYMBOL as a variable whose value is the menu.
MAPS, if non-nil, should be a keymap or a list of keymaps; add
the submenu defined by MENU to the keymap or each of the keymaps,

View file

@ -4420,18 +4420,21 @@ the same set of elements."
(unique (or (and (eq prefix t) (setq prefix fixed))
(and (stringp prefix)
(eq t (try-completion prefix comps))))))
;; if the common prefix is unique, it also is a common
;; suffix, so we should add it for `prefix' elements
(unless (or (and (eq elem 'prefix) (not unique))
(equal prefix ""))
(push prefix res))
;; If there's only one completion, `elem' is not useful
;; any more: it can only match the empty string.
;; FIXME: in some cases, it may be necessary to turn an
;; `any' into a `star' because the surrounding context has
;; changed such that string->pattern wouldn't add an `any'
;; here any more.
(unless unique
(if unique
;; If the common prefix is unique, it also is a common
;; suffix, so we should add it for `prefix' elements.
(push prefix res)
;; `prefix' only wants to include the fixed part before the
;; wildcard, not the result of growing that fixed part.
(when (eq elem 'prefix)
(setq prefix fixed))
(push prefix res)
(push elem res)
;; Extract common suffix additionally to common prefix.
;; Don't do it for `any' since it could lead to a merged

View file

@ -1325,7 +1325,8 @@ in your init files."
;; Create an "for-each" parser, see `c-ts-mode--emacs-set-ranges'
;; for more.
(when c-ts-mode-emacs-sources-support
(treesit-parser-create 'c nil nil 'for-each))
(setq-local treesit-primary-parser
(treesit-parser-create 'c nil nil 'for-each)))
(let ((primary-parser (treesit-parser-create 'c)))
;; Comments.

View file

@ -701,7 +701,8 @@ Return nil if NODE is not a defun node or doesn't have a name."
(require 'heex-ts-mode)
(treesit-parser-create 'heex))
(treesit-parser-create 'elixir)
(setq-local treesit-primary-parser
(treesit-parser-create 'elixir))
(setq-local treesit-language-at-point-function
'elixir-ts--treesit-language-at-point)

View file

@ -1636,7 +1636,7 @@ See `treesit-simple-indent-presets'.")
(goto-char bol)
(setq this-line-has-prefix
(and (looking-at-p adaptive-fill-regexp)
(and (looking-at adaptive-fill-regexp)
(not (string-match-p
(rx bos (* whitespace) eos)
(match-string 0)))))
@ -2938,7 +2938,8 @@ when a major mode sets it.")
(defun treesit-outline-search (&optional bound move backward looking-at)
"Search for the next outline heading in the syntax tree.
See the descriptions of arguments in `outline-search-function'."
For BOUND, MOVE, BACKWARD, LOOKING-AT, see the descriptions in
`outline-search-function'."
(if looking-at
(when-let* ((node (or (treesit-thing-at (pos-eol) treesit-outline-predicate)
(treesit-thing-at (pos-bol) treesit-outline-predicate)))
@ -3047,6 +3048,10 @@ If `treesit-defun-name-function' is non-nil, set up
If `treesit-simple-imenu-settings' is non-nil, set up Imenu.
If either `treesit-outline-predicate' or `treesit-simple-imenu-settings'
are non-nil, and Outline minor mode settings don't alreay exist, setup
Outline minor mode.
If `sexp', `sentence' are defined in `treesit-thing-settings',
enable tree-sitter navigation commands for them.

View file

@ -1336,7 +1336,10 @@ nothing is shown in the echo area."
(let ((new (widget-tabable-at)))
(while (and (eq (widget-tabable-at) new) (not (bobp)))
(backward-char)))
(unless (bobp) (forward-char)))
;; If the widget is at BOB, point is already at the widget's
;; starting position; otherwise, advance point to put it at the
;; start of the widget (cf. bug#69943 and bug#72995).
(unless (and (widget-tabable-at) (bobp)) (forward-char)))
(unless suppress-echo
(widget-echo-help (point)))
(run-hooks 'widget-move-hook))

View file

@ -1644,10 +1644,24 @@ frame's display, or the first available X display. */)
if (NILP (val) && FRAME_LIVE_P (f))
{
Lisp_Object frame;
Lisp_Object frame, val;
XSETFRAME (frame, f);
return pgtk_get_foreign_selection (selection_symbol, target_type,
time_stamp, frame);
val = pgtk_get_foreign_selection (selection_symbol, target_type,
time_stamp, frame);
/* A window property holding just one item is indistinguishable
from an array of one element, and is always decoded as the
former, producing issues with programs that expect the TARGETS
property always to return vectors, even when the toolkit
reports just one data type. Though X sidesteps this ambiguity
by defining TARGETS as returning at least two properties
TARGETS and MULTIPLE, GTK knows no such scruples, and therefore
symbol values (or nil) should be enclosed in vectors when
TARGETS is being requested. (bug#72254) */
if (EQ (target_type, QTARGETS) && (NILP (val) || SYMBOLP (val)))
val = make_vector (NILP (val) ? 0 : 1, val);
return val;
}
if (CONSP (val) && SYMBOLP (XCAR (val)))

View file

@ -504,7 +504,7 @@ treesit_debug_print_parser_list (char *msg, Lisp_Object parser)
SSDATA (SYMBOL_NAME (Vthis_command)),
SSDATA (SYMBOL_NAME (XTS_PARSER (parser)->language_symbol)),
buf_name, BUF_BEG (buf),
BUF_BEGV (buf), BUF_Z (buf), BUF_ZV (buf));
BUF_BEGV (buf), BUF_ZV (buf), BUF_Z (buf));
Lisp_Object tail = BVAR (buf, ts_parser_list);
FOR_EACH_TAIL (tail)
@ -968,6 +968,9 @@ treesit_record_change (ptrdiff_t start_byte, ptrdiff_t old_end_byte,
}
}
static TSRange *treesit_make_ts_ranges (Lisp_Object, Lisp_Object,
uint32_t *);
/* Comment (ref:visible-beg-null) The purpose of visible_beg/end is to
keep track of "which part of the buffer does the tree-sitter tree
see", in order to update the tree correctly. Visible_beg/end have
@ -1096,48 +1099,85 @@ treesit_sync_visible_region (Lisp_Object parser)
XTS_PARSER (parser)->visible_end = visible_end;
/* Fix ranges so that the ranges stays with in visible_end. Here we
try to do minimal work so that the ranges is minimally correct such
that there's no OOB error. Usually treesit-update-ranges should
update the parser with actually correct ranges. */
if (NILP (XTS_PARSER (parser)->last_set_ranges)) return;
uint32_t len;
const TSRange *ranges
= ts_parser_included_ranges (XTS_PARSER (parser)->parser, &len);
/* We might need to discard some ranges that exceeds visible_end, in
that case, new_len is the length of the new ranges array (which
will be shorter than len). */
uint32_t new_len = 0;
uint32_t new_end = 0;
for (int idx = 0; idx < len; idx++)
{
TSRange range = ranges[idx];
/* If this range starts after visible_end, we don't include this
range and the ranges after it in the new ranges. */
if (range.start_byte + visible_beg >= visible_end)
try to do minimal work so that the ranges is minimally correct and
there's no OOB error. Usually treesit-update-ranges should update
the parser with semantically correct ranges.
We start with the charpos ranges, because for bytepos ranges, after
user edits, the ranges start/end might end up inside a multibyte
char! See (ref:bytepos-range-pitfall) below. */
Lisp_Object lisp_ranges = XTS_PARSER (parser)->last_set_ranges;
if (NILP (lisp_ranges)) return;
Lisp_Object new_ranges_head = lisp_ranges;
FOR_EACH_TAIL_SAFE (lisp_ranges)
{
Lisp_Object range = XCAR (lisp_ranges);
ptrdiff_t beg = XFIXNUM (XCAR (range));
ptrdiff_t end = XFIXNUM (XCDR (range));
if (end <= visible_beg)
/* Even the end is before visible_beg, discard this range. */
new_ranges_head = XCDR (new_ranges_head);
else if (beg >= visible_end)
{
/* Even the beg is after visible_end, dicard this range and all
the ranges after it. */
XSETCDR (range, Qnil);
break;
/* If this range's end is after visible_end, we don't include any
ranges after it, and changes the end of this range to
visible_end. */
if (range.end_byte + visible_beg > visible_end)
{
new_end = visible_end - visible_beg;
new_len++;
break;
}
new_len++;
}
if (new_len != len || new_end != 0)
}
else
{
/* At this point, the range overlaps with the visible portion of
the buffer in some way (in front / in back / completely
encased / completely encases). */
if (beg < visible_beg)
XSETCAR (range, make_fixnum (visible_beg));
if (end > visible_end)
XSETCDR (range, make_fixnum (visible_end));
}
}
XTS_PARSER (parser)->last_set_ranges = new_ranges_head;
if (NILP (new_ranges_head))
{
TSRange *new_ranges = xmalloc (sizeof (TSRange) * new_len);
memcpy (new_ranges, ranges, sizeof (TSRange) * new_len);
new_ranges[new_len - 1].end_byte = new_end;
/* TODO: What should we do if this fails? */
ts_parser_set_included_ranges (XTS_PARSER (parser)->parser,
new_ranges, new_len);
xfree (new_ranges);
bool success;
success = ts_parser_set_included_ranges (XTS_PARSER (parser)->parser,
NULL, 0);
eassert (success);
}
else
{
uint32_t len = 0;
TSRange *ts_ranges = treesit_make_ts_ranges (new_ranges_head, parser,
&len);
bool success;
success = ts_parser_set_included_ranges (XTS_PARSER (parser)->parser,
ts_ranges, len);
xfree (ts_ranges);
eassert (success);
}
}
/* (ref:bytepos-range-pitfall) Suppose we have the following buffer
content ([ ] is a unibyte char, [ ] is a multibyte char):
[a][b][c][d][e][ f ]
and the following ranges (denoted by braces):
[a][b][c][d][e][ f ]
{ }{ }
So far so good, now user deletes a unibyte char at the beginning:
[b][c][d][e][ f ]
{ }{ }
Oops, now our range cuts into the multibyte char, bad! */
static void
treesit_check_buffer_size (struct buffer *buffer)
{
@ -1274,13 +1314,16 @@ treesit_read_buffer (void *parser, uint32_t byte_index,
beg = NULL;
len = 0;
}
/* Normal case, read until the gap or visible end. */
/* Normal case, read a character. We can't give tree-sitter the
whole buffer range because we move the gap around, realloc the
buffer, etc; and there's no way to invalidate the previously
given range in tree-sitter. Move over, benchmark shows there's
very little difference between passing a whole chunk vs passing a
single char at once. The only cost is funcall I guess. */
else
{
beg = (char *) BUF_BYTE_ADDRESS (buffer, byte_pos);
ptrdiff_t gap_bytepos = BUF_GPT_BYTE (buffer);
len = (byte_pos < gap_bytepos)
? gap_bytepos - byte_pos : visible_end - byte_pos;
len = BYTES_BY_CHAR_HEAD ((int) *beg);
}
/* We never let tree-sitter to parse buffers that large so this
assertion should never hit. */
@ -1831,6 +1874,48 @@ treesit_make_ranges (const TSRange *ranges, uint32_t len,
return Fnreverse (list);
}
/* Convert lisp ranges to tree-sitter ranges. Set LEN to the length of
the ranges. RANGES must be a valid ranges list, (cons of numbers, no
overlap, etc). PARSER must be a parser. This function doesn't check
for types. Caller must free the returned ranges. */
static TSRange *
treesit_make_ts_ranges (Lisp_Object ranges, Lisp_Object parser, uint32_t *len)
{
ptrdiff_t ranges_len = list_length (ranges);
if (ranges_len > UINT32_MAX)
xsignal (Qargs_out_of_range, list2 (ranges, Flength (ranges)));
*len = (uint32_t) ranges_len;
TSRange *treesit_ranges = xmalloc (sizeof (TSRange) * ranges_len);
struct buffer *buffer = XBUFFER (XTS_PARSER (parser)->buffer);
for (int idx = 0; idx < ranges_len; idx++, ranges = XCDR (ranges))
{
Lisp_Object range = XCAR (ranges);
ptrdiff_t beg_byte = buf_charpos_to_bytepos (buffer,
XFIXNUM (XCAR (range)));
ptrdiff_t end_byte = buf_charpos_to_bytepos (buffer,
XFIXNUM (XCDR (range)));
/* Shouldn't violate assertion since we just checked for
buffer size at the beginning of this function. */
eassert (beg_byte - BUF_BEGV_BYTE (buffer) <= UINT32_MAX);
eassert (end_byte - BUF_BEGV_BYTE (buffer) <= UINT32_MAX);
/* We don't care about points, put in dummy values. */
TSRange rg =
{
{0, 0}, {0, 0},
(uint32_t) beg_byte - XTS_PARSER (parser)->visible_beg,
(uint32_t) end_byte - XTS_PARSER (parser)->visible_beg
};
treesit_ranges[idx] = rg;
}
return treesit_ranges;
}
DEFUN ("treesit-parser-set-included-ranges",
Ftreesit_parser_set_included_ranges,
Streesit_parser_set_included_ranges,
@ -1870,33 +1955,8 @@ buffer. */)
}
else
{
/* Set ranges for PARSER. */
if (list_length (ranges) > UINT32_MAX)
xsignal (Qargs_out_of_range, list2 (ranges, Flength (ranges)));
uint32_t len = (uint32_t) list_length (ranges);
TSRange *treesit_ranges = xmalloc (sizeof (TSRange) * len);
struct buffer *buffer = XBUFFER (XTS_PARSER (parser)->buffer);
/* We can use XFIXNUM, XCAR, XCDR freely because we have checked
the input by treesit_check_range_argument. */
for (int idx = 0; !NILP (ranges); idx++, ranges = XCDR (ranges))
{
Lisp_Object range = XCAR (ranges);
ptrdiff_t beg_byte = buf_charpos_to_bytepos (buffer,
XFIXNUM (XCAR (range)));
ptrdiff_t end_byte = buf_charpos_to_bytepos (buffer,
XFIXNUM (XCDR (range)));
/* Shouldn't violate assertion since we just checked for
buffer size at the beginning of this function. */
eassert (beg_byte - BUF_BEGV_BYTE (buffer) <= UINT32_MAX);
eassert (end_byte - BUF_BEGV_BYTE (buffer) <= UINT32_MAX);
/* We don't care about start and end points, put in dummy
values. */
TSRange rg = {{0, 0}, {0, 0},
(uint32_t) beg_byte - BUF_BEGV_BYTE (buffer),
(uint32_t) end_byte - BUF_BEGV_BYTE (buffer)};
treesit_ranges[idx] = rg;
}
uint32_t len = 0;
TSRange *treesit_ranges = treesit_make_ts_ranges (ranges, parser, &len);
success = ts_parser_set_included_ranges (XTS_PARSER (parser)->parser,
treesit_ranges, len);
xfree (treesit_ranges);
@ -1923,26 +1983,9 @@ See also `treesit-parser-set-included-ranges'. */)
treesit_check_parser (parser);
treesit_initialize ();
/* Our return value depends on the buffer state (BUF_BEGV_BYTE,
etc), so we need to sync up. */
treesit_check_buffer_size (XBUFFER (XTS_PARSER (parser)->buffer));
treesit_sync_visible_region (parser);
/* When the parser doesn't have a range set and we call
ts_parser_included_ranges on it, it doesn't return an empty list,
but rather return DEFAULT_RANGE. (A single range where start_byte
= 0, end_byte = UINT32_MAX). So we need to track whether the
parser is ranged ourselves. */
if (NILP (XTS_PARSER (parser)->last_set_ranges))
return Qnil;
uint32_t len;
const TSRange *ranges
= ts_parser_included_ranges (XTS_PARSER (parser)->parser, &len);
struct buffer *buffer = XBUFFER (XTS_PARSER (parser)->buffer);
return treesit_make_ranges (ranges, len, parser, buffer);
return XTS_PARSER (parser)->last_set_ranges;
}
DEFUN ("treesit-parser-notifiers", Ftreesit_parser_notifiers,

View file

@ -45,12 +45,23 @@ struct Lisp_TS_Parser
same tag. A tag is primarily used to differentiate between
parsers for the same language. */
Lisp_Object tag;
/* The Lisp ranges last set. This is use to compare to the new ranges
the users wants to set, and avoid reparse if the new ranges is the
same as the last set one. This might go out of sync with the
ranges we return from Ftreesit_parser_included_ranges, if we did a
ranges fix in treesit_sync_visible_region, but I don't think
that'll cause any harm. */
/* The Lisp ranges last set. One purpose for it is to compare to the
new ranges the users wants to set, and avoid reparse if the new
ranges is the same as the current one. Another purpose is to store
the ranges in charpos (ts api returns ranges in bytepos). We need
to use charpos so we don't end up having a range cut into a
multibyte character. (See (ref:bytepos-range-pitfall) in treesit.c
for more detail.)
treesit-parser-set-included-ranges sets this field;
treesit-parser-included-ranges directly returns this field, and
before each reparse, treesit_sync_visible_region uses this to
calculate a range for the parser that fits in the visible region.
Trivia: when the parser doesn't have a range set and we call
ts_parser_included_ranges on it, it doesn't return an empty list,
but rather return DEFAULT_RANGE. (A single range where start_byte
= 0, end_byte = UINT32_MAX). */
Lisp_Object last_set_ranges;
/* The buffer associated with this parser. */
Lisp_Object buffer;

View file

@ -306,13 +306,20 @@
6)))
(ert-deftest completion-substring-test-5 ()
;; merge-completions needs to work correctly when
;; Normally a `prefix' wildcard ignores the common prefix to its
;; left, since it only grows the common suffix; but if that common
;; prefix is also a common suffix, it should be included.
(should (equal
(completion-pcm--merge-completions '("ab" "sab") '(prefix "b"))
'("b" "a" prefix)))
(completion-pcm--merge-try '(prefix "b") '("ab" "sab") "" "")
'("ab" . 2)))
(should (equal
(completion-pcm--merge-completions '("ab" "ab") '(prefix "b"))
'("b" "a")))
(completion-pcm--merge-try '(prefix "b") '("ab" "ab") "" "")
'("ab" . 2)))
;; When there's a fixed string before `prefix', that fixed string
;; should always be included.
(should (equal
(completion-pcm--merge-try '("a" prefix "b") '("axb" "ayb") "" "")
'("ab" . 2)))
;; substring completion should successfully complete the entire string
(should (equal
(completion-substring-try-completion "b" '("ab" "ab") nil 0)

View file

@ -129,6 +129,7 @@ uniquify-trailing-separator-p is ignored"
(require 'project)
(ert-deftest uniquify-project-transform ()
"`project-uniquify-dirname-transform' works"
(skip-unless (project-current nil source-directory))
(let ((uniquify-dirname-transform #'project-uniquify-dirname-transform)
(project-vc-name "foo1/bar")
bufs)

View file

@ -344,6 +344,23 @@ return nil, even with a non-nil bubblep argument."
(should (string= "Third" (widget-value (widget-at))))
(widget-forward 1))) ; Should not signal beginning-of-buffer error.
(ert-deftest widget-test-widget-move-bug72995 ()
"Test moving to a widget that starts at buffer position 2."
(with-temp-buffer
;; The first tabable widget begins at position 2 (bug#72995).
(widget-insert " ")
(dolist (el '("First" "Second" "Third"))
(widget-create 'push-button el))
(widget-insert "\n")
(use-local-map widget-keymap)
(widget-setup)
;; Make sure there is no tabable widget at BOB.
(goto-char (point-min))
(should-not (widget-tabable-at))
;; Check that we can move to the first widget after BOB.
(widget-forward 1)
(should (widget-tabable-at))))
(ert-deftest widget-test-color-match ()
"Test that the :match function for the color widget works."
(let ((widget (widget-convert 'color)))

View file

@ -686,6 +686,33 @@ visible_end.)"
(should (equal '((16 . 28)) (treesit-query-range
'javascript query nil nil '(1 . -1)))))))
(ert-deftest treesit-range-fixup-after-edit ()
"Tests if Emacs can fix OOB ranges after deleting text or narrowing."
(skip-unless (treesit-language-available-p 'json))
(with-temp-buffer
(let ((parser (treesit-parser-create 'json)))
(insert "11111111111111111111")
(treesit-parser-set-included-ranges parser '((1 . 20)))
(treesit-parser-root-node parser)
(should (equal (treesit-parser-included-ranges parser)
'((1 . 20))))
(narrow-to-region 5 15)
(should (equal (treesit-parser-included-ranges parser)
'((5 . 15))))
(widen)
;; Trickier ranges
;; 11111111111111111111
;; [ ] [ ]
;; { narrow }
(treesit-parser-set-included-ranges parser '((1 . 7) (10 . 15)))
(should (equal (treesit-parser-included-ranges parser)
'((1 . 7) (10 . 15))))
(narrow-to-region 5 13)
(should (equal (treesit-parser-included-ranges parser)
'((5 . 7) (10 . 13)))))))
;;; Multiple language
(ert-deftest treesit-multi-lang ()