From 3f05b455f7e52e70871f47810fe42f1f36fa783b Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 30 Mar 2025 17:38:25 +0300 Subject: [PATCH 001/395] ; * src/editfns.c (Fmessage): Mention 'inhibit-message' (bug#77257). --- src/editfns.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/editfns.c b/src/editfns.c index e02cf14b968..ecc16a62f76 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -3159,6 +3159,9 @@ Return the message. In batch mode, the message is printed to the standard error stream, followed by a newline. +If the variable `inhibit-message' is non-nil, the message is not +displayed, only logged in the `*Messages*' buffer. + The first argument is a format control string, and the rest are data to be formatted under control of the string. Percent sign (%), grave accent (\\=`) and apostrophe (\\=') are special in the format; see From 38fec86281efd78af24cc435307d55a00223db49 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 30 Mar 2025 19:27:22 +0300 Subject: [PATCH 002/395] ; Improve the documentation of 'slice' display spec (bug#77384). --- doc/lispref/display.texi | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 95b17032a74..3426e764e17 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -5603,12 +5603,20 @@ instead of the text that has the display specification. @item (slice @var{x} @var{y} @var{width} @var{height}) This specification together with @code{image} specifies a @dfn{slice} -(a partial area) of the image to display. The elements @var{y} and -@var{x} specify the top left corner of the slice, within the image; -@var{width} and @var{height} specify the width and height of the -slice. Integers are numbers of pixels. A floating-point number -in the range 0.0--1.0 stands for that fraction of the width or height -of the entire image. +(a partial area) of the image to display. More precisely, the +specification should have the following form: + +@lisp + ((slice @var{x} @var{y} @var{width} @var{height}) @var{image-desc}) +@end lisp + +@noindent +where @var{image-desc} is an image descriptor described above. The +elements @var{x} and @var{y} specify the top left corner of the slice, +within the image; @var{width} and @var{height} specify the width and +height of the slice. Integers are numbers of pixels. A floating-point +number in the range 0.0--1.0 stands for that fraction of the width or +height of the entire image. @item ((margin nil) @var{string}) A display specification of this form means to display @var{string} From 43c9eb3df6050f19211e219c7cb03da7a6d9d6dd Mon Sep 17 00:00:00 2001 From: Stephen Gildea Date: Sun, 30 Mar 2025 11:39:53 -0700 Subject: [PATCH 003/395] Backport expansion of Time Stamp documentation * doc/emacs/files.texi (Time Stamps): Add examples of enabling time stamping with add-hook, setting time-stamp-pattern as a file-local variable, and showing a time stamp at the end of a file. Divide into three sections. * doc/emacs/emacs.texi: Add new nodes to menu. * lisp/info.el (Info-file-list-for-emacs): Remove entry that points Info at time-stamp discussion in the Autotype document. * lisp/time-stamp.el (time-stamp-format, time-stamp-active, time-stamp-count, time-stamp-pattern, time-stamp, time-stamp-string): Expand doc strings. Include Info cross-references. Cherry picked from commits on the main branch. Do not merge to master. --- doc/emacs/emacs.texi | 5 ++ doc/emacs/files.texi | 145 ++++++++++++++++++++++++++++++++++++++----- lisp/info.el | 1 - lisp/time-stamp.el | 86 ++++++++++++++----------- 4 files changed, 186 insertions(+), 51 deletions(-) diff --git a/doc/emacs/emacs.texi b/doc/emacs/emacs.texi index a81c7134a70..d8ca41d737e 100644 --- a/doc/emacs/emacs.texi +++ b/doc/emacs/emacs.texi @@ -486,6 +486,11 @@ Backup Files * Backup Deletion:: Emacs deletes excess numbered backups. * Backup Copying:: Backups can be made by copying or renaming. +Updating Time Stamps Automatically + +* Time Stamp Customization:: How to customize with time-stamp-pattern. +* Time Stamps for One File:: Ensure automatic time-stamp of a specific file. + @ifnottex Auto Reverting Non-File Buffers diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi index c04ac685ee0..2a7017779f6 100644 --- a/doc/emacs/files.texi +++ b/doc/emacs/files.texi @@ -411,7 +411,7 @@ that was visited in the buffer. * Interlocking:: How Emacs protects against simultaneous editing of one file by two users. * Shadowing: File Shadowing. Copying files to ``shadows'' automatically. -* Time Stamps:: Emacs can update time stamps on saved files. +* Time Stamps:: Emacs can update time stamps when a file is saved. @end menu @node Save Commands @@ -992,35 +992,152 @@ File Shadowing is not available on MS Windows. @node Time Stamps @subsection Updating Time Stamps Automatically -@cindex time stamps +@cindex time stamps, automatic file timestamps @cindex modification dates -@cindex locale, date format +@cindex last modified time -You can arrange to put a time stamp in a file, so that it is updated -automatically each time you edit and save the file. The time stamp -must be in the first eight lines of the file, and you should insert it -like this: +You can arrange to have a time stamp in a file be updated +automatically each time you save the file. +(A time stamp may also be called a date stamp or a last modified time.) +Having a time stamp in the text of a file ensures that the time the file +was written will be preserved even if the file is copied or transformed +in a way that loses the file system's modification time. + +There are two steps to setting up automatic time stamping. +First, the file needs a time stamp template +somewhere in the first eight lines. +The template looks like this: @example Time-stamp: <> @end example @noindent -or like this: +or (your choice) like this: @example Time-stamp: " " @end example @findex time-stamp - Then add the function @code{time-stamp} to the hook -@code{before-save-hook} (@pxref{Hooks}). When you save the file, this -function then automatically updates the time stamp with the current -date and time. You can also use the command @kbd{M-x time-stamp} to -update the time stamp manually. By default the time stamp is +With that template in place, you can update the current buffer's time +stamp once immediately with the command @kbd{M-x time-stamp}. +Emacs will check for a template; if a template is found, +Emacs will write the current date, time, author, and/or +other info between the brackets or quotes. +(If the buffer has no template, @code{time-stamp} does nothing.) +After the first time stamp, the line might look like this: + +@example +Time-stamp: <1993-07-06 11:05:14 terryg> +@end example + +Second, configure Emacs to run @code{time-stamp} any time it saves a +file, by adding @code{time-stamp} +to @code{before-save-hook} (@pxref{Hooks}). +You can either customize the option @code{before-save-hook} +(with @kbd{M-x customize-option}, @pxref{Specific Customization}), +or you can edit your init file adding this line: + +@example +(add-hook 'before-save-hook 'time-stamp) +@end example + +@menu +* Time Stamp Customization:: How to customize with time-stamp-pattern. +* Time Stamps for One File:: Ensure automatic time-stamp of a specific file. +@end menu + +@node Time Stamp Customization +@subsubsection Customizing the Time Stamp + +@vindex time-stamp-pattern +To customize the time stamp in a particular file, set the +variable @code{time-stamp-pattern} in that file's local variables +list (@pxref{Specifying File Variables}). +You can change what pattern @code{time-stamp} will match against to +identify a template and where in the file to look for the pattern using +@code{time-stamp-pattern}; for details, see the variable's built-in +documentation (with @kbd{C-h v}, @pxref{Name Help}). + +As a simple example, if this line occurs near the top of a file: + +@example +publishing_year_and_city = "Published nnnn in Boston, Mass."; +@end example + +@noindent +then the following comment at the end of the same file tells +@code{time-stamp} how to identify and update that custom template: + +@example +@group +// Local variables: +// time-stamp-pattern: "Published %Y in Boston" +// End: +@end group +@end example + +This pattern says that the text before the start of the time stamp is +``Published '', and the text after the end is `` in Boston''. +If @code{time-stamp} finds both in one of the first eight lines, +what is between will be replaced by the current year, as requested by +the @code{%Y} format. + +After any change to file-local variables, +type @kbd{M-x normal-mode} to re-read them. + +Here is another example, with the time stamp inserted into +the last paragraph of an HTML document. +Since this template is at the end of the document, not in the first +eight lines, @code{time-stamp-format} starts with @code{-10/} to tell +@code{time-stamp} to look at the last 10 lines. +The @code{%%} asks for the default format +(specified by @code{time-stamp-format}). + +@example +@r{@dots{}} +

Last modified:

+ + + +@end example + +@vindex time-stamp-format +By default the time stamp is formatted according to your locale setting (@pxref{Environment}) and time zone (@pxref{Time of Day,,, elisp, The Emacs Lisp Reference -Manual}). For customizations, see the Custom group @code{time-stamp}. +Manual}). +See the built-in documentation for the variable @code{time-stamp-format} +for specifics and other variables that affect the formatting. + +@node Time Stamps for One File +@subsubsection Forcing Time Stamps for One File + +If you are working on a file with multiple authors, and you cannot +be sure the other authors have enabled time-stamping globally in +their Emacs init files, you can force it to be enabled for a +particular file by adding @code{time-stamp} to that buffer's +@code{before-save-hook} in that file's local variables list. +To extend one of the previous examples: + +@example +@group +// Local variables: +// eval: (add-hook 'before-save-hook 'time-stamp nil t) +// time-stamp-pattern: "Published %Y in Boston" +// End: +@end group +@end example + +@noindent +Although this example shows them both set together, +you can use @code{eval} without also setting @code{time-stamp-pattern} +if you like the default pattern. @node Reverting @section Reverting a Buffer diff --git a/lisp/info.el b/lisp/info.el index b484afc08cc..4aafe223549 100644 --- a/lisp/info.el +++ b/lisp/info.el @@ -4666,7 +4666,6 @@ Advanced commands: ("java" . "ccmode") ("idl" . "ccmode") ("pike" . "ccmode") ("skeleton" . "autotype") ("auto-insert" . "autotype") ("copyright" . "autotype") ("executable" . "autotype") - ("time-stamp" . "autotype") ("tempo" . "autotype") ("hippie-expand" . "autotype") ("cvs" . "pcl-cvs") ("ada" . "ada-mode") "calc" ("calcAlg" . "calc") ("calcDigit" . "calc") ("calcVar" . "calc") diff --git a/lisp/time-stamp.el b/lisp/time-stamp.el index 45de5a185e1..eb438ce3e52 100644 --- a/lisp/time-stamp.el +++ b/lisp/time-stamp.el @@ -31,8 +31,8 @@ ;; (add-hook 'before-save-hook 'time-stamp) ;; Now any time-stamp templates in your files will be updated automatically. -;; See the documentation for the functions `time-stamp' -;; and `time-stamp-toggle-active' for details. +;; For details, see the documentation for function `time-stamp' +;; and the Info node `Time Stamps'. ;;; Code: @@ -64,7 +64,7 @@ with %, as follows. %5z time zone offset: `-0500' (since Emacs 27; see note below) Non-date items: -%% a literal percent character: `%' +%% literal percent character: \"%\" %f file name without directory %F absolute file name %l login name %L full name of logged-in user %q unqualified host name %Q fully-qualified host name @@ -74,12 +74,12 @@ Decimal digits between the % and the type character specify the field width. Strings are truncated on the right. A leading zero in the field width zero-fills a number. -For example, to get the format used by the `date' command, +For example, to get a common format used by the \"date\" command, use \"%3a %3b %2d %02H:%02M:%02S %Z %Y\". The values of non-numeric formatted items depend on the locale setting recorded in `system-time-locale' and `locale-coding-system'. -The examples here are for the default (`C') locale. +The examples here are for the default (\"C\") locale. `time-stamp-time-zone' controls the time zone used. The default padding of some formats has changed to be more compatible @@ -95,7 +95,7 @@ edited by older versions of Emacs also, do not use this format yet." (defcustom time-stamp-active t - "Non-nil to enable time-stamping of buffers by \\[time-stamp]. + "Non-nil enables time-stamping of buffers by \\[time-stamp]. Can be toggled by \\[time-stamp-toggle-active]. This option does not affect when `time-stamp' is run, only what it @@ -229,7 +229,11 @@ your init file, you would be incompatible with other people's files.") (defvar time-stamp-count 1 ;Do not change! "How many templates \\[time-stamp] will look for in a buffer. -The same time stamp will be written in each case. + +If the value is greater than 1, the same time stamp will be written in +each case. If you want to insert different text on different lines, +then instead of changing this variable, include a newline (written as +\"\\n\") in `time-stamp-format' or the format part of `time-stamp-pattern'. `time-stamp-count' is best changed with a file-local variable. If you were to change it in your init file, you would be incompatible @@ -240,55 +244,61 @@ with other people's files.") (defvar time-stamp-pattern nil ;Do not change! "Convenience variable setting all `time-stamp' location and format values. This string has four parts, each of which is optional. -These four parts set `time-stamp-line-limit', `time-stamp-start', -`time-stamp-format', and `time-stamp-end'. See the documentation -for each of these variables for details. +These four parts override `time-stamp-line-limit', `time-stamp-start', +`time-stamp-format' and `time-stamp-end', respectively. See the +documentation for each of these variables for details. The first part is a number followed by a slash; the number sets the number of lines at the beginning (negative counts from end) of the file searched for the time stamp. The number and the slash may be omitted to use the -normal value. +value of `time-stamp-line-limit' as the number. The second part is a regexp identifying the pattern preceding the time stamp. -This part may be omitted to use the normal pattern. +This part may be omitted to use the value of `time-stamp-start'. -The third part specifies the format of the time stamp inserted. See -the documentation for `time-stamp-format' for details. Specify this -part as \"%%\" to use the normal format. +The third part specifies the format of the time stamp inserted. Specify +this part as \"%%\" to use the value of `time-stamp-format'. The fourth part is a regexp identifying the pattern following the time stamp. -This part may be omitted to use the normal pattern. +This part may be omitted to use the value of `time-stamp-end'. The pattern does not need to match the entire line of the time stamp. +The pattern will update time stamp information on multiple lines if the +pattern includes newlines, which can be written as \"\\n\". These variables are best changed with file-local variables. If you were to change `time-stamp-pattern', `time-stamp-line-limit', `time-stamp-start', or `time-stamp-end' in your init file, you would be incompatible with other people's files. -See also `time-stamp-count' and `time-stamp-inserts-lines'. - Examples: -\"-10/\" (sets only `time-stamp-line-limit') +;; time-stamp-pattern: \"-10/\" + (sets only `time-stamp-line-limit') -\"-9/^Last modified: %%$\" (sets `time-stamp-line-limit', -`time-stamp-start' and `time-stamp-end') +// time-stamp-pattern: \"-9/^Last modified: %%$\" + (sets `time-stamp-line-limit', `time-stamp-start' and `time-stamp-end') -\"@set Time-stamp: %:B %1d, %Y$\" (sets `time-stamp-start', -`time-stamp-format' and `time-stamp-end') +@c time-stamp-pattern: \"@set Time-stamp: %:B %1d, %Y$\" + (sets `time-stamp-start', `time-stamp-format' and `time-stamp-end') -\"newcommand{\\\\\\\\timestamp}{%%}\" (sets `time-stamp-start' -and `time-stamp-end')") +%% time-stamp-pattern: \"newcommand{\\\\\\\\timestamp}{%%}\" + (sets `time-stamp-start' and `time-stamp-end') + +See Info node `Time Stamp Customization' for more discussion and more +in-depth examples. + + +See also `time-stamp-count' and `time-stamp-inserts-lines'.") ;;;###autoload(put 'time-stamp-pattern 'safe-local-variable 'stringp) ;;;###autoload (defun time-stamp () - "Update any time stamp string(s) in the buffer. -This function looks for a time stamp template and updates it with -the current date, time, and/or other info. + "Update any time stamp strings (timestamps) in the buffer. +Look for a time stamp template and update it with the current +date, time, author, and/or other info. The template, which you manually create on one of the first 8 lines of the file before running this function, by default can look like @@ -311,12 +321,11 @@ To enable automatic time-stamping for only a specific file, add this line to a local variables list near the end of the file: eval: (add-hook \\='before-save-hook \\='time-stamp nil t) -If the file has no time-stamp template, this function does nothing. +If the file has no time stamp template or if `time-stamp-active' is nil, +this function does nothing. You can set `time-stamp-pattern' in a file's local variables list -to customize the information in the time stamp and where it is written. - -The time stamp is updated only if `time-stamp-active' is non-nil." +to customize the information in the time stamp and where it is written." (interactive) (let ((line-limit time-stamp-line-limit) (ts-start time-stamp-start) @@ -466,10 +475,15 @@ Internal helper used by `time-stamp-string-preprocess'." (format-time-string format time time-stamp-time-zone)) (defun time-stamp-string (&optional ts-format time) - "Generate the new string to be inserted by \\[time-stamp]. -Optionally use format TS-FORMAT instead of `time-stamp-format' to -format the string. Optional second argument TIME is only for testing; -normally the current time is used." + "Return the current time and other info formatted for \\[time-stamp]. +Optional first argument TS-FORMAT gives the format to use; it defaults +to the value of `time-stamp-format'. Thus, with no arguments, +this function returns the string `time-stamp' would use to update +its template in the buffer. The format accepted is similar to the +format used by `format-time-string' with some extensions; see the +documentation of `time-stamp-format' for details. +Optional second argument TIME is only for testing; normally the current +time is used. The time zone is determined by `time-stamp-time-zone'." (if (stringp (or ts-format (setq ts-format time-stamp-format))) (time-stamp-string-preprocess ts-format time))) From 6cac92928a99a2cf33aeeeddf295cf981750391c Mon Sep 17 00:00:00 2001 From: Pip Cet Date: Mon, 17 Feb 2025 15:21:16 +0000 Subject: [PATCH 004/395] Fix compilation errors due to insufficient compiler safety (bug#63288) The default safety level is 1. Restoring the default safety level to 1 after it was temporarily 0 should reset byte-compile-delete-errors to nil, its default level. Failing to do that resulted in miscompilation of code in highly-parallel builds. * lisp/emacs-lisp/cl-macs.el (cl--do-proclaim): Change 'byte-compile-delete-errors' to become t only at 'safety' level 0, not levels 1 or 2. (cherry picked from commit 53a5dada413662389a17c551a00d215e51f5049f) --- lisp/emacs-lisp/cl-macs.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el index 8caf2f1eac0..2a0a9e5c6de 100644 --- a/lisp/emacs-lisp/cl-macs.el +++ b/lisp/emacs-lisp/cl-macs.el @@ -2670,7 +2670,7 @@ Example: (let ((speed (assq (nth 1 (assq 'speed (cdr spec))) '((0 nil) (1 t) (2 t) (3 t)))) (safety (assq (nth 1 (assq 'safety (cdr spec))) - '((0 t) (1 t) (2 t) (3 nil))))) + '((0 t) (1 nil) (2 nil) (3 nil))))) (if speed (setq cl--optimize-speed (car speed) byte-optimize (nth 1 speed))) (if safety (setq cl--optimize-safety (car safety) From 3f9ac99fc7e024678dff1ac3ff38e617ef2606fe Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Tue, 1 Apr 2025 15:24:44 +0200 Subject: [PATCH 005/395] Fix Tramp's file-attributes cache * lisp/net/tramp-adb.el (tramp-adb-handle-file-executable-p): Check also for sticky bit. (tramp-adb-handle-file-readable-p): Simplify. * lisp/net/tramp-gvfs.el (tramp-gvfs-handle-file-executable-p): Check also for sticky bit. Force `file-attributes' check. * lisp/net/tramp-sh.el (tramp-sh-handle-file-executable-p): Check also for sticky bit. (tramp-sh-handle-file-readable-p) (tramp-sh-handle-file-writable-p): Simplify. * lisp/net/tramp-sudoedit.el (tramp-sudoedit-handle-file-executable-p): Check also for sticky bit. (tramp-sudoedit-handle-file-readable-p) (tramp-sudoedit-handle-file-writable-p): Simplify. * lisp/net/tramp.el (tramp-use-file-attributes): Fix docstring. (tramp-handle-file-readable-p, tramp-handle-file-writable-p): Force `file-attributes' check. Use `file-truename' for symbolic links. (tramp-check-cached-permissions): New optional argument FORCE. Fix symlink check. Check also for sticky bit. (Bug#77402) * test/lisp/net/tramp-tests.el (tramp-test20-file-modes-without-file-attributes) (tramp-test21-file-links-without-file-attributes): New tests. --- lisp/net/tramp-adb.el | 17 ++++++++--------- lisp/net/tramp-gvfs.el | 5 +++-- lisp/net/tramp-sh.el | 23 ++++++++++------------- lisp/net/tramp-sudoedit.el | 24 +++++++++++------------- lisp/net/tramp.el | 31 ++++++++++++++++++------------- test/lisp/net/tramp-tests.el | 4 ++++ 6 files changed, 54 insertions(+), 50 deletions(-) diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el index 1ecabd8165f..dee6b7899e9 100644 --- a/lisp/net/tramp-adb.el +++ b/lisp/net/tramp-adb.el @@ -480,11 +480,11 @@ Emacs dired can't find files." (with-tramp-file-property v localname "file-executable-p" ;; Examine `file-attributes' cache to see if request can be ;; satisfied without remote operation. - (if (tramp-use-file-attributes v) - (or (tramp-check-cached-permissions v ?x) - (tramp-check-cached-permissions v ?s)) - (tramp-adb-send-command-and-check - v (format "test -x %s" (tramp-shell-quote-argument localname))))))) + (or (tramp-check-cached-permissions v ?x) + (tramp-check-cached-permissions v ?s) + (tramp-check-cached-permissions v ?t) + (tramp-adb-send-command-and-check + v (format "test -x %s" (tramp-shell-quote-argument localname))))))) (defun tramp-adb-handle-file-exists-p (filename) "Like `file-exists-p' for Tramp files." @@ -498,10 +498,9 @@ Emacs dired can't find files." (with-tramp-file-property v localname "file-readable-p" ;; Examine `file-attributes' cache to see if request can be ;; satisfied without remote operation. - (if (tramp-use-file-attributes v) - (tramp-handle-file-readable-p filename) - (tramp-adb-send-command-and-check - v (format "test -r %s" (tramp-shell-quote-argument localname))))))) + (or (tramp-handle-file-readable-p filename) + (tramp-adb-send-command-and-check + v (format "test -r %s" (tramp-shell-quote-argument localname))))))) (defun tramp-adb-handle-file-writable-p (filename) "Like `file-writable-p' for Tramp files." diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el index 3df69d79fce..9530aa3733a 100644 --- a/lisp/net/tramp-gvfs.el +++ b/lisp/net/tramp-gvfs.el @@ -1467,8 +1467,9 @@ If FILE-SYSTEM is non-nil, return file system attributes." "Like `file-executable-p' for Tramp files." (with-parsed-tramp-file-name (expand-file-name filename) nil (with-tramp-file-property v localname "file-executable-p" - (or (tramp-check-cached-permissions v ?x) - (tramp-check-cached-permissions v ?s))))) + (or (tramp-check-cached-permissions v ?x 'force) + (tramp-check-cached-permissions v ?s 'force) + (tramp-check-cached-permissions v ?t 'force))))) (defun tramp-gvfs-handle-file-name-all-completions (filename directory) "Like `file-name-all-completions' for Tramp files." diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index ef4ddee8a53..4b770e95038 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -1783,10 +1783,10 @@ ID-FORMAT valid values are `string' and `integer'." (with-tramp-file-property v localname "file-executable-p" ;; Examine `file-attributes' cache to see if request can be ;; satisfied without remote operation. - (if (tramp-use-file-attributes v) - (or (tramp-check-cached-permissions v ?x) - (tramp-check-cached-permissions v ?s)) - (tramp-run-test v "-x" localname))))) + (or (tramp-check-cached-permissions v ?x) + (tramp-check-cached-permissions v ?s) + (tramp-check-cached-permissions v ?t) + (tramp-run-test v "-x" localname))))) (defun tramp-sh-handle-file-readable-p (filename) "Like `file-readable-p' for Tramp files." @@ -1794,9 +1794,8 @@ ID-FORMAT valid values are `string' and `integer'." (with-tramp-file-property v localname "file-readable-p" ;; Examine `file-attributes' cache to see if request can be ;; satisfied without remote operation. - (if (tramp-use-file-attributes v) - (tramp-handle-file-readable-p filename) - (tramp-run-test v "-r" localname))))) + (or (tramp-handle-file-readable-p filename) + (tramp-run-test v "-r" localname))))) ;; Functions implemented using the basic functions above. @@ -1826,13 +1825,11 @@ ID-FORMAT valid values are `string' and `integer'." (if (file-exists-p filename) ;; Examine `file-attributes' cache to see if request can be ;; satisfied without remote operation. - (if (tramp-use-file-attributes v) - (tramp-check-cached-permissions v ?w) - (tramp-run-test v "-w" localname)) + (or (tramp-check-cached-permissions v ?w) + (tramp-run-test v "-w" localname)) ;; If file doesn't exist, check if directory is writable. - (and - (file-directory-p (file-name-directory filename)) - (file-writable-p (file-name-directory filename))))))) + (and (file-directory-p (file-name-directory filename)) + (file-writable-p (file-name-directory filename))))))) (defun tramp-sh-handle-file-ownership-preserved-p (filename &optional group) "Like `file-ownership-preserved-p' for Tramp files." diff --git a/lisp/net/tramp-sudoedit.el b/lisp/net/tramp-sudoedit.el index ff01eac5b93..59b4ea46b8c 100644 --- a/lisp/net/tramp-sudoedit.el +++ b/lisp/net/tramp-sudoedit.el @@ -479,11 +479,11 @@ the result will be a local, non-Tramp, file name." (with-tramp-file-property v localname "file-executable-p" ;; Examine `file-attributes' cache to see if request can be ;; satisfied without remote operation. - (if (tramp-use-file-attributes v) - (or (tramp-check-cached-permissions v ?x) - (tramp-check-cached-permissions v ?s)) - (tramp-sudoedit-send-command - v "test" "-x" (file-name-unquote localname)))))) + (or (tramp-check-cached-permissions v ?x) + (tramp-check-cached-permissions v ?s) + (tramp-check-cached-permissions v ?t) + (tramp-sudoedit-send-command + v "test" "-x" (file-name-unquote localname)))))) (defun tramp-sudoedit-handle-file-exists-p (filename) "Like `file-exists-p' for Tramp files." @@ -519,10 +519,9 @@ the result will be a local, non-Tramp, file name." (with-tramp-file-property v localname "file-readable-p" ;; Examine `file-attributes' cache to see if request can be ;; satisfied without remote operation. - (if (tramp-use-file-attributes v) - (tramp-handle-file-readable-p filename) - (tramp-sudoedit-send-command - v "test" "-r" (file-name-unquote localname)))))) + (or (tramp-handle-file-readable-p filename) + (tramp-sudoedit-send-command + v "test" "-r" (file-name-unquote localname)))))) (defun tramp-sudoedit-handle-set-file-modes (filename mode &optional flag) "Like `set-file-modes' for Tramp files." @@ -604,10 +603,9 @@ the result will be a local, non-Tramp, file name." (if (file-exists-p filename) ;; Examine `file-attributes' cache to see if request can be ;; satisfied without remote operation. - (if (tramp-use-file-attributes v) - (tramp-check-cached-permissions v ?w) - (tramp-sudoedit-send-command - v "test" "-w" (file-name-unquote localname))) + (or (tramp-check-cached-permissions v ?w) + (tramp-sudoedit-send-command + v "test" "-w" (file-name-unquote localname))) ;; If file doesn't exist, check if directory is writable. (and (file-directory-p (file-name-directory filename)) diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index ec8835c13f0..6c1a4ae7127 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -3509,7 +3509,7 @@ BODY is the backend specific code." nil))) (defcustom tramp-use-file-attributes t - "Whether to use \"file-attributes\" file property for check. + "Whether to use \"file-attributes\" connection property for check. This is relevant for read, write, and execute permissions. On some file systems using NFS4_ACL, the permission string as returned from `stat' or `ls', is not sufficient to provide more fine-grained information. @@ -4331,13 +4331,12 @@ Let-bind it when necessary.") "Like `file-readable-p' for Tramp files." (with-parsed-tramp-file-name (expand-file-name filename) nil (with-tramp-file-property v localname "file-readable-p" - (or (tramp-check-cached-permissions v ?r) + (or (tramp-check-cached-permissions v ?r 'force) ;; `tramp-check-cached-permissions' doesn't handle symbolic ;; links. (and-let* ((symlink (file-symlink-p filename)) ((stringp symlink)) - ((file-readable-p - (concat (file-remote-p filename) symlink))))))))) + ((file-readable-p (file-truename filename))))))))) (defun tramp-handle-file-regular-p (filename) "Like `file-regular-p' for Tramp files." @@ -4431,7 +4430,12 @@ existing) are returned." (with-parsed-tramp-file-name (expand-file-name filename) nil (with-tramp-file-property v localname "file-writable-p" (if (file-exists-p filename) - (tramp-check-cached-permissions v ?w) + (or (tramp-check-cached-permissions v ?w 'force) + ;; `tramp-check-cached-permissions' doesn't handle + ;; symbolic links. + (and-let* ((symlink (file-symlink-p filename)) + ((stringp symlink)) + ((file-writable-p (file-truename filename)))))) ;; If file doesn't exist, check if directory is writable. (and (file-directory-p (file-name-directory filename)) (file-writable-p (file-name-directory filename))))))) @@ -6424,22 +6428,23 @@ VEC is used for tracing." (when vec (tramp-message vec 7 "locale %s" (or locale "C"))) (or locale "C")))) -(defun tramp-check-cached-permissions (vec access) +(defun tramp-check-cached-permissions (vec access &optional force) "Check `file-attributes' caches for VEC. -Return t if according to the cache access type ACCESS is known to -be granted." +Return t if according to the cache access type ACCESS is known to be +granted, if `tramp-use-file-attributes' mandates this. If FORCE is +non-nil, use connection property \"file-attributes\" mandatory." (when-let* ((offset (cond ((eq ?r access) 1) ((eq ?w access) 2) ((eq ?x access) 3) - ((eq ?s access) 3))) + ((eq ?s access) 3) + ((eq ?t access) 3))) + ((or force (tramp-use-file-attributes vec))) (file-attr (file-attributes (tramp-make-tramp-file-name vec))) + ;; Not a symlink. + ((not (stringp (file-attribute-type file-attr)))) (remote-uid (tramp-get-remote-uid vec 'integer)) (remote-gid (tramp-get-remote-gid vec 'integer))) - (or - ;; Not a symlink. - (eq t (file-attribute-type file-attr)) - (null (file-attribute-type file-attr))) (or ;; World accessible. (eq access (aref (file-attribute-modes file-attr) (+ offset 6))) diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el index 605b26206c4..e22f1afc18b 100644 --- a/test/lisp/net/tramp-tests.el +++ b/test/lisp/net/tramp-tests.el @@ -4279,6 +4279,8 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'." (ignore-errors (delete-file tmp-name1)) (ignore-errors (delete-file tmp-name2))))))) +(tramp--test-deftest-without-file-attributes tramp-test20-file-modes) + ;; Method "smb" could run into "NT_STATUS_REVISION_MISMATCH" error. (defmacro tramp--test-ignore-add-name-to-file-error (&rest body) "Run BODY, ignoring \"error with add-name-to-file\" file error." @@ -4578,6 +4580,8 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (should (string-equal (file-truename dir1) (expand-file-name dir1))) (should (string-equal (file-truename dir2) (expand-file-name dir2))))))) +(tramp--test-deftest-without-file-attributes tramp-test21-file-links) + (ert-deftest tramp-test22-file-times () "Check `set-file-times' and `file-newer-than-file-p'." (skip-unless (tramp--test-enabled)) From a0962074743521447b1549f9e0ecd03325debc0d Mon Sep 17 00:00:00 2001 From: Stephen Gildea Date: Mon, 31 Mar 2025 22:34:20 -0700 Subject: [PATCH 006/395] printed manuals: xrefs in and out of "Preparing Patches" Fix two cases of links where the on-line manual is one document but the manual is split into separate documents for printing: * doc/emacs/package.texi (Fetching Package Sources): fix printed link to "Preparing Patches" to point to separate document. * doc/emacs/vc1-xtra.texi (Preparing Patches): fix printed link to "Directory Variables" to point to separate document. --- doc/emacs/package.texi | 8 +++++++- doc/emacs/vc1-xtra.texi | 9 ++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/doc/emacs/package.texi b/doc/emacs/package.texi index 857584b9933..182efff7afb 100644 --- a/doc/emacs/package.texi +++ b/doc/emacs/package.texi @@ -654,7 +654,13 @@ maintainer, you can use the command @code{package-report-bug} to report a bug via Email. This report will include all the user options that you have customized. If you have made a change you wish to share with the maintainers, first commit your changes then use the command -@code{package-vc-prepare-patch} to share it. @xref{Preparing Patches}. +@code{package-vc-prepare-patch} to share it. +@iftex +@xref{Preparing Patches,,,emacs-xtra, Specialized Emacs Features}. +@end iftex +@ifnottex +@xref{Preparing Patches}. +@end ifnottex @findex package-vc-install-from-checkout @findex package-vc-rebuild diff --git a/doc/emacs/vc1-xtra.texi b/doc/emacs/vc1-xtra.texi index 45bc6d77728..5c448e741f2 100644 --- a/doc/emacs/vc1-xtra.texi +++ b/doc/emacs/vc1-xtra.texi @@ -312,7 +312,14 @@ If you expect to contribute patches on a regular basis, you can set the user option @code{vc-default-patch-addressee} to the address(es) you wish to use. This will be used as the default value when invoking @code{vc-prepare-patch}. Project maintainers may consider setting -this as a directory local variable (@pxref{Directory Variables}). +this as a directory local variable +@iftex +(@pxref{Directory Variables,,Per-Directory Local Variables, +emacs, the Emacs Manual}). +@end iftex +@ifnottex +(@pxref{Directory Variables}). +@end ifnottex @node Customizing VC @subsection Customizing VC From 1e865a2f2889ecbee06b9eefdd82a4cda04d6eee Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Wed, 2 Apr 2025 18:37:22 +0200 Subject: [PATCH 007/395] Explain, how to suppress Tramp warnings * doc/misc/tramp.texi (Frequently Asked Questions): Remove double item. (Traces and Profiles): Mention `warning-suppress-types'. (Bug#77422) --- doc/misc/tramp.texi | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi index 5a2e44456ee..280feb084d1 100644 --- a/doc/misc/tramp.texi +++ b/doc/misc/tramp.texi @@ -6204,17 +6204,6 @@ If these errors can be ignored, set user option non-@code{nil} value. This transforms the error into a warning. -@item -How to ignore errors when changing file attributes? - -@vindex tramp-inhibit-errors-if-setting-file-attributes-fail -Sometimes, for example while saving remote files, errors appear when -changing file attributes like permissions, time stamps, or ownership. -If these errors can be ignored, set user option -@code{tramp-inhibit-errors-if-setting-file-attributes-fail} to a -non-@code{nil} value. This transforms the error into a warning. - - @item How to disable other packages from calling @value{tramp}? @@ -6648,6 +6637,15 @@ the following settings are required: @end group @end lisp +@vindex warning-suppress-types +@value{tramp} warnings are displayed in the @file{*Warnings*} buffer, +which pops up. If you don't want to see this buffer for every +@value{tramp} warning, set @code{warning-suppress-types}: + +@lisp +(setq warning-suppress-types '((tramp))) +@end lisp + If @code{tramp-verbose} is greater than or equal to 10, Lisp backtraces are also added to the @value{tramp} debug buffer in case of errors. From fd5f817882a81b6f64471971c88bdd3d0c126956 Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Thu, 3 Apr 2025 14:57:06 +0200 Subject: [PATCH 008/395] Improve Tramp's initial warnings * lisp/net/tramp-cache.el (tramp-dump-connection-properties): Adapt comment. * lisp/net/tramp-compat.el (tramp-warning): Declare and use it. * lisp/net/tramp-message.el (tramp-warning): Declare `indent'. --- lisp/net/tramp-cache.el | 11 +++++------ lisp/net/tramp-compat.el | 38 +++++++++++++++++++++----------------- lisp/net/tramp-message.el | 2 +- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/lisp/net/tramp-cache.el b/lisp/net/tramp-cache.el index 14ee10416ab..71b8cfa67bf 100644 --- a/lisp/net/tramp-cache.el +++ b/lisp/net/tramp-cache.el @@ -573,12 +573,11 @@ PROPERTIES is a list of file properties (strings)." print-length print-level) ;; Remove `tramp-null-hop'. (remhash tramp-null-hop cache) - ;; Remove temporary data. If there is the key "login-as", we - ;; don't save either, because all other properties might - ;; depend on the login name, and we want to give the - ;; possibility to use another login name later on. Key - ;; "started" exists for the "ftp" method only, which must not - ;; be kept persistent. + ;; If there is the key "login-as", we don't save, because all + ;; other properties might depend on the login name, and we + ;; want to give the possibility to use another login name + ;; later on. Key "started" exists for the "ftp" method only, + ;; which must not be kept persistent. (maphash (lambda (key value) (if (and (tramp-file-name-p key) (hash-table-p value) diff --git a/lisp/net/tramp-compat.el b/lisp/net/tramp-compat.el index c9629a6f3c9..c1fb8ceaa80 100644 --- a/lisp/net/tramp-compat.el +++ b/lisp/net/tramp-compat.el @@ -38,30 +38,34 @@ (require 'xdg) (declare-function tramp-error "tramp-message") +(declare-function tramp-warning "tramp-message") (declare-function tramp-tramp-file-p "tramp") (defvar tramp-temp-name-prefix) (defconst tramp-compat-emacs-compiled-version (eval-when-compile emacs-version) "The Emacs version used for compilation.") -(unless (= emacs-major-version - (car (version-to-list tramp-compat-emacs-compiled-version))) - (lwarn 'tramp :warning - "Tramp has been compiled with Emacs %s, this is Emacs %s" - tramp-compat-emacs-compiled-version emacs-version)) +(with-eval-after-load 'tramp + (unless (= emacs-major-version + (car (version-to-list tramp-compat-emacs-compiled-version))) + (tramp-warning nil + "Tramp has been compiled with Emacs %s, this is Emacs %s" + tramp-compat-emacs-compiled-version emacs-version)) -(with-eval-after-load 'docker-tramp - (lwarn 'tramp :warning - (concat "Package `docker-tramp' has been obsoleted, " - "please use integrated package `tramp-container'"))) -(with-eval-after-load 'kubernetes-tramp - (lwarn 'tramp :warning - (concat "Package `kubernetes-tramp' has been obsoleted, " - "please use integrated package `tramp-container'"))) -(with-eval-after-load 'tramp-nspawn - (lwarn 'tramp :warning - (concat "Package `tramp-nspawn' has been obsoleted, " - "please use integrated package `tramp-container'"))) + (with-eval-after-load 'docker-tramp + (tramp-warning nil + (concat "Package `docker-tramp' has been obsoleted, " + "please use integrated package `tramp-container'"))) + + (with-eval-after-load 'kubernetes-tramp + (tramp-warning nil + (concat "Package `kubernetes-tramp' has been obsoleted, " + "please use integrated package `tramp-container'"))) + + (with-eval-after-load 'tramp-nspawn + (tramp-warning nil + (concat "Package `tramp-nspawn' has been obsoleted, " + "please use integrated package `tramp-container'")))) ;; For not existing functions, obsolete functions, or functions with a ;; changed argument list, there are compiler warnings. We want to diff --git a/lisp/net/tramp-message.el b/lisp/net/tramp-message.el index 73a0ea9ce28..5282b00ec51 100644 --- a/lisp/net/tramp-message.el +++ b/lisp/net/tramp-message.el @@ -467,7 +467,7 @@ the resulting error message." "Show a warning. VEC-OR-PROC identifies the connection to use, remaining arguments passed to `tramp-message'." - (declare (tramp-suppress-trace t)) + (declare (indent 1) (tramp-suppress-trace t)) (let (signal-hook-function) (apply 'tramp-message vec-or-proc 2 fmt-string arguments) (apply 'lwarn 'tramp :warning fmt-string arguments))) From ae7f65f3f9cbe03608c9920e7f2f82a5a82e62d6 Mon Sep 17 00:00:00 2001 From: Stephen Berman Date: Thu, 3 Apr 2025 16:53:35 +0200 Subject: [PATCH 009/395] Fix obsolete documentation of desktop library * doc/emacs/misc.texi (Saving Emacs Sessions): Replace documentation of the long-deleted user option 'desktop-clear-preserve-buffers-regexp' with documentation of 'desktop-clear-preserve-buffers'. --- doc/emacs/misc.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi index 5896dc83fe1..fbcb7294505 100644 --- a/doc/emacs/misc.texi +++ b/doc/emacs/misc.texi @@ -2907,8 +2907,8 @@ invoking @kbd{M-x desktop-read} next. The @code{desktop-clear} command kills all buffers except for internal ones, and clears the global variables listed in @code{desktop-globals-to-clear}. If you want it to preserve certain buffers, customize the variable -@code{desktop-clear-preserve-buffers-regexp}, whose value is a regular -expression matching the names of buffers not to kill. +@code{desktop-clear-preserve-buffers}, whose value is a list of regular +expressions matching the names of buffers not to kill. @vindex desktop-globals-to-save If you want to save minibuffer history from one session to From 9869aa1a1003fbd4b3c7d51f9cdd7e77bd68d985 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 29 Mar 2025 21:15:02 -0700 Subject: [PATCH 010/395] Tighten the criteria for a defun in typescript-ts-mode (bug#77369) * lisp/progmodes/typescript-ts-mode.el: (typescript-ts-mode--defun-type-regexp): New variable (backported from master). (typescript-ts-mode--defun-predicate): New function. (typescript-ts-base-mode): Use new predicate. --- lisp/progmodes/typescript-ts-mode.el | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index 0ffcb144771..871dbc2e3dc 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -452,6 +452,27 @@ See `treesit-thing-settings' for more information.") "Nodes that designate sexps in TypeScript. See `treesit-thing-settings' for more information.") +(defvar typescript-ts-mode--defun-type-regexp + (rx bos (or "internal_module" + "interface_declaration" + "class_declaration" + "method_definition" + "function_declaration" + "lexical_declaration") + eos) + "Settings for `treesit-defun-type-regexp'.") + +(defun typescript-ts-mode--defun-predicate (node) + "Check if NODE is a defun." + (pcase (treesit-node-type node) + ("lexical_declaration" + (treesit-node-match-p + (treesit-node-child-by-field-name + (treesit-node-child node 0 'named) + "value") + "arrow_function")) + (_ t))) + ;;;###autoload (define-derived-mode typescript-ts-base-mode prog-mode "TypeScript" "Generic major mode for editing TypeScript. @@ -470,10 +491,8 @@ This mode is intended to be inherited by concrete major modes." '((?\; . after) (?\{ . after) (?\} . before))) ;; Navigation. (setq-local treesit-defun-type-regexp - (regexp-opt '("class_declaration" - "method_definition" - "function_declaration" - "lexical_declaration"))) + (cons typescript-ts-mode--defun-type-regexp + #'typescript-ts-mode--defun-predicate)) (setq-local treesit-defun-name-function #'js--treesit-defun-name) (setq-local treesit-thing-settings From 99d70ce6c265744b21e1ffe6c034ded833917139 Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Fri, 4 Apr 2025 14:29:00 +0200 Subject: [PATCH 011/395] Fix Tramp problem with loooongish file names * lisp/net/tramp-sh.el (tramp-readlink-file-truename): New defconst. (tramp-bundle-read-file-names): Use new %m and %q format specifiers. (tramp-sh-handle-file-truename): Use `tramp-readlink-file-truename'. (tramp-bundle-read-file-names, tramp-get-remote-readlink): Simplify. (tramp-expand-script): Add format specifiers %m and %q for test commands. Addapt readlink call. Reported by Stacey Marshall . --- lisp/net/tramp-sh.el | 93 ++++++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 42 deletions(-) diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index 4b770e95038..9d74c2fd088 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -644,6 +644,14 @@ we have this shell function. Format specifiers are replaced by `tramp-expand-script', percent characters need to be doubled.") +(defconst tramp-readlink-file-truename + "if %m -h \"$1\"; then echo t; else echo nil; fi +%r \"$1\"" + "Shell script to produce output suitable for use with `file-truename' +on the remote file system. +Format specifiers are replaced by `tramp-expand-script', percent +characters need to be doubled.") + (defconst tramp-perl-file-truename "%p -e ' use File::Spec; @@ -1147,11 +1155,11 @@ characters need to be doubled.") (defconst tramp-bundle-read-file-names "echo \"(\" while read file; do - quoted=`echo \"$file\" | sed -e \"s/\\\"/\\\\\\\\\\\\\\\\\\\"/\"` - printf \"(%%b\" \"\\\"$quoted\\\"\" - if %s \"$file\"; then printf \" %%b\" t; else printf \" %%b\" nil; fi - if %s \"$file\"; then printf \" %%b\" t; else printf \" %%b\" nil; fi - if %s \"$file\"; then printf \" %%b)\n\" t; else printf \" %%b)\n\" nil; fi + quoted=`echo \"$file\" | sed -e \"s/\\\"/\\\\\\\\\\\\\\\\\\\"/\"` + printf \"(%%b\" \"\\\"$quoted\\\"\" + if %q \"$file\"; then printf \" %%b\" t; else printf \" %%b\" nil; fi + if %m -r \"$file\"; then printf \" %%b\" t; else printf \" %%b\" nil; fi + if %m -d \"$file\"; then printf \" %%b)\n\" t; else printf \" %%b)\n\" nil; fi done echo \")\"" "Script to check file attributes of a bundle of files. @@ -1287,18 +1295,15 @@ Operations not mentioned here will be handled by the normal Emacs functions.") (cond ;; Use GNU readlink --canonicalize-missing where available. ((tramp-get-remote-readlink v) + (tramp-maybe-send-script + v tramp-readlink-file-truename "tramp_readlink_file_truename") (tramp-send-command-and-check - v (format - (concat - "(if %s -h \"%s\"; then echo t; else echo nil; fi) && " - "%s --canonicalize-missing %s") - (tramp-get-test-command v) - (tramp-shell-quote-argument localname) - (tramp-get-remote-readlink v) - (tramp-shell-quote-argument localname))) + v (format "tramp_readlink_file_truename %s" + (tramp-shell-quote-argument localname))) (with-current-buffer (tramp-get-connection-buffer v) (goto-char (point-min)) - (tramp-set-file-property v localname "file-symlink-marker" (read (current-buffer))) + (tramp-set-file-property + v localname "file-symlink-marker" (read (current-buffer))) ;; We cannot call `read', the file name isn't quoted. (forward-line) (buffer-substring (point) (line-end-position)))) @@ -1314,7 +1319,8 @@ Operations not mentioned here will be handled by the normal Emacs functions.") (tramp-shell-quote-argument localname))) (with-current-buffer (tramp-get-connection-buffer v) (goto-char (point-min)) - (tramp-set-file-property v localname "file-symlink-marker" (read (current-buffer))) + (tramp-set-file-property + v localname "file-symlink-marker" (read (current-buffer))) (read (current-buffer)))) ;; Do it yourself. @@ -3595,12 +3601,7 @@ FILES must be the local names only. The cache attributes to be filled are described in `tramp-bundle-read-file-names'." (when files (tramp-maybe-send-script - vec - (format tramp-bundle-read-file-names - (tramp-get-file-exists-command vec) - (format "%s -r" (tramp-get-test-command vec)) - (format "%s -d" (tramp-get-test-command vec))) - "tramp_bundle_read_file_names") + vec tramp-bundle-read-file-names "tramp_bundle_read_file_names") (dolist (elt @@ -3986,14 +3987,15 @@ Fall back to normal file name handler if no Tramp handler exists." (defun tramp-expand-script (vec script) "Expand SCRIPT with remote files or commands. -\"%a\", \"%h\", \"%l\", \"%o\", \"%p\", \"%r\", \"%s\" and \"%y\" -format specifiers are replaced by the respective `awk', -`hexdump', `ls', `od', `perl', `readlink', `stat' and `python' -commands. \"%n\" is replaced by \"2>/dev/null\", and \"%t\" is -replaced by a temporary file name. If VEC is nil, the respective -local commands are used. If there is a format specifier which -cannot be expanded, this function returns nil." - (if (not (string-match-p (rx (| bol (not "%")) "%" (any "ahlnoprsty")) script)) +\"%a\", \"%h\", \"%l\", \"%m\", \"%o\", \"%p\", \"%q\", \"%r\", \"%s\" +and \"%y\" format specifiers are replaced by the respective `awk', +`hexdump', `ls', `test', od', `perl', `test -e', `readlink', `stat' and +`python' commands. \"%n\" is replaced by \"2>/dev/null\", and \"%t\" is +replaced by a temporary file name. If VEC is nil, the respective local +commands are used. If there is a format specifier which cannot be +expanded, this function returns nil." + (if (not (string-match-p + (rx (| bol (not "%")) "%" (any "ahlmnopqrsty")) script)) script (catch 'wont-work (let ((awk (when (string-match-p (rx (| bol (not "%")) "%a") script) @@ -4016,6 +4018,12 @@ cannot be expanded, this function returns nil." (or (tramp-get-ls-command vec) (throw 'wont-work nil)) (tramp-sh--quoting-style-options vec)))) + (test (when (string-match-p (rx (| bol (not "%")) "%m") script) + (or (tramp-get-test-command vec) + (throw 'wont-work nil)))) + (test-e (when (string-match-p (rx (| bol (not "%")) "%q") script) + (or (tramp-get-file-exists-command vec) + (throw 'wont-work nil)))) (od (when (string-match-p (rx (| bol (not "%")) "%o") script) (or (if vec (tramp-get-remote-od vec) (executable-find "od")) (throw 'wont-work nil)))) @@ -4031,11 +4039,13 @@ cannot be expanded, this function returns nil." (executable-find "python")) (throw 'wont-work nil)))) (readlink (when (string-match-p (rx (| bol (not "%")) "%r") script) - (or - (if vec - (tramp-get-remote-readlink vec) - (executable-find "readlink")) - (throw 'wont-work nil)))) + (format "%s %s" + (or + (if vec + (tramp-get-remote-readlink vec) + (executable-find "readlink")) + (throw 'wont-work nil)) + "--canonicalize-missing"))) (stat (when (string-match-p (rx (| bol (not "%")) "%s") script) (or (if vec @@ -4050,8 +4060,8 @@ cannot be expanded, this function returns nil." (format-spec script (format-spec-make - ?a awk ?h hdmp ?l ls ?n dev ?o od ?p perl - ?r readlink ?s stat ?t tmp ?y python)))))) + ?a awk ?h hdmp ?l ls ?m test ?n dev ?o od ?p perl + ?q test-e ?r readlink ?s stat ?t tmp ?y python)))))) (defun tramp-maybe-send-script (vec script name) "Define in remote shell function NAME implemented as SCRIPT. @@ -5850,12 +5860,11 @@ Nonexistent directories are removed from spec." "Determine remote `readlink' command." (with-tramp-connection-property vec "readlink" (tramp-message vec 5 "Finding a suitable `readlink' command") - (let ((result (tramp-find-executable - vec "readlink" (tramp-get-remote-path vec)))) - (when (and result - (tramp-send-command-and-check - vec (format "%s --canonicalize-missing /" result))) - result)))) + (when-let* ((result (tramp-find-executable + vec "readlink" (tramp-get-remote-path vec))) + ((tramp-send-command-and-check + vec (format "%s --canonicalize-missing /" result)))) + result))) (defun tramp-get-remote-touch (vec) "Determine remote `touch' command." From d582ed9dc9be516f17dc9a526c3f9615001a46a6 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 5 Apr 2025 10:30:30 +0800 Subject: [PATCH 012/395] Disable desktop-restore-frames by default on Android * lisp/desktop.el (desktop-restore-frames): Default to nil when \(featurep 'android). * doc/emacs/misc.texi (Saving Emacs Sessions): Adjust to match. --- doc/emacs/misc.texi | 13 ++++++++----- etc/NEWS | 7 +++++++ lisp/desktop.el | 10 +++++++--- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi index 08a7f910c5c..8b0f96a3de3 100644 --- a/doc/emacs/misc.texi +++ b/doc/emacs/misc.texi @@ -2924,11 +2924,14 @@ can use @kbd{M-x desktop-read} to restore a previously-saved desktop if the current Emacs session didn't load any desktop yet. @vindex desktop-restore-frames - By default, the desktop tries to save and restore the frame and -window configuration. To disable this, set -@code{desktop-restore-frames} to @code{nil}. (See that variable's -documentation for some related options that you can customize to -fine-tune this behavior.) + By default, the desktop tries to save and restore the frame and window +configuration.@footnote{Except on Android, where this option defaults to +@code{nil} because the window manager (@pxref{Android Windowing}) is too +prohibitive to admit of restoring frame configurations.} To disable or +enable this, set @code{desktop-restore-frames} to @code{nil} or any +non-@code{nil} value respectively. (See that variable's documentation +for some related options that you can customize to fine-tune this +behavior.) @vindex frameset-filter-alist When the desktop restores the frame and window configuration, it diff --git a/etc/NEWS b/etc/NEWS index dc77aff7ef2..fc202a795e4 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -2085,6 +2085,13 @@ Put differently, this enables input events to be read and recursive editing sessions to be started from non-main threads. The only platform where this remains unsupported is Nextstep (GNUstep or Mac OS). +--- +** 'desktop-restore-frames' has been disabled by default on Android systems. +Restrictions imposed on clients by the window manager on these systems +are too prohibitive to admit of restoring frame configurations, and on +the same account many window management facilities are unimplemented by +Emacs also. + --- ** 'NSSpeechRecognitionUsageDescription' now included in "Info.plist" (macOS). Should Emacs (or any built-in shell) invoke a process using macOS speech diff --git a/lisp/desktop.el b/lisp/desktop.el index 761d4558700..4067b5a1286 100644 --- a/lisp/desktop.el +++ b/lisp/desktop.el @@ -423,13 +423,17 @@ host is off-line." :type '(repeat symbol) :group 'desktop) -(defcustom desktop-restore-frames t +(defcustom desktop-restore-frames (not (featurep 'android)) "When non-nil, save and restore the frame and window configuration. See related options `desktop-restore-reuses-frames', -`desktop-restore-in-current-display', and `desktop-restore-forces-onscreen'." +`desktop-restore-in-current-display', and `desktop-restore-forces-onscreen'. + +This option is enabled by default elsewhere than on Android, where it is +disabled by default as programs are too handicapped by the window +manager for frames to be restored." :type 'boolean :group 'desktop - :version "24.4") + :version "31.1") (defcustom desktop-restore-in-current-display t "Controls how restoring of frames treats displays. From cd41247dc18f4e478ffb296198229ee22d44668c Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Fri, 4 Apr 2025 23:53:10 -0400 Subject: [PATCH 013/395] perl-mode.el: Avoid obsolete font-lock face vars * lisp/progmodes/perl-mode.el (perl-mode-abbrev-table): Merge defvar into the definition. (perl-font-lock-keywords-1, perl-font-lock-keywords-2): Avoid obsolete font-lock face vars. --- lisp/progmodes/perl-mode.el | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/lisp/progmodes/perl-mode.el b/lisp/progmodes/perl-mode.el index c95cf3af017..7820a599301 100644 --- a/lisp/progmodes/perl-mode.el +++ b/lisp/progmodes/perl-mode.el @@ -96,9 +96,8 @@ "Face used for non-scalar variables." :version "28.1") -(defvar perl-mode-abbrev-table nil - "Abbrev table in use in `perl-mode' buffers.") -(define-abbrev-table 'perl-mode-abbrev-table ()) +(define-abbrev-table 'perl-mode-abbrev-table () + "Abbrev table in use in perl-mode buffers.") (defvar-keymap perl-mode-map :doc "Keymap used in Perl mode." @@ -165,19 +164,19 @@ ;; ;; Fontify function and package names in declarations. ("\\<\\(package\\|sub\\)\\>[ \t]*\\(\\(?:\\sw\\|::\\)+\\)?" - (1 font-lock-keyword-face) (2 font-lock-function-name-face nil t)) + (1 'font-lock-keyword-face) (2 'font-lock-function-name-face nil t)) ("\\(?:^\\|[^$@%&\\]\\)\\<\\(import\\|no\\|require\\|use\\)\\>[ \t]*\\(\\(?:\\sw\\|::\\)+\\)?" - (1 font-lock-keyword-face) (2 font-lock-constant-face nil t))) + (1 'font-lock-keyword-face) (2 'font-lock-constant-face nil t))) "Subdued level highlighting for Perl mode.") (defconst perl-font-lock-keywords-2 (append '(;; Fontify function, variable and file name references. They have to be ;; handled first because they might conflict with keywords. - ("&\\(\\sw+\\(::\\sw+\\)*\\)" 1 font-lock-function-name-face) + ("&\\(\\sw+\\(::\\sw+\\)*\\)" 1 'font-lock-function-name-face) ;; Additionally fontify non-scalar variables. `perl-non-scalar-variable' ;; will underline them by default. - ("[$*]{?\\(\\sw+\\(::\\sw+\\)*\\)" 1 font-lock-variable-name-face) + ("[$*]{?\\(\\sw+\\(::\\sw+\\)*\\)" 1 'font-lock-variable-name-face) ("\\([@%]\\|\\$#\\)\\(\\sw+\\(::\\sw+\\)*\\)" (2 'perl-non-scalar-variable))) perl-font-lock-keywords-1 @@ -191,13 +190,13 @@ "\\>") ;; ;; Fontify declarators and prefixes as types. - ("\\<\\(has\\|local\\|my\\|our\\|state\\)\\>" . font-lock-keyword-face) ; declarators - ("<\\(\\sw+\\)>" 1 font-lock-constant-face) + ("\\<\\(has\\|local\\|my\\|our\\|state\\)\\>" . 'font-lock-keyword-face) ; declarators + ("<\\(\\sw+\\)>" 1 'font-lock-constant-face) ;; ;; Fontify keywords with/and labels as we do in `c++-font-lock-keywords'. ("\\<\\(continue\\|goto\\|last\\|next\\|redo\\)\\>[ \t]*\\(\\sw+\\)?" - (1 font-lock-keyword-face) (2 font-lock-constant-face nil t)) - ("^[ \t]*\\(\\sw+\\)[ \t]*:[^:]" 1 font-lock-constant-face))) + (1 'font-lock-keyword-face) (2 'font-lock-constant-face nil t)) + ("^[ \t]*\\(\\sw+\\)[ \t]*:[^:]" 1 'font-lock-constant-face))) "Gaudy level highlighting for Perl mode.") (defvar perl-font-lock-keywords perl-font-lock-keywords-1 @@ -631,7 +630,7 @@ create a new comment." ;; Outline support (defvar perl-outline-regexp - (concat (mapconcat 'cadr perl-imenu-generic-expression "\\|") + (concat (mapconcat #'cadr perl-imenu-generic-expression "\\|") "\\|^=cut\\>")) (defun perl-outline-level () From 3ee021dc19e314f6f456867ec43c25aed5cc41b8 Mon Sep 17 00:00:00 2001 From: Eshel Yaron Date: Fri, 28 Mar 2025 17:57:35 +0100 Subject: [PATCH 014/395] ; (find-function-search-for-symbol): Be cautious with macros. * lisp/emacs-lisp/find-func.el (find-function-search-for-symbol): Only attempt to expand macros in trusted buffers. (Bug#77341) --- lisp/emacs-lisp/find-func.el | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lisp/emacs-lisp/find-func.el b/lisp/emacs-lisp/find-func.el index 8f488a9c00a..6bdfb4bc38b 100644 --- a/lisp/emacs-lisp/find-func.el +++ b/lisp/emacs-lisp/find-func.el @@ -487,11 +487,14 @@ The search is done in the source for library LIBRARY." ;; If the regexp search didn't find the location of ;; the symbol (for example, because it is generated by ;; a macro), try a slightly more expensive search that - ;; expands macros until it finds the symbol. + ;; expands macros until it finds the symbol. Since + ;; macro-expansion involves arbitrary code execution, + ;; only attempt it in trusted buffers. (cons (current-buffer) - (find-function--search-by-expanding-macros - (current-buffer) symbol type - form-matcher-factory)))))))))) + (when (trusted-content-p) + (find-function--search-by-expanding-macros + (current-buffer) symbol type + form-matcher-factory))))))))))) ;;;###autoload (defun find-function-update-type-alist (symbol type variable) From cffe5a02454f0d2201172c07a239bd9a3682ad68 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 5 Apr 2025 10:11:03 +0300 Subject: [PATCH 015/395] ; Fix wording of recent documentation changes * lisp/desktop.el (desktop-restore-frames): * etc/NEWS: * doc/emacs/misc.texi (Saving Emacs Sessions): Fix wording of the recent changes. --- doc/emacs/misc.texi | 15 ++++++++------- etc/NEWS | 6 +++--- lisp/desktop.el | 6 +++--- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi index 8b0f96a3de3..5feee108331 100644 --- a/doc/emacs/misc.texi +++ b/doc/emacs/misc.texi @@ -2925,13 +2925,14 @@ if the current Emacs session didn't load any desktop yet. @vindex desktop-restore-frames By default, the desktop tries to save and restore the frame and window -configuration.@footnote{Except on Android, where this option defaults to -@code{nil} because the window manager (@pxref{Android Windowing}) is too -prohibitive to admit of restoring frame configurations.} To disable or -enable this, set @code{desktop-restore-frames} to @code{nil} or any -non-@code{nil} value respectively. (See that variable's documentation -for some related options that you can customize to fine-tune this -behavior.) +configuration.@footnote{ +Except on Android, where this option defaults to @code{nil} because the +window manager (@pxref{Android Windowing}) is too prohibitive, and +doesn't allow restoring frame configurations.} +To disable or enable this, set @code{desktop-restore-frames} to +@code{nil} or any non-@code{nil} value respectively. (See that +variable's documentation for some related options that you can customize +to fine-tune this behavior.) @vindex frameset-filter-alist When the desktop restores the frame and window configuration, it diff --git a/etc/NEWS b/etc/NEWS index fc202a795e4..5ee1e3596dd 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -2088,9 +2088,9 @@ where this remains unsupported is Nextstep (GNUstep or Mac OS). --- ** 'desktop-restore-frames' has been disabled by default on Android systems. Restrictions imposed on clients by the window manager on these systems -are too prohibitive to admit of restoring frame configurations, and on -the same account many window management facilities are unimplemented by -Emacs also. +are too prohibitive and don't allow restoring frame configurations. +(For the same reason many window management facilities are also not +implemented by Emacs.) --- ** 'NSSpeechRecognitionUsageDescription' now included in "Info.plist" (macOS). diff --git a/lisp/desktop.el b/lisp/desktop.el index 4067b5a1286..b19889c5c42 100644 --- a/lisp/desktop.el +++ b/lisp/desktop.el @@ -428,9 +428,9 @@ host is off-line." See related options `desktop-restore-reuses-frames', `desktop-restore-in-current-display', and `desktop-restore-forces-onscreen'. -This option is enabled by default elsewhere than on Android, where it is -disabled by default as programs are too handicapped by the window -manager for frames to be restored." +This option is enabled by default, except on Android. It is disabled by +default on Android because the window manager there prevents programs from +restoring frames." :type 'boolean :group 'desktop :version "31.1") From c73e4cdece0d97f3f5793590fefa258923dca08b Mon Sep 17 00:00:00 2001 From: Visuwesh Date: Sun, 23 Mar 2025 11:28:16 +0530 Subject: [PATCH 016/395] Improve formatting of 'setopt' suggestion in *Help* buffer * lisp/help-fns.el (help--recommend-setopt): Remove function, and... (help-fns--customize-variable): ... move the relevant code here to keep related code in the same place. Change the formatting to also include the :set function if it is set to a named function. (Bug#77173) --- lisp/help-fns.el | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/lisp/help-fns.el b/lisp/help-fns.el index ee615bfea29..6c4c3f4da97 100644 --- a/lisp/help-fns.el +++ b/lisp/help-fns.el @@ -875,20 +875,6 @@ the C sources, too." (function-get function 'disabled)) (insert " This function is disabled.\n"))) -(add-hook 'help-fns-describe-variable-functions #'help--recommend-setopt) -(defun help--recommend-setopt (symbol) - ;; TODO: This would be better if added to the docstring itself, but I - ;; ran into `byte-compile-dynamic-docstring' and gave up. - (when (and (get symbol 'custom-set) - ;; Don't override manually written documentation. - (not (string-match (rx word-start "setopt" word-end) - (documentation-property - symbol 'variable-documentation)))) - ;; FIXME: `princ` removes text properties added by s-c-k. - (princ (substitute-command-keys "\ -Setting this variable with `setq' has no effect; use either `setopt' -or \\[customize-option] to change its value.\n\n")))) - (defun help-fns--first-release-regexp (symbol) (let* ((name (symbol-name symbol)) (quoted (regexp-quote name))) @@ -1602,12 +1588,26 @@ it is displayed along with the global value." (defun help-fns--customize-variable (variable &optional text) ;; Make a link to customize if this variable can be customized. (when (custom-variable-p variable) - (let ((customize-label "customize")) + (let ((customize-label "customize") + (custom-set (get variable 'custom-set))) (princ (concat " You can " customize-label (or text " this variable."))) + (when (and custom-set + ;; Don't override manually written documentation. + (not (string-match (rx word-start "setopt" word-end) + (documentation-property + variable 'variable-documentation)))) + (princ (substitute-quotes + (concat "\n Setting this variable directly with `setq' may not take effect;" + "\n use either customize or `setopt'" + ;; Skip text if `custom-set' property is an + ;; anonymous function. + (when (symbolp custom-set) + (concat ", or call `" (symbol-name custom-set) "'")) + ".")))) (with-current-buffer standard-output (save-excursion - (re-search-backward (concat "\\(" customize-label "\\)")) - (help-xref-button 1 'help-customize-variable variable))) + (while (re-search-backward (concat "\\(" customize-label "\\)") nil t) + (help-xref-button 1 'help-customize-variable variable)))) (terpri)))) (add-hook 'help-fns-describe-variable-functions From 8fc18d0968a0f7ef610b6868a35e731c778991ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?El=C3=ADas=20Gabriel=20P=C3=A9rez?= Date: Wed, 19 Mar 2025 12:01:22 -0600 Subject: [PATCH 017/395] Optionally display function docstring in eldoc Allow display (optionally) function docstring in eldoc. (Bug#77124) * etc/NEWS: Document changes. * lisp/progmodes/elisp-mode.el (elisp-eldoc-funcall-with-docstring-length): New user option. (elisp-eldoc-funcall-with-docstring): New function. --- etc/NEWS | 13 +++++++++++ lisp/progmodes/elisp-mode.el | 44 ++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/etc/NEWS b/etc/NEWS index 5ee1e3596dd..caef5080422 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -565,6 +565,19 @@ The prompts 'opstring' and 'active-opstring' can now either be strings or functions. This is useful when your prompts can benefit from dynamic content. +** ElDoc +--- +*** New eldoc function 'elisp-eldoc-funcall-with-docstring'. +This function includes the current function docstring in eldoc echo area +and can be used as a more detailed alternative to 'elisp-eldoc-funcall'. + +--- +*** New user option 'elisp-eldoc-funcall-with-docstring-length'. +This user option specifies how long function docstring must be displayed +in 'elisp-eldoc-funcall-with-docstring'. If set to 'short' only display +cut docstring before period. Otherwise if set to 'full', display full +docstring.' + --- ** Buffer Menu diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el index a34f29bffea..748d2f11360 100644 --- a/lisp/progmodes/elisp-mode.el +++ b/lisp/progmodes/elisp-mode.el @@ -1845,6 +1845,50 @@ Intended for `eldoc-documentation-functions' (which see)." 'font-lock-function-name-face 'font-lock-keyword-face))))) +(defcustom elisp-eldoc-funcall-with-docstring-length 'short + "Control length of doc string shown by `elisp-eldoc-funcall-with-docstring'. +If set to `short', only show the first sentence of the doc string. +Otherwise if set to `full', display full doc string." + :type '(choice + (const :tag "Short" short) + (const :tag "Full" full)) + :group 'elisp + :version "31.1") + +(defun elisp-eldoc-funcall-with-docstring (callback &rest _ignored) + "Document function call at point by calling CALLBACK. +Intended for `eldoc-documentation-functions' (which see). +Compared to `elisp-eldoc-funcall', this also includes the +current function doc string, doc string length depends on +`elisp-eldoc-funcall-with-docstring-length'." + (let* ((sym-info (elisp--fnsym-in-current-sexp)) + (fn-sym (car sym-info)) + (doc (when (fboundp fn-sym) + (propertize + (cdr (help-split-fundoc + (condition-case nil (documentation fn-sym t) + (invalid-function nil)) + fn-sym)) + 'face 'font-lock-doc-face)))) + (when fn-sym + (funcall callback + (concat (apply #'elisp-get-fnsym-args-string sym-info) + ;; Ensure not display the docstring in the + ;; mode-line. + (when (and doc (not (minibufferp))) + (concat + "\n" + (pcase elisp-eldoc-funcall-with-docstring-length + ('full doc) + ('short + (save-match-data + (when (string-match "\\." doc) + (concat "\n" (substring doc 0 (match-end 0)))))))))) + :thing fn-sym + :face (if (functionp fn-sym) + 'font-lock-function-name-face + 'font-lock-keyword-face))))) + (defun elisp-eldoc-var-docstring (callback &rest _ignored) "Document variable at point by calling CALLBACK. Intended for `eldoc-documentation-functions' (which see). From d6f1b25d2e5e83f472cf9cd35bea43c066fbd4f3 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 5 Apr 2025 12:17:12 +0300 Subject: [PATCH 018/395] ; * etc/NEWS: Fix last change. --- etc/NEWS | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index caef5080422..527ab00ec2b 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -573,10 +573,10 @@ and can be used as a more detailed alternative to 'elisp-eldoc-funcall'. --- *** New user option 'elisp-eldoc-funcall-with-docstring-length'. -This user option specifies how long function docstring must be displayed -in 'elisp-eldoc-funcall-with-docstring'. If set to 'short' only display -cut docstring before period. Otherwise if set to 'full', display full -docstring.' +This user option specifies how long function doc string must be +displayed in 'elisp-eldoc-funcall-with-docstring'. If set to 'short' +(the default), only display the first sentence of the doc string. +Otherwise, if set to 'full', display the full doc string.' --- ** Buffer Menu From ef6203b64aaf53cd986caf17bd49b6ffe840c93a Mon Sep 17 00:00:00 2001 From: Paul Nelson Date: Sun, 30 Mar 2025 13:31:58 +0200 Subject: [PATCH 019/395] Extend prettify-symbols-alist in TeX mode * lisp/textmodes/tex-mode.el (tex--prettify-symbols-alist): Add further math symbols, quotes and fractions. (Bug#77381) --- lisp/textmodes/tex-mode.el | 120 ++++++++++++++++++++++++++++++++++--- 1 file changed, 113 insertions(+), 7 deletions(-) diff --git a/lisp/textmodes/tex-mode.el b/lisp/textmodes/tex-mode.el index ad1d4fa1f88..ea1bf3807c3 100644 --- a/lisp/textmodes/tex-mode.el +++ b/lisp/textmodes/tex-mode.el @@ -3185,9 +3185,14 @@ There might be text before point." ("\\bigcap" . ?⋂) ("\\bigcirc" . ?◯) ("\\bigcup" . ?⋃) + ("\\bigodot" . ?⨀) + ("\\bigoplus" . ?⨁) + ("\\bigotimes" . ?⨂) + ("\\bigsqcup" . ?⨆) ("\\bigstar" . ?★) ("\\bigtriangledown" . ?▽) ("\\bigtriangleup" . ?△) + ("\\biguplus" . ?⨄) ("\\bigvee" . ?⋁) ("\\bigwedge" . ?⋀) ("\\blacklozenge" . ?✦) @@ -3204,12 +3209,11 @@ There might be text before point." ("\\bullet" . ?•) ("\\bumpeq" . ?≏) ("\\cap" . ?∩) + ("\\cdot" . ?⋅) ("\\cdots" . ?⋯) ("\\centerdot" . ?·) ("\\checkmark" . ?✓) ("\\chi" . ?χ) - ("\\cdot" . ?⋅) - ("\\cdots" . ?⋯) ("\\circ" . ?∘) ("\\circeq" . ?≗) ("\\circlearrowleft" . ?↺) @@ -3286,11 +3290,15 @@ There might be text before point." ("\\hookleftarrow" . ?↩) ("\\hookrightarrow" . ?↪) ("\\iff" . ?⇔) + ("\\iiiint" . ?⨌) + ("\\iiint" . ?∭) + ("\\iint" . ?∬) ("\\imath" . ?ı) ("\\in" . ?∈) ("\\infty" . ?∞) ("\\int" . ?∫) ("\\intercal" . ?⊺) + ("\\jmath" . ?ȷ) ("\\langle" . 10216) ; Literal ?⟨ breaks indentation. ("\\lbrace" . ?{) ("\\lbrack" . ?\[) @@ -3323,6 +3331,7 @@ There might be text before point." ("\\rhd" . ?▷) ("\\ll" . ?≪) ("\\llcorner" . ?⌞) + ("\\lll" . ?⋘) ("\\lnapprox" . ?⋦) ("\\lneq" . ?≨) ("\\lneqq" . ?≨) @@ -3400,6 +3409,8 @@ There might be text before point." ("\\nvdash" . ?⊬) ("\\nwarrow" . ?↖) ("\\odot" . ?⊙) + ("\\oiiint" . ?∰) + ("\\oiint" . ?∯) ("\\oint" . ?∮) ("\\ominus" . ?⊖) ("\\oplus" . ?⊕) @@ -3508,10 +3519,12 @@ There might be text before point." ("\\vDash" . ?⊨) ("\\varepsilon" . ?ε) ("\\varphi" . ?φ) + ("\\varpi" . ?ϖ) ("\\varprime" . ?′) ("\\varpropto" . ?∝) ("\\varrho" . ?ϱ) ("\\varsigma" . ?ς) + ("\\vartheta" . ?ϑ) ("\\vartriangleleft" . ?⊲) ("\\vartriangleright" . ?⊳) ("\\vdash" . ?⊢) @@ -3522,19 +3535,60 @@ There might be text before point." ("\\wedge" . ?∧) ("\\wp" . ?℘) ("\\wr" . ?≀) - ("\\Bbb{N}" . ?ℕ) ; AMS commands for blackboard bold - ("\\Bbb{P}" . ?ℙ) ; Also sometimes \mathbb. + ("\\Bbb{A}" . ?𝔸) ; AMS commands for blackboard bold + ("\\Bbb{B}" . ?𝔹) ; Also sometimes \mathbb. + ("\\Bbb{C}" . ?ℂ) + ("\\Bbb{D}" . ?𝔻) + ("\\Bbb{E}" . ?𝔼) + ("\\Bbb{F}" . ?𝔽) + ("\\Bbb{G}" . ?𝔾) + ("\\Bbb{H}" . ?ℍ) + ("\\Bbb{I}" . ?𝕀) + ("\\Bbb{J}" . ?𝕁) + ("\\Bbb{K}" . ?𝕂) + ("\\Bbb{L}" . ?𝕃) + ("\\Bbb{M}" . ?𝕄) + ("\\Bbb{N}" . ?ℕ) + ("\\Bbb{O}" . ?𝕆) + ("\\Bbb{P}" . ?ℙ) ("\\Bbb{Q}" . ?ℚ) ("\\Bbb{R}" . ?ℝ) + ("\\Bbb{S}" . ?𝕊) ("\\Bbb{T}" . ?𝕋) + ("\\Bbb{U}" . ?𝕌) + ("\\Bbb{V}" . ?𝕍) + ("\\Bbb{W}" . ?𝕎) + ("\\Bbb{X}" . ?𝕏) + ("\\Bbb{Y}" . ?𝕐) ("\\Bbb{Z}" . ?ℤ) - ("\\mathbb{N}" . ?ℕ) ; AMS commands for blackboard bold - ("\\mathbb{P}" . ?ℙ) ; Also sometimes \mathbb. + ("\\mathbb{A}" . ?𝔸) ; AMS commands for blackboard bold + ("\\mathbb{B}" . ?𝔹) ; Also sometimes \mathbb. + ("\\mathbb{C}" . ?ℂ) + ("\\mathbb{D}" . ?𝔻) + ("\\mathbb{E}" . ?𝔼) + ("\\mathbb{F}" . ?𝔽) + ("\\mathbb{G}" . ?𝔾) + ("\\mathbb{H}" . ?ℍ) + ("\\mathbb{I}" . ?𝕀) + ("\\mathbb{J}" . ?𝕁) + ("\\mathbb{K}" . ?𝕂) + ("\\mathbb{L}" . ?𝕃) + ("\\mathbb{M}" . ?𝕄) + ("\\mathbb{N}" . ?ℕ) + ("\\mathbb{O}" . ?𝕆) + ("\\mathbb{P}" . ?ℙ) ("\\mathbb{Q}" . ?ℚ) ("\\mathbb{R}" . ?ℝ) + ("\\mathbb{S}" . ?𝕊) ("\\mathbb{T}" . ?𝕋) + ("\\mathbb{U}" . ?𝕌) + ("\\mathbb{V}" . ?𝕍) + ("\\mathbb{W}" . ?𝕎) + ("\\mathbb{X}" . ?𝕏) + ("\\mathbb{Y}" . ?𝕐) ("\\mathbb{Z}" . ?ℤ) ("\\pm" . ?±) + ("\\pounds" . ?£) ("\\|" . ?‖) ("\\varkappa" . ?ϰ) ;; caligraphic @@ -3738,7 +3792,59 @@ There might be text before point." ("\\textdivorced" . ?⚮) ("\\textlbrackdbl" . 10214) ; Literal ?⟦ breaks indentation ("\\textrbrackdbl" . 10215) ; Literal ?⟧ breaks indentation - ("\\textinterrobangdown" . ?⸘)) + ("\\textinterrobangdown" . ?⸘) + + ;; TeX quotes + ("``" . ?“) + ("''" . ?”) + + ;; Unicode Fractions + ("\\frac{1}{2}" . "½") + ("\\frac{1}{3}" . "⅓") + ("\\frac{2}{3}" . "⅔") + ("\\frac{1}{4}" . "¼") + ("\\frac{3}{4}" . "¾") + ("\\frac{1}{5}" . "⅕") + ("\\frac{2}{5}" . "⅖") + ("\\frac{3}{5}" . "⅗") + ("\\frac{4}{5}" . "⅘") + ("\\frac{1}{6}" . "⅙") + ("\\frac{5}{6}" . "⅚") + ("\\frac{1}{7}" . "⅐") + ("\\frac{1}{8}" . "⅛") + ("\\frac{3}{8}" . "⅜") + ("\\frac{5}{8}" . "⅝") + ("\\frac{7}{8}" . "⅞") + ("\\frac{1}{9}" . "⅑") + ("\\frac{1}{10}" . "⅒") + ("\\tfrac{1}{2}" . "½") + ("\\tfrac{1}{3}" . "⅓") + ("\\tfrac{2}{3}" . "⅔") + ("\\tfrac{1}{4}" . "¼") + ("\\tfrac{3}{4}" . "¾") + ("\\tfrac{1}{5}" . "⅕") + ("\\tfrac{2}{5}" . "⅖") + ("\\tfrac{3}{5}" . "⅗") + ("\\tfrac{4}{5}" . "⅘") + ("\\tfrac{1}{6}" . "⅙") + ("\\tfrac{5}{6}" . "⅚") + ("\\tfrac{1}{7}" . "⅐") + ("\\tfrac{1}{8}" . "⅛") + ("\\tfrac{3}{8}" . "⅜") + ("\\tfrac{5}{8}" . "⅝") + ("\\tfrac{7}{8}" . "⅞") + ("\\tfrac{1}{9}" . "⅑") + ("\\tfrac{1}{10}" . "⅒") + + ;; Other symbols + ("\\S" . ?§) + ("\\Finv" . ?Ⅎ) + ("\\Game" . ?⅁) + ("\\ " . 9141) ; Literal ?⎵ breaks indentation + ("\\lvert" . ?|) + ("\\rvert" . ?|) + ("\\lVert" . ?‖) + ("\\rVert" . ?‖)) "A `prettify-symbols-alist' usable for (La)TeX modes.") (defun tex--prettify-symbols-compose-p (_start end _match) From 2d0b5f34a008979d34f337c872bcf93a296c6ec2 Mon Sep 17 00:00:00 2001 From: Paul Nelson Date: Mon, 31 Mar 2025 15:37:14 +0200 Subject: [PATCH 020/395] Restrict symbol prettification to displayable glyphs * lisp/international/mule.el (char-displayable-on-frame-p): New function used to determine whether a character can be meaningfully displayed on a given frame. * doc/lispref/display.texi (Fontsets): Document it. * lisp/progmodes/prog-mode.el (prettify-symbols--composition-displayable-p): New function used to restrict to displayable prettification symbols. This prevents issues with missing characters appearing as boxes. (prettify-symbols--make-keywords): Use it. (Bug#77381) --- doc/lispref/display.texi | 8 ++++++++ etc/NEWS | 10 ++++++++++ lisp/international/mule.el | 26 ++++++++++++++++++++++++++ lisp/progmodes/prog-mode.el | 31 +++++++++++++++++++++++++++++-- 4 files changed, 73 insertions(+), 2 deletions(-) diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index de0639187ab..0ba3b9d8d05 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -4122,6 +4122,14 @@ available, since it also checks whether the coding system for the text terminal can encode the character (@pxref{Terminal I/O Encoding}). @end defun +@defun char-displayable-on-frame-p char frame +This function behaves like @code{char-displayable-p} does (relative to +@var{frame}), but in the graphical case, it does not perform the final +check of whether the underlying text terminal can encode the character. +It thus provides a displayability check for @var{char} more specific to +@var{frame}. +@end defun + @node Low-Level Font @subsection Low-Level Font Representation @cindex font property diff --git a/etc/NEWS b/etc/NEWS index 527ab00ec2b..e3e63b939f9 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -64,6 +64,9 @@ init file. * Changes in Emacs 31.1 +** `prettify-symbols-mode' attempts to ignore undisplayable characters. +Previously, such characters would be rendered as, e.g., white boxes. + +++ ** 'standard-display-table' now has more extra slots. 'standard-display-table' has been extended to allow specifying glyphs @@ -1792,6 +1795,13 @@ It has been promoted from 'subr-x' to the C code. You can now directly pass it a string or a buffer rather than a function. Actually passing it a function is now deprecated. ++++ +** New function 'char-displayable-on-frame-p'. +'char-displayable-on-frame-p' returns non-nil if Emacs ought to be able +to display its char argument on a given frame. This new function, +unlike 'char-displayable-p', does not check whether the character can be +encoded by the underlying terminal. + +++ ** New macros 'static-when' and 'static-unless'. Like 'static-if', these macros evaluate their condition at diff --git a/lisp/international/mule.el b/lisp/international/mule.el index f72cc815287..cb2aa5b9480 100644 --- a/lisp/international/mule.el +++ b/lisp/international/mule.el @@ -528,6 +528,32 @@ per-character basis, this may not be accurate." (throw 'tag3 charset))) charset-list) nil))))))))))) + +(defun char-displayable-on-frame-p (char &optional frame) + "Return non-nil if CHAR can be displayed in FRAME. +FRAME nil means the selected frame. + +This function provides a stricter test than `char-displayable-p' does +for determining if a character will display properly: in the graphical +case, it does not check whether the underlying terminal can encode the +character. + +Specifically, this function returns non-nil: + +- for a text terminal, if `char-displayable-p' returns non-nil. + +- for a graphical terminal, if `char-displayable-p' returns either t or + a font object. + +The two functions differ in behavior (i.e., `char-displayable-strict-p' +returns nil but `char-displayable-p' does not) if the underlying +terminal is graphical and can encode the character, but FRAME cannot." + (let ((display-capability (with-selected-frame (or frame (selected-frame)) + (char-displayable-p char)))) + (if (display-graphic-p frame) + (or (eq display-capability t) + (fontp display-capability)) + display-capability))) ;; Save the ASCII case table in case we need it later. Some locales ;; (such as Turkish) modify the case behavior of ASCII characters, diff --git a/lisp/progmodes/prog-mode.el b/lisp/progmodes/prog-mode.el index 77724e04f11..33e0d354fee 100644 --- a/lisp/progmodes/prog-mode.el +++ b/lisp/progmodes/prog-mode.el @@ -230,10 +230,37 @@ Regexp match data 0 specifies the characters to be composed." ;; Return nil because we're not adding any face property. nil) +(defun prettify-symbols--composition-displayable-p (composition) + "Return non-nil if COMPOSITION can be displayed with the current fonts. +COMPOSITION can be a single character, a string, or a sequence (vector or +list) of characters and composition rules as described in the documentation +of `prettify-symbols-alist' and `compose-region'." + (cond + ((characterp composition) + (char-displayable-on-frame-p composition)) + ((stringp composition) + (seq-every-p #'char-displayable-on-frame-p composition)) + ((seqp composition) + ;; check that every even-indexed element is displayable + (seq-every-p + (lambda (idx-elt) + (if (evenp (car idx-elt)) + (char-displayable-on-frame-p (cdr idx-elt)) + t)) + (seq-map-indexed #'cons composition))) + (t + ;; silently ignore invalid compositions + t))) + (defun prettify-symbols--make-keywords () (if prettify-symbols-alist - `((,(regexp-opt (mapcar 'car prettify-symbols-alist) t) - (0 (prettify-symbols--compose-symbol ',prettify-symbols-alist)))) + (let ((filtered-alist + (seq-filter + (lambda (elt) + (prettify-symbols--composition-displayable-p (cdr elt))) + prettify-symbols-alist))) + `((,(regexp-opt (mapcar 'car filtered-alist) t) + (0 (prettify-symbols--compose-symbol ',filtered-alist))))) nil)) (defvar-local prettify-symbols--keywords nil) From c94f0d3dc82a72baa0ba8d69beda220aaf0b2d91 Mon Sep 17 00:00:00 2001 From: Pengji Zhang Date: Wed, 2 Apr 2025 20:52:30 +0800 Subject: [PATCH 021/395] Fix mouse highlighting for compact mode lines (bug#77336) When 'mode-line-compact' is non-nil, the mode line string is displayed as a whole. That confuses the computation of ranges of mouse highlighting on the mode line because all the glyphs have the same Lisp object source. As such, in this commit we instead split the mode line string by sources, and display those elements one by one, so the boundaries of each element could be correctly detected for the purpose of mouse highlighting. * src/xdisp.c (display_mode_line): Display mode line elements one by one when 'mode-line-compact' is non-nil. (display_mode_element): Record source element number of the stored string via a text property. (Fformat_mode_line): Initialize 'mode_line_elt_no' to 0. (syms_of_xdisp): New symbol for the text property. --- src/xdisp.c | 153 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 110 insertions(+), 43 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index 61c464d0f36..1340716e4a1 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -13674,6 +13674,9 @@ static Lisp_Object mode_line_proptrans_alist; /* List of strings making up the mode-line. */ static Lisp_Object mode_line_string_list; +/* Element number for the stored mode line string. */ +static ptrdiff_t mode_line_elt_no; + /* Base face property when building propertized mode line string. */ static Lisp_Object mode_line_string_face; static Lisp_Object mode_line_string_face_prop; @@ -27766,57 +27769,94 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format) { /* The window is wide enough; just display the mode line we just computed. */ - display_string (NULL, mode_string, Qnil, - 0, 0, &it, 0, 0, 0, - STRING_MULTIBYTE (mode_string)); + Lisp_Object start = make_fixnum (0), end; + Lisp_Object elt; + + /* Display the mode line string one element by one element. + This is to make the ranges of mouse highlighting + correct. */ + do + { + end = Fnext_single_property_change (start, Qmode_line_elt_no, + mode_string, Qnil); + elt = Fsubstring (mode_string, start, end); + display_string (NULL, elt, Qnil, 0, 0, &it, 0, 0, 0, + STRING_MULTIBYTE (elt)); + start = end; + } + while (!NILP (end)); } else { /* Compress the mode line. */ - ptrdiff_t i = 0, i_byte = 0, start = 0; + ptrdiff_t i = 0, i_byte = 0; int prev = 0; + Lisp_Object start = make_fixnum (0), end; + Lisp_Object elt = empty_unibyte_string; - while (i < SCHARS (mode_string)) + /* Display the mode line string one element by one element. + This is to make the ranges of mouse highlighting + correct. */ + do { - int c = fetch_string_char_advance (mode_string, &i, &i_byte); - if (c == ' ' && prev == ' ') + end = Fnext_single_property_change (start, + Qmode_line_elt_no, + mode_string, + make_fixnum (SCHARS (mode_string))); + while (i < XFIXNUM (end)) { - Lisp_Object prev_pos = make_fixnum (i - 1); - - /* SPC characters with 'display' properties are not - really "empty", since they have non-trivial visual - effects on the mode line. */ - if (NILP (Fget_text_property (prev_pos, Qdisplay, - mode_string))) + int c = fetch_string_char_advance (mode_string, &i, &i_byte); + if (c == ' ' && prev == ' ') { - display_string (NULL, - Fsubstring (mode_string, - make_fixnum (start), - prev_pos), - Qnil, 0, 0, &it, 0, 0, 0, - STRING_MULTIBYTE (mode_string)); - /* Skip past the rest of the space characters. */ - while (c == ' ' && i < SCHARS (mode_string) - && NILP (Fget_text_property (make_fixnum (i), - Qdisplay, - mode_string))) - { - c = fetch_string_char_advance (mode_string, - &i, &i_byte); - } - start = i - 1; - } - } - prev = c; - } + Lisp_Object prev_pos = make_fixnum (i - 1); + Lisp_Object display = Fget_text_property (prev_pos, + Qdisplay, + mode_string); - /* Display the final bit. */ - if (start < i) - display_string (NULL, - Fsubstring (mode_string, make_fixnum (start), - make_fixnum (i)), - Qnil, 0, 0, &it, 0, 0, 0, - STRING_MULTIBYTE (mode_string)); + /* SPC characters with 'display' properties are not + really "empty", since they have non-trivial visual + effects on the mode line. */ + if (NILP (display)) + { + elt = concat2 (elt, Fsubstring (mode_string, + start, + prev_pos)); + + /* Skip past the rest of the space characters. */ + Lisp_Object display = Fget_text_property (make_fixnum (i), + Qdisplay, + mode_string); + while (c == ' ' && i < XFIXNUM (end) + && NILP (display)) + { + c = fetch_string_char_advance (mode_string, + &i, &i_byte); + display = Fget_text_property (make_fixnum (i), + Qdisplay, + mode_string); + } + + /* Skip the final space no matter how the loop + above ends. */ + if (c == ' ' && NILP (display)) + start = end; + else + start = make_fixnum (i - 1); + } + } + prev = c; + } + + /* Append the final bit. */ + if (XFIXNUM (start) < XFIXNUM (end)) + elt = concat2 (elt, Fsubstring (mode_string, start, end)); + + display_string (NULL, elt, Qnil, 0, 0, &it, 0, 0, 0, + STRING_MULTIBYTE (elt)); + elt = empty_unibyte_string; + start = end; + } + while (XFIXNUM (end) < SCHARS (mode_string)); } } pop_kboard (); @@ -27938,6 +27978,20 @@ display_mode_element (struct it *it, int depth, int field_width, int precision, if (depth > 100) elt = build_string ("*too-deep*"); + /* NOTE: Increment the number only for 'MODE_LINE_STRING', because for + other cases this variable is not used. So we do not need to reset + the variable in every callers of this function. + + NOTE: This might result in gaps in the stored element numbers + because some elements are processed recursively. However, we + cannot increment this number when the number is stored because an + element could be stored by parts. For example, "a%b" is stored as + two elements in the 'mode_line_string_list', but they should be + considered as one element, so we cannot increment this number when + "a" is stored. */ + if (mode_line_target == MODE_LINE_STRING) + mode_line_elt_no++; + depth++; switch (XTYPE (elt)) @@ -28035,7 +28089,11 @@ display_mode_element (struct it *it, int depth, int field_width, int precision, n += store_mode_line_noprop (SSDATA (elt), -1, prec); break; case MODE_LINE_STRING: - n += store_mode_line_string (NULL, elt, true, 0, prec, Qnil); + { + AUTO_LIST2 (src, Qmode_line_elt_no, + make_fixnum (mode_line_elt_no)); + n += store_mode_line_string (NULL, elt, true, 0, prec, src); + } break; case MODE_LINE_DISPLAY: n += display_string (NULL, elt, Qnil, 0, 0, it, @@ -28088,8 +28146,10 @@ display_mode_element (struct it *it, int depth, int field_width, int precision, Lisp_Object mode_string = Fsubstring (elt, make_fixnum (charpos), make_fixnum (endpos)); + AUTO_LIST2 (src, Qmode_line_elt_no, + make_fixnum (mode_line_elt_no)); n += store_mode_line_string (NULL, mode_string, false, - 0, 0, Qnil); + 0, 0, src); } break; case MODE_LINE_DISPLAY: @@ -28169,6 +28229,8 @@ display_mode_element (struct it *it, int depth, int field_width, int precision, { Lisp_Object tem = build_string (spec); props = Ftext_properties_at (make_fixnum (charpos), elt); + props = plist_put (props, Qmode_line_elt_no, + make_fixnum (mode_line_elt_no)); /* Should only keep face property in props */ n += store_mode_line_string (NULL, tem, false, field, prec, props); @@ -28384,6 +28446,9 @@ display_mode_element (struct it *it, int depth, int field_width, int precision, n += store_mode_line_noprop ("", field_width - n, 0); break; case MODE_LINE_STRING: + /* NOTE: Padding implicitly has 'mode-line-elt-no' property + to be nil. Normally padding spaces are between two real + elements, so this should be good. */ n += store_mode_line_string ("", Qnil, false, field_width - n, 0, Qnil); break; @@ -28591,6 +28656,7 @@ are the selected window and the WINDOW's buffer). */) } push_kboard (FRAME_KBOARD (it.f)); + mode_line_elt_no = 0; display_mode_element (&it, 0, 0, 0, format, Qnil, false); pop_kboard (); @@ -37678,6 +37744,7 @@ be let-bound around code that needs to disable messages temporarily. */); DEFSYM (Qfontification_functions, "fontification-functions"); DEFSYM (Qlong_line_optimizations_in_fontification_functions, "long-line-optimizations-in-fontification-functions"); + DEFSYM (Qmode_line_elt_no, "mode-line-elt-no"); /* Name of the symbol which disables Lisp evaluation in 'display' properties. This is used by enriched.el. */ From bf7b3c5ddd5f66cd0f4927c983789128b43056ba Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 5 Apr 2025 12:35:42 +0300 Subject: [PATCH 022/395] ; * src/xdisp.c (display_mode_line, display_mode_element): Fix comments. --- src/xdisp.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index 1340716e4a1..4a0ea5778ba 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -27774,7 +27774,7 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format) /* Display the mode line string one element by one element. This is to make the ranges of mouse highlighting - correct. */ + correct. */ do { end = Fnext_single_property_change (start, Qmode_line_elt_no, @@ -27788,7 +27788,7 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format) } else { - /* Compress the mode line. */ + /* Compress the mode line. */ ptrdiff_t i = 0, i_byte = 0; int prev = 0; Lisp_Object start = make_fixnum (0), end; @@ -27796,7 +27796,7 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format) /* Display the mode line string one element by one element. This is to make the ranges of mouse highlighting - correct. */ + correct. */ do { end = Fnext_single_property_change (start, @@ -27822,7 +27822,7 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format) start, prev_pos)); - /* Skip past the rest of the space characters. */ + /* Skip past the rest of the space characters. */ Lisp_Object display = Fget_text_property (make_fixnum (i), Qdisplay, mode_string); @@ -27837,7 +27837,7 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format) } /* Skip the final space no matter how the loop - above ends. */ + above ends. */ if (c == ' ' && NILP (display)) start = end; else @@ -27847,7 +27847,7 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format) prev = c; } - /* Append the final bit. */ + /* Append the final bit. */ if (XFIXNUM (start) < XFIXNUM (end)) elt = concat2 (elt, Fsubstring (mode_string, start, end)); @@ -27886,7 +27886,7 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format) glyph wider. We actually add only as much space as is available for the last glyph of the modeline and whatever space is left beyond it, since that glyph could be only - partially visible */ + partially visible. */ if (box_thickness > 0) last->pixel_width += max (0, (box_thickness - (it.current_x - it.last_visible_x))); @@ -27988,7 +27988,7 @@ display_mode_element (struct it *it, int depth, int field_width, int precision, element could be stored by parts. For example, "a%b" is stored as two elements in the 'mode_line_string_list', but they should be considered as one element, so we cannot increment this number when - "a" is stored. */ + "a" is stored. */ if (mode_line_target == MODE_LINE_STRING) mode_line_elt_no++; From 183ab3372e24c80217db8cc8ba22bf1ac48100a4 Mon Sep 17 00:00:00 2001 From: Billy Lei Date: Sat, 15 Mar 2025 14:46:31 +0800 Subject: [PATCH 023/395] Add input method for languages based on Burmese This adds 4 new input methods: . Burmese . Burmese Visual . Shan . Mon * lisp/leim/quail/burmese.el: New file. (Bug#77026) --- lisp/leim/quail/burmese.el | 388 +++++++++++++++++++++++++++++++++++++ 1 file changed, 388 insertions(+) create mode 100644 lisp/leim/quail/burmese.el diff --git a/lisp/leim/quail/burmese.el b/lisp/leim/quail/burmese.el new file mode 100644 index 00000000000..c1a655e55f4 --- /dev/null +++ b/lisp/leim/quail/burmese.el @@ -0,0 +1,388 @@ +;;; burmese.el --- Quail package for inputting Burmese -*- coding: utf-8; lexical-binding:t -*- + +;; Copyright (C) 2007-2025 Free Software Foundation, Inc. + +;; Author: Billy Lei +;; Keywords: multilingual, input method, Burmese + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: + +;;; Code: + +(require 'quail) + + +(quail-define-package + "burmese" "Burmese" "MY" nil "Burmese input method (in phonetic order)." nil t t t t nil nil nil nil nil t) + +(quail-define-rules + ("1" ?၁) + ("2" ?၂) + ("3" ?၃) + ("4" ?၄) + ("5" ?၅) + ("6" ?၆) + ("7" ?၇) + ("8" ?၈) + ("9" ?၉) + ("0" ?၀) + + ("!" ?ဍ) + ("@" ?ၒ) + ("#" ?ဋ) + ("$" ?ၓ) + ("%" ?ၔ) + ("^" ?ၕ) + ("&" ?ရ) + + ("`" ?ၐ) + ("~" ?ဎ) + + ("Q" ?ဈ) + ("W" ?ဝ) + ("E" ?ဣ) + ("R" ?၎) + ("T" ?ဤ) + ("Y" ?၌) + ("U" ?ဥ) + ("I" ?၍) + ("O" ?ဿ) + ("P" ?ဏ) + ("{" ?ဧ) + ("}" ?ဪ) + + ("A" ?ဗ) + ("S" ?ှ) + ("D" ?ီ) + ("F" ?္) + ("G" ?ွ) + ("H" ?ံ) + ("J" ?ဲ) + ("K" ?ဒ) + ("L" ?ဓ) + + ("Z" ?ဇ) + ("X" ?ဌ) + ("C" ?ဃ) + ("V" ?ဠ) + ("B" ?ယ) + ("N" ?ဉ) + ("M" ["ဦ"]) + ("<" ?၊) + (">" ?။) + ("?" ??) + + ("q" ?ဆ) + ("w" ?တ) + ("e" ?န) + ("r" ?မ) + ("t" ?အ) + ("y" ?ပ) + ("u" ?က) + ("i" ?င) + ("o" ?သ) + ("p" ?စ) + ("[" ?ဟ) + ("]" ?ဩ) + + ("a" ?ေ) + ("s" ?ျ) + ("d" ?ိ) + ("f" ?်) + ("g" ?ါ) + ("h" ?့) + ("j" ?ြ) + ("k" ?ု) + ("l" ?ူ) + (";" ?း) + (":" ?ဂ) + + ("z" ?ဖ) + ("x" ?ထ) + ("c" ?ခ) + ("v" ?လ) + ("b" ?ဘ) + ("n" ?ည) + ("m" ?ာ) + ) + +(quail-define-package + "burmese-visual" "Burmese" "MYV" nil "Burmese input method (in visual order). + +A more common way to input Burmese, which allows inputing the vowel ေ in visual order. +" nil t t t t nil nil nil nil nil t) + +(quail-define-rules + ("1" ?၁) + ("2" ?၂) + ("3" ?၃) + ("4" ?၄) + ("5" ?၅) + ("6" ?၆) + ("7" ?၇) + ("8" ?၈) + ("9" ?၉) + ("0" ?၀) + + ("!" ?ဍ) + ("@" ?ၒ) + ("#" ?ဋ) + ("$" ?ၓ) + ("%" ?ၔ) + ("^" ?ၕ) + ("&" ?ရ) + + ("`" ?ၐ) + ("~" ?ဎ) + + ("Q" ?ဈ) + ("W" ?ဝ) + ("E" ?ဣ) + ("R" ?၎) + ("T" ?ဤ) + ("Y" ?၌) + ("U" ?ဥ) + ("I" ?၍) + ("O" ?ဿ) + ("P" ?ဏ) + ("{" ?ဧ) + ("}" ?ဪ) + + ("A" ?ဗ) + ("S" ?ှ) + ("D" ?ီ) + ("F" ?္) + ("G" ?ွ) + ("H" ?ံ) + ("J" ?ဲ) + ("K" ?ဒ) + ("L" ?ဓ) + + ("Z" ?ဇ) + ("X" ?ဌ) + ("C" ?ဃ) + ("V" ?ဠ) + ("B" ?ယ) + ("N" ?ဉ) + ("M" ["ဦ"]) + ("<" ?၊) + (">" ?။) + + ("q" ?ဆ) + ("w" ?တ) + ("e" ?န) + ("r" ?မ) + ("t" ?အ) + ("y" ?ပ) + ("u" ?က) + ("i" ?င) + ("o" ?သ) + ("p" ?စ) + ("[" ?ဟ) + ("]" ["ဩ"]) + + ("a" ?ေ) + ("s" ?ျ) + ("d" ?ိ) + ("f" ?်) + ("g" ?ါ) + ("h" ?့) + ("j" ?ြ) + ("k" ?ု) + ("l" ?ူ) + (";" ?း) + (":" ?ဂ) + + ("z" ?ဖ) + ("x" ?ထ) + ("c" ?ခ) + ("v" ?လ) + ("b" ?ဘ) + ("n" ?ည) + ("m" ?ာ) + + ("au" ["ကေ"]) ("ac" ["ခေ"]) ("a:" ["ဂေ"]) ("aC" ["ဃေ"]) ("ai" ["ငေ"]) + ("ap" ["စေ"]) ("aq" ["ဆေ"]) ("aZ" ["ဇေ"]) ("aQ" ["ဈေ"]) ("an" ["ညေ"]) + ("a#" ["ဋေ"]) ("aX" ["ဌေ"]) ("a!" ["ဍေ"]) ("a~" ["ဎေ"]) ("aP" ["ဏေ"]) + ("aw" ["တေ"]) ("ax" ["ထေ"]) ("aK" ["ဒေ"]) ("aL" ["ဓေ"]) ("ae" ["နေ"]) + ("ay" ["ပေ"]) ("az" ["ဖေ"]) ("aA" ["ဗေ"]) ("ab" ["ဘေ"]) ("ar" ["မေ"]) + ("aB" ["ယေ"]) ("a&" ["ရေ"]) ("av" ["လေ"]) ("aW" ["ဝေ"]) ("ao" ["သေ"]) + ("a[" ["ဟေ"]) ("aV" ["ဠေ"]) ("at" ["အေ"]) + ) + +(quail-define-package + "shan" "Burmese" "SHN" nil "Shan input method." nil t t t t nil nil nil nil nil t) + +(quail-define-rules + ("Q" ?ꩡ) + ("W" ?တ) + ("E" ?ꧣ) + ("R" ?႞) + ("T" ?ြ) + ("Y" ?ၿ) + ("U" ?ၷ) + ("I" ?ရ) + ("O" ?သ) + ("P" ?ႀ) + + ("A" ?ဵ) + ("S" ?ႅ) + ("D" ?ီ) + ("F" ?ႂ) + ("G" ?ႂ) + ("H" ?့) + ("J" ?ႆ) + ("K" ?ဒ) + ("L" ?ႊ) + + ("Z" ?ၾ) + ("X" ?ꩪ) + ("C" ?ꧠ) + ("V" ?ꩮ) + ("B" ?ျ) + ("N" ?႟) + ("M" ?ႃ) + ("<" ?၊) + (">" ?။) + + ("q" ?ၸ) + ("w" ?တ) + ("e" ?ၼ) + ("r" ?မ) + ("t" ?ဢ) + ("y" ?ပ) + ("u" ?ၵ) + ("i" ?င) + ("o" ?ဝ) + ("p" ?ႁ) + + ("a" ?ေ) + ("s" ?ႄ) + ("d" ?ိ) + ("f" ?်) + ("g" ?ွ) + ("h" ?ႉ) + ("j" ?ႇ) + ("k" ?ု) + ("l" ?ူ) + (";" ?ႈ) + (":" ?း) + + ("z" ?ၽ) + ("x" ?ထ) + ("c" ?ၶ) + ("v" ?လ) + ("b" ?ယ) + ("n" ?ၺ) + ("m" ?ၢ) + ) + + +(quail-define-package + "mon" "Burmese" "MON" nil "Mon input method." nil t t t t nil nil nil nil nil t) + +(quail-define-rules + ("1" ?၁) + ("2" ?၂) + ("3" ?၃) + ("4" ?၄) + ("5" ?၅) + ("6" ?၆) + ("7" ?၇) + ("8" ?၈) + ("9" ?၉) + ("0" ?၀) + + ("!" ?ဍ) + ("@" ?ၒ) + ("#" ?ဋ) + ("$" ?ၓ) + ("^" ?ဵ) + ("&" ?ရ) + + ("`" ?ၝ) + ("~" ?ဎ) + + ("Q" ?ၛ) + ("W" ?ဝ) + ("E" ?ဣ) + ("R" ?ၟ) + ("T" ?ဳ) + ("Y" ?ၠ) + ("U" ?ဥ) + ("I" ?၎) + ("O" ?ဿ) + ("P" ?ဏ) + ("{" ?ဨ) + ("}" ?/) + + ("A" ?ဗ) + ("S" ?ှ) + ("D" ?ီ) + ("F" ?္) + ("G" ?ွ) + ("H" ?ံ) + ("J" ?ဲ) + ("K" ?ဒ) + ("L" ?ဓ) + + ("Z" ?ဇ) + ("X" ?ဌ) + ("C" ?ဃ) + ("V" ?ဠ) + ("B" ?ၐ) + ("N" ?ဉ) + ("M" ?ၔ) + ("<" ?ၞ) + (">" ?ၕ) + ("?" ?၊) + ("/" ?။) + + ("q" ?ဆ) + ("w" ?တ) + ("e" ?န) + ("r" ?မ) + ("t" ?အ) + ("y" ?ပ) + ("u" ?က) + ("i" ?ၚ) + ("o" ?သ) + ("p" ?စ) + ("[" ?ဟ) + ("]" ?ဩ) + + ("a" ?ေ) + ("s" ?ျ) + ("d" ?ိ) + ("f" ?်) + ("g" ?ါ) + ("h" ?ဴ) + ("j" ?ြ) + ("k" ?ု) + ("l" ?ူ) + (";" ?း) + + ("z" ?ဖ) + ("x" ?ထ) + ("c" ?ခ) + ("v" ?လ) + ("b" ?ဘ) + ("n" ?ည) + ("m" ?ာ) + ) +;;; burmese.el ends here From a4ee1e6709b57e6aed3ff6e800ab8fb83b706d65 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 5 Apr 2025 12:48:42 +0300 Subject: [PATCH 024/395] ; * etc/NEWS: Announce new input methods (bug#77026). --- etc/NEWS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/etc/NEWS b/etc/NEWS index e3e63b939f9..61474af7fcb 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -477,6 +477,10 @@ Additionally, there is a general-purpose 'haudenosaunee-postfix' input method to facilitate writing in the orthographies of the five languages simultaneously. +--- +*** New input methods for languages based on Burmese. +These include: Burmese, Burmese (visual order), Shan, and Mon. + --- ** 'visual-wrap-prefix-mode' now supports variable-pitch fonts. When using 'visual-wrap-prefix-mode' in buffers with variable-pitch From 52e7a71e3f90fede27864e366977e23bfc193891 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 5 Apr 2025 13:24:22 +0300 Subject: [PATCH 025/395] Teach 'current-column' to account for images * src/indent.c (check_display_width): Handle 'image' and 'slice' display specs, instead of using the width of the underlying text. Accept 2 additional arguments: WINDOW and SCAN_BYTE. (Bug#76107) --- src/indent.c | 110 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 84 insertions(+), 26 deletions(-) diff --git a/src/indent.c b/src/indent.c index 01cea221368..b4f3c349dc5 100644 --- a/src/indent.c +++ b/src/indent.c @@ -466,13 +466,21 @@ current_column (void) } +static void restore_window_buffer (Lisp_Object); + /* Check the presence of a display property and compute its width. + POS and POS_BYTE are the character and byte positions of the + display property and COL is the column number at POS. If a property was found and its width was found as well, return its width (>= 0) and set the position of the end of the property in ENDPOS. - Otherwise just return -1. */ + Otherwise just return -1. + WINDOW is the window to use when it is important; nil stands for + the selected window. */ static int -check_display_width (ptrdiff_t pos, ptrdiff_t col, ptrdiff_t *endpos) +check_display_width (Lisp_Object window, + ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t col, + ptrdiff_t *endpos) { Lisp_Object val, overlay; @@ -482,30 +490,80 @@ check_display_width (ptrdiff_t pos, ptrdiff_t col, ptrdiff_t *endpos) int width = -1; Lisp_Object plist = Qnil; - /* Handle '(space ...)' display specs. */ - if (CONSP (val) && EQ (Qspace, XCAR (val))) - { /* FIXME: Use calc_pixel_width_or_height. */ - Lisp_Object prop; - EMACS_INT align_to_max = - (col < MOST_POSITIVE_FIXNUM - INT_MAX - ? (EMACS_INT) INT_MAX + col - : MOST_POSITIVE_FIXNUM); + if (CONSP (val)) + { + Lisp_Object xcar = XCAR (val); - plist = XCDR (val); - if ((prop = plist_get (plist, QCwidth), - RANGED_FIXNUMP (0, prop, INT_MAX)) - || (prop = plist_get (plist, QCrelative_width), - RANGED_FIXNUMP (0, prop, INT_MAX))) - width = XFIXNUM (prop); - else if (FLOATP (prop) && 0 <= XFLOAT_DATA (prop) - && XFLOAT_DATA (prop) <= INT_MAX) - width = (int)(XFLOAT_DATA (prop) + 0.5); - else if ((prop = plist_get (plist, QCalign_to), - RANGED_FIXNUMP (col, prop, align_to_max))) - width = XFIXNUM (prop) - col; - else if (FLOATP (prop) && col <= XFLOAT_DATA (prop) - && (XFLOAT_DATA (prop) <= align_to_max)) - width = (int)(XFLOAT_DATA (prop) + 0.5) - col; + /* Handle '(space ...)' display specs. */ + if (EQ (Qspace, xcar)) + { /* FIXME: Use calc_pixel_width_or_height. */ + Lisp_Object prop; + EMACS_INT align_to_max = + (col < MOST_POSITIVE_FIXNUM - INT_MAX + ? (EMACS_INT) INT_MAX + col + : MOST_POSITIVE_FIXNUM); + + plist = XCDR (val); + if ((prop = plist_get (plist, QCwidth), + RANGED_FIXNUMP (0, prop, INT_MAX)) + || (prop = plist_get (plist, QCrelative_width), + RANGED_FIXNUMP (0, prop, INT_MAX))) + width = XFIXNUM (prop); + else if (FLOATP (prop) && 0 <= XFLOAT_DATA (prop) + && XFLOAT_DATA (prop) <= INT_MAX) + width = (int)(XFLOAT_DATA (prop) + 0.5); + else if ((prop = plist_get (plist, QCalign_to), + RANGED_FIXNUMP (col, prop, align_to_max))) + width = XFIXNUM (prop) - col; + else if (FLOATP (prop) && col <= XFLOAT_DATA (prop) + && (XFLOAT_DATA (prop) <= align_to_max)) + width = (int)(XFLOAT_DATA (prop) + 0.5) - col; + } + /* Handle images. */ + else if (EQ (Qimage, xcar) + || EQ (Qslice, xcar) + /* 'insert-sliced-image' creates property of the form + ((slice ...) image ...) */ + || (CONSP (xcar) && EQ (Qslice, XCAR (xcar)))) + { + specpdl_ref count = SPECPDL_INDEX (); + struct window *w = decode_live_window (window); + + /* If needed, set the window's buffer temporarily to the + current buffer and its window-point to POS. */ + if (XBUFFER (w->contents) != current_buffer) + { + Lisp_Object oldbuf + = list4 (window, w->contents, + make_fixnum (marker_position (w->pointm)), + make_fixnum (marker_byte_position (w->pointm))); + record_unwind_protect (restore_window_buffer, oldbuf); + wset_buffer (w, Fcurrent_buffer ()); + set_marker_both (w->pointm, w->contents, pos, pos_byte); + } + + struct text_pos startpos; + struct it it; + SET_TEXT_POS (startpos, pos, pos_byte); + void *itdata = bidi_shelve_cache (); + record_unwind_protect_void (unwind_display_working_on_window); + display_working_on_window_p = true; + start_display (&it, w, startpos); + it.last_visible_x = 1000000; /* prevent image clipping */ + /* Forcing HPOS non-zero prevents the display code from + generating line/wrap-prefix and line numbers, which + would otherwise skew the X coordinate we obtain below. */ + it.hpos = 1; + /* The POS+1 value is a trick: move_it_in_display_line + will not return until it finished processing the entire + image, even if it covers more than one buffer position. */ + move_it_in_display_line (&it, pos + 1, -1, MOVE_TO_POS); + /* The caller wants the width in units of the frame's + canonical character width. */ + width = ((double)it.current_x / FRAME_COLUMN_WIDTH (it.f)) + 0.5; + bidi_unshelve_cache (itdata, 0); + unbind_to (count, Qnil); + } } /* Handle 'display' strings. */ else if (STRINGP (val)) @@ -652,7 +710,7 @@ scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol, { /* Check display property. */ ptrdiff_t endp; - int width = check_display_width (scan, col, &endp); + int width = check_display_width (window, scan, scan_byte, col, &endp); if (width >= 0) { col += width; From 5987d77f40bf72a268d35d1f2a88f7cd00c17459 Mon Sep 17 00:00:00 2001 From: James Thomas Date: Fri, 14 Mar 2025 15:54:31 +0530 Subject: [PATCH 026/395] * lisp/gnus/nnfeed.el (nnfeed--write-server): Use default print settings. Bug#77113 --- lisp/gnus/nnfeed.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/gnus/nnfeed.el b/lisp/gnus/nnfeed.el index 3ae3d759fdb..d07a5c0539d 100644 --- a/lisp/gnus/nnfeed.el +++ b/lisp/gnus/nnfeed.el @@ -294,7 +294,7 @@ group names to their data, which should be a vector of the form ((hash-table-p s))) (with-temp-file f (insert ";;;; -*- mode: lisp-data -*- DO NOT EDIT\n") - (prin1 s (current-buffer)) + (prin1 s (current-buffer) t) (insert "\n") t) t) From 684adc07c28ce96b8da1fa2bea31dbf0c8833d92 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 5 Apr 2025 15:09:20 +0300 Subject: [PATCH 027/395] ; Fix a recent backport * lisp/progmodes/typescript-ts-mode.el (treesit-node-child-by-field-name, treesit-node-match-p) (treesit-node-type): Declare. Do not merge to master. --- lisp/progmodes/typescript-ts-mode.el | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index 871dbc2e3dc..b4b078950c3 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -38,6 +38,9 @@ (declare-function treesit-parser-create "treesit.c") (declare-function treesit-query-capture "treesit.c") (declare-function treesit-query-compile "treesit.c") +(declare-function treesit-node-child-by-field-name "treesit.c") +(declare-function treesit-node-match-p "treesit.c") +(declare-function treesit-node-type "treesit.c") (defcustom typescript-ts-mode-indent-offset 2 "Number of spaces for each indentation step in `typescript-ts-mode'." From 5fc1bd879e41e79601cff27db175d2ad22eafb66 Mon Sep 17 00:00:00 2001 From: shipmints Date: Fri, 4 Apr 2025 13:25:55 -0400 Subject: [PATCH 028/395] Add tab-bar test for "effectively dedicated window" (bug#71386) * test/lisp/tab-bar-tests.el (tab-bar-tests-quit-restore-window): New test for 'delete-frame' for effectively-dedicated windows. --- test/lisp/tab-bar-tests.el | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/test/lisp/tab-bar-tests.el b/test/lisp/tab-bar-tests.el index c0e12cf159c..a26d15ce977 100644 --- a/test/lisp/tab-bar-tests.el +++ b/test/lisp/tab-bar-tests.el @@ -134,7 +134,7 @@ ;; Clean up the tab afterwards (tab-close)) - ;; 3. Don't delete the frame with dedicated window + ;; 3.1. Don't delete the frame with dedicated window ;; from the second tab (bug#71386) (with-selected-frame (make-frame frame-params) (switch-to-buffer (generate-new-buffer "test1")) @@ -150,8 +150,25 @@ (kill-buffer) (should (eq (length (frame-list)) 1))) - ;; Clean up tabs afterwards - (tab-bar-tabs-set nil))) + ;; 3.2. Don't delete the frame with an effectively-dedicated window + ;; from the second tab (bug#71386) + (with-selected-frame (make-frame frame-params) + (let ((switch-to-prev-buffer-skip #'always) + (kill-buffer-quit-windows nil)) + (switch-to-buffer (generate-new-buffer "test1")) + (tab-bar-new-tab) + (switch-to-buffer (generate-new-buffer "test2")) + ;; This makes the window effectively dedicated. + (set-window-prev-buffers nil nil) + ;; Killing the buffer should close the tab, leave one open tab, + ;; and not delete the frame. + (kill-buffer) + (should (eq (length (tab-bar-tabs)) 1)) + (should (eq (length (frame-list)) 2)) + (delete-frame)))) + + ;; Clean up tabs afterwards + (tab-bar-tabs-set nil)) (provide 'tab-bar-tests) ;;; tab-bar-tests.el ends here From c418e454b3a9d103a5a59c76e1c36f3597de6798 Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Sat, 5 Apr 2025 18:41:00 +0000 Subject: [PATCH 029/395] macroexp--expand-all: Don't call function-get on non-symbols * lisp/emacs-lisp/macroexp.el (macroexp--expand-all): Don't call function-get on non-symbols (bug#77550). --- lisp/emacs-lisp/macroexp.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el index 64ec634620a..533b3a3a1b8 100644 --- a/lisp/emacs-lisp/macroexp.el +++ b/lisp/emacs-lisp/macroexp.el @@ -489,7 +489,7 @@ Assumes the caller has bound `macroexpand-all-environment'." (macroexp--unfold-lambda `(,fn ,eexp . ,eargs))) (_ `(,fn ,eexp . ,eargs))))) (`(funcall . ,_) form) ;bug#53227 - (`(,func . ,_) + (`(,(and func (pred symbolp)) . ,_) (let ((handler (function-get func 'compiler-macro))) ;; Macro expand compiler macros. This cannot be delayed to ;; byte-optimize-form because the output of the compiler-macro can From a5f574429db1f820cc4d25bfb0e700aae050dc07 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 6 Apr 2025 09:09:32 +0800 Subject: [PATCH 030/395] vc-dir-mark-file: Consistently don't allow marking a subdirectory * lisp/vc/vc-dir.el (vc-dir-mark-file): Don't allow marking a subdirectory if its parent is already marked. This fixes an inconsistency whereby if a subdirectory was already marked then its parent could not be marked, but not vice-versa (bug #76769). --- lisp/vc/vc-dir.el | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lisp/vc/vc-dir.el b/lisp/vc/vc-dir.el index fd3fc10822d..4f497eed8a1 100644 --- a/lisp/vc/vc-dir.el +++ b/lisp/vc/vc-dir.el @@ -684,15 +684,15 @@ With prefix argument ARG, move that many lines." (file (ewoc-data crt)) (isdir (vc-dir-fileinfo->directory file)) ;; Forbid marking a directory containing marked files in its - ;; tree, or a file in a marked directory tree. - (conflict (if isdir - (vc-dir-children-marked-p crt) - (vc-dir-parent-marked-p crt)))) - (when conflict - (error (if isdir - "File `%s' in this directory is already marked" + ;; tree, or a file or directory in a marked directory tree. + (child-conflict (and isdir (vc-dir-children-marked-p crt))) + (parent-conflict (vc-dir-parent-marked-p crt))) + (when (or child-conflict parent-conflict) + (error (if child-conflict + "Entry `%s' in this directory is already marked" "Parent directory `%s' is already marked") - (vc-dir-fileinfo->name conflict))) + (vc-dir-fileinfo->name (or child-conflict + parent-conflict)))) (setf (vc-dir-fileinfo->marked file) t) (ewoc-invalidate vc-ewoc crt) (unless (or arg (mouse-event-p last-command-event)) From c0b1b54d734a45698da9df0841700c4c15785b11 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 6 Apr 2025 11:09:22 +0800 Subject: [PATCH 031/395] Fix dired-vc-next-action generating inconsistent marks * lisp/vc/vc-dir.el (vc-dir-mark-files): Document that directories passed to this function must have trailing slashes. Don't mark both a directory and also items under it (bug#76769). * lisp/dired-aux.el (dired-vc-next-action): Update docstring. --- lisp/dired-aux.el | 12 ++++++------ lisp/vc/vc-dir.el | 12 +++++++++++- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el index d7d4a394c4a..f278b201ca6 100644 --- a/lisp/dired-aux.el +++ b/lisp/dired-aux.el @@ -3963,12 +3963,12 @@ If only regular files are in the fileset, call `vc-next-action' with the same value of the VERBOSE argument (interactively, the prefix argument). -If one or more directories are in the fileset, start `vc-dir' in the root -directory of the repository that includes the current directory, with -the same files/directories marked in the VC-Directory buffer that were -marked in the original Dired buffer. If the current directory doesn't -belong to a VCS repository, prompt for a repository directory. In this -case, the VERBOSE argument is ignored." +If one or more directories are in the fileset, start `vc-dir' in the +root directory of the repository that includes the current directory, +with all directories in the fileset marked in the VC-Directory buffer +that were marked in the original Dired buffer. If the current directory +doesn't belong to a VCS repository, prompt for a repository directory. +In this case, the VERBOSE argument is ignored." (interactive "P" dired-mode) (let* ((marked-files (dired-get-marked-files nil nil nil nil t)) diff --git a/lisp/vc/vc-dir.el b/lisp/vc/vc-dir.el index 4f497eed8a1..93c11fdbc68 100644 --- a/lisp/vc/vc-dir.el +++ b/lisp/vc/vc-dir.el @@ -774,7 +774,17 @@ If UNMARK (interactively, the prefix), unmark instead." (defun vc-dir-mark-files (mark-files) "Mark files specified by file names in the argument MARK-FILES. -MARK-FILES should be a list of absolute filenames." +MARK-FILES should be a list of absolute filenames. +Directories must have trailing slashes." + ;; Filter out subitems that would be implicitly marked. + (setq mark-files (sort mark-files)) + (let ((next mark-files)) + (while next + (when (string-suffix-p "/" (car next)) + (while (string-prefix-p (car next) (cadr next)) + (rplacd next (cddr next)))) + (setq next (cdr next)))) + (ewoc-map (lambda (filearg) (when (member (expand-file-name (vc-dir-fileinfo->name filearg)) From 936b2efdb389488d291086d5c2189fd1a7170aa6 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 6 Apr 2025 11:18:57 +0800 Subject: [PATCH 032/395] Teach VC-Dir to automatically add and remove marks on other lines * lisp/vc/vc-dir.el (vc-dir-allow-mass-mark-changes): New option. (vc-dir-parent-marked-p): Replace with ... (vc-dir--parent): ... this. (vc-dir-children-marked-p): Replace with ... (vc-dir--children): ... this. (vc-dir-mark-file): Unmark subitems before marking a directory. Offer to unmark a directory before marking a subitem. (vc-dir-unmark-file): For an implicitly marked item, offer to unmark it by marking everything else that's implicitly marked. For an unmarked directory with marked subitems, offer to unmark them all. * etc/NEWS: Document the changes. --- etc/NEWS | 11 ++++ lisp/vc/vc-dir.el | 146 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 125 insertions(+), 32 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 61474af7fcb..35e6edcd712 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1489,6 +1489,17 @@ its default value. Effectively, the default value hasn't changed, since 'vc-resolve-conflicts' defaults to t, the previous default value for 'vc-git-resolve-conflicts'. +--- +*** VC-Dir can now automatically add and remove marks on other lines. +When you try to use a mark or unmark command where doing so would only +be permitted if other lines were marked or unmarked first, Emacs +will now ask you if you'd like to change the marks on those other lines. +For example, if you try to mark a file contained within a directory that +is already marked, Emacs will offer to unmark the directory, first. +Previously, Emacs would simply refuse to make any changes. +You can customize 'vc-dir-allow-mass-mark-changes' to restore the old +behavior or dispense with the prompting. + ** Diff mode +++ diff --git a/lisp/vc/vc-dir.el b/lisp/vc/vc-dir.el index 93c11fdbc68..1074986090e 100644 --- a/lisp/vc/vc-dir.el +++ b/lisp/vc/vc-dir.el @@ -126,6 +126,38 @@ See `run-hooks'." (defvar vc-dir-backend nil "The backend used by the current *vc-dir* buffer.") +(defcustom vc-dir-allow-mass-mark-changes 'ask + "If non-nil, VC-Dir commands may mark or unmark many items at once. + +When a directory in VC-Dir is marked, then for most VCS, this means that +all files within it are implicitly marked as well. +For consistency, the mark and unmark commands (principally \\\\[vc-dir-mark] and \\[vc-dir-unmark]) will +not explicitly mark or unmark entries if doing so would result in a +situation where both a directory and a file or directory within it are +both marked. + +With the default value of this variable, `ask', if you attempt to mark +or unmark a particular item and doing so consistent with these +restrictions would require other items to be marked or unmarked too, +Emacs will prompt you to confirm that you do mean for the other items to +be marked or unmarked. + +If this variable is nil, the commands will refuse to do anything if they +would need to mark or unmark other entries too. +If this variable is any other non-nil value, the commands will always +proceed to mark and unmark other entries, without asking. + +There is one operation where marking or unmarking other entries in order +to mark or unmark the entry at point is unlikely to be surprising: +when you use \\[vc-dir-mark] on a directory which already has marked items within it. +In this case, the subitems are unmarked regardless of the value of this +option." + :type '(choice (const :tag "Don't allow" nil) + (const :tag "Prompt to allow" ask) + (const :tag "Allow without prompting" t)) + :group 'vc + :version "31.1") + (defun vc-dir-move-to-goal-column () ;; Used to keep the cursor on the file name column. (beginning-of-line) @@ -640,9 +672,9 @@ With prefix argument ARG, move that many lines." (error (vc-dir-next-line 1)))))) (funcall mark-unmark-function))) -(defun vc-dir-parent-marked-p (arg) - ;; Non-nil iff a parent directory of arg is marked. - ;; Return value, if non-nil is the `ewoc-data' for the marked parent. +(defun vc-dir--parent (arg &optional if-marked) + "Return the parent node of ARG. +If IF-MARKED, return the nearest marked parent." (let* ((argdir (vc-dir-node-directory arg)) ;; (arglen (length argdir)) (crt arg) @@ -655,46 +687,58 @@ With prefix argument ARG, move that many lines." (dir (vc-dir-node-directory crt))) (and (vc-dir-fileinfo->directory data) (string-prefix-p dir argdir) - (vc-dir-fileinfo->marked data) - (setq found data)))) + (or (not if-marked) (vc-dir-fileinfo->marked data)) + (setq found crt)))) found)) -(defun vc-dir-children-marked-p (arg) - ;; Non-nil iff a child of ARG is marked. - ;; Return value, if non-nil, is the `ewoc-data' for the marked child. - (let* ((argdir-re (concat "\\`" (regexp-quote (vc-dir-node-directory arg)))) +(defun vc-dir--children (arg &optional only-marked) + "Return a list of children of ARG. If ONLY-MARKED, only those marked." + (let* ((argdir-re (concat "\\`" + (regexp-quote (vc-dir-node-directory arg)))) (is-child t) (crt arg) (found nil)) (while (and is-child - (null found) (setq crt (ewoc-next vc-ewoc crt))) - (let ((data (ewoc-data crt)) - (dir (vc-dir-node-directory crt))) - (if (string-match argdir-re dir) - (if (vc-dir-fileinfo->marked data) - (setq found data)) - ;; We are done, we got to an entry that is not a child of `arg'. - (setq is-child nil)))) + (if (string-match argdir-re (vc-dir-node-directory crt)) + (when (or (not only-marked) + (vc-dir-fileinfo->marked (ewoc-data crt))) + (push crt found)) + ;; We are done, we got to an entry that is not a child of `arg'. + (setq is-child nil))) found)) (defun vc-dir-mark-file (&optional arg) ;; Mark ARG or the current file and move to the next line. (let* ((crt (or arg (ewoc-locate vc-ewoc))) (file (ewoc-data crt)) - (isdir (vc-dir-fileinfo->directory file)) - ;; Forbid marking a directory containing marked files in its - ;; tree, or a file or directory in a marked directory tree. - (child-conflict (and isdir (vc-dir-children-marked-p crt))) - (parent-conflict (vc-dir-parent-marked-p crt))) - (when (or child-conflict parent-conflict) - (error (if child-conflict - "Entry `%s' in this directory is already marked" - "Parent directory `%s' is already marked") - (vc-dir-fileinfo->name (or child-conflict - parent-conflict)))) + (to-inval (list crt))) + ;; We do not allow a state in which a directory is marked and also + ;; some of its files are marked. If the user's intent is clear, + ;; adjust things for them so that they can proceed. + (if-let* (((vc-dir-fileinfo->directory file)) + (children (vc-dir--children crt t))) + ;; The user wants to mark a directory where some of its children + ;; are already marked. The user's intent is quite clear, so + ;; unconditionally unmark the children. + (dolist (child children) + (setf (vc-dir-fileinfo->marked (ewoc-data child)) nil) + (push child to-inval)) + (when-let* ((parent (vc-dir--parent crt t)) + (name (vc-dir-fileinfo->name (ewoc-data parent)))) + ;; The user seems to want to mark an entry whose directory is + ;; already marked. As the file is already implicitly marked for + ;; most VCS, they may not really intend this. + (when (or (not vc-dir-allow-mass-mark-changes) + (and (eq vc-dir-allow-mass-mark-changes 'ask) + (not (yes-or-no-p + (format "`%s' is already marked; unmark it?" + name))))) + (error "`%s' is already marked" name)) + (setf (vc-dir-fileinfo->marked (ewoc-data parent)) nil) + (push parent to-inval))) (setf (vc-dir-fileinfo->marked file) t) - (ewoc-invalidate vc-ewoc crt) + (apply #'ewoc-invalidate vc-ewoc to-inval) (unless (or arg (mouse-event-p last-command-event)) (vc-dir-next-line 1)))) @@ -816,9 +860,47 @@ Directories must have trailing slashes." (defun vc-dir-unmark-file () ;; Unmark the current file and move to the next line. (let* ((crt (ewoc-locate vc-ewoc)) - (file (ewoc-data crt))) - (setf (vc-dir-fileinfo->marked file) nil) - (ewoc-invalidate vc-ewoc crt) + (file (ewoc-data crt)) + to-inval) + (if (vc-dir-fileinfo->marked file) + (progn (setf (vc-dir-fileinfo->marked file) nil) + (push crt to-inval)) + ;; The current item is not explicitly marked, but its containing + ;; directory is marked. So this item is implicitly marked, for + ;; most VCS. Offer to change that. + (if-let* ((parent (vc-dir--parent crt t)) + (all-children (vc-dir--children parent))) + (when (and vc-dir-allow-mass-mark-changes + (or (not (eq vc-dir-allow-mass-mark-changes 'ask)) + (yes-or-no-p + (format "\ +Replace mark on `%s' with marks on all subitems but this one?" + (vc-dir-fileinfo->name file))))) + (let ((subtree (if (vc-dir-fileinfo->directory file) + (cons crt (vc-dir--children crt)) + (list crt (vc-dir--parent crt))))) + (setf (vc-dir-fileinfo->marked (ewoc-data parent)) nil) + (push parent to-inval) + (dolist (child all-children) + (setf (vc-dir-fileinfo->marked (ewoc-data child)) + (not (memq child subtree))) + (push child to-inval)))) + ;; The current item is a directory that's not marked, implicitly + ;; or explicitly, but it has marked items below it. + ;; Offer to unmark those. + (when-let* + (((vc-dir-fileinfo->directory file)) + (children (vc-dir--children crt t)) + ((and vc-dir-allow-mass-mark-changes + (or (not (eq vc-dir-allow-mass-mark-changes 'ask)) + (yes-or-no-p + (format "Unmark all items within `%s'?" + (vc-dir-fileinfo->name file))))))) + (dolist (child children) + (setf (vc-dir-fileinfo->marked (ewoc-data child)) nil) + (push child to-inval))))) + (when to-inval + (apply #'ewoc-invalidate vc-ewoc to-inval)) (unless (mouse-event-p last-command-event) (vc-dir-next-line 1)))) From 8ae7224b8fae59229b186853b300822bd70a8ec4 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 6 Apr 2025 11:46:23 +0800 Subject: [PATCH 033/395] ; VC credits: Add some names --- lisp/vc/vc.el | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el index 2db2a017525..c8bd4ca9e63 100644 --- a/lisp/vc/vc.el +++ b/lisp/vc/vc.el @@ -38,6 +38,9 @@ ;; J.D. Smith ;; Andre Spiegel ;; Richard Stallman +;; Dmitry Gutov +;; Juri Linkov +;; Sean Whitton ;; ;; In July 2007 ESR returned and redesigned the mode to cope better ;; with modern version-control systems that do commits by fileset From bb756b195a7bc6b4cf3286d891a38459dac23cde Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Sun, 6 Apr 2025 09:11:06 +0200 Subject: [PATCH 034/395] ; Fix typo in Tramp * lisp/net/tramp-cache.el (with-tramp-saved-connection-property): Fix typo. --- lisp/net/tramp-cache.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/net/tramp-cache.el b/lisp/net/tramp-cache.el index 71b8cfa67bf..87e7feae188 100644 --- a/lisp/net/tramp-cache.el +++ b/lisp/net/tramp-cache.el @@ -473,10 +473,10 @@ used to cache connection properties of the local machine." (hash (tramp-get-hash-table key)) (cached (and (hash-table-p hash) (gethash ,property hash tramp-cache-undefined)))) - (tramp-message key 7 "Saved %s %s" property cached) + (tramp-message key 7 "Saved %s %s" ,property cached) (unwind-protect (progn ,@body) ;; Reset PROPERTY. Recompute hash, it could have been flushed. - (tramp-message key 7 "Restored %s %s" property cached) + (tramp-message key 7 "Restored %s %s" ,property cached) (setq hash (tramp-get-hash-table key)) (if (not (eq cached tramp-cache-undefined)) (puthash ,property cached hash) From 417d14a95eeb7294528d6c2dbba394c31254ff4a Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 6 Apr 2025 19:03:23 +0800 Subject: [PATCH 035/395] ; * admin/MAINTAINERS: Complete the handover of VC Changed agreed with Dmitry Gutov . --- admin/MAINTAINERS | 4 ---- 1 file changed, 4 deletions(-) diff --git a/admin/MAINTAINERS b/admin/MAINTAINERS index a47af03eeee..c505c4d4cd2 100644 --- a/admin/MAINTAINERS +++ b/admin/MAINTAINERS @@ -241,9 +241,6 @@ Sean Whitton ============================================================================== 2. Areas that someone is willing to maintain, although he would not necessarily mind if someone else was the official maintainer. -This list also includes people who are in the process of handing over -maintainership to someone listed above, but who want to continue to be -CC'd as though they were still the primary maintainer, in the meantime. ============================================================================== Eli Zaretskii @@ -339,7 +336,6 @@ Tassilo Horn Dmitry Gutov lisp/whitespace.el - lisp/vc/* Vibhav Pant lisp/net/browse-url.el From 819f92cb12b07938623e18384e86371ee101495a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sun, 6 Apr 2025 14:00:23 +0100 Subject: [PATCH 036/395] Icomplete: check flag before rendering vertical indicators Fixes: bug#77546 * lisp/icomplete.el (icomplete-vertical--add-indicator-to-selected): Rework. (icomplete--render-vertical): Fix bug. --- lisp/icomplete.el | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lisp/icomplete.el b/lisp/icomplete.el index d0cc5674ba7..d3b09ebc869 100644 --- a/lisp/icomplete.el +++ b/lisp/icomplete.el @@ -926,9 +926,8 @@ away from the bottom. Counts wrapped lines as real lines." (scroll-up (- icomplete-prospects-height lines-to-bottom)))))) (defun icomplete-vertical--add-indicator-to-selected (comp) - "Add indicators to the selected/unselected COMP completions." - (if (and icomplete-vertical-render-prefix-indicator - (get-text-property 0 'icomplete-selected comp)) + "Add indicator to completion COMP according to its selection state." + (if (get-text-property 0 'icomplete-selected comp) (concat (propertize icomplete-vertical-selected-prefix-indicator 'face 'icomplete-vertical-selected-prefix-indicator-face) comp) @@ -1012,8 +1011,11 @@ away from the bottom. Counts wrapped lines as real lines." ;; Serialize completions and section titles into a list ;; of lines to render (cl-loop - for (comp prefix suffix section) in tuples - do (setq comp (icomplete-vertical--add-indicator-to-selected comp)) + for (comp-no-indicator prefix suffix section) in tuples + for comp = + (if icomplete-vertical-render-prefix-indicator + (icomplete-vertical--add-indicator-to-selected comp-no-indicator) + comp-no-indicator) when section collect (propertize section 'face 'icomplete-section) into lines-aux and count 1 into nsections-aux From ba13e7de32d08028ab7bffdd73dab271a95ea453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sun, 6 Apr 2025 14:07:53 +0100 Subject: [PATCH 037/395] Icomplete: rename some internal helper functions (bug#77546) The naming convention for internal functions is --foo not --foo * lisp/icomplete.el (icomplete--adjust-lines-for-column): Rename from icomplete-vertical--adjust-lines-for-column. (icomplete--ensure-visible-lines-inside-buffer): Rename from icomplete-vertical--ensure-visible-lines-inside-buffer. (icomplete--add-indicator-to-selected): Rename from icomplete-vertical--add-indicator-to-selected. (icomplete--render-vertical): Use new internal function names. --- lisp/icomplete.el | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lisp/icomplete.el b/lisp/icomplete.el index d3b09ebc869..35842b53e6b 100644 --- a/lisp/icomplete.el +++ b/lisp/icomplete.el @@ -884,7 +884,7 @@ by `group-function''s second \"transformation\" protocol." else collect (list tr prefix suffix )) annotated))) -(defun icomplete-vertical--adjust-lines-for-column (lines buffer data) +(defun icomplete--adjust-lines-for-column (lines buffer data) "Adjust the LINES to align with the column in BUFFER based on DATA." (if icomplete-vertical-in-buffer-adjust-list (let* ((column (current-column)) @@ -914,7 +914,7 @@ by `group-function''s second \"transformation\" protocol." lines)) lines)) -(defun icomplete-vertical--ensure-visible-lines-inside-buffer () +(defun icomplete--ensure-visible-lines-inside-buffer () "Ensure the completion list is visible in regular buffers only. Scrolls the screen to be at least `icomplete-prospects-height' real lines away from the bottom. Counts wrapped lines as real lines." @@ -925,7 +925,7 @@ away from the bottom. Counts wrapped lines as real lines." (when (< lines-to-bottom icomplete-prospects-height) (scroll-up (- icomplete-prospects-height lines-to-bottom)))))) -(defun icomplete-vertical--add-indicator-to-selected (comp) +(defun icomplete--add-indicator-to-selected (comp) "Add indicator to completion COMP according to its selection state." (if (get-text-property 0 'icomplete-selected comp) (concat (propertize icomplete-vertical-selected-prefix-indicator @@ -956,11 +956,11 @@ away from the bottom. Counts wrapped lines as real lines." (when (and icomplete-scroll (not icomplete--scrolled-completions) (not icomplete--scrolled-past)) - (icomplete-vertical--ensure-visible-lines-inside-buffer)) + (icomplete--ensure-visible-lines-inside-buffer)) (when (and icomplete-scroll icomplete--scrolled-completions (null icomplete--scrolled-past)) - (icomplete-vertical--ensure-visible-lines-inside-buffer) + (icomplete--ensure-visible-lines-inside-buffer) (cl-loop with preds for (comp . rest) on comps when (equal comp (car icomplete--scrolled-completions)) @@ -1014,7 +1014,7 @@ away from the bottom. Counts wrapped lines as real lines." for (comp-no-indicator prefix suffix section) in tuples for comp = (if icomplete-vertical-render-prefix-indicator - (icomplete-vertical--add-indicator-to-selected comp-no-indicator) + (icomplete--add-indicator-to-selected comp-no-indicator) comp-no-indicator) when section collect (propertize section 'face 'icomplete-section) into lines-aux @@ -1041,7 +1041,7 @@ away from the bottom. Counts wrapped lines as real lines." (t (min (ceiling nsections 2) (length scroll-above)))) lines)) (when icomplete--in-region-buffer - (setq lines (icomplete-vertical--adjust-lines-for-column + (setq lines (icomplete--adjust-lines-for-column lines icomplete--in-region-buffer completion-in-region--data))) ;; At long last, render final string return value. This may still ;; kick out lines at the end. From 7f60aa45aab4191a44d6d83ec6c3004e4901469b Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Mon, 7 Apr 2025 10:03:46 +0800 Subject: [PATCH 038/395] vc-git-checkin: Don't relativize names of temporary files * lisp/vc/vc-git.el (vc-git-checkin) (vc-git--stash-staged-changes): Don't relativize names of temporary files passed to 'git apply --cached'. More generally, these are not files managed by the underlying VCS, so they shouldn't go in the FILE-OR-LIST argument to vc-git-command. --- lisp/vc/vc-git.el | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el index 932dddaefbb..869e9737422 100644 --- a/lisp/vc/vc-git.el +++ b/lisp/vc/vc-git.el @@ -1202,7 +1202,7 @@ It is based on `log-edit-mode', and has Git-specific extensions." (with-temp-file patch-file (insert vc-git-patch-string)) (unwind-protect - (vc-git-command nil 0 patch-file "apply" "--cached") + (vc-git-command nil 0 nil "apply" "--cached" patch-file) (delete-file patch-file)))) (when to-stash (vc-git--stash-staged-changes files))) ;; When operating on the whole tree, better pass "-a" than ".", @@ -1228,7 +1228,7 @@ It is based on `log-edit-mode', and has Git-specific extensions." (unwind-protect (progn (with-temp-file cached (vc-git-command t 0 nil "stash" "show" "-p")) - (vc-git-command nil 0 cached "apply" "--cached")) + (vc-git-command nil 0 nil "apply" "--cached" cached)) (delete-file cached)) (vc-git-command nil 0 nil "stash" "drop"))))) @@ -1259,7 +1259,8 @@ It is based on `log-edit-mode', and has Git-specific extensions." (unwind-protect (progn (vc-git-command nil 0 nil "read-tree" "HEAD") - (vc-git-command nil 0 cached "apply" "--cached") + (vc-git-command nil 0 nil "apply" "--cached" + cached) (setq tree (git-string "write-tree"))) (delete-file index)))) (delete-file cached)) From 3ccd25f6b01bcd2e103faa86b11c10017b64e69b Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Mon, 7 Apr 2025 10:05:08 +0800 Subject: [PATCH 039/395] * lisp/vc/vc-git.el (vc-git-checkin): Actually pass down TO-STASH. --- lisp/vc/vc-git.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el index 869e9737422..fe9791d2f47 100644 --- a/lisp/vc/vc-git.el +++ b/lisp/vc/vc-git.el @@ -1204,7 +1204,7 @@ It is based on `log-edit-mode', and has Git-specific extensions." (unwind-protect (vc-git-command nil 0 nil "apply" "--cached" patch-file) (delete-file patch-file)))) - (when to-stash (vc-git--stash-staged-changes files))) + (when to-stash (vc-git--stash-staged-changes to-stash))) ;; When operating on the whole tree, better pass "-a" than ".", ;; since "." fails when we're committing a merge. (apply #'vc-git-command nil 0 From 1e100f482c5f07fc6cd55f32065c62244856bff2 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Mon, 7 Apr 2025 10:19:58 +0800 Subject: [PATCH 040/395] ; * lisp/vc/ediff-wind.el (ediff-with-live-window): Use cl-once-only --- lisp/vc/ediff-wind.el | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lisp/vc/ediff-wind.el b/lisp/vc/ediff-wind.el index aefa17de2c6..076c742ef58 100644 --- a/lisp/vc/ediff-wind.el +++ b/lisp/vc/ediff-wind.el @@ -257,11 +257,10 @@ keyboard input to go into icons." If WINDOW is not live (or not a window) do nothing and don't evaluate BODY, instead returning nil." (declare (indent 1) (debug (form body))) - (let ((w (gensym "window"))) - `(let ((,w ,window)) - (when (window-live-p ,w) - (with-selected-window ,w - ,@body))))) + (cl-once-only (window) + `(when (window-live-p ,window) + (with-selected-window ,window + ,@body)))) (defun ediff-get-window-by-clicking (_wind _prev-wind wind-number) (let (event) From e9e11f7281899aa206ff6f62a183fa83cde48e95 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Mon, 7 Apr 2025 11:28:13 +0800 Subject: [PATCH 041/395] Add bindings for vc-git-stash-delete-at-point, vc-git-stash-delete * lisp/vc/vc-git.el (vc-git-stash-map): Bind "D" to vc-git-stash-delete-at-point. (vc-dir-git-mode-map): Bind "z d" to vc-git-stash-delete. * etc/NEWS: Announce the new bindings. --- etc/NEWS | 5 +++++ lisp/vc/vc-git.el | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 35e6edcd712..3653158349d 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1500,6 +1500,11 @@ Previously, Emacs would simply refuse to make any changes. You can customize 'vc-dir-allow-mass-mark-changes' to restore the old behavior or dispense with the prompting. +--- +*** New VC-Dir bindings 'z d' and 'D' to delete Git stashes. +These correspond to the existing 'z p' to pop a stash and 'P' to pop the +stash at point. + ** Diff mode +++ diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el index fe9791d2f47..f41d51fe34a 100644 --- a/lisp/vc/vc-git.el +++ b/lisp/vc/vc-git.el @@ -817,7 +817,8 @@ or an empty string if none." "=" #'vc-git-stash-show-at-point "RET" #'vc-git-stash-show-at-point "A" #'vc-git-stash-apply-at-point - "P" #'vc-git-stash-pop-at-point) + "P" #'vc-git-stash-pop-at-point + "D" #'vc-git-stash-delete-at-point) (defvar-keymap vc-git-stash-button-map :parent vc-git-stash-shared-map @@ -2448,7 +2449,8 @@ the function returns nil." (defvar-keymap vc-dir-git-mode-map "z c" #'vc-git-stash "z s" #'vc-git-stash-snapshot - "z p" #'vc-git-stash-pop) + "z p" #'vc-git-stash-pop + "z d" #'vc-git-stash-delete) (define-minor-mode vc-dir-git-mode "A minor mode for git-specific commands in `vc-dir-mode' buffers. From 94148549d782af3fb6677bc121fd5fc8dee3ea63 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Mon, 7 Apr 2025 11:30:37 +0800 Subject: [PATCH 042/395] ; Note existing binding of vc-git-stash-delete-at-point --- etc/NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/NEWS b/etc/NEWS index 3653158349d..63957628b98 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1503,7 +1503,7 @@ behavior or dispense with the prompting. --- *** New VC-Dir bindings 'z d' and 'D' to delete Git stashes. These correspond to the existing 'z p' to pop a stash and 'P' to pop the -stash at point. +stash at point (deleting the stash at point is also bound to C-k). ** Diff mode From f75f8f3d6a09fe3dda3e747665187a0c34c19eaf Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Sun, 6 Apr 2025 23:56:36 -0400 Subject: [PATCH 043/395] cedet: Pass object name via explicit `:object-name` arg * lisp/cedet/srecode/insert.el (srecode-parse-input): * lisp/cedet/srecode/compile.el (srecode-compile-one-template-tag) (srecode-compile-inserter): Pass object name via explicit `:object-name` arg to `srecode-template`, `srecode-template-inserter-variable`, and children of `srecode-template`. * lisp/cedet/semantic/mru-bookmark.el (semantic-mrub-push): Pass object name via explicit `:object-name` arg to `semantic-bookmark`. --- lisp/cedet/semantic/mru-bookmark.el | 2 +- lisp/cedet/srecode/compile.el | 8 +++++--- lisp/cedet/srecode/insert.el | 6 +++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lisp/cedet/semantic/mru-bookmark.el b/lisp/cedet/semantic/mru-bookmark.el index edb8e091a2a..edb2fe414e6 100644 --- a/lisp/cedet/semantic/mru-bookmark.el +++ b/lisp/cedet/semantic/mru-bookmark.el @@ -197,7 +197,7 @@ The resulting bookmark is then sorted within the ring." (ring-remove ring idx)) (setq idx (1+ idx))) ;; Create a new mark - (let ((sbm (semantic-bookmark (semantic-tag-name tag) + (let ((sbm (semantic-bookmark :object-name (semantic-tag-name tag) :tag tag))) ;; Take the mark, and update it for the current state. (ring-insert ring sbm) diff --git a/lisp/cedet/srecode/compile.el b/lisp/cedet/srecode/compile.el index 08082b9ecc1..9fe499be83a 100644 --- a/lisp/cedet/srecode/compile.el +++ b/lisp/cedet/srecode/compile.el @@ -361,7 +361,7 @@ STATE is the current compile state as an object of class :where 'end))))))) ;; Construct and return the template object. - (srecode-template (semantic-tag-name tag) + (srecode-template :object-name (semantic-tag-name tag) :context context :args (nreverse addargs) :dictionary root-dict @@ -504,7 +504,8 @@ PROPS are additional properties that might need to be passed to the inserter constructor." ;;(message "Compile: %s %S" name props) (if (not key) - (apply #'make-instance 'srecode-template-inserter-variable name props) + (apply #'make-instance 'srecode-template-inserter-variable + :object-name name props) (let ((classes (eieio-class-children 'srecode-template-inserter)) (new nil)) ;; Loop over the various subclasses and @@ -515,7 +516,8 @@ to the inserter constructor." (when (and (not (class-abstract-p (car classes))) (equal (oref-default (car classes) key) key)) ;; Create the new class, and apply state. - (setq new (apply #'make-instance (car classes) name props)) + (setq new (apply #'make-instance (car classes) + :object-name name props)) (srecode-inserter-apply-state new STATE) ) (setq classes (cdr classes))) diff --git a/lisp/cedet/srecode/insert.el b/lisp/cedet/srecode/insert.el index 2e70469fa39..a28a4f0e63c 100644 --- a/lisp/cedet/srecode/insert.el +++ b/lisp/cedet/srecode/insert.el @@ -860,10 +860,10 @@ applied to the text between the section start and the "For the section inserter INS, parse INPUT. Shorten input until the END token is found. Return the remains of INPUT." - (let* ((out (srecode-compile-split-code tag input STATE - (oref ins object-name)))) + (let* ((name (oref ins object-name)) + (out (srecode-compile-split-code tag input STATE name))) (oset ins template (srecode-template - (eieio-object-name-string ins) + :object-name name :context nil :args nil :code (cdr out))) From 05680dc6c59be73ebe6c5cfa28d4c095edd661f4 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Sun, 6 Apr 2025 17:25:43 -0400 Subject: [PATCH 044/395] cedet: Delete obsolete object name arg to EIEIO constructors For classes that don't inherit from `eieio-named`, this argument is ignored anyway. * lisp/auth-source-pass.el (auth-source-pass-backend): Delete obsolete object-name argument to `auth-source-backend` constructor. * lisp/cedet/ede/config.el (ede-config-get-configuration): Delete obsolete object-name argument to ede-config constructor. * lisp/cedet/ede/cpp-root.el (ede-find-target): Delete obsolete object-name argument to `ede-cpp-root-target` constructor. * lisp/cedet/ede/locate.el (ede-enable-locate-on-project): Delete obsolete object-name argument to ede-locate constructor. * lisp/cedet/ede/project-am.el (project-am-load-makefile): Delete obsolete object-name argument to `project-am-makefile` constructor. * lisp/cedet/semantic/complete.el (semantic-complete-read-tag-buffer-deep) (semantic-complete-read-tag-local-members) (semantic-complete-read-tag-project, semantic-complete-read-tag-analyzer): Delete obsolete object-name argument to `semantic-collector-buffer-deep`, `semantic-collector-local-members`, `semantic-collector-project-brutish`, and `semantic-collector-analyze-completions` constructors. * lisp/cedet/semantic/db-ebrowse.el (semanticdb-create-database): Delete obsolete object-name argument to `semanticdb-project-database-ebrowse` constructor. * lisp/cedet/semantic/db-file.el (semanticdb-create-database): Delete obsolete object-name argument to `semanticdb-project-database-file` constructor. * lisp/cedet/semantic/db-typecache.el (semanticdb-get-typecache): Delete obsolete object-name argument to `semanticdb-typecache` constructor. * lisp/cedet/semantic/db.el (semanticdb-get-table-index) (semanticdb-create-table): Delete obsolete object-name argument to `semanticdb-default-find-index-class`, new-table-class, and desired-class constructors. * lisp/cedet/semantic/bovine/c.el (semantic-analyze-tag-references): * lisp/cedet/semantic/analyze/refs.el (semantic-analyze-tag-references-default): Delete obsolete object-name argument to `semantic-analyze-references` constructor. * lisp/cedet/srecode/compile.el (srecode-compile-templates): Delete obsolete object-name argument to `srecode-compile-state` and `srecode-dictionary-compound-variable` constructors. * lisp/cedet/srecode/cpp.el (srecode-semantic-apply-tag-to-dict) (srecode-c-apply-templates): Delete obsolete object-name argument to `srecode-semantic-tag` constructors. * lisp/cedet/srecode/dictionary.el (srecode-dictionary-add-entries) (srecode-compound-toString): Delete obsolete object-name argument to `srecode-dictionary-compound-variable` and `srecode-field` constructors. * lisp/cedet/srecode/insert.el (srecode-insert-method-field): Delete obsolete object-name argument to `srecode-field-value` constructor. * lisp/cedet/srecode/semantic.el (srecode-semantic-handle-:tag) (srecode-semantic-insert-tag, srecode-semantic-apply-tag-to-dict-default): Delete obsolete object-name argument to `srecode-semantic-tag` constructors. * lisp/cedet/srecode/table.el (srecode-mode-table-new): Delete obsolete object-name argument to `srecode-template-table` constructor. --- lisp/auth-source-pass.el | 1 - lisp/cedet/ede/config.el | 9 ++------- lisp/cedet/ede/cpp-root.el | 2 +- lisp/cedet/ede/locate.el | 2 +- lisp/cedet/ede/project-am.el | 2 +- lisp/cedet/semantic/analyze/refs.el | 3 +-- lisp/cedet/semantic/bovine/c.el | 3 +-- lisp/cedet/semantic/complete.el | 10 ++++------ lisp/cedet/semantic/db-ebrowse.el | 6 +----- lisp/cedet/semantic/db-file.el | 4 ---- lisp/cedet/semantic/db-typecache.el | 2 +- lisp/cedet/semantic/db.el | 4 +--- lisp/cedet/srecode/compile.el | 5 ++--- lisp/cedet/srecode/cpp.el | 6 ++---- lisp/cedet/srecode/dictionary.el | 4 ++-- lisp/cedet/srecode/insert.el | 3 +-- lisp/cedet/srecode/semantic.el | 8 +++----- lisp/cedet/srecode/table.el | 1 - 18 files changed, 24 insertions(+), 51 deletions(-) diff --git a/lisp/auth-source-pass.el b/lisp/auth-source-pass.el index e68a3e9129e..50f80288288 100644 --- a/lisp/auth-source-pass.el +++ b/lisp/auth-source-pass.el @@ -149,7 +149,6 @@ HOSTS can be a string or a list of strings." (defvar auth-source-pass-backend (auth-source-backend - (when (<= emacs-major-version 25) "password-store") :source "." ;; not used :type 'password-store :search-function #'auth-source-pass-search) diff --git a/lisp/cedet/ede/config.el b/lisp/cedet/ede/config.el index 89e83386879..fb21baf2985 100644 --- a/lisp/cedet/ede/config.el +++ b/lisp/cedet/ede/config.el @@ -154,14 +154,9 @@ the directory isn't on the `safe' list, ask to add it to the safe list." (when (file-exists-p fname) (message "Ignoring EDE config file for now and creating a new one. Use C-c . g to load it.") ;; Set how it was ignored. - (if loadask - (setq ignore-type 'manual) - (setq ignore-type 'auto)) - ) + (setq ignore-type (if loadask 'manual 'auto))) ;; Create a new one. - (setq config (make-instance class - "Configuration" - :file fname)) + (setq config (make-instance class :file fname)) (oset config ignored-file ignore-type) ;; Set initial values based on project. diff --git a/lisp/cedet/ede/cpp-root.el b/lisp/cedet/ede/cpp-root.el index a43bd2f6f2a..4616d196716 100644 --- a/lisp/cedet/ede/cpp-root.el +++ b/lisp/cedet/ede/cpp-root.el @@ -327,7 +327,7 @@ If one doesn't exist, create a new one for this directory." (ans (object-assoc dir :path targets)) ) (when (not ans) - (setq ans (ede-cpp-root-target dir + (setq ans (ede-cpp-root-target :name (file-name-nondirectory (directory-file-name dir)) :path dir diff --git a/lisp/cedet/ede/locate.el b/lisp/cedet/ede/locate.el index bad8952ec60..1651b4d3ad3 100644 --- a/lisp/cedet/ede/locate.el +++ b/lisp/cedet/ede/locate.el @@ -89,7 +89,7 @@ based on `ede-locate-setup-options'." (when (called-interactively-p 'interactive) (message "Setting locator to ede-locate-base")) (setq ans 'ede-locate-base)) - (oset proj locate-obj (make-instance ans "Loc" :root root)) + (oset proj locate-obj (make-instance ans :root root)) (when (called-interactively-p 'interactive) (message "Setting locator to %s" ans)) )) diff --git a/lisp/cedet/ede/project-am.el b/lisp/cedet/ede/project-am.el index f45cf1b8616..e66751ba9b1 100644 --- a/lisp/cedet/ede/project-am.el +++ b/lisp/cedet/ede/project-am.el @@ -480,7 +480,7 @@ This is used when subprojects are made in named subdirectories." (bug (nth 2 pi)) (cof (nth 3 pi)) (ampf (project-am-makefile - pn :name pn + :name pn :version ver :mailinglist (or bug "") :file fn))) diff --git a/lisp/cedet/semantic/analyze/refs.el b/lisp/cedet/semantic/analyze/refs.el index 45e74c2b27a..3d3dfdc7975 100644 --- a/lisp/cedet/semantic/analyze/refs.el +++ b/lisp/cedet/semantic/analyze/refs.el @@ -89,8 +89,7 @@ Use `semantic-analyze-current-tag' to debug this fcn." (setq allhits (semantic--analyze-refs-full-lookup tag scope t)) - (semantic-analyze-references (semantic-tag-name tag) - :tag tag + (semantic-analyze-references :tag tag :tagdb db :scope scope :rawsearchdata allhits) diff --git a/lisp/cedet/semantic/bovine/c.el b/lisp/cedet/semantic/bovine/c.el index 81639b98176..659e30a45d9 100644 --- a/lisp/cedet/semantic/bovine/c.el +++ b/lisp/cedet/semantic/bovine/c.el @@ -1256,8 +1256,7 @@ Use `semantic-analyze-current-tag' to debug this fcn." (setq allhits (semantic--analyze-refs-full-lookup tag scope t))) ;; (setq refs - (semantic-analyze-references (semantic-tag-name tag) - :tag tag + (semantic-analyze-references :tag tag :tagdb db :scope scope :rawsearchdata allhits)))) ;;) diff --git a/lisp/cedet/semantic/complete.el b/lisp/cedet/semantic/complete.el index 736025e1d54..e0d16d6fbce 100644 --- a/lisp/cedet/semantic/complete.el +++ b/lisp/cedet/semantic/complete.el @@ -1899,7 +1899,7 @@ completion text in ghost text." (mapcar (lambda (class) (let* ((C (intern (car class))) - (doc (documentation-property C 'variable-documentation)) + (doc (cl--class-docstring (cl--find-class C))) (doc1 (car (split-string doc "\n"))) ) (list 'const @@ -1930,7 +1930,7 @@ DEFAULT-TAG is a semantic tag or string to use as the default value. If INITIAL-INPUT is non-nil, insert it in the minibuffer initially. HISTORY is a symbol representing a variable to store the history in." (semantic-complete-read-tag-engine - (semantic-collector-buffer-deep prompt :buffer (current-buffer)) + (semantic-collector-buffer-deep :buffer (current-buffer)) (semantic-displayer-traditional-with-focus-highlight) ;;(semantic-displayer-tooltip) prompt @@ -1952,7 +1952,7 @@ DEFAULT-TAG is a semantic tag or string to use as the default value. If INITIAL-INPUT is non-nil, insert it in the minibuffer initially. HISTORY is a symbol representing a variable to store the history in." (semantic-complete-read-tag-engine - (semantic-collector-local-members prompt :buffer (current-buffer)) + (semantic-collector-local-members :buffer (current-buffer)) (semantic-displayer-traditional-with-focus-highlight) ;;(semantic-displayer-tooltip) prompt @@ -1974,8 +1974,7 @@ DEFAULT-TAG is a semantic tag or string to use as the default value. If INITIAL-INPUT is non-nil, insert it in the minibuffer initially. HISTORY is a symbol representing a variable to store the history in." (semantic-complete-read-tag-engine - (semantic-collector-project-brutish prompt - :buffer (current-buffer) + (semantic-collector-project-brutish :buffer (current-buffer) :path (current-buffer) ) (semantic-displayer-traditional-with-focus-highlight) @@ -2049,7 +2048,6 @@ prompts. these are calculated from the CONTEXT variable passed in." (setq syms (nreverse (cdr (nreverse syms)))) (semantic-complete-read-tag-engine (semantic-collector-analyze-completions - prompt :buffer (oref context buffer) :context context) (semantic-displayer-traditional-with-focus-highlight) diff --git a/lisp/cedet/semantic/db-ebrowse.el b/lisp/cedet/semantic/db-ebrowse.el index 3e34f4a1ea1..51e52afa64a 100644 --- a/lisp/cedet/semantic/db-ebrowse.el +++ b/lisp/cedet/semantic/db-ebrowse.el @@ -309,11 +309,7 @@ If there is no database for DIRECTORY available, then ) (if found (setq db found) - (setq db (make-instance - dbeC - directory - :ebrowse-struct ebd - )) + (setq db (make-instance dbeC :ebrowse-struct ebd)) (oset db reference-directory directory)) ;; Once we recycle or make a new DB, refresh the diff --git a/lisp/cedet/semantic/db-file.el b/lisp/cedet/semantic/db-file.el index f15e6e69cb0..3edbc4a2fcd 100644 --- a/lisp/cedet/semantic/db-file.el +++ b/lisp/cedet/semantic/db-file.el @@ -138,10 +138,6 @@ If DIRECTORY doesn't exist, create a new one." (unless db (setq db (make-instance dbc ; Create the database requested. Perhaps - (concat (file-name-nondirectory - (directory-file-name - directory)) - "/") :file fn :tables nil :semantic-tag-version semantic-tag-version :semanticdb-version semanticdb-file-version))) diff --git a/lisp/cedet/semantic/db-typecache.el b/lisp/cedet/semantic/db-typecache.el index 62eb72af08f..92ddb65ef68 100644 --- a/lisp/cedet/semantic/db-typecache.el +++ b/lisp/cedet/semantic/db-typecache.el @@ -136,7 +136,7 @@ If there is no table, create one, and fill it in." ;; Make sure we have a cache object in the DB index. (when (not cache) ;; The object won't change as we fill it with stuff. - (setq cache (semanticdb-typecache (semanticdb-full-filename table))) + (setq cache (semanticdb-typecache)) (oset idx type-cache cache)) cache)) diff --git a/lisp/cedet/semantic/db.el b/lisp/cedet/semantic/db.el index ffbb3431a81..375e43f2561 100644 --- a/lisp/cedet/semantic/db.el +++ b/lisp/cedet/semantic/db.el @@ -188,7 +188,6 @@ If one doesn't exist, create it." (oref obj index) (let ((idx nil)) (setq idx (funcall semanticdb-default-find-index-class - (concat (eieio-object-name obj) " index") ;; Fill in the defaults :table obj )) @@ -413,7 +412,6 @@ If the table for FILE does not exist, create one." ;; This implementation will satisfy autoloaded classes ;; for tables. (setq newtab (funcall (oref db new-table-class) - (file-name-nondirectory file) :file (file-name-nondirectory file) )) (setf (slot-value newtab 'parent-db) db) @@ -486,7 +484,7 @@ other than :table." (if obj obj ;; Just return it. ;; No object, let's create a new one and return that. - (setq obj (funcall desired-class "Cache" :table table)) + (setq obj (make-instance desired-class :table table)) (object-add-to-list table 'cache obj) obj))) diff --git a/lisp/cedet/srecode/compile.el b/lisp/cedet/srecode/compile.el index 9fe499be83a..05f70583c2a 100644 --- a/lisp/cedet/srecode/compile.el +++ b/lisp/cedet/srecode/compile.el @@ -199,8 +199,7 @@ STATE is the current compilation state." (tag nil) (class nil) (table nil) - (STATE (srecode-compile-state (file-name-nondirectory - (buffer-file-name)))) + (STATE (srecode-compile-state)) (mode nil) (application nil) (framework nil) @@ -263,7 +262,7 @@ STATE is the current compilation state." ;; Create a compound dictionary value from "value". (require 'srecode/dictionary) (let ((cv (srecode-dictionary-compound-variable - name :value value))) + :value value))) (setq vars (cons (cons name cv) vars))) )) ) diff --git a/lisp/cedet/srecode/cpp.el b/lisp/cedet/srecode/cpp.el index d49ccde24fa..63613969191 100644 --- a/lisp/cedet/srecode/cpp.el +++ b/lisp/cedet/srecode/cpp.el @@ -146,8 +146,7 @@ specified in a C file." (value-dict (srecode-dictionary-add-section-dictionary dict "VALUE"))) (srecode-semantic-apply-tag-to-dict - (srecode-semantic-tag (semantic-tag-name value-tag) - :prime value-tag) + (srecode-semantic-tag :prime value-tag) value-dict)) ;; Discriminate using statements referring to namespaces and @@ -224,8 +223,7 @@ specified in a C file." (let ((template-dict (srecode-dictionary-add-section-dictionary templates-dict "ARGS"))) (srecode-semantic-apply-tag-to-dict - (srecode-semantic-tag (semantic-tag-name template) - :prime template) + (srecode-semantic-tag :prime template) template-dict))))) ) diff --git a/lisp/cedet/srecode/dictionary.el b/lisp/cedet/srecode/dictionary.el index 2fbed835bdd..bac3b7c48d3 100644 --- a/lisp/cedet/srecode/dictionary.el +++ b/lisp/cedet/srecode/dictionary.el @@ -369,7 +369,7 @@ values but STATE is nil." (srecode-dictionary-set-value dict name (srecode-dictionary-compound-variable - name :value value :state state))))) + :value value :state state))))) (setq entries (nthcdr 2 entries))) dict) @@ -536,7 +536,7 @@ inserted with a new editable field.") (error "Unknown default value for value %S" name))) ;; Create a field from the inserter. - (srecode-field name :name name + (srecode-field :name name :start start :end (point) :prompt (oref sti prompt) diff --git a/lisp/cedet/srecode/insert.el b/lisp/cedet/srecode/insert.el index a28a4f0e63c..7189ad27c92 100644 --- a/lisp/cedet/srecode/insert.el +++ b/lisp/cedet/srecode/insert.el @@ -648,8 +648,7 @@ Use DICTIONARY to resolve values." Use DICTIONARY to resolve values." (let* ((default (srecode-insert-ask-default sti dictionary)) (compound-value - (srecode-field-value (oref sti object-name) - :firstinserter sti + (srecode-field-value :firstinserter sti :defaultvalue default)) ) ;; Return this special compound value as the thing to insert. diff --git a/lisp/cedet/srecode/semantic.el b/lisp/cedet/srecode/semantic.el index bfacda54557..1db041cdfd0 100644 --- a/lisp/cedet/srecode/semantic.el +++ b/lisp/cedet/srecode/semantic.el @@ -129,8 +129,7 @@ variable default values, and other things." larg nil nil))) ;; Apply the sub-argument to the subdictionary. (srecode-semantic-apply-tag-to-dict - (srecode-semantic-tag (semantic-tag-name larg) - :prime larg) + (srecode-semantic-tag :prime larg) subdict) ) ;; Next! @@ -203,8 +202,7 @@ variable default values, and other things." (when (not tag) (error "No tag for current template. Use the semantic kill-ring")) (srecode-semantic-apply-tag-to-dict - (srecode-semantic-tag (semantic-tag-name tag) - :prime tag) + (srecode-semantic-tag :prime tag) dict))) ;;; :tagtype ARGUMENT HANDLING @@ -394,7 +392,7 @@ as `function' will leave point where code might be inserted." ;; Resolve TAG into the dictionary. We may have a :tag arg ;; from the macro such that we don't need to do this. (when (not (srecode-dictionary-lookup-name dict "TAG")) - (let ((tagobj (srecode-semantic-tag (semantic-tag-name tag) :prime tag)) + (let ((tagobj (srecode-semantic-tag :prime tag)) ) (srecode-semantic-apply-tag-to-dict tagobj dict))) diff --git a/lisp/cedet/srecode/table.el b/lisp/cedet/srecode/table.el index ba87c0a01d2..6f98038b614 100644 --- a/lisp/cedet/srecode/table.el +++ b/lisp/cedet/srecode/table.el @@ -180,7 +180,6 @@ INIT are the initialization parameters for the new template table." (old (srecode-mode-table-find mt file)) (attr (file-attributes file)) (new (apply #'srecode-template-table - (file-name-nondirectory file) :file file :filesize (file-attribute-size attr) :filedate (file-attribute-modification-time attr) From 48b41d595c37a7fd7b2a1e97fd0dcadc24e1a6bb Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Sun, 6 Apr 2025 19:00:53 -0400 Subject: [PATCH 045/395] cedet: Don't abuse initargs for slot names * lisp/cedet/ede/base.el (ede-normalize-file/directory): * lisp/cedet/ede/emacs.el (initialize-instance): * lisp/cedet/ede/generic.el (initialize-instance): * lisp/cedet/ede/linux.el (initialize-instance, project-rescan): * lisp/cedet/srecode/map.el (srecode-map-update-map): * lisp/cedet/srecode/srt-mode.el (srecode-parse-this-macro): * lisp/cedet/ede/simple.el (ede-simple-load): Use slot names rather than initargs with oref/oset/slot-value/... --- lisp/cedet/ede/base.el | 12 ++++++------ lisp/cedet/ede/emacs.el | 2 +- lisp/cedet/ede/generic.el | 2 +- lisp/cedet/ede/linux.el | 8 ++++---- lisp/cedet/ede/simple.el | 2 +- lisp/cedet/srecode/map.el | 2 +- lisp/cedet/srecode/srt-mode.el | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lisp/cedet/ede/base.el b/lisp/cedet/ede/base.el index 4e27cd0cb69..599b855991d 100644 --- a/lisp/cedet/ede/base.el +++ b/lisp/cedet/ede/base.el @@ -627,14 +627,14 @@ instead of the current project." "Fills :directory or :file slots if they're missing in project THIS. The other slot will be used to calculate values. PROJECT-FILE-NAME is a name of project file (short name, like `pom.xml', etc." - (when (and (or (not (slot-boundp this :file)) - (not (oref this file))) - (slot-boundp this :directory) + (when (and (not (and (slot-boundp this 'file) + (oref this file))) + (slot-boundp this 'directory) (oref this directory)) (oset this file (expand-file-name project-file-name (oref this directory)))) - (when (and (or (not (slot-boundp this :directory)) - (not (oref this directory))) - (slot-boundp this :file) + (when (and (not (and (slot-boundp this 'directory) + (oref this directory))) + (slot-boundp this 'file) (oref this file)) (oset this directory (file-name-directory (oref this file)))) ) diff --git a/lisp/cedet/ede/emacs.el b/lisp/cedet/ede/emacs.el index c51968ebb8c..ca91a7e4ffb 100644 --- a/lisp/cedet/ede/emacs.el +++ b/lisp/cedet/ede/emacs.el @@ -118,7 +118,7 @@ All directories need at least one target.") "Make sure the targets slot is bound." (cl-call-next-method) (unless (slot-boundp this 'targets) - (oset this :targets nil))) + (oset this targets nil))) ;;; File Stuff ;; diff --git a/lisp/cedet/ede/generic.el b/lisp/cedet/ede/generic.el index 162f37f9373..7c6e2ec715f 100644 --- a/lisp/cedet/ede/generic.el +++ b/lisp/cedet/ede/generic.el @@ -153,7 +153,7 @@ The class allocated value is replace by different sub classes.") "Make sure the targets slot is bound." (cl-call-next-method) (unless (slot-boundp this 'targets) - (oset this :targets nil)) + (oset this targets nil)) ) (cl-defmethod ede-project-root ((this ede-generic-project)) diff --git a/lisp/cedet/ede/linux.el b/lisp/cedet/ede/linux.el index d42f91c7500..34296972ddd 100644 --- a/lisp/cedet/ede/linux.el +++ b/lisp/cedet/ede/linux.el @@ -227,7 +227,7 @@ All directories need at least one target.") "Make sure the targets slot is bound." (cl-call-next-method) (unless (slot-boundp this 'targets) - (oset this :targets nil))) + (oset this targets nil))) ;;; File Stuff ;; @@ -377,9 +377,9 @@ Argument COMMAND is the command to use for compiling the target." (inc (ede-linux--include-path dir bdir arch)) (ver (ede-linux-version dir))) (oset this version ver) - (oset this :build-directory bdir) - (oset this :architecture arch) - (oset this :include-path inc) + (oset this build-directory bdir) + (oset this architecture arch) + (oset this include-path inc) )) (provide 'ede/linux) diff --git a/lisp/cedet/ede/simple.el b/lisp/cedet/ede/simple.el index f1f61c50421..3f7a359a445 100644 --- a/lisp/cedet/ede/simple.el +++ b/lisp/cedet/ede/simple.el @@ -86,7 +86,7 @@ ROOTPROJ is nil, since we will only create a single EDE project here." (obj nil)) (when pf (setq obj (eieio-persistent-read pf)) - (oset obj :directory dir) + (oset obj directory dir) ) obj)) diff --git a/lisp/cedet/srecode/map.el b/lisp/cedet/srecode/map.el index 784e0c2d931..923cca4be0c 100644 --- a/lisp/cedet/srecode/map.el +++ b/lisp/cedet/srecode/map.el @@ -338,7 +338,7 @@ if that file is NEW, otherwise assume the mode has not changed." ;; Only do the save if we are dirty, or if we are in an interactive ;; Emacs. (when (and dirty (not noninteractive) - (slot-boundp srecode-current-map :file)) + (slot-boundp srecode-current-map 'file)) (eieio-persistent-save srecode-current-map)) )) diff --git a/lisp/cedet/srecode/srt-mode.el b/lisp/cedet/srecode/srt-mode.el index 44c82e55b53..369730521e8 100644 --- a/lisp/cedet/srecode/srt-mode.el +++ b/lisp/cedet/srecode/srt-mode.el @@ -503,7 +503,7 @@ section or ? for an ask variable." (when inserter (let ((base (cons (oref inserter object-name) - (if (and (slot-boundp inserter :secondname) + (if (and (slot-boundp inserter 'secondname) (oref inserter secondname)) (split-string (oref inserter secondname) ":") From f0c1de75e128c3b35f8b6e9324a6bd58057af6cb Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Sun, 6 Apr 2025 19:05:06 -0400 Subject: [PATCH 046/395] cedet: Prefer `slot-value` over `eieio-object-name-string` * lisp/cedet/srecode/mode.el (srecode-minor-mode-templates-menu): * lisp/cedet/srecode/insert.el (srecode-insert-subtemplate): * lisp/cedet/srecode/compile.el (srecode-dump): Prefer `slot-value` over `eieio-object-name-string` since we know it's an `eieio-named` object. --- lisp/cedet/srecode/compile.el | 4 ++-- lisp/cedet/srecode/insert.el | 2 +- lisp/cedet/srecode/mode.el | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lisp/cedet/srecode/compile.el b/lisp/cedet/srecode/compile.el index 05f70583c2a..95e86c63a90 100644 --- a/lisp/cedet/srecode/compile.el +++ b/lisp/cedet/srecode/compile.el @@ -590,7 +590,7 @@ A list of defined variables VARS provides a variable table." (cl-defmethod srecode-dump ((tmp srecode-template)) "Dump the contents of the SRecode template tmp." (princ "== Template \"") - (princ (eieio-object-name-string tmp)) + (princ (slot-value tmp 'object-name)) (princ "\" in context ") (princ (oref tmp context)) (princ "\n") @@ -636,7 +636,7 @@ Argument INDENT specifies the indentation level for the list." (cl-defmethod srecode-dump ((ins srecode-template-inserter) _indent) "Dump the state of the SRecode template inserter INS." (princ "INS: \"") - (princ (eieio-object-name-string ins)) + (princ (slot-value ins 'object-name)) (when (oref ins secondname) (princ "\" : \"") (princ (oref ins secondname))) diff --git a/lisp/cedet/srecode/insert.el b/lisp/cedet/srecode/insert.el index 7189ad27c92..3b4da876a2c 100644 --- a/lisp/cedet/srecode/insert.el +++ b/lisp/cedet/srecode/insert.el @@ -805,7 +805,7 @@ Arguments ESCAPE-START and ESCAPE-END are the current escape sequences in use." (srecode-insert-report-error dict "Only section dictionaries allowed for `%s'" - (eieio-object-name-string sti))) + (slot-value sti 'object-name))) ;; Output the code from the sub-template. (srecode-insert-method (slot-value sti slot) dict)) diff --git a/lisp/cedet/srecode/mode.el b/lisp/cedet/srecode/mode.el index e266a7a679a..573f1f6afd7 100644 --- a/lisp/cedet/srecode/mode.el +++ b/lisp/cedet/srecode/mode.el @@ -207,7 +207,7 @@ MENU-DEF is the menu to bind this into." (ctxtcons (assoc ctxt alltabs)) (bind (if (slot-boundp temp 'binding) (oref temp binding))) - (name (eieio-object-name-string temp))) + (name (slot-value temp 'object-name))) (when (not ctxtcons) (if (string= context ctxt) From 308a5ff0f8997a287a496993d92f92c6a8a0f393 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Sun, 6 Apr 2025 23:24:30 -0400 Subject: [PATCH 047/395] (srecode-macro-help): Use `cl--class-docstring` * lisp/cedet/srecode/srt-mode.el (srecode-macro-help): Don't rely on `variable-documentation`. --- lisp/cedet/srecode/srt-mode.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/cedet/srecode/srt-mode.el b/lisp/cedet/srecode/srt-mode.el index 369730521e8..45040246fb2 100644 --- a/lisp/cedet/srecode/srt-mode.el +++ b/lisp/cedet/srecode/srt-mode.el @@ -276,7 +276,7 @@ we can tell font lock about them.") (prin1 (format "%c" key)) ))) (terpri) - (princ (documentation-property C 'variable-documentation)) + (princ (cl--class-docstring (cl--find-class C))) (terpri) (when showexample (princ "Example:") From 71afa12941ebbd6fa2c010064de01db681985279 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Sun, 6 Apr 2025 23:39:40 -0400 Subject: [PATCH 048/395] eieio: Emit compilation warnings a bit more thoroughly We used to warn about unknown slots only in `oref`: add the same check for `oset` and `slot-boundp`. Similarly, we warned about obsolete name args only when calling the constructors: add the same check to `make-instance`. * lisp/emacs-lisp/eieio-core.el (eieio--check-slot-name): New function extracted from the compiler-macro of `eieio-oref`. (eieio-oref, eieio-oset): Use it. * lisp/emacs-lisp/eieio.el (slot-boundp): Use it. (eieio--constructor-macro): Add category to warning. (make-instance): Add compiler-macro to warn about obsolete name. --- lisp/emacs-lisp/eieio-core.el | 22 ++++++++++++---------- lisp/emacs-lisp/eieio.el | 17 ++++++++++++++++- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/lisp/emacs-lisp/eieio-core.el b/lisp/emacs-lisp/eieio-core.el index f95fd65fa5c..b3a8698e31d 100644 --- a/lisp/emacs-lisp/eieio-core.el +++ b/lisp/emacs-lisp/eieio-core.el @@ -740,18 +740,19 @@ Argument FN is the function calling this verifier." ;;; Get/Set slots in an object. +(eval-and-compile + (defun eieio--check-slot-name (exp _obj slot &rest _) + (pcase slot + ((and (or `',name (and name (pred keywordp))) + (guard (not (eieio--known-slot-name-p name)))) + (macroexp-warn-and-return + (format-message "Unknown slot `%S'" name) + exp nil 'compile-only name)) + (_ exp)))) + (defun eieio-oref (obj slot) "Return the value in OBJ at SLOT in the object vector." - (declare (compiler-macro - (lambda (exp) - (ignore obj) - (pcase slot - ((and (or `',name (and name (pred keywordp))) - (guard (not (eieio--known-slot-name-p name)))) - (macroexp-warn-and-return - (format-message "Unknown slot `%S'" name) - exp nil 'compile-only name)) - (_ exp)))) + (declare (compiler-macro eieio--check-slot-name) ;; FIXME: Make it a gv-expander such that the hash-table lookup is ;; only performed once when used in `push' and friends? (gv-setter eieio-oset)) @@ -822,6 +823,7 @@ Fills in CLASS's SLOT with its default value." (defun eieio-oset (obj slot value) "Do the work for the macro `oset'. Fills in OBJ's SLOT with VALUE." + (declare (compiler-macro eieio--check-slot-name)) (cl-check-type slot symbol) (cond ((cl-typep obj '(or eieio-object cl-structure-object)) diff --git a/lisp/emacs-lisp/eieio.el b/lisp/emacs-lisp/eieio.el index 424baafc503..2a80c5d7c3e 100644 --- a/lisp/emacs-lisp/eieio.el +++ b/lisp/emacs-lisp/eieio.el @@ -304,7 +304,7 @@ and reference them using the function `class-option'." ;; but hide it so we don't trigger indefinitely. `(,(car whole) (identity ,(car slots)) ,@(cdr slots)) - nil nil (car slots)))) + '(obsolete eieio-constructor-name-arg) nil (car slots)))) ;;; Get/Set slots in an object. ;; @@ -554,6 +554,7 @@ after they are created." Setting a slot's value makes it bound. Calling `slot-makeunbound' will make a slot unbound. OBJECT can be an instance or a class." + (declare (compiler-macro eieio--check-slot-name)) ;; Skip typechecking while retrieving this value. (let ((eieio-skip-typecheck t)) ;; Return nil if the magic symbol is in there. @@ -700,6 +701,20 @@ for each slot. For example: (make-instance \\='foo :slot1 value1 :slotN valueN)") +(put 'make-instance 'compiler-macro + (lambda (whole class &rest slots) + (if (or (null slots) (keywordp (car slots)) + ;; Detect the second pass! + (eq 'identity (car-safe (car slots)))) + whole + (macroexp-warn-and-return + (format "Obsolete name arg %S to `make-instance'" (car slots)) + ;; Keep the name arg, for backward compatibility, + ;; but hide it so we don't trigger indefinitely. + `(,(car whole) ,class (identity ,(car slots)) + ,@(cdr slots)) + '(obsolete eieio-constructor-name-arg) nil (car slots))))) + (define-obsolete-function-alias 'constructor #'make-instance "25.1") (cl-defmethod make-instance From aca9f8c50aeea36f85e602272e97a6adfc93283a Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Sun, 6 Apr 2025 23:43:37 -0400 Subject: [PATCH 049/395] lisp/emacs-lisp/eieio-custom.el: Require `eieio-base` to silence warning --- lisp/emacs-lisp/eieio-custom.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/emacs-lisp/eieio-custom.el b/lisp/emacs-lisp/eieio-custom.el index 3f5291d0dee..375a1652d3d 100644 --- a/lisp/emacs-lisp/eieio-custom.el +++ b/lisp/emacs-lisp/eieio-custom.el @@ -31,6 +31,7 @@ ;; `:custom'. (require 'eieio) +(require 'eieio-base) ;; For `eieio-named's slot. (require 'widget) (require 'wid-edit) From 31c5fd3bfba31687de31e1e4c3d3501401f023bc Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Sun, 6 Apr 2025 23:49:37 -0400 Subject: [PATCH 050/395] test/eieio: Silence warnings about slots and obsolete name arg * test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el (eieio-test-method-order-list-3, eieio-test-method-order-list-6) (eieio-test-method-order-list-7, eieio-test-method-order-list-8): Delete obsolete name argument to constructors. (eieio-test-method-order-list-4): Make sure backward compatibility is active when testing the obsolete name arg. * test/lisp/jsonrpc-tests.el (jsonrpc--call-with-emacsrpc-fixture): Delete obsolete name argument to constructor. * test/lisp/emacs-lisp/eieio-tests/eieio-tests.el (derived-value): Silence unknown slot warning. --- .../eieio-tests/eieio-test-methodinvoke.el | 12 +++++++----- test/lisp/emacs-lisp/eieio-tests/eieio-tests.el | 3 +++ test/lisp/jsonrpc-tests.el | 1 - 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el b/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el index c9da7d92deb..13c33a219ee 100644 --- a/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el +++ b/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el @@ -138,7 +138,7 @@ (:AFTER eitest-B-base1) (:AFTER eitest-B) ))) - (eitest-F (eitest-B nil)) + (eitest-F (eitest-B)) (setq eieio-test-method-order-list (nreverse eieio-test-method-order-list)) (eieio-test-match ans))) @@ -153,7 +153,9 @@ (ert-deftest eieio-test-method-order-list-4 () ;; Both of these situations should succeed. (should (eitest-H 'eitest-A)) - (should (eitest-H (eitest-A nil)))) + (let ((eieio-backward-compatibility t)) + (with-suppressed-warnings ((obsolete eieio-constructor-name-arg)) + (should (eitest-H (eitest-A nil)))))) ;;; Return value from :PRIMARY ;; @@ -213,7 +215,7 @@ (:STATIC C-base1) (:STATIC C-base2) ))) - (C nil) + (C) (setq eieio-test-method-order-list (nreverse eieio-test-method-order-list)) (eieio-test-match ans))) @@ -262,7 +264,7 @@ (:PRIMARY D-base2) (:PRIMARY D-base0) ))) - (eitest-F (D nil)) + (eitest-F (D)) (setq eieio-test-method-order-list (nreverse eieio-test-method-order-list)) (eieio-test-match ans))) @@ -304,7 +306,7 @@ (:PRIMARY E-base2) (:PRIMARY E-base0) ))) - (eitest-F (E nil)) + (eitest-F (E)) (setq eieio-test-method-order-list (nreverse eieio-test-method-order-list)) (eieio-test-match ans))) diff --git a/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el b/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el index 51996fe51be..fced6bc3df2 100644 --- a/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el +++ b/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el @@ -430,6 +430,9 @@ METHOD is the method that was attempting to be called." (defclass virtual-slot-class () ((base-value :initarg :base-value)) "Class has real slot :base-value and simulated slot :derived-value.") + +(eieio-declare-slots derived-value) + (with-suppressed-warnings ((obsolete defmethod) (obsolete defgeneric)) (defmethod slot-missing ((vsc virtual-slot-class) diff --git a/test/lisp/jsonrpc-tests.el b/test/lisp/jsonrpc-tests.el index 68eaae6c44b..148f5870434 100644 --- a/test/lisp/jsonrpc-tests.el +++ b/test/lisp/jsonrpc-tests.el @@ -76,7 +76,6 @@ (setq endpoint (make-instance 'jsonrpc--test-client - "Emacs RPC client" :process (open-network-stream "JSONRPC test tcp endpoint" nil "localhost" From ae5c608eca636ad1c5c76294d81f16a16d2ec3b5 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Mon, 7 Apr 2025 11:54:06 -0400 Subject: [PATCH 051/395] (Freplace_region_contents): Fix point preservation (bug#77607) * src/editfns.c (Freplace_region_contents): Save excursion around temporary restriction (bug#77607) and remove `record_unwind_protect_excursion` made redundant by commit 40d8650d5177. --- src/editfns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editfns.c b/src/editfns.c index 9590b49dc25..669d3cdb140 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -1968,6 +1968,7 @@ a buffer or a string. But this is deprecated. */) if (FUNCTIONP (source)) { specpdl_ref count = SPECPDL_INDEX (); + record_unwind_protect_excursion (); record_unwind_protect (save_restriction_restore, save_restriction_save ()); Fnarrow_to_region (beg, end); @@ -2119,7 +2120,6 @@ a buffer or a string. But this is deprecated. */) Fundo_boundary (); bool modification_hooks_inhibited = false; - record_unwind_protect_excursion (); /* We are going to make a lot of small modifications, and having the modification hooks called for each of them will slow us down. From 9663c959c73d6cca0c56f833d80ff1d9e9708b70 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Mon, 7 Apr 2025 12:41:49 -0400 Subject: [PATCH 052/395] eieio: Improve some obsolecence warnings and fix # names * lisp/emacs-lisp/eieio.el (eieio--constructor-macro): Improve message. (eieio-object-name-string): Avoid repeated class name in the output of `eieio-object-name`. (make-instance, clone): Improve message. * lisp/emacs-lisp/eieio-core.el (eieio-defclass-autoload): Use the same obsolescence warning as elsewhere. --- lisp/emacs-lisp/eieio-core.el | 4 +--- lisp/emacs-lisp/eieio.el | 14 ++++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lisp/emacs-lisp/eieio-core.el b/lisp/emacs-lisp/eieio-core.el index b3a8698e31d..99f8feb9644 100644 --- a/lisp/emacs-lisp/eieio-core.el +++ b/lisp/emacs-lisp/eieio-core.el @@ -208,9 +208,7 @@ It creates an autoload function for CNAME's constructor." ;; turn this into a usable self-pointing symbol (when eieio-backward-compatibility (set cname cname) - (make-obsolete-variable cname (format "\ -use '%s or turn off `eieio-backward-compatibility' instead" cname) - "25.1")) + (make-obsolete-variable cname (format "use '%s instead" cname) "25.1")) (when (memq nil parents) ;; If some parents aren't yet fully defined, just ignore them for now. diff --git a/lisp/emacs-lisp/eieio.el b/lisp/emacs-lisp/eieio.el index 2a80c5d7c3e..d66915260c8 100644 --- a/lisp/emacs-lisp/eieio.el +++ b/lisp/emacs-lisp/eieio.el @@ -293,12 +293,15 @@ and reference them using the function `class-option'." (apply #'make-instance ',name slots)))))) (defun eieio--constructor-macro (whole &rest slots) + ;; When `eieio-backward-compatibility' is removed, we should + ;; remove this compiler-macro, until then, it's best to emit a compile-time + ;; warning even if `eieio-backward-compatibility' is nil, I think. (if (or (null slots) (keywordp (car slots)) ;; Detect the second pass! (eq 'identity (car-safe (car slots)))) whole (macroexp-warn-and-return - (format "Obsolete name arg %S to constructor %S" + (format "Obsolete name argument %S to constructor %S" (car slots) (car whole)) ;; Keep the name arg, for backward compatibility, ;; but hide it so we don't trigger indefinitely. @@ -405,7 +408,7 @@ contents of field NAME is matched against PAT, or they can be of (cl-defgeneric eieio-object-name-string (obj) "Return a string which is OBJ's name." (or (gethash obj eieio--object-names) - (format "%s-%x" (eieio-object-class obj) (sxhash-eq obj)))) + (format "%x" (sxhash-eq obj)))) (define-obsolete-function-alias 'object-name-string #'eieio-object-name-string "24.4") @@ -702,6 +705,9 @@ for each slot. For example: (make-instance \\='foo :slot1 value1 :slotN valueN)") (put 'make-instance 'compiler-macro + ;; When `eieio-backward-compatibility' is removed, we should + ;; remove this compiler-macro, until then, it's best to emit a compile-time + ;; warning even if `eieio-backward-compatibility' is nil, I think. (lambda (whole class &rest slots) (if (or (null slots) (keywordp (car slots)) ;; Detect the second pass! @@ -730,7 +736,7 @@ calls `initialize-instance' on that object." (let ((x (car slots))) (or (stringp x) (null x)))) (funcall (if eieio-backward-compatibility #'ignore #'message) - "Obsolete name %S passed to %S constructor" + "Obsolete name argument %S passed to %S constructor" (pop slots) class)) ;; Call the initialize method on the new object with the slots ;; that were passed down to us. @@ -837,7 +843,7 @@ first and modify the returned object.") (let ((nobj (copy-sequence obj))) (if (stringp (car params)) (funcall (if eieio-backward-compatibility #'ignore #'message) - "Obsolete name %S passed to clone" (pop params))) + "Obsolete name argument %S passed to clone" (pop params))) (if params (shared-initialize nobj params)) nobj)) From 9f25d46568bf0a4d617145537db4c8aaf5e0219b Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Mon, 7 Apr 2025 21:41:35 -0400 Subject: [PATCH 053/395] (Fload, Feval_buffer): Emit a warning when lexbind is unset (bug#74145) This emits a warning at run-time rather than at compile time. * src/lread.c (get_lexical_binding): New function. (Fload, Feval_buffer): Use it. (syms_of_lread): New var `internal--get-default-lexical-binding-function`. * lisp/files.el: Set it. (internal--get-default-lexical-binding): New function. --- etc/NEWS | 7 ++++++- lisp/files.el | 24 ++++++++++++++++++++++++ src/lread.c | 30 ++++++++++++++++++++---------- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 63957628b98..c08b0052639 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1828,14 +1828,19 @@ Like 'static-if', these macros evaluate their condition at macro-expansion time and are useful for writing code that can work across different Emacs versions. +** Lexical binding + --- -** You can change the default value of 'lexical-binding'. +*** You can change the default value of 'lexical-binding'. While the default is still the use of dynamic binding dialect of Elisp in those places that don't explicitly set 'lexical-binding' you can change it globally with: (set-default-toplevel-value 'lexical-binding t) +--- +*** Loading a file displays a warning if there is no 'lexical-binding' cookie. + +++ ** New macros 'incf' and 'decf'. They increment or decrement the value stored in a variable (a symbol), diff --git a/lisp/files.el b/lisp/files.el index eb49f25ee27..7ba4079a650 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -4277,6 +4277,30 @@ all the specified local variables, but ignores any settings of \"mode:\"." (push elem file-local-variables-alist))) (hack-local-variables-apply)))))) +(defun internal--get-default-lexical-binding (from) + (let ((mib (lambda (node) (buttonize node (lambda (_) (info node)))))) + (or (and (bufferp from) (zerop (buffer-size from))) + (and (stringp from) + (eql 0 (file-attribute-size (file-attributes from)))) + (display-warning + '(files missing-lexbind-cookie) + (format-message "Missing `lexical-binding' cookie in %S. +You can add one with `M-x elisp-enable-lexical-binding RET'. +See `%s' and `%s' +for more information." + (if (not (and (bufferp from) + (equal (buffer-name from) " *load*") + load-file-name)) + from + (abbreviate-file-name load-file-name)) + (funcall mib "(elisp)Selecting Lisp Dialect") + (funcall mib "(elisp)Converting to Lexical Binding")) + :warning)) + (default-toplevel-value 'lexical-binding))) + +(setq internal--get-default-lexical-binding-function + #'internal--get-default-lexical-binding) + (defun hack-local-variables--find-variables (&optional handle-mode) "Return all local variables in the current buffer. If HANDLE-MODE is nil, we gather all the specified local diff --git a/src/lread.c b/src/lread.c index add8deb3954..445e5cd1fba 100644 --- a/src/lread.c +++ b/src/lread.c @@ -1271,6 +1271,18 @@ close_file_unwind_android_fd (void *ptr) #endif +static Lisp_Object +get_lexical_binding (Lisp_Object stream, Lisp_Object from) +{ + lexical_cookie_t lexc = lisp_file_lexical_cookie (stream); + return (lexc == Cookie_Lex ? Qt + : lexc == Cookie_Dyn ? Qnil + : (NILP (from) /* Loading a byte-compiled file. */ + || NILP (Vinternal__get_default_lexical_binding_function) + ? Fdefault_toplevel_value (Qlexical_binding) + : calln (Vinternal__get_default_lexical_binding_function, from))); +} + DEFUN ("load", Fload, Sload, 1, 5, 0, doc: /* Execute a file of Lisp code named FILE. First try FILE with `.elc' appended, then try with `.el', then try @@ -1720,11 +1732,8 @@ Return t if the file exists and loads successfully. */) } else { - lexical_cookie_t lexc = lisp_file_lexical_cookie (Qget_file_char); Fset (Qlexical_binding, - (lexc == Cookie_Lex ? Qt - : lexc == Cookie_Dyn ? Qnil - : Fdefault_toplevel_value (Qlexical_binding))); + get_lexical_binding (Qget_file_char, compiled ? Qnil : file)); if (! version || version >= 22) readevalloop (Qget_file_char, &input, hist_file_name, @@ -2609,11 +2618,7 @@ This function preserves the position of point. */) specbind (Qstandard_output, tem); record_unwind_protect_excursion (); BUF_TEMP_SET_PT (XBUFFER (buf), BUF_BEGV (XBUFFER (buf))); - lexical_cookie_t lexc = lisp_file_lexical_cookie (buf); - specbind (Qlexical_binding, - lexc == Cookie_Lex ? Qt - : lexc == Cookie_Dyn ? Qnil - : Fdefault_toplevel_value (Qlexical_binding)); + specbind (Qlexical_binding, get_lexical_binding (buf, buf)); BUF_TEMP_SET_PT (XBUFFER (buf), BUF_BEGV (XBUFFER (buf))); readevalloop (buf, 0, filename, !NILP (printflag), unibyte, Qnil, Qnil, Qnil); @@ -5169,7 +5174,7 @@ obarray_index (struct Lisp_Obarray *oa, const char *str, ptrdiff_t size_byte) return knuth_hash (reduce_emacs_uint_to_hash_hash (hash), oa->size_bits); } -/* Return the symbol in OBARRAY whose names matches the string +/* Return the symbol in OBARRAY whose name matches the string of SIZE characters (SIZE_BYTE bytes) at PTR. If there is no such symbol, return the integer bucket number of where the symbol would be if it were present. @@ -6145,6 +6150,11 @@ through `require'. */); DEFSYM (Qchar_from_name, "char-from-name"); + DEFVAR_LISP ("internal--get-default-lexical-binding-function", + Vinternal__get_default_lexical_binding_function, + doc: /* Function to decide default lexical-binding. */); + Vinternal__get_default_lexical_binding_function = Qnil; + DEFVAR_LISP ("read-symbol-shorthands", Vread_symbol_shorthands, doc: /* Alist of known symbol-name shorthands. This variable's value can only be set via file-local variables. From 9b7402c5fdbae1ec88c47101e9e8f74fcbffe5ec Mon Sep 17 00:00:00 2001 From: Po Lu Date: Tue, 8 Apr 2025 09:46:16 +0800 Subject: [PATCH 054/395] ; * src/lread.c (get_lexical_binding): Fix coding style. --- src/lread.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/lread.c b/src/lread.c index 445e5cd1fba..d39330bd0eb 100644 --- a/src/lread.c +++ b/src/lread.c @@ -1275,12 +1275,15 @@ static Lisp_Object get_lexical_binding (Lisp_Object stream, Lisp_Object from) { lexical_cookie_t lexc = lisp_file_lexical_cookie (stream); - return (lexc == Cookie_Lex ? Qt - : lexc == Cookie_Dyn ? Qnil - : (NILP (from) /* Loading a byte-compiled file. */ - || NILP (Vinternal__get_default_lexical_binding_function) - ? Fdefault_toplevel_value (Qlexical_binding) - : calln (Vinternal__get_default_lexical_binding_function, from))); + return ((lexc == Cookie_Lex + ? Qt + : (lexc == Cookie_Dyn + ? Qnil + : ((NILP (from) /* Loading a byte-compiled file. */ + || NILP (Vinternal__get_default_lexical_binding_function)) + ? Fdefault_toplevel_value (Qlexical_binding) + : calln (Vinternal__get_default_lexical_binding_function, + from))))); } DEFUN ("load", Fload, Sload, 1, 5, 0, From b392038560736d4413bc1b31671a9aa826ff873e Mon Sep 17 00:00:00 2001 From: Po Lu Date: Tue, 8 Apr 2025 10:26:18 +0800 Subject: [PATCH 055/395] Replace some calls to `intern' with DEFSYMs * src/filelock.c (lock_file, unlock_file_handle_error): Call constant symbols rather than interning them all the time. (syms_of_filelock): New symbols Qask_user_about_lock, Quserlock__handle_unlock_error, and Quserlock__ask_user_about_supersession_threat. --- src/filelock.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/filelock.c b/src/filelock.c index e61c6776e3e..2f5744334e0 100644 --- a/src/filelock.c +++ b/src/filelock.c @@ -605,7 +605,7 @@ lock_file (Lisp_Object fn) && NILP (Fverify_visited_file_modtime (subject_buf)) && !NILP (Ffile_exists_p (fn)) && !(!NILP (lfname) && current_lock_owner (NULL, lfname) == I_OWN_IT)) - calln (intern ("userlock--ask-user-about-supersession-threat"), fn); + calln (Quserlock__ask_user_about_supersession_threat, fn); /* Don't do locking if the user has opted out. */ if (!NILP (lfname)) @@ -623,7 +623,7 @@ lock_file (Lisp_Object fn) memmove (dot + replacementlen, dot + 1, pidlen); strcpy (dot + replacementlen + pidlen, ")"); memcpy (dot, replacement, replacementlen); - attack = calln (intern ("ask-user-about-lock"), fn, + attack = calln (Qask_user_about_lock, fn, build_string (lock_info.user)); /* Take the lock if the user said so. */ if (!NILP (attack)) @@ -653,7 +653,7 @@ unlock_file (Lisp_Object fn) static Lisp_Object unlock_file_handle_error (Lisp_Object err) { - calln (intern ("userlock--handle-unlock-error"), err); + calln (Quserlock__handle_unlock_error, err); return Qnil; } @@ -827,6 +827,10 @@ Info node `(emacs)Interlocking'. */); DEFSYM (Qfile_locked_p, "file-locked-p"); DEFSYM (Qmake_lock_file_name, "make-lock-file-name"); DEFSYM (Qstring_replace, "string-replace"); + DEFSYM (Qask_user_about_lock, "ask-user-about-lock"); + DEFSYM (Quserlock__handle_unlock_error, "userlock--handle-unlock-error"); + DEFSYM (Quserlock__ask_user_about_supersession_threat, + "userlock--ask-user-about-supersession-threat"); defsubr (&Slock_file); defsubr (&Sunlock_file); From 9dc6177206a10efcc3a25894aa7aabaa54044adc Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Mon, 7 Apr 2025 22:48:01 -0400 Subject: [PATCH 056/395] lisp/files.el (internal--get-default-lexical-binding): Handle nested loads --- lisp/files.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lisp/files.el b/lisp/files.el index 7ba4079a650..5102f3f6d01 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -4289,7 +4289,9 @@ You can add one with `M-x elisp-enable-lexical-binding RET'. See `%s' and `%s' for more information." (if (not (and (bufferp from) - (equal (buffer-name from) " *load*") + (string-match-p + "\\` \\*load\\*\\(-[0-9]+\\)?\\'" + (buffer-name from)) load-file-name)) from (abbreviate-file-name load-file-name)) From 19257efbf712dc026572a88b46d456d0c4b8c365 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Mon, 7 Apr 2025 23:24:21 -0400 Subject: [PATCH 057/395] lisp/files.el (internal--get-default-lexical-binding): Buttonize the M-x --- lisp/files.el | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/lisp/files.el b/lisp/files.el index 5102f3f6d01..845168121c8 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -4278,26 +4278,36 @@ all the specified local variables, but ignores any settings of \"mode:\"." (hack-local-variables-apply)))))) (defun internal--get-default-lexical-binding (from) - (let ((mib (lambda (node) (buttonize node (lambda (_) (info node)))))) + (let ((mib (lambda (node) (buttonize node (lambda (_) (info node)) + nil "mouse-2: Jump to Info node")))) (or (and (bufferp from) (zerop (buffer-size from))) (and (stringp from) (eql 0 (file-attribute-size (file-attributes from)))) - (display-warning - '(files missing-lexbind-cookie) - (format-message "Missing `lexical-binding' cookie in %S. -You can add one with `M-x elisp-enable-lexical-binding RET'. + (let ((source + (if (not (and (bufferp from) + (string-match-p "\\` \\*load\\*\\(-[0-9]+\\)?\\'" + (buffer-name from)) + load-file-name)) + from + (abbreviate-file-name load-file-name)))) + (display-warning + '(files missing-lexbind-cookie) + (format-message "Missing `lexical-binding' cookie in %S. +You can add one with `M-x %s RET'. See `%s' and `%s' for more information." - (if (not (and (bufferp from) - (string-match-p - "\\` \\*load\\*\\(-[0-9]+\\)?\\'" - (buffer-name from)) - load-file-name)) - from - (abbreviate-file-name load-file-name)) - (funcall mib "(elisp)Selecting Lisp Dialect") - (funcall mib "(elisp)Converting to Lexical Binding")) - :warning)) + source + (buttonize "elisp-enable-lexical-binding" + (lambda (_) + (pop-to-buffer + (if (bufferp source) source + (find-file-noselect source))) + (call-interactively + #'elisp-enable-lexical-binding)) + nil "mouse-2: Add cookie") + (funcall mib "(elisp)Selecting Lisp Dialect") + (funcall mib "(elisp)Converting to Lexical Binding")) + :warning))) (default-toplevel-value 'lexical-binding))) (setq internal--get-default-lexical-binding-function From ef8c4779dd4fd2a00d9ca4e572e42608628bce50 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Tue, 8 Apr 2025 13:17:17 +0800 Subject: [PATCH 058/395] Update descriptions of VC's capabilities for Git and Mercurial * doc/emacs/maintaining.texi (Version Control Systems): Update descriptions of VC's capabilities for Git and Mercurial. --- doc/emacs/maintaining.texi | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi index 6e9653dcdc8..c761dc33c86 100644 --- a/doc/emacs/maintaining.texi +++ b/doc/emacs/maintaining.texi @@ -190,8 +190,8 @@ which it refers to as @dfn{back ends}: @item Git is a decentralized version control system originally invented by Linus Torvalds to support development of Linux (his kernel). VC -supports many common Git operations, but others, such as repository -syncing, must be done from the command line. +supports all the common Git operations, but notably, Git rebases other +than simply to edit a commit message must be done from the command line. @cindex CVS @item @@ -235,8 +235,7 @@ everything you can do with RCS can be done through VC. @cindex Mercurial @item Mercurial (hg) is a decentralized version control system broadly -resembling Git. VC supports most Mercurial commands, with the -exception of repository sync operations. +resembling Git. VC supports most Mercurial commands. @cindex bzr @cindex Bazaar From 5f89eadb3f5a3794a6ee6acc7c5a3e6b26ab590d Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Tue, 8 Apr 2025 13:24:15 +0800 Subject: [PATCH 059/395] ; Drop Mtn from comment now vc-mtn is obsolete --- test/lisp/vc/vc-tests.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lisp/vc/vc-tests.el b/test/lisp/vc/vc-tests.el index f13a200cd99..e7852d53f99 100644 --- a/test/lisp/vc/vc-tests.el +++ b/test/lisp/vc/vc-tests.el @@ -368,7 +368,7 @@ This checks also `vc-backend' and `vc-responsible-backend'." 'vc-not-supported) (message "vc-state5 unsupported") ;; unregistered: Bzr Git RCS Hg - ;; unsupported: CVS Mtn SCCS SRC SVN + ;; unsupported: CVS SCCS SRC SVN (message "vc-state5 %s %s" backend (vc-state tmp-name backend)) (should (memq (vc-state tmp-name backend) '(nil unregistered)))))) From b784f194f8320d326c755dd49b31210977aae0e7 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Tue, 8 Apr 2025 14:09:07 +0800 Subject: [PATCH 060/395] Factor out vc-only-files-state-and-model * lisp/dired-aux.el (vc-compatible-state): Delete declaration. (vc-only-files-state-and-model): Declare. (dired-vc-deduce-fileset): Factor out vc-only-files-state-and-model. * lisp/vc/vc-dir.el (require): Require cl-lib at load time, too. (vc-only-files-state-and-model): Declare. (vc-dir-deduce-fileset): Factor out vc-only-files-state-and-model. * lisp/vc/vc.el (vc-only-files-state-and-model): New function, factored out of dired-vc-deduce-fileset and vc-dir-deduce-fileset. --- lisp/dired-aux.el | 38 ++++++++++++++++---------------------- lisp/vc/vc-dir.el | 27 +++++++++------------------ lisp/vc/vc.el | 18 ++++++++++++++++++ 3 files changed, 43 insertions(+), 40 deletions(-) diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el index f278b201ca6..676044972e9 100644 --- a/lisp/dired-aux.el +++ b/lisp/dired-aux.el @@ -3992,31 +3992,25 @@ In this case, the VERBOSE argument is ignored." (add-hook 'vc-dir-refresh-hook transient-hook nil t)) (vc-next-action verbose)))) -(declare-function vc-compatible-state "vc") +(declare-function vc-only-files-state-and-model "vc") ;;;###autoload -(defun dired-vc-deduce-fileset (&optional state-model-only-files not-state-changing) +(defun dired-vc-deduce-fileset + (&optional state-model-only-files not-state-changing) (let ((backend (vc-responsible-backend default-directory)) - (files (dired-get-marked-files nil nil nil nil t)) - only-files-list - state - model) - (when (and (not not-state-changing) (cl-some #'file-directory-p files)) - (user-error "State changing VC operations on directories supported only in `vc-dir'")) - - (when state-model-only-files - (setq only-files-list (mapcar (lambda (file) (cons file (vc-state file))) files)) - (setq state (cdar only-files-list)) - ;; Check that all files are in a consistent state, since we use that - ;; state to decide which operation to perform. - (dolist (crt (cdr only-files-list)) - (unless (vc-compatible-state (cdr crt) state) - (error "When applying VC operations to multiple files, the files are required\nto be in similar VC states.\n%s in state %s clashes with %s in state %s" - (car crt) (cdr crt) (caar only-files-list) state))) - (setq only-files-list (mapcar 'car only-files-list)) - (when (and state (not (eq state 'unregistered))) - (setq model (vc-checkout-model backend only-files-list)))) - (list backend files only-files-list state model))) + (files (dired-get-marked-files nil nil nil nil t))) + (when (and (not not-state-changing) + (cl-some #'file-directory-p files)) + (user-error "\ +State-changing VC operations on directories supported only from VC-Dir")) + (if state-model-only-files + (let ((only-files-list (mapcar (lambda (file) + (cons file (vc-state file))) + files))) + (cl-list* backend files + (vc-only-files-state-and-model only-files-list + backend))) + (list backend files)))) (provide 'dired-aux) diff --git a/lisp/vc/vc-dir.el b/lisp/vc/vc-dir.el index 1074986090e..b9d733d934b 100644 --- a/lisp/vc/vc-dir.el +++ b/lisp/vc/vc-dir.el @@ -44,7 +44,7 @@ (require 'seq) ;;; Code: -(eval-when-compile (require 'cl-lib)) +(require 'cl-lib) (declare-function fileloop-continue "fileloop") @@ -1464,12 +1464,11 @@ state of item at point, if any." (defun vc-dir-printer (fileentry) (vc-call-backend vc-dir-backend 'dir-printer fileentry)) +(declare-function vc-only-files-state-and-model "vc") + (defun vc-dir-deduce-fileset (&optional state-model-only-files) (let ((marked (vc-dir-marked-files)) - files - only-files-list - state - model) + files only-files-list) (if marked (progn (setq files marked) @@ -1479,19 +1478,11 @@ state of item at point, if any." (setq files (list crt)) (when state-model-only-files (setq only-files-list (vc-dir-child-files-and-states))))) - - (when state-model-only-files - (setq state (cdar only-files-list)) - ;; Check that all files are in a consistent state, since we use that - ;; state to decide which operation to perform. - (dolist (crt (cdr only-files-list)) - (unless (vc-compatible-state (cdr crt) state) - (error "When applying VC operations to multiple files, the files are required\nto be in similar VC states.\n%s in state %s clashes with %s in state %s" - (car crt) (cdr crt) (caar only-files-list) state))) - (setq only-files-list (mapcar #'car only-files-list)) - (when (and state (not (eq state 'unregistered))) - (setq model (vc-checkout-model vc-dir-backend only-files-list)))) - (list vc-dir-backend files only-files-list state model))) + (if state-model-only-files + (cl-list* vc-dir-backend files + (vc-only-files-state-and-model only-files-list + vc-dir-backend)) + (list vc-dir-backend files)))) ;;;###autoload (defun vc-dir-root () diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el index c8bd4ca9e63..42591076d5c 100644 --- a/lisp/vc/vc.el +++ b/lisp/vc/vc.el @@ -1284,6 +1284,24 @@ BEWARE: this function may change the current buffer." (unless (vc-backend buffer-file-name) (error "File %s is not under version control" buffer-file-name)))) +(defun vc-only-files-state-and-model (files backend) + "Compute last three `vc-deduce-fileset' return value elements for FILES. +FILES should be a pair, or list of pairs, of files and their VC states. +BACKEND is the VC backend responsible for FILES." + (let ((state (cdar files)) + (files* (mapcar #'car (ensure-list files)))) + ;; Check that all files are in a consistent state, since we use that + ;; state to decide which operation to perform. + (dolist (crt (cdr files)) + (unless (vc-compatible-state (cdr crt) state) + (error "\ +To apply VC operations to multiple files, the files must be in similar VC states. +%s in state %s clashes with %s in state %s" + (car crt) (cdr crt) (caar files) state))) + (list files* state + (and state (not (eq state 'unregistered)) + (vc-checkout-model backend files*))))) + ;;; Support for the C-x v v command. ;; This is where all the single-file-oriented code from before the fileset ;; rewrite lives. From 577ddbb9b79c067d296d50f3e8a04c193c1632b3 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Tue, 8 Apr 2025 15:12:17 +0800 Subject: [PATCH 061/395] ; Fix last change: ensure-list does not ensure a proper list --- lisp/vc/vc.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el index 42591076d5c..bc3d4cdbb68 100644 --- a/lisp/vc/vc.el +++ b/lisp/vc/vc.el @@ -1289,7 +1289,8 @@ BEWARE: this function may change the current buffer." FILES should be a pair, or list of pairs, of files and their VC states. BACKEND is the VC backend responsible for FILES." (let ((state (cdar files)) - (files* (mapcar #'car (ensure-list files)))) + (files* (mapcar #'car + (if (proper-list-p files) files (list files))))) ;; Check that all files are in a consistent state, since we use that ;; state to decide which operation to perform. (dolist (crt (cdr files)) From 13f439ce98c4cdd57bddfa671f071e31fa2badc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Tue, 8 Apr 2025 08:43:14 +0100 Subject: [PATCH 062/395] Eglot: check textDocument/publishDiagnostics version (bug#77588) * lisp/progmodes/eglot.el (eglot--versioned-identifier): Move up. (eglot-handle-notification textDocument/publishDiagnostics): Check eglot--versioned-identifier --- lisp/progmodes/eglot.el | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index c937283122e..bfa67ebfff0 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -2657,9 +2657,12 @@ Value is (TRUENAME . (:uri STR)), where STR is what is sent to the server on textDocument/didOpen and similar calls. TRUENAME is the expensive cached value of `file-truename'.") +(defvar-local eglot--versioned-identifier 0) + (cl-defmethod eglot-handle-notification - (server (_method (eql textDocument/publishDiagnostics)) &key uri diagnostics - &allow-other-keys) ; FIXME: doesn't respect `eglot-strict-mode' + (server (_method (eql textDocument/publishDiagnostics)) + &key uri diagnostics version + &allow-other-keys) ; FIXME: doesn't respect `eglot-strict-mode' "Handle notification publishDiagnostics." (cl-flet ((eglot--diag-type (sev) (cond ((null sev) 'eglot-error) @@ -2681,6 +2684,8 @@ expensive cached value of `file-truename'.") (with-current-buffer buffer (cl-loop initially + (if (and version (/= version eglot--versioned-identifier)) + (cl-return)) (setq flymake-list-only-diagnostics (assoc-delete-all path flymake-list-only-diagnostics)) for diag-spec across diagnostics @@ -2809,8 +2814,6 @@ Sets `eglot--TextDocumentIdentifier-cache' (which see) as a side effect." `(,truename . (:uri ,(eglot-path-to-uri truename :truenamep t)))))) (cdr eglot--TextDocumentIdentifier-cache)) -(defvar-local eglot--versioned-identifier 0) - (defun eglot--VersionedTextDocumentIdentifier () "Compute VersionedTextDocumentIdentifier object for current buffer." (append (eglot--TextDocumentIdentifier) From 30fb2ac07a74d88908013ea80c62fe6317b3a590 Mon Sep 17 00:00:00 2001 From: Jeremy Bryant Date: Mon, 7 Apr 2025 21:47:39 +0100 Subject: [PATCH 063/395] ; * CONTRIBUTE: Clarify single-line commit should end with a period. --- CONTRIBUTE | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTE b/CONTRIBUTE index aa6a59cd432..06e6fe45c84 100644 --- a/CONTRIBUTE +++ b/CONTRIBUTE @@ -238,6 +238,8 @@ formatting them: there will be no individual ChangeLog entries beyond the one in the summary line. +- If the commit message is a single-line, it should end with a period. + - If the commit has more than one author, the commit message should contain separate lines to mention the other authors, like the following: From d283db577339ee247826bfa1e8c1808dad823858 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Tue, 8 Apr 2025 20:36:42 +0800 Subject: [PATCH 064/395] Fix window selection after log-edit-show-diff, again In October I installed a change to vc-diff-patch-string and labelled it as "Fix window selection after log-edit-show-diff" but that change only fixed the problem within log-view-modify-change-comment. This change should fix window selection after C-c C-d in ordinary checkins. * lisp/vc/log-edit.el (log-edit-diff-fileset): Use save-selected-window in order to respect the documented requirement that values of log-edit-diff-function leave the Log Edit buffer's window selected when they return. --- lisp/vc/log-edit.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/vc/log-edit.el b/lisp/vc/log-edit.el index 0da0b90975c..3c3288777c8 100644 --- a/lisp/vc/log-edit.el +++ b/lisp/vc/log-edit.el @@ -857,7 +857,8 @@ comment history, see `log-edit-comment-ring', and hides `log-edit-files-buf'." (defun log-edit-diff-fileset () "Display diffs for the files to be committed." (interactive) - (vc-diff nil nil (list log-edit-vc-backend vc-log-fileset))) + (save-selected-window + (vc-diff nil nil (list log-edit-vc-backend vc-log-fileset)))) (defun log-edit-show-diff () "Show the diff for the files to be committed." From 646ccd5e67db701ed9f632492d1bfbe3f6110cb4 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Tue, 8 Apr 2025 19:04:41 +0300 Subject: [PATCH 065/395] Fix prettify-symbols-mode with composition rules * lisp/progmodes/prog-mode.el (prettify-symbols--composition-displayable-p): Fix a thinko. Patch by Visuwesh . (Bug#77627) --- lisp/progmodes/prog-mode.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/progmodes/prog-mode.el b/lisp/progmodes/prog-mode.el index 33e0d354fee..6c6b14d455a 100644 --- a/lisp/progmodes/prog-mode.el +++ b/lisp/progmodes/prog-mode.el @@ -244,8 +244,8 @@ of `prettify-symbols-alist' and `compose-region'." ;; check that every even-indexed element is displayable (seq-every-p (lambda (idx-elt) - (if (evenp (car idx-elt)) - (char-displayable-on-frame-p (cdr idx-elt)) + (if (evenp (cdr idx-elt)) + (char-displayable-on-frame-p (car idx-elt)) t)) (seq-map-indexed #'cons composition))) (t From 7ff674d7125452b0ce6a8d39cb667eacb90f3df2 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Tue, 8 Apr 2025 13:10:30 -0400 Subject: [PATCH 066/395] (internal--get-default-lexical-binding): Be more failsafe * lisp/files.el (internal--get-default-lexical-binding): Try and avoid signaling an error. Make it easier to suppress the warning for a specific file. --- lisp/files.el | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/lisp/files.el b/lisp/files.el index 845168121c8..ad6047bd02d 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -4290,24 +4290,31 @@ all the specified local variables, but ignores any settings of \"mode:\"." load-file-name)) from (abbreviate-file-name load-file-name)))) - (display-warning - '(files missing-lexbind-cookie) - (format-message "Missing `lexical-binding' cookie in %S. + (condition-case nil + (display-warning + `(files missing-lexbind-cookie + ,(if (bufferp source) 'eval-buffer source)) + (format-message "Missing `lexical-binding' cookie in %S. You can add one with `M-x %s RET'. See `%s' and `%s' for more information." - source - (buttonize "elisp-enable-lexical-binding" - (lambda (_) - (pop-to-buffer - (if (bufferp source) source - (find-file-noselect source))) - (call-interactively - #'elisp-enable-lexical-binding)) - nil "mouse-2: Add cookie") - (funcall mib "(elisp)Selecting Lisp Dialect") - (funcall mib "(elisp)Converting to Lexical Binding")) - :warning))) + source + (buttonize "elisp-enable-lexical-binding" + (lambda (_) + (pop-to-buffer + (if (bufferp source) source + (find-file-noselect source))) + (call-interactively + #'elisp-enable-lexical-binding)) + nil "mouse-2: Add cookie") + (funcall mib "(elisp)Selecting Lisp Dialect") + (funcall mib "(elisp)Converting to Lexical Binding")) + :warning) + ;; In various corner-case situations, `display-warning' may + ;; fail (e.g. not yet defined, or can't be (auto)loaded), + ;; so use a simple fallback that won't get in the way. + (error + (message "Missing `lexical-binding' cookie in %S" source))))) (default-toplevel-value 'lexical-binding))) (setq internal--get-default-lexical-binding-function From 5e0daa1ef77d2a5fe5b65b8f0fa6c4eab83a2498 Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Tue, 8 Apr 2025 20:40:10 +0300 Subject: [PATCH 067/395] New function treesit-parsers-at for treesit-language-at (bug#77256). * doc/lispref/parsing.texi (Multiple Languages): The variable 'treesit-language-at-point-function' is now optional for multi-language major modes. Add description of 'treesit-parsers-at'. * lisp/treesit.el (treesit-language-at-point-function): Change the the docstring to remove the dissuasion against deriving the language from parser ranges. (treesit-language-at): Use the first parser from 'treesit-parsers-at' as the default return value when 'treesit-language-at-point-function' is nil. Adapt the docstring. (treesit-node-at): Use 'treesit-parsers-at'. (treesit-parsers-at): New function. (treesit-local-parsers-at): Use 'treesit-parsers-at' with the most part of the body moved to it. (treesit-local-parsers-on): Replace the overlay property 'treesit-parser' with 'treesit-parser-local-p' in the docstring. (treesit-up-list, treesit-simple-imenu, treesit-outline-level): Use 'treesit-parsers-at'. * lisp/progmodes/c-ts-mode.el (c-ts-mode): Don't set 'treesit-language-at-point-function'. * lisp/progmodes/elixir-ts-mode.el (elixir-ts--treesit-language-at-point): Remove. (elixir-ts-mode): Don't set 'treesit-language-at-point-function'. * lisp/progmodes/js.el (js--treesit-language-at-point): Remove. (js-ts-mode): Don't set 'treesit-language-at-point-function'. * lisp/progmodes/php-ts-mode.el (php-ts-mode--html-language-at-point) (php-ts-mode--language-at-point): Remove. (php-ts-mode): Don't set 'treesit-language-at-point-function'. * lisp/textmodes/mhtml-ts-mode.el (mhtml-ts-mode--language-at-point): Remove. (mhtml-ts-mode): Don't set 'treesit-language-at-point-function'. Use 'treesit-language-at' for mode-line lighter. --- doc/lispref/parsing.texi | 48 ++++++++++--- etc/NEWS | 29 ++++---- lisp/progmodes/c-ts-mode.el | 2 - lisp/progmodes/elixir-ts-mode.el | 15 ---- lisp/progmodes/js.el | 17 ----- lisp/progmodes/php-ts-mode.el | 28 -------- lisp/textmodes/mhtml-ts-mode.el | 21 +----- lisp/treesit.el | 118 +++++++++++++++++++------------ 8 files changed, 127 insertions(+), 151 deletions(-) diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi index 3e8e0851f2c..f7be47dc044 100644 --- a/doc/lispref/parsing.texi +++ b/doc/lispref/parsing.texi @@ -1814,12 +1814,12 @@ ranges for each parser are correct before using parsers in a buffer, and call @code{treesit-language-at} to figure out the language responsible for the text at some position. These two functions don't work by themselves; they need major modes to set @code{treesit-range-settings} -and @code{treesit-language-at-point-function}, which do the actual work. +and optionally @code{treesit-language-at-point-function}, which do the actual work. These functions and variables are explained in more detail towards the end of the section. In short, multi-language major modes should set -@code{treesit-primary-parser}, @code{treesit-range-settings}, and +@code{treesit-primary-parser}, @code{treesit-range-settings}, and optionally @code{treesit-language-at-point-function} before calling @code{treesit-major-mode-setup}. @@ -1921,9 +1921,9 @@ This function returns the language of the text at buffer position @var{pos}. Under the hood it calls @code{treesit-language-at-point-function} and returns its return value. If @code{treesit-language-at-point-function} is @code{nil}, -this function returns the language of the first parser in the returned -value of @code{treesit-parser-list}. If there is no parser in the -buffer, it returns @code{nil}. +this function returns the language of the deepest parser by embed level +among parsers returned by @code{treesit-parsers-at}. If there is no +parser at that buffer position, it returns @code{nil}. @end defun @heading Supporting multiple languages in major modes @@ -2011,7 +2011,7 @@ directly translate into operations shown above. @end group @group -;; Major modes with multiple languages should always set +;; Major modes with multiple languages can optionally set ;; `treesit-language-at-point-function' (which see). (setq treesit-language-at-point-function (lambda (pos) @@ -2094,17 +2094,45 @@ language of the buffer text at @var{pos}. This variable is used by @code{treesit-language-at}. @end defvar -@defun treesit-local-parsers-at &optional pos language +@defun treesit-parsers-at &optional pos language with-host only +This function returns all parsers at @var{pos} in the current buffer. +@var{pos} defaults to point. The returned parsers are sorted by the +decreasing embed level. + +If @var{language} is non-@code{nil}, return parsers only for that +language. + +If @var{with-host} is non-@code{nil}, return a list of +@w{@code{(@var{parser} . @var{host-parser})}} where @var{host-parser} +is the host parser which created the @var{parser}. + +If @var{only} is non-@code{nil}, return all parsers including the +primary parser. + +The argument @var{only} can be a list of symbols that specify what +parsers to include in the return value. + +If @var{only} contains the symbol @code{local}, include local parsers. +Local parsers are those which only parse a limited region marked by an +overlay with a non-@code{nil} @code{treesit-parser-local-p} property. + +If @var{only} contains the symbol @code{global}, include non-local parsers +excluding the primary parser. + +If @var{only} contains the symbol `primary', include the primary parser. +@end defun + +@defun treesit-local-parsers-at &optional pos language with-host This function returns all the local parsers at @var{pos} in the current buffer. @var{pos} defaults to point. Local parsers are those which only parse a limited region marked by an -overlay with a non-@code{nil} @code{treesit-parser} property. If -@var{language} is non-@code{nil}, only return parsers for that +overlay with a non-@code{nil} @code{treesit-parser-local-p} property. +If @var{language} is non-@code{nil}, only return parsers for that language. @end defun -@defun treesit-local-parsers-on &optional beg end language +@defun treesit-local-parsers-on &optional beg end language with-host This function is the same as @code{treesit-local-parsers-at}, but it returns the local parsers in the range between @var{beg} and @var{end} instead of at point. diff --git a/etc/NEWS b/etc/NEWS index c08b0052639..fa8b0bf89a8 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1994,18 +1994,6 @@ in the old rules with new ones, then returns the modified rules. In a multi-language major mode it is sometimes necessary to modify rules from one of the major modes to better suit the new multilingual context. -+++ -*** New command 'treesit-explore'. -This command replaces 'treesit-explore-mode'. It turns on -'treesit-explore-mode' if it’s not on, and pops up the explorer buffer -if it’s already on. - -+++ -*** 'treesit-explore-mode' now supports local parsers. -Now 'treesit-explore-mode' (or 'treesit-explore') prompts for a parser -rather than a language, and it’s now possible to select a local parser -at point to explore. - +++ *** New variable 'treesit-aggregated-simple-imenu-settings'. This variable allows major modes to setup Imenu for multiple languages. @@ -2023,6 +2011,23 @@ tree-sitter modes. Users can customize this variable to add simple custom indentation rules for tree-sitter major modes. ++++ +*** 'treesit-language-at-point-function' is now optional. +Multi-language major modes can rely on the default return value from +'treesit-language-at' that uses the new function 'treesit-parsers-at'. + ++++ +*** New command 'treesit-explore'. +This command replaces 'treesit-explore-mode'. It turns on +'treesit-explore-mode' if it’s not on, and pops up the explorer buffer +if it’s already on. + ++++ +*** 'treesit-explore-mode' now supports local parsers. +Now 'treesit-explore-mode' (or 'treesit-explore') prompts for a parser +rather than a language, and it’s now possible to select a local parser +at point to explore. + +++ ** New optional BUFFER argument for 'string-pixel-width'. If supplied, 'string-pixel-width' will use any face remappings from diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index fa5f8567b60..c49e928884a 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -1488,8 +1488,6 @@ in your init files." (setq-local treesit-range-settings (treesit-range-rules 'c-ts-mode--emacs-set-ranges)) - (setq-local treesit-language-at-point-function - (lambda (_pos) 'c)) (treesit-font-lock-recompute-features '(emacs-devel))) ;; Inject doxygen parser for comment. diff --git a/lisp/progmodes/elixir-ts-mode.el b/lisp/progmodes/elixir-ts-mode.el index d50692d87c0..9a0418eaf29 100644 --- a/lisp/progmodes/elixir-ts-mode.el +++ b/lisp/progmodes/elixir-ts-mode.el @@ -596,18 +596,6 @@ With ARG, do it many times. Negative ARG means move backward." (back-to-indentation) (point))) -(defun elixir-ts--treesit-language-at-point (point) - "Return the language at POINT." - (let ((node (treesit-node-at point 'elixir))) - (if (and (equal (treesit-node-type node) "quoted_content") - (let ((prev-sibling (treesit-node-prev-sibling node t))) - (and (treesit-node-p prev-sibling) - (string-match-p - (rx bos (or "H" "F") eos) - (treesit-node-text prev-sibling))))) - 'heex - 'elixir))) - (defun elixir-ts--defun-p (node) "Return non-nil when NODE is a defun." (member (treesit-node-text @@ -702,9 +690,6 @@ Return nil if NODE is not a defun node or doesn't have a name." (setq-local treesit-primary-parser (treesit-parser-create 'elixir)) - (setq-local treesit-language-at-point-function - 'elixir-ts--treesit-language-at-point) - ;; Font-lock. (setq-local treesit-font-lock-settings elixir-ts--font-lock-settings) (setq-local treesit-font-lock-feature-list diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index f319d1d2fa9..69d05feb594 100644 --- a/lisp/progmodes/js.el +++ b/lisp/progmodes/js.el @@ -3730,22 +3730,6 @@ Return nil if there is no name or if NODE is not a defun node." eos)))) (_ t))) -(defun js--treesit-language-at-point (point) - "Return the language at POINT." - (let* ((node (treesit-node-at point 'javascript)) - (node-type (treesit-node-type node)) - (node-start (treesit-node-start node)) - (node-end (treesit-node-end node))) - (if (not (treesit-ready-p 'jsdoc t)) - 'javascript - (if (equal node-type "comment") - (save-excursion - (goto-char node-start) - (if (search-forward "/**" node-end t) - 'jsdoc - 'javascript)) - 'javascript)))) - ;;; Main Function ;;;###autoload @@ -4006,7 +3990,6 @@ See `treesit-thing-settings' for more information.") ;; Tree-sitter setup. (setq-local treesit-primary-parser (treesit-parser-create 'javascript)) - (setq-local treesit-language-at-point-function #'js--treesit-language-at-point) ;; Indent. (setq-local treesit-simple-indent-rules js--treesit-indent-rules) diff --git a/lisp/progmodes/php-ts-mode.el b/lisp/progmodes/php-ts-mode.el index fb5cf46f9e5..33c44693cf4 100644 --- a/lisp/progmodes/php-ts-mode.el +++ b/lisp/progmodes/php-ts-mode.el @@ -1150,32 +1150,6 @@ For NODE, OVERRIDE, START, and END, see `treesit-font-lock-rules'." 'font-lock-warning-face override start end)) -(defun php-ts-mode--html-language-at-point (point) - "Return the language at POINT assuming the point is within a HTML region." - (let* ((node (treesit-node-at point 'html)) - (parent (treesit-node-parent node)) - (node-query (format "(%s (%s))" - (treesit-node-type parent) - (treesit-node-type node)))) - (cond - ((string-equal "(script_element (raw_text))" node-query) 'javascript) - ((string-equal "(style_element (raw_text))" node-query) 'css) - (t 'html)))) - -(defun php-ts-mode--language-at-point (point) - "Return the language at POINT." - (let* ((node (treesit-node-at point 'php)) - (node-type (treesit-node-type node)) - (parent (treesit-node-parent node)) - (node-query (format "(%s (%s))" (treesit-node-type parent) node-type))) - (save-excursion - (goto-char (treesit-node-start node)) - (cond - ((not (member node-query '("(program (text))" - "(text_interpolation (text))"))) - 'php) - (t (php-ts-mode--html-language-at-point point)))))) - ;;; Imenu @@ -1466,8 +1440,6 @@ Depends on `c-ts-common-comment-setup'." (start_tag (tag_name)) (raw_text) @cap)))) - (setq-local treesit-language-at-point-function #'php-ts-mode--language-at-point) - ;; Navigation. (setq-local treesit-defun-type-regexp (regexp-opt '("class_declaration" diff --git a/lisp/textmodes/mhtml-ts-mode.el b/lisp/textmodes/mhtml-ts-mode.el index 25af6a0a1e0..0c98ec472b2 100644 --- a/lisp/textmodes/mhtml-ts-mode.el +++ b/lisp/textmodes/mhtml-ts-mode.el @@ -211,21 +211,6 @@ Optional ARGUMENTS to to be passed to it." "Menu bar for `mhtml-ts-mode'." css-mode--menu) -;; To enable some basic treesiter functionality, you should define -;; a function that recognizes which grammar is used at-point. -;; This function should be assigned to `treesit-language-at-point-function' -(defun mhtml-ts-mode--language-at-point (point) - "Return the language at POINT assuming the point is within a HTML buffer." - (let* ((node (treesit-node-at point 'html)) - (parent (treesit-node-parent node)) - (node-query (format "(%s (%s))" - (treesit-node-type parent) - (treesit-node-type node)))) - (cond - ((equal "(script_element (raw_text))" node-query) (js--treesit-language-at-point point)) - ((equal "(style_element (raw_text))" node-query) 'css) - (t 'html)))) - ;; Custom font-lock function that's used to apply color to css color ;; The signature of the function should be conforming to signature ;; QUERY-SPEC required by `treesit-font-lock-rules'. @@ -440,7 +425,7 @@ Calls REPORT-FN directly. Requires tidy." ;;;###autoload (define-derived-mode mhtml-ts-mode html-ts-mode - '("HTML+" (:eval (let ((lang (mhtml-ts-mode--language-at-point (point)))) + '("HTML+" (:eval (let ((lang (treesit-language-at (point)))) (cond ((eq lang 'html) "") ((eq lang 'javascript) "JS") ((eq lang 'css) "CSS"))))) @@ -514,10 +499,6 @@ Powered by tree-sitter." (setq-local c-ts-common--comment-regexp js--treesit-jsdoc-comment-regexp)) - - ;; Many treesit functions need to know the language at-point. - ;; So you should define such a function. - (setq-local treesit-language-at-point-function #'mhtml-ts-mode--language-at-point) (setq-local prettify-symbols-alist mhtml-ts-mode--prettify-symbols-alist) ;; Indent. diff --git a/lisp/treesit.el b/lisp/treesit.el index 07861603244..888f067e0cc 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -174,26 +174,19 @@ The function is called with one argument, the position of point. In general, this function should call `treesit-node-at' with an explicit language (usually the host language), and determine the -language at point using the type of the returned node. - -DO NOT derive the language at point from parser ranges. It's -cumbersome and can't deal with some edge cases.") +language at point using the type of the returned node.") (defun treesit-language-at (position) "Return the language at POSITION. -This function assumes that parser ranges are up-to-date. It -returns the return value of `treesit-language-at-point-function' -if it's non-nil, otherwise it returns the language of the first -parser in `treesit-parser-list', or nil if there is no parser. - -In a multi-language buffer, make sure -`treesit-language-at-point-function' is implemented! Otherwise -`treesit-language-at' wouldn't return the correct result." +When there are multiple parsers that covers POSITION, determine +the most relevant parser (hence language) by their embed level. +If `treesit-language-at-point-function' is non-nil, return +the return value of that function instead." (if treesit-language-at-point-function (funcall treesit-language-at-point-function position) - (when-let* ((parser (car (treesit-parser-list)))) - (treesit-parser-language parser)))) + (treesit-parser-language + (car (treesit-parsers-at position))))) ;;; Node API supplement @@ -247,8 +240,9 @@ language and doesn't match the language of the local parser." (parser-or-lang (let* ((local-parser (car (treesit-local-parsers-at pos parser-or-lang))) - (global-parser (car (treesit-parser-list - nil parser-or-lang))) + (global-parser (car (treesit-parsers-at + pos parser-or-lang nil + '(primary global)))) (parser (or local-parser global-parser))) (when parser (treesit-parser-root-node parser)))) @@ -267,13 +261,10 @@ language and doesn't match the language of the local parser." (local-parser ;; Find the local parser with highest ;; embed-level at point. - (car (seq-sort-by #'treesit-parser-embed-level - (lambda (a b) - (> (or a 0) (or b 0))) - (treesit-local-parsers-at - pos lang)))) - (global-parser (car (treesit-parser-list - nil lang))) + (car (treesit-local-parsers-at pos lang))) + (global-parser (car (treesit-parsers-at + pos lang nil + '(primary global)))) (parser (or local-parser global-parser))) (when parser (treesit-parser-root-node parser)))))) @@ -851,30 +842,68 @@ those inside are kept." if (<= start (car range) (cdr range) end) collect range)) +(defun treesit-parsers-at (&optional pos language with-host only) + "Return all parsers at POS. + +POS defaults to point. The returned parsers are sorted by +the decreasing embed level. + +If LANGUAGE is non-nil, only return parsers for LANGUAGE. + +If WITH-HOST is non-nil, return a list of (PARSER . HOST-PARSER) +instead. HOST-PARSER is the host parser which created the PARSER. + +If ONLY is nil, return all parsers including the primary parser. + +The argument ONLY can be a list of symbols that specify what +parsers to include in the return value. + +If ONLY contains the symbol `local', include local parsers. +Local parsers are those which only parse a limited region marked +by an overlay with non-nil `treesit-parser-local-p' property. + +If ONLY contains the symbol `global', include non-local parsers +excluding the primary parser. + +If ONLY contains the symbol `primary', include the primary parser." + (let ((res nil)) + ;; Refer to (ref:local-parser-overlay) for more explanation of local + ;; parser overlays. + (dolist (ov (overlays-at (or pos (point)))) + (when-let* ((parser (overlay-get ov 'treesit-parser)) + (host-parser (or (null with-host) + (overlay-get ov 'treesit-host-parser))) + (_ (or (null language) + (eq (treesit-parser-language parser) + language))) + (_ (or (null only) + (and (memq 'local only) (memq 'global only)) + (and (memq 'local only) + (overlay-get ov 'treesit-parser-local-p)) + (and (memq 'global only) + (not (overlay-get ov 'treesit-parser-local-p)))))) + (push (if with-host (cons parser host-parser) parser) res))) + (when (or (null only) (memq 'primary only)) + (setq res (cons treesit-primary-parser res))) + (seq-sort-by (lambda (p) + (treesit-parser-embed-level + (or (car-safe p) p))) + (lambda (a b) + (> (or a 0) (or b 0))) + res))) + (defun treesit-local-parsers-at (&optional pos language with-host) "Return all the local parsers at POS. POS defaults to point. Local parsers are those which only parse a limited region marked -by an overlay with non-nil `treesit-parser' property. +by an overlay with non-nil `treesit-parser-local-p' property. If LANGUAGE is non-nil, only return parsers for LANGUAGE. If WITH-HOST is non-nil, return a list of (PARSER . HOST-PARSER) instead. HOST-PARSER is the host parser which created the local PARSER." - (let ((res nil)) - ;; Refer to (ref:local-parser-overlay) for more explanation of local - ;; parser overlays. - (dolist (ov (overlays-at (or pos (point)))) - (let ((parser (overlay-get ov 'treesit-parser)) - (host-parser (overlay-get ov 'treesit-host-parser)) - (local-p (overlay-get ov 'treesit-parser-local-p))) - (when (and parser host-parser local-p - (or (null language) - (eq (treesit-parser-language parser) - language))) - (push (if with-host (cons parser host-parser) parser) res)))) - (nreverse res))) + (treesit-parsers-at pos language with-host '(local))) (defun treesit-local-parsers-on (&optional beg end language with-host) "Return the list of local parsers that cover the region between BEG and END. @@ -883,7 +912,7 @@ BEG and END default to the beginning and end of the buffer's accessible portion. Local parsers are those that have an `embedded' tag, and only parse a -limited region marked by an overlay with a non-nil `treesit-parser' +limited region marked by an overlay with a non-nil `treesit-parser-local-p' property. If LANGUAGE is non-nil, only return parsers for LANGUAGE. If WITH-HOST is non-nil, return a list of (PARSER . HOST-PARSER) @@ -3139,9 +3168,7 @@ ARG is described in the docstring of `up-list'." (setq parent (treesit-parent-until parent pred))) (unless parent - (let ((parsers (seq-keep (lambda (o) - (overlay-get o 'treesit-host-parser)) - (overlays-at (point) t)))) + (let ((parsers (mapcar #'cdr (treesit-parsers-at (point) nil t '(global local))))) (while (and (not parent) parsers) (setq parent (treesit-parent-until (treesit-node-at (point) (car parsers)) pred) @@ -3891,9 +3918,8 @@ by `treesit-simple-imenu-settings'." (lambda (entry) (let* ((lang (car entry)) (settings (cdr entry)) - (global-parser (car (treesit-parser-list nil lang))) - (local-parsers - (treesit-parser-list nil lang 'embedded))) + (global-parser (car (treesit-parsers-at nil lang nil '(primary global)))) + (local-parsers (treesit-local-parsers-at nil lang))) (cons (treesit-language-display-name lang) ;; No one says you can't have both global and local ;; parsers for the same language. E.g., Rust uses @@ -4033,9 +4059,7 @@ For BOUND, MOVE, BACKWARD, LOOKING-AT, see the descriptions in (setq level (1+ level))) ;; Continue counting the host nodes. - (dolist (parser (seq-keep (lambda (o) - (overlay-get o 'treesit-host-parser)) - (overlays-at (point) t))) + (dolist (parser (mapcar #'cdr (treesit-parsers-at (point) nil t '(global local)))) (let* ((node (treesit-node-at (point) parser)) (lang (treesit-parser-language parser)) (pred (alist-get lang treesit-aggregated-outline-predicate))) From bec2de20469db0767d2bd7f60f0d4dfb20269614 Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Tue, 8 Apr 2025 20:43:41 +0300 Subject: [PATCH 068/395] * lisp/treesit.el (treesit--after-change): New function. (treesit-major-mode-setup): Set 'outline-minor-mode-hook' to add 'treesit--after-change' with 'treesit-update-ranges' to 'after-change-functions' (bug#77256). --- lisp/treesit.el | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/lisp/treesit.el b/lisp/treesit.el index 888f067e0cc..8e57a6dae14 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -4068,6 +4068,10 @@ For BOUND, MOVE, BACKWARD, LOOKING-AT, see the descriptions in level)) +(defun treesit--after-change (beg end _len) + "Force updating the ranges after each text change." + (treesit-update-ranges beg end)) + ;;; Hideshow mode (defun treesit-hs-block-end () @@ -4362,7 +4366,16 @@ before calling this function." (setq treesit-outline-predicate #'treesit-outline-predicate--from-imenu)) (setq-local outline-search-function #'treesit-outline-search - outline-level #'treesit-outline-level)) + outline-level #'treesit-outline-level) + (add-hook 'outline-minor-mode-hook + (lambda () + (if (bound-and-true-p outline-minor-mode) + (add-hook 'after-change-functions + #'treesit--after-change + 0 t) + (remove-hook 'after-change-functions + #'treesit--after-change t))) + nil t)) ;; Remove existing local parsers. (dolist (ov (overlays-in (point-min) (point-max))) From 0fbba16387513e7692b46885833e4a9c218251f0 Mon Sep 17 00:00:00 2001 From: Spencer Baugh Date: Mon, 18 Nov 2024 12:26:55 -0500 Subject: [PATCH 069/395] Preserve an explicit * in pcm-try-completion An explicitly typed * has different semantics from automatically inserted PCM wildcards, so it should be preserved on try-completion. We already do this in some cases, but now we do it more. This is especially significant for filename completion: removing an explicit * can take us from ~/src/emacs/trunk/*/minibuf to ~/src/emacs/trunk//minibuf The explicit double slash is interpreted by the file name completion table to mean "start completing from the root directory", so deleting the * here substantially changes semantics. * lisp/minibuffer.el (completion-pcm--merge-completions): Don't drop important wildcards. (bug#74420) * test/lisp/minibuffer-tests.el (completion-pcm-test-7): Add tests. --- lisp/minibuffer.el | 21 +++++++++++++----- test/lisp/minibuffer-tests.el | 42 +++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 99abb70b16c..d7ee7a8205a 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -4500,12 +4500,17 @@ the same set of elements." ;; Then for each of those non-constant elements, extract the ;; commonality between them. (let ((res ()) - (fixed "")) + (fixed "") + ;; Accumulate each stretch of wildcards, and process them as a unit. + (wildcards ())) ;; Make the implicit trailing `any' explicit. (dolist (elem (append pattern '(any))) (if (stringp elem) - (setq fixed (concat fixed elem)) + (progn + (setq fixed (concat fixed elem)) + (setq wildcards nil)) (let ((comps ())) + (push elem wildcards) (dolist (cc (prog1 ccs (setq ccs nil))) (push (car cc) comps) (push (cdr cc) ccs)) @@ -4529,14 +4534,16 @@ the same set of 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) + (when (seq-some (lambda (elem) (eq elem 'prefix)) wildcards) (setq prefix fixed)) (push prefix res) - (push elem res) + ;; Push all the wildcards in this stretch, to preserve `point' and + ;; `star' wildcards before ELEM. + (setq res (append wildcards res)) ;; Extract common suffix additionally to common prefix. ;; Don't do it for `any' since it could lead to a merged ;; completion that doesn't itself match the candidates. - (when (and (memq elem '(star point prefix)) + (when (and (seq-some (lambda (elem) (memq elem '(star point prefix))) wildcards) ;; If prefix is one of the completions, there's no ;; suffix left to find. (not (assoc-string prefix comps t))) @@ -4550,7 +4557,9 @@ the same set of elements." comps)))))) (cl-assert (stringp suffix)) (unless (equal suffix "") - (push suffix res))))) + (push suffix res)))) + ;; We pushed these wildcards on RES, so we're done with them. + (setq wildcards nil)) (setq fixed ""))))) ;; We return it in reverse order. res))))) diff --git a/test/lisp/minibuffer-tests.el b/test/lisp/minibuffer-tests.el index e320020d28b..59ac5ab9578 100644 --- a/test/lisp/minibuffer-tests.el +++ b/test/lisp/minibuffer-tests.el @@ -258,6 +258,48 @@ (car (completion-pcm-all-completions "li-pac*" '("do-not-list-packages") nil 7))))) +(ert-deftest completion-pcm-test-7 () + ;; Wildcards are preserved even when right before a delimiter. + (should (equal + (completion-pcm-try-completion + "x*/" + '("x1/y1" "x2/y2") + nil 3) + '("x*/y" . 4))) + ;; Or around point. + (should (equal + (completion-pcm--merge-try + '(point star "foo") '("xxfoo" "xyfoo") "" "") + '("x*foo" . 1))) + (should (equal + (completion-pcm--merge-try + '(star point "foo") '("xxfoo" "xyfoo") "" "") + '("x*foo" . 2))) + ;; This is important if the wildcard is at the start of a component. + (should (equal + (completion-pcm-try-completion + "*/minibuf" + '("lisp/minibuffer.el" "src/minibuf.c") + nil 9) + '("*/minibuf" . 9))) + ;; A series of wildcards is preserved (for now), along with point's position. + (should (equal + (completion-pcm--merge-try + '(star star point star "foo") '("xxfoo" "xyfoo") "" "") + '("x***foo" . 3))) + ;; The series of wildcards is considered together; if any of them wants the common suffix, it's generated. + (should (equal + (completion-pcm--merge-try + '(prefix any) '("xfoo" "yfoo") "" "") + '("foo" . 0))) + ;; We consider each series of wildcards separately: if one series + ;; wants the common suffix, but the next one does not, it doesn't get + ;; the common suffix. + (should (equal + (completion-pcm--merge-try + '(prefix any "bar" any) '("xbarxfoo" "ybaryfoo") "" "") + '("bar" . 3)))) + (ert-deftest completion-substring-test-1 () ;; One third of a match! (should (equal From 40b0c83988267c891e7d0ecf241cc2c0135d5ce1 Mon Sep 17 00:00:00 2001 From: Spencer Baugh Date: Wed, 2 Apr 2025 17:21:24 -0400 Subject: [PATCH 070/395] Use relative names where possible in package-quickstart.el package-quickstart.el hardcodes many absolute file names, which makes it break if user-emacs-directory moves, or in other situations. To be slightly more robust to this, use relative file names to packages that are located in the same directory as package-quickstart.el. * lisp/emacs-lisp/package.el (package--quickstart-dir, package--quickstart-rel): Add. (package-quickstart-refresh): Use package--quickstart-rel on file names. (bug#77468) --- lisp/emacs-lisp/package.el | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index b9a8dacab15..bec44a6b637 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el @@ -4591,6 +4591,19 @@ activations need to be changed, such as when `package-load-list' is modified." (delete-file (concat package-quickstart-file "c")) (delete-file package-quickstart-file))) +(defvar package--quickstart-dir nil + "Set by `package-quickstart-file' to the directory containing it.") + +(defun package--quickstart-rel (file) + "Return an expr depending on `package--quickstart-dir' which evaluates to FILE. + +If FILE is in `package--quickstart-dir', returns an expression that is +relative to that directory, so if that directory is moved we can still +find FILE." + (if (file-in-directory-p file package--quickstart-dir) + `(file-name-concat package--quickstart-dir ,(file-relative-name file package--quickstart-dir)) + file)) + (defun package-quickstart-refresh () "(Re)Generate the `package-quickstart-file'." (interactive) @@ -4605,7 +4618,8 @@ activations need to be changed, such as when `package-load-list' is modified." ;; aren't truncated. (print-length nil) (print-level nil) - (Info-directory-list '(""))) + (Info-directory-list '("")) + (package--quickstart-dir nil)) (dolist (elt package-alist) (condition-case err (package-activate (car elt)) @@ -4617,12 +4631,16 @@ activations need to be changed, such as when `package-load-list' is modified." (emacs-lisp-mode) ;For `syntax-ppss'. (insert ";;; Quickstart file to activate all packages at startup -*- lexical-binding:t -*-\n") (insert ";; ¡¡ This file is autogenerated by `package-quickstart-refresh', DO NOT EDIT !!\n\n") + (setq package--quickstart-dir + (file-name-directory (expand-file-name package-quickstart-file))) + (insert (pp '(setq package--quickstart-dir + (file-name-directory (expand-file-name load-file-name))))) (dolist (pkg package--quickstart-pkgs) (let* ((file ;; Prefer uncompiled files (and don't accept .so files). (let ((load-suffixes '(".el" ".elc"))) (locate-library (package--autoloads-file-name pkg)))) - (pfile (prin1-to-string file))) + (pfile (prin1-to-string (package--quickstart-rel file)))) (insert "(let* ((load-file-name " pfile ")\ \(load-true-file-name load-file-name))\n") (insert-file-contents file) @@ -4638,12 +4656,13 @@ activations need to be changed, such as when `package-load-list' is modified." (append ',(mapcar #'package-desc-name package--quickstart-pkgs) package-activated-list))) (current-buffer)) - (let ((info-dirs (butlast Info-directory-list))) + (let ((info-dirs + (mapcar #'package--quickstart-rel (butlast Info-directory-list)))) (when info-dirs (pp `(progn (require 'info) (info-initialize) (setq Info-directory-list - (append ',info-dirs Info-directory-list))) + (append (list . ,info-dirs) Info-directory-list))) (current-buffer)))) ;; Use `\s' instead of a space character, so this code chunk is not ;; mistaken for an actual file-local section of package.el. From 3e22c73fb612edb1879c83d24396dd8e7db40ffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Tue, 8 Apr 2025 22:15:26 +0100 Subject: [PATCH 071/395] Eglot: announce support for diagnostic version checks (bug#77588) * lisp/progmodes/eglot.el (eglot-client-capabilities): Mention versionSupport. --- lisp/progmodes/eglot.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index bfa67ebfff0..8231c542d29 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -1080,6 +1080,7 @@ object." :callHierarchy `(:dynamicRegistration :json-false) :typeHierarchy `(:dynamicRegistration :json-false) :publishDiagnostics (list :relatedInformation :json-false + :versionSupport t ;; TODO: We can support :codeDescription after ;; adding an appropriate UI to ;; Flymake. From 686032ddaf31cacae9a6cd963d9fcbc85ba3905a Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 9 Apr 2025 10:35:38 +0800 Subject: [PATCH 072/395] ; * src/minibuf.c (syms_of_minibuf): Improve some wording. --- src/minibuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/minibuf.c b/src/minibuf.c index b0d54bd51f0..28ec780b24e 100644 --- a/src/minibuf.c +++ b/src/minibuf.c @@ -2480,7 +2480,7 @@ basic completion functions like `try-completion' and `all-completions'. */); DEFVAR_BOOL ("minibuffer-allow-text-properties", minibuffer_allow_text_properties, doc: /* Non-nil means `read-from-minibuffer' should not discard text properties. -The value could be let-bound or buffer-local in the minibuffer. +Lisp code can let-bind this, or make it buffer-local in the minibuffer. This also affects `read-string', or any of the functions that do minibuffer input with completion, but it does not affect `read-minibuffer' that always discards text properties. */); From 2310c12658c4b563f9860cb1196bab0d56c6f94d Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 9 Apr 2025 11:04:26 +0800 Subject: [PATCH 073/395] ; vc-setup-buffer: Don't pass a string to buffer-live-p. --- lisp/vc/vc-dispatcher.el | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lisp/vc/vc-dispatcher.el b/lisp/vc/vc-dispatcher.el index 9e238560710..090f5fff4a9 100644 --- a/lisp/vc/vc-dispatcher.el +++ b/lisp/vc/vc-dispatcher.el @@ -177,8 +177,9 @@ Another is that undo information is not kept." (defun vc-setup-buffer (buf) "Prepare BUF for executing a slave command and make it current." (let ((camefrom (current-buffer)) - (olddir default-directory)) - (set-buffer (get-buffer-create buf)) + (olddir default-directory) + (buf (get-buffer-create buf))) + (set-buffer buf) (let ((oldproc (get-buffer-process (current-buffer)))) ;; If we wanted to wait for oldproc to finish before doing ;; something, we'd have used vc-eval-after. From 253364e2c71bfaaa3ca623ed23f1cae6548a16c7 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 9 Apr 2025 12:37:32 +0800 Subject: [PATCH 074/395] VC-Dir: Offer to register files before checking in * lisp/vc/vc.el (vc-only-files-state-and-model): Rewrite checking that all files are in compatible VC states. In particular, consistently return 'edited' when all files are either added, removed or edited, instead of allowing the return value to depend on the order of the files in VC-Dir, and offer to registered unregistered files if doing so would allow the operation to proceed. (vc-compatible-state): Delete. (vc-next-action): Replace call to vc-compatible-state. Document, in this command's docstring, the new feature implemented in vc-only-files-state-and-model. * etc/NEWS: Announce the new feature. --- etc/NEWS | 7 +++++++ lisp/vc/vc.el | 47 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index fa8b0bf89a8..71eada99ed8 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1505,6 +1505,13 @@ behavior or dispense with the prompting. These correspond to the existing 'z p' to pop a stash and 'P' to pop the stash at point (deleting the stash at point is also bound to C-k). +--- +*** VC-Dir now offers to register files when checking in mixed filesets. +Previously, if some files to be checked in were unregistered but others +were added, removed or edited, Emacs would refuse to proceed. +Now Emacs prompts to first register the unregistered files, so that all +files in the fileset are in a compatible state for a checkin. + ** Diff mode +++ diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el index bc3d4cdbb68..12f86907470 100644 --- a/lisp/vc/vc.el +++ b/lisp/vc/vc.el @@ -1288,17 +1288,40 @@ BEWARE: this function may change the current buffer." "Compute last three `vc-deduce-fileset' return value elements for FILES. FILES should be a pair, or list of pairs, of files and their VC states. BACKEND is the VC backend responsible for FILES." - (let ((state (cdar files)) - (files* (mapcar #'car - (if (proper-list-p files) files (list files))))) + (let* ((files (if (proper-list-p files) files (list files))) + files* states-alist states state) ;; Check that all files are in a consistent state, since we use that ;; state to decide which operation to perform. - (dolist (crt (cdr files)) - (unless (vc-compatible-state (cdr crt) state) - (error "\ + (pcase-dolist (`(,file . ,state) files) + (push file files*) + (push file (alist-get state states-alist nil nil #'eq))) + (setq states (mapcar #'car states-alist)) + (cond ((length= states 1) + (setq state (car states))) + ((cl-subsetp states '(added removed edited)) + (setq state 'edited)) + + ;; Special, but common case: + ;; checking in both changes and new files at once. + ((and (cl-subsetp states '(added removed edited unregistered)) + (y-or-n-p "Some files are unregistered; register them first?")) + (vc-register (list backend + (cdr (assq 'unregistered states-alist)))) + (setq state 'edited)) + + (t + (let* ((pred (lambda (elt) + (memq (car elt) '(added removed edited)))) + (compat-alist (cl-remove-if-not pred states-alist)) + (other-alist (cl-remove-if pred states-alist)) + (first (car (or compat-alist other-alist))) + (second (if compat-alist + (car other-alist) + (cadr other-alist)))) + (error "\ To apply VC operations to multiple files, the files must be in similar VC states. %s in state %s clashes with %s in state %s" - (car crt) (cdr crt) (caar files) state))) + (cadr first) (car first) (cadr second) (car second))))) (list files* state (and state (not (eq state 'unregistered)) (vc-checkout-model backend files*))))) @@ -1314,12 +1337,6 @@ To apply VC operations to multiple files, the files must be in similar VC states (or (eq (vc-checkout-model backend (list file)) 'implicit) (memq (vc-state file) '(edited needs-merge conflict)))))) -(defun vc-compatible-state (p q) - "Control which states can be in the same commit." - (or - (eq p q) - (and (member p '(edited added removed)) (member q '(edited added removed))))) - (defun vc-read-backend (prompt &optional backends default) (let ((backends (or backends vc-handled-backends)) (completion-ignore-case t)) @@ -1344,6 +1361,8 @@ For modern merging-based version control systems: backend with which to register the fileset. If every work file in the VC fileset is either added or modified, pop up a *vc-log* buffer to commit the fileset changes. + (If some are added or modified and some are unregistered, offer to + register the unregistered ones, first.) For a centralized version control system, if any work file in the VC fileset is out of date, offer to update the fileset. @@ -1432,7 +1451,7 @@ from which to check out the file(s)." ;; do nothing (message "Fileset is up-to-date")))) ;; Files have local changes - ((vc-compatible-state state 'edited) + ((memq state '(added removed edited)) (let ((ready-for-commit files)) ;; CVS, SVN and bzr don't care about read-only (bug#9781). ;; RCS does, SCCS might (someone should check...). From 09887a2d41f61dff749860fe41a5e8382bb03bd9 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 9 Apr 2025 13:34:55 +0800 Subject: [PATCH 075/395] Rename some of the new window layout commands * lisp/window-x.el (rotate-window-layout-counterclockwise): Rename to window-layout-rotate-anticlockwise. (rotate-window-layout-clockwise): Rename to window-layout-rotate-clockwise. (flip-window-layout-horizontally): Rename to window-layout-flip-leftright. (flip-window-layout-vertically): Rename to window-layout-flip-topdown. (transpose-window-layout): Rename to window-layout-transpose. * doc/lispref/windows.texi (Changing Window Layouts): * etc/NEWS: * lisp/ldefs-boot.el (rotate-window-layout-counterclockwise) (rotate-window-layout-clockwise, flip-window-layout-horizontally) (flip-window-layout-vertically, transpose-window-layout): Update for the renames. --- doc/lispref/windows.texi | 12 ++++++------ etc/NEWS | 6 +++--- lisp/ldefs-boot.el | 10 +++++----- lisp/window-x.el | 10 +++++----- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index 417c323be6b..3a8dffd1af1 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -2256,7 +2256,7 @@ unless stated otherwise. counterclockwise. @cindex rotate window layout -@deffn Command rotate-window-layout-clockwise &optional window +@deffn Command window-layout-rotate-clockwise &optional window This command rotates the window layout clockwise by 90 degrees. Imagine a layout with three live windows @var{A}, @var{B} and @var{C} as depicted on the left below. Then this command will produce the layout @@ -2276,8 +2276,8 @@ on the right. @end smallexample @end deffn -@deffn Command rotate-window-layout-counterclockwise &optional window -This is like @code{rotate-window-layout-clockwise} but rotates the +@deffn Command window-layout-rotate-anticlockwise &optional window +This is like @code{window-layout-rotate-clockwise} but rotates the layout in the opposite direction as demonstrated in the example below. @smallexample @@ -2298,7 +2298,7 @@ The next two commands @sc{flip} the window layout---rotate it around an imaginary horizontal or vertical axis. @cindex flip window layout -@deffn Command flip-window-layout-vertically &optional window +@deffn Command window-layout-flip-topdown &optional window This command flips windows such that windows on the bottom become windows on the top and vice-versa as in the example below. @@ -2316,7 +2316,7 @@ windows on the top and vice-versa as in the example below. @end smallexample @end deffn -@deffn Command flip-window-layout-horizontally &optional window +@deffn Command window-layout-flip-leftright &optional window This command rearranges window in a way that the windows on the right become the window on the left, and vice-versa. @@ -2338,7 +2338,7 @@ The next command can be used for @sc{transposing} windows---changing horizontal splits to vertical ones and vice-versa. @cindex transposing windows -@deffn Command transpose-window-layout &optional window +@deffn Command window-layout-transpose &optional window This command reorganizes windows such that every horizontal split becomes a vertical split and vice versa. diff --git a/etc/NEWS b/etc/NEWS index 71eada99ed8..8d66e4f6bdd 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -227,9 +227,9 @@ albeit as a variable, not a user option. +++ *** New functions to modify window layout. Several functions to modify the window layout have been added: -'rotate-window-layout-clockwise', 'rotate-window-layout-anticlockwise', -'flip-window-layout-vertically', 'flip-window-layout-horizontally', -'transpose-window-layout', 'rotate-windows', and 'rotate-windows-back'. +'window-layout-rotate-clockwise', 'window-layout-rotate-anticlockwise', +'window-layout-flip-topdown', 'window-layout-flip-leftright', +'window-layout-transpose', 'rotate-windows', and 'rotate-windows-back'. +++ *** Windmove commands now move to skipped windows if invoked twice in a row. diff --git a/lisp/ldefs-boot.el b/lisp/ldefs-boot.el index c1deb84754d..e1e203875f4 100644 --- a/lisp/ldefs-boot.el +++ b/lisp/ldefs-boot.el @@ -38064,7 +38064,7 @@ mode. ;;; Generated autoloads from window-x.el -(autoload 'rotate-window-layout-counterclockwise "window-x" "\ +(autoload 'window-layout-rotate-anticlockwise "window-x" "\ Rotate window layout of WINDOW counterclockwise by 90 degrees. If WINDOW is nil, it defaults to the root window of the selected frame. @@ -38073,7 +38073,7 @@ Interactively, a prefix argument says to rotate the parent window of the selected window. (fn &optional WINDOW)" t) -(autoload 'rotate-window-layout-clockwise "window-x" "\ +(autoload 'window-layout-rotate-clockwise "window-x" "\ Rotate window layout under WINDOW clockwise by 90 degrees. If WINDOW is nil, it defaults to the root window of the selected frame. @@ -38082,7 +38082,7 @@ Interactively, a prefix argument says to rotate the parent window of the selected window. (fn &optional WINDOW)" t) -(autoload 'flip-window-layout-horizontally "window-x" "\ +(autoload 'window-layout-flip-leftright "window-x" "\ Horizontally flip windows under WINDOW. Flip the window layout so that the window on the right becomes the @@ -38094,7 +38094,7 @@ Interactively, a prefix argument says to flip the parent window of the selected window. (fn &optional WINDOW)" t) -(autoload 'flip-window-layout-vertically "window-x" "\ +(autoload 'window-layout-flip-topdown "window-x" "\ Vertically flip windows under WINDOW. Flip the window layout so that the top window becomes the bottom window, @@ -38106,7 +38106,7 @@ Interactively, a prefix argument says to flip the parent window of the selected window. (fn &optional WINDOW)" t) -(autoload 'transpose-window-layout "window-x" "\ +(autoload 'window-layout-transpose "window-x" "\ Transpose windows under WINDOW. Reorganize the windows under WINDOW so that every horizontal split diff --git a/lisp/window-x.el b/lisp/window-x.el index ad34f67c9c0..37344e9101a 100644 --- a/lisp/window-x.el +++ b/lisp/window-x.el @@ -77,7 +77,7 @@ where HEIGHT and WIDTH are the normal height and width of the window. (if current-prefix-arg (window-parent) (window-main-window))) ;;;###autoload -(defun rotate-window-layout-counterclockwise (&optional window) +(defun window-layout-rotate-anticlockwise (&optional window) "Rotate window layout of WINDOW counterclockwise by 90 degrees. If WINDOW is nil, it defaults to the root window of the selected frame. @@ -88,7 +88,7 @@ selected window." (window--transpose window '(right . above) nil)) ;;;###autoload -(defun rotate-window-layout-clockwise (&optional window) +(defun window-layout-rotate-clockwise (&optional window) "Rotate window layout under WINDOW clockwise by 90 degrees. If WINDOW is nil, it defaults to the root window of the selected frame. @@ -99,7 +99,7 @@ selected window." (window--transpose window '(left . below) nil)) ;;;###autoload -(defun flip-window-layout-horizontally (&optional window) +(defun window-layout-flip-leftright (&optional window) "Horizontally flip windows under WINDOW. Flip the window layout so that the window on the right becomes the @@ -113,7 +113,7 @@ selected window." (window--transpose window '(below . left) t)) ;;;###autoload -(defun flip-window-layout-vertically (&optional window) +(defun window-layout-flip-topdown (&optional window) "Vertically flip windows under WINDOW. Flip the window layout so that the top window becomes the bottom window, @@ -127,7 +127,7 @@ selected window." (window--transpose window '(above . right) t)) ;;;###autoload -(defun transpose-window-layout (&optional window) +(defun window-layout-transpose (&optional window) "Transpose windows under WINDOW. Reorganize the windows under WINDOW so that every horizontal split From 378bea99b1a41a38c3915fa65e9adce4ec177197 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Wed, 9 Apr 2025 14:25:29 +0300 Subject: [PATCH 076/395] ; Fix doc strings of a few Dired commands * lisp/dired-aux.el (dired-do-chown, dired-do-touch) (dired-do-chgrp, dired-do-chmod): Doc fix. (Bug#77650) --- lisp/dired-aux.el | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el index a6d04647af8..bd3ab188ffa 100644 --- a/lisp/dired-aux.el +++ b/lisp/dired-aux.el @@ -490,9 +490,11 @@ List has a form of (file-name full-file-name (attribute-list))." (defun dired-do-chmod (&optional arg) "Change the mode of the marked (or next ARG) files. Both octal numeric modes like `644' and symbolic modes like `g+w' -are supported. Type \\\ -\\[next-history-element] to pull the file attributes of the file -at point into the minibuffer. +are supported. +After invoking the command, \ +type \\\\[next-history-element] \ +to pull the file attributes +of the file at point into the minibuffer. See Info node `(coreutils)File permissions' for more information. Alternatively, see the man page for \"chmod(1)\". @@ -541,9 +543,10 @@ has no effect on MS-Windows." ;;;###autoload (defun dired-do-chgrp (&optional arg) "Change the group of the marked (or next ARG) files. -Type \\\\[next-history-element] \ -to pull the file attributes of the file at point -into the minibuffer." +After invoking the command, \ +type \\\\[next-history-element] \ +to pull the file attributes +of the file at point into the minibuffer." (interactive "P" dired-mode) (if (and (memq system-type '(ms-dos windows-nt)) (not (file-remote-p default-directory))) @@ -553,9 +556,10 @@ into the minibuffer." ;;;###autoload (defun dired-do-chown (&optional arg) "Change the owner of the marked (or next ARG) files. -Type \\\\[next-history-element] \ -to pull the file attributes of the file at point -into the minibuffer." +After invoking the command, \ +type \\\\[next-history-element] \ +to pull the file attributes +of the file at point into the minibuffer." (interactive "P" dired-mode) (if (and (memq system-type '(ms-dos windows-nt)) (not (file-remote-p default-directory))) @@ -566,9 +570,10 @@ into the minibuffer." (defun dired-do-touch (&optional arg) "Change the timestamp of the marked (or next ARG) files. This calls touch. -Type Type \\\\[next-history-element] \ -to pull the file attributes of the file at point -into the minibuffer." +After invoking the command, \ +type \\\\[next-history-element] \ +to pull the file attributes +of the file at point into the minibuffer." (interactive "P" dired-mode) (dired-do-chxxx "Timestamp" dired-touch-program 'touch arg)) From 4b9d571a558fe75df67045ce5dd6d964d4956295 Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Wed, 9 Apr 2025 20:24:42 +0300 Subject: [PATCH 077/395] * lisp/subr.el (defvar-local): Change 'indent' to 'defun' (bug#77256). --- lisp/subr.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/subr.el b/lisp/subr.el index be847aab28a..164ed2a6f63 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -197,7 +197,7 @@ pair. Like `defvar' but additionally marks the variable as being automatically buffer-local wherever it is set. \n(fn SYMBOL &optional VALUE DOCSTRING)" - (declare (debug defvar) (doc-string 3) (indent 2)) + (declare (debug defvar) (doc-string 3) (indent defun)) ;; Can't use backquote here, it's too early in the bootstrap. (let ((value (car-safe args)) (docstring (car-safe (cdr-safe args)))) From fa247a24a5ec9cf10865f0ac3711eddfd0ad3546 Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Wed, 9 Apr 2025 20:40:09 +0300 Subject: [PATCH 078/395] Improve 'treesit-outline-search'. * lisp/treesit.el (treesit-outline-search): Remove temporary arg 'recursive'. Use iteration to visit more ranges until the next outline heading is found. * lisp/progmodes/php-ts-mode.el (php-ts-mode): Set 'treesit-outline-predicate' explicitly. --- lisp/progmodes/php-ts-mode.el | 12 +++++- lisp/treesit.el | 79 +++++++++++++++++++---------------- 2 files changed, 54 insertions(+), 37 deletions(-) diff --git a/lisp/progmodes/php-ts-mode.el b/lisp/progmodes/php-ts-mode.el index 33c44693cf4..2d9755d8b0a 100644 --- a/lisp/progmodes/php-ts-mode.el +++ b/lisp/progmodes/php-ts-mode.el @@ -1520,7 +1520,7 @@ Depends on `c-ts-common-comment-setup'." (setq-local electric-indent-chars (append "{}():;," electric-indent-chars)) - ;; Imenu/Which-function/Outline + ;; Imenu/Which-function (setq-local treesit-simple-imenu-settings '(("Class" "\\`class_declaration\\'" nil nil) ("Enum" "\\`enum_declaration\\'" nil nil) @@ -1532,6 +1532,16 @@ Depends on `c-ts-common-comment-setup'." ("Variable" "\\`variable_name\\'" nil nil) ("Constant" "\\`const_element\\'" nil nil))) + ;; Outline + (setq-local treesit-outline-predicate + (rx bos (or "class_declaration" + "function_definition" + "interface_declaration" + "method_declaration" + "namespace_definition" + "trait_declaration") + eos)) + ;; Font-lock. (setq-local treesit-font-lock-settings (append (php-ts-mode--font-lock-settings) diff --git a/lisp/treesit.el b/lisp/treesit.el index 8e57a6dae14..71e650ca203 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -3985,7 +3985,7 @@ this variable takes priority.") (or (and current-valid current) (and next-valid (treesit-thing-at next pred))))) -(defun treesit-outline-search (&optional bound move backward looking-at recursive) +(defun treesit-outline-search (&optional bound move backward looking-at) "Search for the next outline heading in the syntax tree. For BOUND, MOVE, BACKWARD, LOOKING-AT, see the descriptions in `outline-search-function'." @@ -4004,48 +4004,55 @@ For BOUND, MOVE, BACKWARD, LOOKING-AT, see the descriptions in (if (eq (point) (pos-bol)) (if (bobp) (point) (1- (point))) (pos-eol)))) - (pred (if treesit-aggregated-outline-predicate - (alist-get (treesit-language-at (or bob-pos pos)) - treesit-aggregated-outline-predicate) - treesit-outline-predicate)) + (pred (unless bob-pos + (if treesit-aggregated-outline-predicate + (alist-get (treesit-language-at pos) + treesit-aggregated-outline-predicate) + treesit-outline-predicate))) (found (or bob-pos (treesit-navigate-thing pos (if backward -1 1) 'beg pred))) - (closest (unless bob-pos + (closest (when (and treesit-aggregated-outline-predicate (not bob-pos)) (if backward (previous-single-char-property-change pos 'treesit-parser) (next-single-char-property-change pos 'treesit-parser))))) - ;; Handle multi-language modes - (if (and closest - (not (eq closest (if backward (point-min) (point-max)))) - (not recursive) - (or - ;; Possibly was inside the local parser, and when can't find - ;; more matches inside it then need to go over the closest - ;; parser boundary to the primary parser. - (not found) - ;; Possibly skipped the local parser, either while navigating - ;; inside the primary parser, or inside a local parser - ;; interspersed by ranges of other local parsers, e.g. - ;;