From 11e7ae3964e192b0e4bcc437a04278ee727e720b Mon Sep 17 00:00:00 2001 From: Po Lu Date: Thu, 12 Sep 2024 08:22:25 +0800 Subject: [PATCH 01/18] Fix bug#72254 * src/pgtkselect.c (Fpgtk_get_selection_internal): If requesting TARGETS with just one result, return it as a vector. (bug#72254) --- src/pgtkselect.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/pgtkselect.c b/src/pgtkselect.c index 271411b87ca..9e172c58602 100644 --- a/src/pgtkselect.c +++ b/src/pgtkselect.c @@ -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))) From 2c6b7b2da9f011c6aaf38e5dd24f137b0c033945 Mon Sep 17 00:00:00 2001 From: Stefan Kangas Date: Thu, 12 Sep 2024 23:01:08 +0200 Subject: [PATCH 02/18] ; * admin/MAINTAINERS: Remove some entries for Artur Malabarba. Change agreed with Artur Malabarba . --- admin/MAINTAINERS | 5 ----- 1 file changed, 5 deletions(-) diff --git a/admin/MAINTAINERS b/admin/MAINTAINERS index f65a9decadc..6c77501fee3 100644 --- a/admin/MAINTAINERS +++ b/admin/MAINTAINERS @@ -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 From d66b70f3607c7cce99f8d67c18c1a4b13af1970c Mon Sep 17 00:00:00 2001 From: Stefan Kangas Date: Fri, 13 Sep 2024 00:17:35 +0200 Subject: [PATCH 03/18] * doc/misc/auth.texi: Minor copy edits. --- doc/misc/auth.texi | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/doc/misc/auth.texi b/doc/misc/auth.texi index bb4beb38837..17467f81941 100644 --- a/doc/misc/auth.texi +++ b/doc/misc/auth.texi @@ -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} From 79f68597abade27939397e0c2a50eec833e64daf Mon Sep 17 00:00:00 2001 From: Robert Pluim Date: Fri, 13 Sep 2024 09:50:01 +0200 Subject: [PATCH 04/18] ; * etc/ORG-NEWS: Fix typo. --- etc/ORG-NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index eeab970e3e1..bb8d5d32065 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -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. From ca3932121a893df3c4b08dbe11f2c002da4a421f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= Date: Fri, 13 Sep 2024 12:13:53 +0200 Subject: [PATCH 05/18] Don't fail uniquify-tests in non-version-controlled source trees * test/lisp/uniquify-tests.el (uniquify-project-transform): Skip test if there is no project (bug#73205). --- test/lisp/uniquify-tests.el | 1 + 1 file changed, 1 insertion(+) diff --git a/test/lisp/uniquify-tests.el b/test/lisp/uniquify-tests.el index 4124ce056d3..9b33c9d7d47 100644 --- a/test/lisp/uniquify-tests.el +++ b/test/lisp/uniquify-tests.el @@ -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) From 8e1187e336f6763f03cc8c03cf6c02e97c34dac7 Mon Sep 17 00:00:00 2001 From: Robert Pluim Date: Fri, 13 Sep 2024 15:42:39 +0200 Subject: [PATCH 06/18] Improve NEWS entries * etc/NEWS: Fix typos, and add information about default values of new user options. --- etc/NEWS | 84 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 18d4c6b2158..9b66e67c49a 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -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'. From 272df33fb8bde41887bfa4b03ed8223b9c03c572 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 14 Sep 2024 09:52:59 +0300 Subject: [PATCH 07/18] ; * CONTRIBUTE: Minor copyedits. --- CONTRIBUTE | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTE b/CONTRIBUTE index 7c5c07771eb..fdd8a768830 100644 --- a/CONTRIBUTE +++ b/CONTRIBUTE @@ -205,8 +205,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 From c70bd0e3fe9c2f5b1fcdce7939c07449f8a5ec4c Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Fri, 13 Sep 2024 00:23:13 -0700 Subject: [PATCH 08/18] Fix tree-sitter indent preset prev-adaptive-prefix * lisp/treesit.el (treesit-simple-indent-presets): Use looking-at so the call to match-string has the match data to work with. --- lisp/treesit.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/treesit.el b/lisp/treesit.el index 3ac8575aad4..e0bcbe965c6 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -1647,7 +1647,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))))) From 76faf7e60910ffc29b134fa4d16e3d8c176097a7 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Fri, 13 Sep 2024 22:53:06 -0700 Subject: [PATCH 09/18] Revert "Read more on each call to treesit's buffer reader" This reverts commit bf23382f1f2d6ea072db4e4750f8a345f77a3ef2. We move around the gap, narrow regions, ralloc, etc, and don't have a way to invalidate previously given range. So tree-sitter can't be given the full range. --- src/treesit.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/treesit.c b/src/treesit.c index ee83486b92a..2b43c505dfa 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -1228,13 +1228,11 @@ 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. */ 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. */ From 6a6d7925c9ddbf558f70932661ee943262aea4ca Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Fri, 13 Sep 2024 21:42:17 -0700 Subject: [PATCH 10/18] Fix range handling so it works for multibyte buffer (bug#73204) Here by multibyte buffer I mean buffer that includes non-ASCII characters. The problem is illustrated by this comment, which I copied from the source: ====================================================================== (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! ====================================================================== * src/treesit.c (treesit_debug_print_parser_list): Minor fix. (treesit_sync_visible_region): Change the way we fixup ranges, instead of using the bytepos ranges from tree-sitter, we use the cached lisp charpos ranges. (treesit_make_ts_ranges): New function. (Ftreesit_parser_set_included_ranges): Refactor out the new function treesit_make_ts_ranges. (Ftreesit_parser_included_ranges): Rather than getting the ranges from tree-sitter, just return the cached lisp ranges. * src/treesit.h (Lisp_TS_Parser): Add some comment. * test/src/treesit-tests.el (treesit-range-fixup-after-edit): New test. --- src/treesit.c | 213 +++++++++++++++++++++++--------------- src/treesit.h | 23 ++-- test/src/treesit-tests.el | 27 +++++ 3 files changed, 173 insertions(+), 90 deletions(-) diff --git a/src/treesit.c b/src/treesit.c index 2b43c505dfa..9958d8a4c2a 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -499,7 +499,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) @@ -922,6 +922,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 @@ -1050,48 +1053,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) { @@ -1228,7 +1268,12 @@ treesit_read_buffer (void *parser, uint32_t byte_index, beg = NULL; len = 0; } - /* Normal case, read a character. */ + /* 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); @@ -1739,6 +1784,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, @@ -1778,33 +1865,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); @@ -1831,26 +1893,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, diff --git a/src/treesit.h b/src/treesit.h index f8227a64b0a..3fc42a4ba24 100644 --- a/src/treesit.h +++ b/src/treesit.h @@ -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; diff --git a/test/src/treesit-tests.el b/test/src/treesit-tests.el index 3431ba5f4dd..98aaeb62781 100644 --- a/test/src/treesit-tests.el +++ b/test/src/treesit-tests.el @@ -684,6 +684,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 () From 2f243fb91d6d2c4c4e4a6dbbd94ef5b13d543732 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 14 Sep 2024 00:19:47 -0700 Subject: [PATCH 11/18] ; Minor doc fix in treesit.el * lisp/treesit.el (treesit-outline-search): Mention parameters. (treesit-major-mode-setup): Mention outline setup. --- lisp/treesit.el | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lisp/treesit.el b/lisp/treesit.el index e0bcbe965c6..27019742777 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -2949,7 +2949,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))) @@ -3058,6 +3059,10 @@ If `treesit-defun-name-function' is non-nil, set up If `treesit-simple-imenu-settings' is non-nil, set up Imenu. +If `treesit-outline-predicate' or `treesit-simple-imenu-settings', 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. From 3cad7cc8dc823b8b1dd66d7777a01778e1a4defe Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 14 Sep 2024 00:46:05 -0700 Subject: [PATCH 12/18] Set treesit-primary-parser for c and elixir ts mode For buffers with multiple parsers, it's important to set this variable so font-lock invalidation works smoothly. * lisp/progmodes/c-ts-mode.el (c-ts-mode): Set treesit-primary-parser. * lisp/progmodes/elixir-ts-mode.el (elixir-ts-mode): Set treesit-primary-parser. --- lisp/progmodes/c-ts-mode.el | 3 ++- lisp/progmodes/elixir-ts-mode.el | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 6c406a8acd9..f5cd36c68c7 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -1318,7 +1318,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))) (treesit-parser-create 'c) ;; Comments. diff --git a/lisp/progmodes/elixir-ts-mode.el b/lisp/progmodes/elixir-ts-mode.el index 815827ed13c..a3e11658468 100644 --- a/lisp/progmodes/elixir-ts-mode.el +++ b/lisp/progmodes/elixir-ts-mode.el @@ -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) From ad289f364e5c508d6f5d6ae530ee919c5fa43335 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 14 Sep 2024 11:55:08 +0300 Subject: [PATCH 13/18] ; Improve documentation of 'easy-menu-define' * doc/lispref/keymaps.texi (Easy Menu): * lisp/emacs-lisp/easymenu.el (easy-menu-define): Document that SYMBOL is also defined as a variable. (Bug#73108) --- doc/lispref/keymaps.texi | 3 ++- lisp/emacs-lisp/easymenu.el | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/lispref/keymaps.texi b/doc/lispref/keymaps.texi index a67d8da244e..a207b0cbb9d 100644 --- a/doc/lispref/keymaps.texi +++ b/doc/lispref/keymaps.texi @@ -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, diff --git a/lisp/emacs-lisp/easymenu.el b/lisp/emacs-lisp/easymenu.el index 6740c2af58d..0a273ef0f7c 100644 --- a/lisp/emacs-lisp/easymenu.el +++ b/lisp/emacs-lisp/easymenu.el @@ -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, From 57d93d0259a3cc9a180b1bcb3cec3f670485f82c Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 14 Sep 2024 12:02:56 +0300 Subject: [PATCH 14/18] ; * lisp/treesit.el (treesit-major-mode-setup): Doc fix. --- lisp/treesit.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lisp/treesit.el b/lisp/treesit.el index 27019742777..67be1e7d583 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -3059,9 +3059,9 @@ If `treesit-defun-name-function' is non-nil, set up If `treesit-simple-imenu-settings' is non-nil, set up Imenu. -If `treesit-outline-predicate' or `treesit-simple-imenu-settings', and -Outline minor mode settings don't alreay exist, setup Outline minor -mode. +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. From 3cda1fdc3b755dd329617cabc266e2b86894d0cb Mon Sep 17 00:00:00 2001 From: Spencer Baugh Date: Mon, 26 Aug 2024 10:12:51 -0400 Subject: [PATCH 15/18] Correctly include fixed strings before a prefix wildcard in PCM In 03ac16ece40ba3e3ba805d6a61cc457d84bf3792 I fixed a bug with the PCM implementation of substring completion, relating to the handling of PCM wildcards. However, this fix was incomplete. This change completes the fix by also including a fixed string if it appears before a 'prefix' wildcard, even if 'try-completion' doesn't discover that fixed string grows to a unique completion. I discovered this bug while working on enhancements to PCM completion related to 'completion-pcm-leading-wildcard'. * lisp/minibuffer.el (completion-pcm--merge-completions): Include fixed strings before 'prefix wildcard. (Bug#72819) * test/lisp/minibuffer-tests.el (completion-substring-test-5): Add a test for this behavior. --- lisp/minibuffer.el | 15 +++++++++------ test/lisp/minibuffer-tests.el | 17 ++++++++++++----- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index bef565378ea..216385d9cdf 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -4384,18 +4384,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 diff --git a/test/lisp/minibuffer-tests.el b/test/lisp/minibuffer-tests.el index df36bce4634..38c2b8c4552 100644 --- a/test/lisp/minibuffer-tests.el +++ b/test/lisp/minibuffer-tests.el @@ -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) From b115c2d5ebaa9819fc0a12b0df75f9b1080d53e6 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 14 Sep 2024 12:26:54 +0300 Subject: [PATCH 16/18] ; * lisp/minibuffer.el (completion-pcm--merge-completions): Fix comments. --- lisp/minibuffer.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 216385d9cdf..fef8e1df86e 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -4391,8 +4391,8 @@ the same set of elements." ;; changed such that string->pattern wouldn't add an `any' ;; here any more. (if unique - ;; if the common prefix is unique, it also is a common - ;; suffix, so we should add it for `prefix' elements + ;; 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. From ef0276de82b8ac517ea8c15ee504f290c6528c73 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 14 Sep 2024 12:33:36 +0300 Subject: [PATCH 17/18] ; * lisp/cus-edit.el (setopt): Doc fix. (Bug#73098) --- lisp/cus-edit.el | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el index 469f4334b44..de7c3ea7cb6 100644 --- a/lisp/cus-edit.el +++ b/lisp/cus-edit.el @@ -1060,6 +1060,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)) From d509a35699738519d42a35d72827b1111425669c Mon Sep 17 00:00:00 2001 From: Stephen Berman Date: Sat, 14 Sep 2024 12:42:49 +0200 Subject: [PATCH 18/18] Fix regression in widget-move (bug#72995) * lisp/wid-edit.el (widget-move): Avoid advancing point only if it is at the start of a widget at BOB. * test/lisp/wid-edit-tests.el (widget-test-widget-move-bug72995): New test. --- lisp/wid-edit.el | 5 ++++- test/lisp/wid-edit-tests.el | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el index e7e6351fcab..77e506960a2 100644 --- a/lisp/wid-edit.el +++ b/lisp/wid-edit.el @@ -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)) diff --git a/test/lisp/wid-edit-tests.el b/test/lisp/wid-edit-tests.el index d416eb99022..03e7e5a7b7d 100644 --- a/test/lisp/wid-edit-tests.el +++ b/test/lisp/wid-edit-tests.el @@ -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)))