From e8b85f225d9094aa05a6be1739245e816f0101a6 Mon Sep 17 00:00:00 2001 From: Manuel Giraud Date: Fri, 6 Jan 2023 11:29:20 +0100 Subject: [PATCH 01/55] Rearrange the "Saving Emacs Sessions" section of the user manual * doc/emacs/misc.texi (Saving Emacs Sessions): Organize this node more logically with main behavior and important features near the top. (Bug#60600) --- doc/emacs/misc.texi | 136 +++++++++++++++++++++++--------------------- 1 file changed, 70 insertions(+), 66 deletions(-) diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi index 5b60e93bb3d..b707a7faa7c 100644 --- a/doc/emacs/misc.texi +++ b/doc/emacs/misc.texi @@ -2707,18 +2707,70 @@ when point is on the first byte of a multibyte sequence in the file. @cindex reload files @cindex desktop -@vindex desktop-restore-frames Use the desktop library to save the state of Emacs from one session -to another. Once you save the Emacs @dfn{desktop}---the buffers, -their file names, major modes, buffer positions, and so on---then -subsequent Emacs sessions reload the saved desktop. By default, -the desktop also tries to save 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.) +to another. The Emacs @dfn{desktop} consists of the buffers, their +file names, major modes, buffer positions, and so on. + +@vindex desktop-save-mode +@findex desktop-save-mode +To enable this feature, use the Customization buffer (@pxref{Easy +Customization}) to set @code{desktop-save-mode} to @code{t} for future +sessions, or add this line in your init file (@pxref{Init File}): + +@example +(desktop-save-mode 1) +@end example + +@vindex desktop-path +@vindex desktop-auto-save-timeout + If you turn on @code{desktop-save-mode} in your init file, then when +Emacs starts, it looks for a saved desktop in @code{desktop-path} +(which defaults to @code{user-emacs-directory} and then your home +directory) and uses the first desktop it finds. While Emacs runs with +@code{desktop-save-mode} turned on, it by default auto-saves the +desktop whenever any of it changes. The variable +@code{desktop-auto-save-timeout} determines how frequently Emacs +checks for modifications to your desktop. The desktop is also saved +when you exit Emacs. + +@findex desktop-change-dir +@findex desktop-revert + You can have separate saved desktops in different directories. You +can save the current desktop and reload one saved in another directory +by typing @kbd{M-x desktop-change-dir}. Typing @kbd{M-x +desktop-revert} reverts to the desktop previously reloaded. + +@vindex desktop-load-locked-desktop + The file in which Emacs saves the desktop is locked while the +session runs, to avoid inadvertently overwriting it from another Emacs +session. That lock is normally removed when Emacs exits, but if Emacs +or your system crashes, the lock stays, and when you restart Emacs, it +will by default ask you whether to use the locked desktop file. You +can avoid the question by customizing the variable +@code{desktop-load-locked-desktop} to either @code{nil}, which means +never load the desktop in this case, or @code{t}, which means load the +desktop without asking. Finally, the @code{check-pid} value means to +load the file if the Emacs process that has locked the desktop is not +running on the local machine. This should not be used in +circumstances where the locking Emacs might still be running on +another machine. This could be the case in multi-user environments +where your home directory is mounted remotely using NFS or similar. + +@findex desktop-save +@findex desktop-read + Whenever you want, you can use the command @kbd{M-x desktop-save} to +force saving the current desktop. If you do not want to use the +automatic @code{desktop-save-mode}, you can use @kbd{M-x desktop-save} +and then @kbd{M-x desktop-read} to restore a previous desktop. + +@vindex desktop-restore-frames + By default, the desktop also tries to save 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.) @vindex desktop-files-not-to-save -Information about buffers visiting remote files is not saved by + Information about buffers visiting remote files is not saved by default. Customize the variable @code{desktop-files-not-to-save} to change this. @@ -2733,39 +2785,6 @@ those parameters in your init file will be ignored. To disable this, customize the value of @code{frameset-filter-alist} to filter out the frame parameters you don't want to be restored. -@findex desktop-save -@vindex desktop-save-mode - You can save the desktop manually with the command @kbd{M-x -desktop-save}. You can also enable automatic saving of the desktop -when you exit Emacs, and automatic restoration of the last saved -desktop when Emacs starts: use the Customization buffer (@pxref{Easy -Customization}) to set @code{desktop-save-mode} to @code{t} for future -sessions, or add this line in your init file (@pxref{Init File}): - -@example -(desktop-save-mode 1) -@end example - -@findex desktop-change-dir -@findex desktop-revert -@vindex desktop-path - If you turn on @code{desktop-save-mode} in your init file, then when -Emacs starts, it looks for a saved desktop in the current directory. -(More precisely, it looks in the directories specified by -@code{desktop-path}, and uses the first desktop it finds.) -Thus, you can have separate saved desktops in different directories, -and the starting directory determines which one Emacs reloads. You -can save the current desktop and reload one saved in another directory -by typing @kbd{M-x desktop-change-dir}. Typing @kbd{M-x -desktop-revert} reverts to the desktop previously reloaded. - - Specify the option @samp{--no-desktop} on the command line when you -don't want it to reload any saved desktop. This turns off -@code{desktop-save-mode} for the current session. Starting Emacs with -the @samp{--no-init-file} option also disables desktop reloading, -since it bypasses the init file, where @code{desktop-save-mode} is -usually turned on. - @vindex desktop-restore-eager By default, all the buffers in the desktop are restored in one go. However, this may be slow if there are a lot of buffers in the @@ -2783,30 +2802,12 @@ 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. - If you want to save minibuffer history from one session to -another, use the @code{savehist} library. - -@vindex desktop-auto-save-timeout - While Emacs runs with @code{desktop-save-mode} turned on, it by -default auto-saves the desktop whenever any of it changes. The -variable @code{desktop-auto-save-timeout} determines how frequently -Emacs checks for modifications to your desktop. - -@vindex desktop-load-locked-desktop - The file in which Emacs saves the desktop is locked while the -session runs, to avoid inadvertently overwriting it from another Emacs -session. That lock is normally removed when Emacs exits, but if Emacs -or your system crashes, the lock stays, and when you restart Emacs, it -will by default ask you whether to use the locked desktop file. You -can avoid the question by customizing the variable -@code{desktop-load-locked-desktop} to either @code{nil}, which means -never load the desktop in this case, or @code{t}, which means load the -desktop without asking. Finally, the @code{check-pid} value means to -load the file if the Emacs process that has locked the desktop is not -running on the local machine. This should not be used in -circumstances where the locking Emacs might still be running on -another machine. This could be the case in multi-user environments -where your home directory is mounted remotely using NFS or similar. + Specify the option @samp{--no-desktop} on the command line when you +don't want it to reload any saved desktop. This turns off +@code{desktop-save-mode} for the current session. Starting Emacs with +the @samp{--no-init-file} option also disables desktop reloading, +since it bypasses the init file, where @code{desktop-save-mode} is +usually turned on. @cindex desktop restore in daemon mode When Emacs starts in daemon mode, it cannot ask you any questions, @@ -2820,6 +2821,9 @@ first client connects, by calling @code{desktop-read} in a hook function that you add to @code{server-after-make-frame-hook} (@pxref{Creating Frames,,, elisp, The Emacs Lisp Reference Manual}). + If you want to save minibuffer history from one session to +another, use the @code{savehist} library. + @node Recursive Edit @section Recursive Editing Levels @cindex recursive editing level From 7f9588685a0e1fe2dd0fcc5c3204426ac81cc6ac Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 7 Jan 2023 10:47:44 +0200 Subject: [PATCH 02/55] ; Fix last change * doc/emacs/misc.texi (Saving Emacs Sessions): Minor rewording and rearrangements. (Bug#60600) --- doc/emacs/misc.texi | 125 ++++++++++++++++++++++++-------------------- 1 file changed, 69 insertions(+), 56 deletions(-) diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi index b707a7faa7c..e2764c34482 100644 --- a/doc/emacs/misc.texi +++ b/doc/emacs/misc.texi @@ -2705,15 +2705,16 @@ when point is on the first byte of a multibyte sequence in the file. @cindex restore session @cindex remember editing session @cindex reload files -@cindex desktop - Use the desktop library to save the state of Emacs from one session -to another. The Emacs @dfn{desktop} consists of the buffers, their -file names, major modes, buffer positions, and so on. +@cindex desktop configuration + You can use the desktop library to save the state of Emacs from one +session to another. The saved Emacs @dfn{desktop configuration} +includes the buffers, their file names, major modes, buffer positions, +window and frame configuration, and some important global variables. @vindex desktop-save-mode @findex desktop-save-mode -To enable this feature, use the Customization buffer (@pxref{Easy + To enable this feature, use the Customization buffer (@pxref{Easy Customization}) to set @code{desktop-save-mode} to @code{t} for future sessions, or add this line in your init file (@pxref{Init File}): @@ -2728,17 +2729,27 @@ Emacs starts, it looks for a saved desktop in @code{desktop-path} (which defaults to @code{user-emacs-directory} and then your home directory) and uses the first desktop it finds. While Emacs runs with @code{desktop-save-mode} turned on, it by default auto-saves the -desktop whenever any of it changes. The variable -@code{desktop-auto-save-timeout} determines how frequently Emacs -checks for modifications to your desktop. The desktop is also saved -when you exit Emacs. +desktop whenever any of the desktop configuration changes. The +variable @code{desktop-auto-save-timeout} determines how frequently +Emacs checks for modifications to your desktop. The desktop is also +saved when you exit Emacs. + +@cindex disable restoring of desktop configuration + Specify the option @samp{--no-desktop} on the Emacs command line +when you don't want it to reload any saved desktop configurations. +This turns off @code{desktop-save-mode} for the current session. +Starting Emacs with the @samp{--no-init-file} option also disables +desktop reloading, since it bypasses the init file, where +@code{desktop-save-mode} is usually turned on. @findex desktop-change-dir @findex desktop-revert - You can have separate saved desktops in different directories. You -can save the current desktop and reload one saved in another directory -by typing @kbd{M-x desktop-change-dir}. Typing @kbd{M-x -desktop-revert} reverts to the desktop previously reloaded. + You can have separate saved desktop configurations in different +directories; starting Emacs from a directory where you have a saved +desktop configuration will restore that configuration. You can save +the current desktop and reload the one saved in another directory by +typing @kbd{M-x desktop-change-dir}. Typing @kbd{M-x desktop-revert} +reverts to the previously reloaded desktop. @vindex desktop-load-locked-desktop The file in which Emacs saves the desktop is locked while the @@ -2749,33 +2760,46 @@ will by default ask you whether to use the locked desktop file. You can avoid the question by customizing the variable @code{desktop-load-locked-desktop} to either @code{nil}, which means never load the desktop in this case, or @code{t}, which means load the -desktop without asking. Finally, the @code{check-pid} value means to -load the file if the Emacs process that has locked the desktop is not -running on the local machine. This should not be used in -circumstances where the locking Emacs might still be running on -another machine. This could be the case in multi-user environments -where your home directory is mounted remotely using NFS or similar. +desktop without asking. You can also customize the variable to the +special value @code{check-pid}, which means to load the file if the +Emacs process that has locked the desktop is not running on the local +machine. This should not be used in circumstances where the locking +Emacs might still be running on another machine, which could be the +case in multi-user environments where your home directory is mounted +remotely using NFS or similar. + +@cindex desktop restore in daemon mode + When Emacs starts in daemon mode, it cannot ask you any questions, +so if it finds the desktop file locked, it will not load it, unless +@code{desktop-load-locked-desktop} is @code{t}. Note that restoring +the desktop in daemon mode is somewhat problematic for other reasons: +e.g., the daemon cannot use GUI features, so parameters such as frame +position, size, and decorations cannot be restored. For that reason, +you may wish to delay restoring the desktop in daemon mode until the +first client connects, by calling @code{desktop-read} (see below) in a +hook function that you add to @code{server-after-make-frame-hook} +(@pxref{Creating Frames,,, elisp, The Emacs Lisp Reference Manual}). @findex desktop-save @findex desktop-read Whenever you want, you can use the command @kbd{M-x desktop-save} to -force saving the current desktop. If you do not want to use the -automatic @code{desktop-save-mode}, you can use @kbd{M-x desktop-save} -and then @kbd{M-x desktop-read} to restore a previous desktop. +force immediate saving of the current desktop. This is useful either +if you do not want to use the automatic desktop restoration, and thus +don't turn on @code{desktop-save-mode}, or when you have made +significant changes to the desktop, and want to make sure the +configuration doesn't get lost if Emacs or your system crashes. You +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 also tries to save 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.) - -@vindex desktop-files-not-to-save - Information about buffers visiting remote files is not saved by -default. Customize the variable @code{desktop-files-not-to-save} to -change this. + 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.) @vindex frameset-filter-alist - When the desktop restores the frame and window configuration, it + When the desktop restores the frame and window configuration, it uses the recorded values of frame parameters, disregarding any settings for those parameters you have in your init file (@pxref{Init File}). This means that frame parameters such as fonts and faces for @@ -2783,7 +2807,13 @@ the restored frames will come from the desktop file, where they were saved when you exited your previous Emacs session; any settings for those parameters in your init file will be ignored. To disable this, customize the value of @code{frameset-filter-alist} to filter out the -frame parameters you don't want to be restored. +frame parameters you don't want to be restored; they will then be set +according to your customizations in the init file. + +@vindex desktop-files-not-to-save + Information about buffers visiting remote files is not saved by +default. Customize the variable @code{desktop-files-not-to-save} to +change this. @vindex desktop-restore-eager By default, all the buffers in the desktop are restored in one go. @@ -2795,32 +2825,15 @@ remaining buffers are restored lazily, when Emacs is idle. @findex desktop-clear @vindex desktop-globals-to-clear @vindex desktop-clear-preserve-buffers-regexp - Type @kbd{M-x desktop-clear} to empty the Emacs desktop. This kills -all buffers except for internal ones, and clears the global variables -listed in @code{desktop-globals-to-clear}. If you want this to -preserve certain buffers, customize the variable + Type @kbd{M-x desktop-clear} to empty the Emacs desktop; this can be +useful, for example, if you want to switch to another desktop by +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. - Specify the option @samp{--no-desktop} on the command line when you -don't want it to reload any saved desktop. This turns off -@code{desktop-save-mode} for the current session. Starting Emacs with -the @samp{--no-init-file} option also disables desktop reloading, -since it bypasses the init file, where @code{desktop-save-mode} is -usually turned on. - -@cindex desktop restore in daemon mode - When Emacs starts in daemon mode, it cannot ask you any questions, -so if it finds the desktop file locked, it will not load it, unless -@code{desktop-load-locked-desktop} is @code{t}. Note that restoring -the desktop in daemon mode is somewhat problematic for other reasons: -e.g., the daemon cannot use GUI features, so parameters such as frame -position, size, and decorations cannot be restored. For that reason, -you may wish to delay restoring the desktop in daemon mode until the -first client connects, by calling @code{desktop-read} in a hook -function that you add to @code{server-after-make-frame-hook} -(@pxref{Creating Frames,,, elisp, The Emacs Lisp Reference Manual}). - If you want to save minibuffer history from one session to another, use the @code{savehist} library. From f58452e3ae7ed595566028010128c99e3afb572b Mon Sep 17 00:00:00 2001 From: kobarity Date: Sun, 1 Jan 2023 21:09:10 +0900 Subject: [PATCH 03/55] Fix 'python-shell-buffer-substring' when START is in middle of 1st line * lisp/progmodes/python.el (python-shell-buffer-substring): Instead of checking whether START is point-min, check whether START is in the first line. (Bug#60466) * test/lisp/progmodes/python-tests.el (python-shell-buffer-substring-18): New test. --- lisp/progmodes/python.el | 9 +++++---- test/lisp/progmodes/python-tests.el | 10 ++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 59164d7d50c..c399bbc64f8 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -3766,15 +3766,16 @@ the python shell: (line-beginning-position) start)))) (substring (buffer-substring-no-properties start end)) - (starts-at-point-min-p (save-restriction - (widen) - (= (point-min) start))) + (starts-at-first-line-p (save-restriction + (widen) + (goto-char start) + (= (line-number-at-pos) 1))) (encoding (python-info-encoding)) (toplevel-p (zerop (save-excursion (goto-char start) (python-util-forward-comment 1) (current-indentation)))) - (fillstr (cond (starts-at-point-min-p + (fillstr (cond (starts-at-first-line-p nil) ((not no-cookie) (concat diff --git a/test/lisp/progmodes/python-tests.el b/test/lisp/progmodes/python-tests.el index eac558db10f..df71990278e 100644 --- a/test/lisp/progmodes/python-tests.el +++ b/test/lisp/progmodes/python-tests.el @@ -4520,6 +4520,16 @@ def foo(): (python-tests-look-at "\"\"\"")) "# -*- coding: utf-8 -*-\n\nif True:\n a = 1\n b = 2\n\n")))) +(ert-deftest python-shell-buffer-substring-18 () + "Check substring from the part of the first line." + (python-tests-with-temp-buffer + "s = 'test' +" + (should (string= (python-shell-buffer-substring + (python-tests-look-at "'test'") + (pos-eol)) + "'test'")))) + ;;; Shell completion From e0fef510b00d00b4a2e89b310e7ac3b64ab3455b Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 7 Jan 2023 11:25:52 +0200 Subject: [PATCH 04/55] ; Minor rewording of tree-sitter terminology * doc/lispref/parsing.texi (Retrieving Nodes): Minor rewording. (Bug#60555) --- doc/lispref/parsing.texi | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi index 9635427f940..b55af912f9b 100644 --- a/doc/lispref/parsing.texi +++ b/doc/lispref/parsing.texi @@ -540,11 +540,15 @@ This function returns the list of @var{parser}'s notifier functions. Here's some terminology and conventions we use when documenting tree-sitter functions. -We talk about a node being ``smaller'' or ``larger'', and ``lower'' or -``higher''. A smaller and lower node is lower in the syntax tree and -therefore spans a smaller portion of buffer text; a larger and higher -node is higher up in the syntax tree, it contains many smaller nodes -as its children, and therefore spans a larger portion of text. +A node in a syntax tree spans some portion of the program text in the +buffer. We say that a node is ``smaller'' or ``larger'' than another +if it spans, respectively, a smaller or larger portion of buffer text +than the other node. Since nodes that are deeper (``lower'') in the +tree are children of the nodes that are ``higher'' in the tree, it +follows that a lower node will always be smaller than a node that is +higher in the node hierarchy. A node that is higher up in the syntax +tree contains one or more smaller nodes as its children, and therefore +spans a larger portion of buffer text. When a function cannot find a node, it returns @code{nil}. For convenience, all functions that take a node as argument and return From 86a3462e3d286d4d39337ad450987bbba9415f16 Mon Sep 17 00:00:00 2001 From: Dmitry Gutov Date: Sat, 7 Jan 2023 13:16:56 +0200 Subject: [PATCH 05/55] (treesit-simple-indent-presets): Do that for 'or' as well. * lisp/treesit.el (treesit-simple-indent-presets): Do that for 'or' as well. --- lisp/treesit.el | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lisp/treesit.el b/lisp/treesit.el index 11a78bddcd8..7205e43916d 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -1187,9 +1187,12 @@ See `treesit-simple-indent-presets'.") res)))) (cons 'or (lambda (&rest fns) (lambda (node parent bol &rest _) - (seq-find - (lambda (fn) (funcall fn node parent bol)) - fns)))) + (let (res) + (catch 'break + (dolist (fn fns) + (setq res (funcall fn node parent bol)) + (and res (throw 'break t)))) + res)))) (cons 'not (lambda (fn) (lambda (node parent bol &rest _) (not (funcall fn node parent bol))))) From e9341119fe462c53b1f8d6650a3b6729a0728a0a Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 7 Jan 2023 15:25:11 +0200 Subject: [PATCH 06/55] ; Fix documentation of etc/DOC * doc/lispref/help.texi (Documentation Basics): Doc strings of preloaded symbols are no longer in etc/DOC. --- doc/lispref/help.texi | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/lispref/help.texi b/doc/lispref/help.texi index de5ed76c7f7..d902113122f 100644 --- a/doc/lispref/help.texi +++ b/doc/lispref/help.texi @@ -69,14 +69,14 @@ Variables}. The string is stored in the variable's @cindex @file{DOC} (documentation) file Sometimes, Emacs does not keep documentation strings in memory. There are two such circumstances. Firstly, to save memory, the -documentation for preloaded functions and variables (including -primitives) is kept in a file named @file{DOC}, in the directory -specified by @code{doc-directory} (@pxref{Accessing Documentation}). -Secondly, when a function or variable is loaded from a byte-compiled -file, Emacs avoids loading its documentation string (@pxref{Docs and -Compilation}). In both cases, Emacs looks up the documentation string -from the file only when needed, such as when the user calls @kbd{C-h -f} (@code{describe-function}) for a function. +documentation for primitive functions (@pxref{What Is a Function}) and +built-in variables is kept in a file named @file{DOC}, in the +directory specified by @code{doc-directory} (@pxref{Accessing +Documentation}). Secondly, when a function or variable is loaded from +a byte-compiled file, Emacs avoids loading its documentation string +(@pxref{Docs and Compilation}). In both cases, Emacs looks up the +documentation string from the file only when needed, such as when the +user calls @kbd{C-h f} (@code{describe-function}) for a function. Documentation strings can contain special @dfn{key substitution sequences}, referring to key bindings which are looked up only when From 7f855b5297b2806fa508e73de98cb8cecc6e7d8d Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 7 Jan 2023 19:16:47 +0200 Subject: [PATCH 07/55] ; Fix description of etc/DOC * doc/lispref/help.texi (Accessing Documentation): Doc strings of preloaded symbols are no longer in etc/DOC. --- doc/lispref/help.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/lispref/help.texi b/doc/lispref/help.texi index d902113122f..59b6b6dab1d 100644 --- a/doc/lispref/help.texi +++ b/doc/lispref/help.texi @@ -303,7 +303,7 @@ for in the directory @code{doc-directory}. Usually @var{filename} is @defvar doc-directory This variable holds the name of the directory which should contain the file @code{"DOC"} that contains documentation strings for -built-in and preloaded functions and variables. +built-in functions and variables. In most cases, this is the same as @code{data-directory}. They may be different when you run Emacs from the directory where you built it, From 0cb686ffb6bbc017d3b71acbf40ed3e5c1a32863 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 7 Jan 2023 19:57:30 +0200 Subject: [PATCH 08/55] Document the 'definition-name' property. * doc/lispref/symbols.texi (Standard Properties): Document 'definition-name'. * doc/lispref/functions.texi (Defining Functions): Describe how to use 'definition-name' when generating function definitions at run time. (Bug#60568) --- doc/lispref/functions.texi | 14 ++++++++++++++ doc/lispref/symbols.texi | 17 +++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi index 3a8eddb93ea..f5572e447d3 100644 --- a/doc/lispref/functions.texi +++ b/doc/lispref/functions.texi @@ -685,6 +685,20 @@ Here are some examples: @end group @end example +@cindex defining functions dynamically +Most Emacs functions are part of the source code of Lisp programs, and +are defined when the Emacs Lisp reader reads the program source before +executing it. However, you can also define functions dynamically at +run time, e.g., by generating @code{defun} calls when your program's +code is executed. If you do this, be aware that Emacs's Help +commands, such as @kbd{C-h f}, which present in the @file{*Help*} +buffer a button to jump to the function's definition, might be unable +to find the source code because generating a function dynamically +usually looks very different from the usual static calls to +@code{defun}. You can make the job of finding the code which +generates such functions easier by using the @code{definition-name} +property, @pxref{Standard Properties}. + @cindex override existing functions @cindex redefine existing functions Be careful not to redefine existing functions unintentionally. diff --git a/doc/lispref/symbols.texi b/doc/lispref/symbols.texi index 183367c0cda..5b53cbe310a 100644 --- a/doc/lispref/symbols.texi +++ b/doc/lispref/symbols.texi @@ -555,6 +555,23 @@ value, saved value, customized-but-unsaved value, and themed values. Do not set them directly; they are managed by @code{defcustom} and related functions. @xref{Variable Definitions}. +@item definition-name +This property is used to find the definition of a symbol in the source +code, when it might be hard to find the definition by textual search +of the source file. For example, a @code{define-derived-mode} +(@pxref{Derived Modes}) might define a mode-specific function or a +variable implicitly; or your Lisp program might generate a run-time +call to @code{defun} to define a function (@pxref{Defining +Functions}). In these and similar cases, the @code{definition-name} +property of the symbol should be another symbol whose definition can +be found by textual search and whose code defines the original symbol. +In the example with @code{define-derived-mode}, the value of this +property of the functions and variables it defines should be the mode +symbol. The Emacs Help commands such as @kbd{C-h f} (@pxref{Help,,, +emacs, The GNU Emacs Manual}) use this property to show the definition +of a symbol via a button in the @file{*Help*} buffer where the +symbol's documentation is shown. + @item disabled If the value is non-@code{nil}, the named function is disabled as a command. @xref{Disabling Commands}. From 1df2826639c912396fac0af108301533dac71406 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 7 Jan 2023 14:58:37 -0800 Subject: [PATCH 09/55] Add c-or-c++-ts-mode (bug#59613) * lisp/progmodes/c-ts-mode.el (c-ts-mode--c-or-c++-regexp): New variable. (c-or-c++-ts-mode): New mode. * etc/NEWS: Mention c-or-c++-ts-mode. --- etc/NEWS | 5 +++++ lisp/progmodes/c-ts-mode.el | 44 +++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/etc/NEWS b/etc/NEWS index 5901b2718e9..c7cfead5fd0 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -3210,6 +3210,11 @@ programs in the C language. An optional major mode based on the tree-sitter library for editing programs in the C++ language. ++++ +*** New major mode 'c-or-c++-ts-mode'. +A function that automatically guesses the language of a header file, +and enables either 'c-ts-mode' or 'c++-ts-mode' accordingly. + +++ *** New major mode 'java-ts-mode'. An optional major mode based on the tree-sitter library for editing diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 30a14ecdfae..b8c4313c0f9 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -822,6 +822,50 @@ Set up: (treesit-major-mode-setup)) +;; We could alternatively use parsers, but if this works well, I don't +;; see the need to change. This is copied verbatim from cc-guess.el. +(defconst c-ts-mode--c-or-c++-regexp + (eval-when-compile + (let ((id "[a-zA-Z_][a-zA-Z0-9_]*") (ws "[ \t]+") (ws-maybe "[ \t]*") + (headers '("string" "string_view" "iostream" "map" "unordered_map" + "set" "unordered_set" "vector" "tuple"))) + (concat "^" ws-maybe "\\(?:" + "using" ws "\\(?:namespace" ws + "\\|" id "::" + "\\|" id ws-maybe "=\\)" + "\\|" "\\(?:inline" ws "\\)?namespace" + "\\(:?" ws "\\(?:" id "::\\)*" id "\\)?" ws-maybe "{" + "\\|" "class" ws id + "\\(?:" ws "final" "\\)?" ws-maybe "[:{;\n]" + "\\|" "struct" ws id "\\(?:" ws "final" ws-maybe "[:{\n]" + "\\|" ws-maybe ":\\)" + "\\|" "template" ws-maybe "<.*?>" + "\\|" "#include" ws-maybe "<" (regexp-opt headers) ">" + "\\)"))) + "A regexp applied to C header files to check if they are really C++.") + +;;;###autoload +(defun c-or-c++-ts-mode () + "Analyze buffer and enable either C or C++ mode. + +Some people and projects use .h extension for C++ header files +which is also the one used for C header files. This makes +matching on file name insufficient for detecting major mode that +should be used. + +This function attempts to use file contents to determine whether +the code is C or C++ and based on that chooses whether to enable +`c-ts-mode' or `c++-ts-mode'." + (interactive) + (if (save-excursion + (save-restriction + (save-match-data ; Why `save-match-data'? + (widen) + (goto-char (point-min)) + (re-search-forward c-ts-mode--c-or-c++-regexp nil t)))) + (c++-ts-mode) + (c-ts-mode))) + (provide 'c-ts-mode) ;;; c-ts-mode.el ends here From 757c2c25922e9c9dea33dd34f0112b631ea5c208 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 7 Jan 2023 15:26:56 -0800 Subject: [PATCH 10/55] Fix c-ts-mode--looking-at-star Not the topic of bug#60270 but reported in one of the replies. * lisp/progmodes/c-ts-mode.el (c-ts-mode--looking-at-star): Check not the character after point but character after BOL. Otherwise indentation is wrong when point is not at BOL. --- lisp/progmodes/c-ts-mode.el | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index b8c4313c0f9..a6ab454012d 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -205,11 +205,13 @@ beginning of grandparent." (treesit-node-parent parent) parent))))) -(defun c-ts-mode--looking-at-star (&rest _) +(defun c-ts-mode--looking-at-star (_n _p bol &rest _) "A tree-sitter simple indent matcher. Matches if there is a \"*\" after point (ignoring whitespace in between)." - (looking-at (rx (* (syntax whitespace)) "*"))) + (save-excursion + (goto-char bol) + (looking-at (rx (* (syntax whitespace)) "*")))) (defun c-ts-mode--comment-start-after-first-star (_n parent &rest _) "A tree-sitter simple indent anchor. From 7c356934fbb07d6b0f267f8d21ffc9b3f7d9d1c3 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 7 Jan 2023 15:45:05 -0800 Subject: [PATCH 11/55] Support namespaces in c++-ts-mode (bug#60397) Not a complete fix. See the next commit. * lisp/progmodes/c-ts-mode.el (c-ts-mode--indent-styles): Add rules. (c-ts-mode--defun-name): Add namespace_definition. (c-ts-base-mode): Add namespace_definition to treesit-defun-type-regexp. --- lisp/progmodes/c-ts-mode.el | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index a6ab454012d..43d714dbb20 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -151,7 +151,9 @@ MODE is either `c' or `cpp'." ((parent-is "call_expression") parent 0) ((parent-is "enumerator_list") parent-bol c-ts-mode-indent-offset) ,@(when (eq mode 'cpp) - '(((node-is "access_specifier") parent-bol 0))) + '(((node-is "access_specifier") parent-bol 0) + ;; Indent the body of namespace definitions. + ((parent-is "declaration_list") parent-bol c-ts-mode-indent-offset))) ((parent-is "field_declaration_list") parent-bol c-ts-mode-indent-offset) ((parent-is "initializer_list") parent-bol c-ts-mode-indent-offset) ((parent-is "if_statement") parent-bol c-ts-mode-indent-offset) @@ -538,7 +540,8 @@ Return nil if NODE is not a defun node or doesn't have a name." (c-ts-mode--declarator-identifier (treesit-node-child-by-field-name node "declarator"))) ((or "struct_specifier" "enum_specifier" - "union_specifier" "class_specifier") + "union_specifier" "class_specifier" + "namespace_definition") (treesit-node-child-by-field-name node "name"))) t)) @@ -743,7 +746,8 @@ Set up: "struct_specifier" "enum_specifier" "union_specifier" - "class_specifier")) + "class_specifier" + "namespace_definition")) #'c-ts-mode--defun-valid-p)) (setq-local treesit-defun-skipper #'c-ts-mode--defun-skipper) (setq-local treesit-defun-name-function #'c-ts-mode--defun-name) From 614f8c431d3e47d0e930207809454efc7118850d Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 7 Jan 2023 16:03:37 -0800 Subject: [PATCH 12/55] Optionally include the namespace in c-ts-mode--declarator-identifier This is an additional fix for bug#60397. * lisp/progmodes/c-ts-mode.el: (c-ts-mode--declarator-identifier): New parameter QUALIFIED. (c-ts-mode--defun-name): Use qualified identifier. --- lisp/progmodes/c-ts-mode.el | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 43d714dbb20..a35a0f12f51 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -423,20 +423,29 @@ MODE is either `c' or `cpp'." ;;; Font-lock helpers -(defun c-ts-mode--declarator-identifier (node) - "Return the identifier of the declarator node NODE." +(defun c-ts-mode--declarator-identifier (node &optional qualified) + "Return the identifier of the declarator node NODE. + +If QUALIFIED is non-nil, include the names space part of the +identifier and return a qualified_identifier." (pcase (treesit-node-type node) ;; Recurse. ((or "attributed_declarator" "parenthesized_declarator") - (c-ts-mode--declarator-identifier (treesit-node-child node 0 t))) + (c-ts-mode--declarator-identifier (treesit-node-child node 0 t) + qualified)) ((or "pointer_declarator" "reference_declarator") - (c-ts-mode--declarator-identifier (treesit-node-child node -1))) + (c-ts-mode--declarator-identifier (treesit-node-child node -1) + qualified)) ((or "function_declarator" "array_declarator" "init_declarator") (c-ts-mode--declarator-identifier - (treesit-node-child-by-field-name node "declarator"))) + (treesit-node-child-by-field-name node "declarator") + qualified)) ("qualified_identifier" - (c-ts-mode--declarator-identifier - (treesit-node-child-by-field-name node "name"))) + (if qualified + node + (c-ts-mode--declarator-identifier + (treesit-node-child-by-field-name node "name") + qualified))) ;; Terminal case. ((or "identifier" "field_identifier") node))) @@ -538,7 +547,8 @@ Return nil if NODE is not a defun node or doesn't have a name." (pcase (treesit-node-type node) ((or "function_definition" "declaration") (c-ts-mode--declarator-identifier - (treesit-node-child-by-field-name node "declarator"))) + (treesit-node-child-by-field-name node "declarator") + t)) ((or "struct_specifier" "enum_specifier" "union_specifier" "class_specifier" "namespace_definition") From ee3e8d3f927eba45b6863d4b2448376aacb02501 Mon Sep 17 00:00:00 2001 From: Dmitry Gutov Date: Sun, 8 Jan 2023 03:56:32 +0200 Subject: [PATCH 13/55] (ruby-ts--font-lock-settings): Improve highlighting in patterns * lisp/progmodes/ruby-ts-mode.el (ruby-ts--font-lock-settings): Improve highlighting in patterns: highlight values not keys as variable in the usual case; highlight keys when no value; highlight the "as pattern" variable. --- lisp/progmodes/ruby-ts-mode.el | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el index 5f5de500435..9ec771e2fff 100644 --- a/lisp/progmodes/ruby-ts-mode.el +++ b/lisp/progmodes/ruby-ts-mode.el @@ -304,7 +304,12 @@ values of OVERRIDE" (array_pattern (identifier) @font-lock-variable-name-face) (keyword_pattern - key: (hash_key_symbol) @font-lock-variable-name-face) + value: (identifier) @font-lock-variable-name-face) + (keyword_pattern + key: (hash_key_symbol) @font-lock-variable-name-face + !value) + (as_pattern + name: (identifier) @font-lock-variable-name-face) (in_clause pattern: (identifier) @font-lock-variable-name-face)) From 508389ad2bb3e33269a66f2fcb020839b5a9a132 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 7 Jan 2023 16:32:46 -0800 Subject: [PATCH 14/55] Add documentation for c/c++-ts-mode (bug#60443) Explain that tree-sitter c modes and cc-mode c modes don't share config variables. * lisp/progmodes/c-ts-mode.el (c-ts-mode) (c++-ts-mode): Update docstring. --- lisp/progmodes/c-ts-mode.el | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index a35a0f12f51..ae50c0ef991 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -798,7 +798,11 @@ Set up: ;;;###autoload (define-derived-mode c-ts-mode c-ts-base-mode "C" - "Major mode for editing C, powered by tree-sitter." + "Major mode for editing C, powered by tree-sitter. + +This mode is independent from the classic cc-mode.el based +`c-mode', so configuration variables of that mode, like +`c-basic-offset', don't affect this mode." :group 'c (unless (treesit-ready-p 'c) @@ -820,7 +824,11 @@ Set up: ;;;###autoload (define-derived-mode c++-ts-mode c-ts-base-mode "C++" - "Major mode for editing C++, powered by tree-sitter." + "Major mode for editing C++, powered by tree-sitter. + +This mode is independent from the classic cc-mode.el based +`c++-mode', so configuration variables of that mode, like +`c-basic-offset', don't affect this mode." :group 'c++ (unless (treesit-ready-p 'cpp) From 16f1e47ca8b2e0948691d63e8a0cbf30c5685301 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 7 Jan 2023 16:52:17 -0800 Subject: [PATCH 15/55] ; * lisp/align.el (align-c++-modes): Add c/c++-ts-mode. This fixes bug#60463. --- lisp/align.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/align.el b/lisp/align.el index 569186d241d..79a75dcec79 100644 --- a/lisp/align.el +++ b/lisp/align.el @@ -179,7 +179,8 @@ If nil, then no messages will ever be printed to the minibuffer." :type '(choice (const :tag "Align a large region silently" nil) integer) :group 'align) -(defcustom align-c++-modes '(c++-mode c-mode java-mode) +(defcustom align-c++-modes '( c++-mode c-mode java-mode + c-ts-mode c++-ts-mode) "A list of modes whose syntax resembles C/C++." :type '(repeat symbol) :group 'align) From cc1de953d4fa203b3a0c58a63e0251b515be991d Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 7 Jan 2023 16:54:43 -0800 Subject: [PATCH 16/55] ; * lisp/progmodes/gud.el (gud-tooltip-modes): Add ts- modes. Prompted by bug#60463. --- lisp/progmodes/gud.el | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lisp/progmodes/gud.el b/lisp/progmodes/gud.el index cb766c68411..3b792354cbc 100644 --- a/lisp/progmodes/gud.el +++ b/lisp/progmodes/gud.el @@ -3608,8 +3608,9 @@ Treats actions as defuns." (kill-local-variable 'gdb-define-alist) (remove-hook 'after-save-hook #'gdb-create-define-alist t)))) -(defcustom gud-tooltip-modes '(gud-mode c-mode c++-mode fortran-mode - python-mode) +(defcustom gud-tooltip-modes '( gud-mode c-mode c++-mode fortran-mode + python-mode c-ts-mode c++-ts-mode + python-ts-mode) "List of modes for which to enable GUD tooltips." :type '(repeat (symbol :tag "Major mode")) :group 'tooltip) From ef7f3c6388be1299e3834f7c96889f0e17745c24 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 7 Jan 2023 17:26:26 -0800 Subject: [PATCH 17/55] Fix use of treesit-ready-p in c/c++-ts-mode * lisp/progmodes/c-ts-mode.el: (c-ts-mode) (c++-ts-mode): Put setup code in a when form. --- lisp/progmodes/c-ts-mode.el | 52 ++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index ae50c0ef991..d2280f1d382 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -805,22 +805,17 @@ This mode is independent from the classic cc-mode.el based `c-basic-offset', don't affect this mode." :group 'c - (unless (treesit-ready-p 'c) - (error "Tree-sitter for C isn't available")) - - (treesit-parser-create 'c) - - ;; Comments. - (setq-local comment-start "/* ") - (setq-local comment-end " */") - - (setq-local treesit-simple-indent-rules - (c-ts-mode--set-indent-style 'c)) - - ;; Font-lock. - (setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'c)) - - (treesit-major-mode-setup)) + (when (treesit-ready-p 'c) + (treesit-parser-create 'c) + ;; Comments. + (setq-local comment-start "/* ") + (setq-local comment-end " */") + ;; Indent. + (setq-local treesit-simple-indent-rules + (c-ts-mode--set-indent-style 'c)) + ;; Font-lock. + (setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'c)) + (treesit-major-mode-setup))) ;;;###autoload (define-derived-mode c++-ts-mode c-ts-base-mode "C++" @@ -831,20 +826,17 @@ This mode is independent from the classic cc-mode.el based `c-basic-offset', don't affect this mode." :group 'c++ - (unless (treesit-ready-p 'cpp) - (error "Tree-sitter for C++ isn't available")) - - (treesit-parser-create 'cpp) - (setq-local syntax-propertize-function - #'c-ts-mode--syntax-propertize) - - (setq-local treesit-simple-indent-rules - (c-ts-mode--set-indent-style 'cpp)) - - ;; Font-lock. - (setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'cpp)) - - (treesit-major-mode-setup)) + (when (treesit-ready-p 'cpp) + (treesit-parser-create 'cpp) + ;; Syntax. + (setq-local syntax-propertize-function + #'c-ts-mode--syntax-propertize) + ;; Indent. + (setq-local treesit-simple-indent-rules + (c-ts-mode--set-indent-style 'cpp)) + ;; Font-lock. + (setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'cpp)) + (treesit-major-mode-setup))) ;; We could alternatively use parsers, but if this works well, I don't ;; see the need to change. This is copied verbatim from cc-guess.el. From 8575043f56b6b09001d53657f91eb2bb706e802a Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 7 Jan 2023 17:46:27 -0800 Subject: [PATCH 18/55] Remove duplicate entries in c-ts-mode's Imenu Right now the Class subindex includes top-level functions, which is wrong. This change ensures the Class subindex only contain classes and functions nested in those classes. * lisp/progmodes/c-ts-mode.el: (c-ts-mode--defun-for-class-in-imenu-p): New function. * lisp/progmodes/c-ts-mode.el (c-ts-base-mode): Use the new function. --- lisp/progmodes/c-ts-mode.el | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index d2280f1d382..3463600bda2 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -583,6 +583,23 @@ Ie, NODE is not nested." node "declarator")) "function_declarator"))))) +(defun c-ts-mode--defun-for-class-in-imenu-p (node) + "Check if NODE is a valid entry for the Class subindex. + +Basically, if NODE is a class, return non-nil; if NODE is a +function but is under a class, return non-nil; if NODE is a +top-level function, return nil. + +This is for the Class subindex in +`treesit-simple-imenu-settings'." + (pcase (treesit-node-type node) + ;; The Class subindex only has class_specifier and + ;; function_definition. + ("class_specifier" t) + ("function_definition" + ;; Return t if this function is nested in a class. + (treesit-node-top-level node "class_specifier")))) + (defun c-ts-mode--defun-skipper () "Custom defun skipper for `c-ts-mode' and friends. Structs in C ends with a semicolon, but the semicolon is not @@ -788,7 +805,7 @@ Set up: ("Class" ,(rx bos (or "class_specifier" "function_definition") eos) - ,pred nil)))) + c-ts-mode--defun-for-class-in-imenu-p nil)))) (setq-local treesit-font-lock-feature-list '(( comment definition) From 73168793c015d3da6b21bc96db784f9ef9225cbb Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 7 Jan 2023 18:11:03 -0800 Subject: [PATCH 19/55] Fix label indentation for Linux style in c-ts-mode (bug#60543) Reference: 1. https://www.gnu.org/software/indent/manual/indent/Common-styles.html 2. https://www.gnu.org/software/indent/manual/indent/Option-Summary.html The GNU indent manual says Linux style should use -il1 flag, which means "indent labels to column 1". * lisp/progmodes/c-ts-mode.el (c-ts-mode--indent-styles): Indent label to column 1 in Linux style. --- lisp/progmodes/c-ts-mode.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 3463600bda2..f58fac40ce2 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -169,7 +169,9 @@ MODE is either `c' or `cpp'." ((match "while" "do_statement") parent 0) ,@common) (k&r ,@common) - (linux ,@common) + (linux + ((node-is "labeled_statement") point-min 1) + ,@common) (bsd ((parent-is "if_statement") parent-bol 0) ((parent-is "for_statement") parent-bol 0) From 2cdd75a18ff8815ca22a04228e3282e54097e242 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jostein=20Kj=C3=B8nigsen?= Date: Wed, 4 Jan 2023 09:13:23 +0100 Subject: [PATCH 20/55] Fix highlighting of variable-declarations in typescript-ts-mode (bug#60546) - Highlight variable declarations in catch-clauses. - Remove highlighting of variables where not declarations (improve consistency with other *-ts-modes). * lisp/progmodes/typescript-ts-mode.el: (typescript-ts-mode--font-lock-settings): See above. --- lisp/progmodes/typescript-ts-mode.el | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index 5a9a7eea959..b26dca101db 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -194,7 +194,10 @@ Argument LANGUAGE is either `typescript' or `tsx'." name: (array_pattern (identifier) (identifier) @font-lock-function-name-face) - value: (array (number) (function)))) + value: (array (number) (function))) + + (catch_clause + parameter: (identifier) @font-lock-variable-name-face)) :language language :override t @@ -223,17 +226,7 @@ Argument LANGUAGE is either `typescript' or `tsx'." parameters: [(_ (identifier) @font-lock-variable-name-face) (_ (_ (identifier) @font-lock-variable-name-face)) - (_ (_ (_ (identifier) @font-lock-variable-name-face)))]) - - (return_statement (identifier) @font-lock-variable-name-face) - - (binary_expression left: (identifier) @font-lock-variable-name-face) - (binary_expression right: (identifier) @font-lock-variable-name-face) - - (arguments (identifier) @font-lock-variable-name-face) - - (parenthesized_expression (identifier) @font-lock-variable-name-face) - (parenthesized_expression (_ (identifier) @font-lock-variable-name-face))) + (_ (_ (_ (identifier) @font-lock-variable-name-face)))])) :language language :override t @@ -245,8 +238,6 @@ Argument LANGUAGE is either `typescript' or `tsx'." (pair key: (property_identifier) @font-lock-variable-name-face) - (pair value: (identifier) @font-lock-variable-name-face) - ((shorthand_property_identifier) @font-lock-property-face) ((shorthand_property_identifier_pattern) From 38b63f4c3ce55f998f00ba9a9a48d6f1b4533f7d Mon Sep 17 00:00:00 2001 From: Theodor Thornhill Date: Sat, 7 Jan 2023 13:04:07 +0100 Subject: [PATCH 21/55] Add indentation rule for concatenated_string (bug#60572) * lisp/progmodes/c-ts-mode.el (c-ts-mode--indent-styles): Indent to parent-bol. --- lisp/progmodes/c-ts-mode.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index f58fac40ce2..66f179f2f7f 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -138,6 +138,7 @@ MODE is either `c' or `cpp'." ((parent-is "function_definition") parent-bol 0) ((parent-is "conditional_expression") first-sibling 0) ((parent-is "assignment_expression") parent-bol c-ts-mode-indent-offset) + ((parent-is "concatenated_string") parent-bol c-ts-mode-indent-offset) ((parent-is "comma_expression") first-sibling 0) ((parent-is "init_declarator") parent-bol c-ts-mode-indent-offset) ((parent-is "parenthesized_expression") first-sibling 1) From 800e15e3be0569efdaa5e42c82937b1c87b7ec58 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 7 Jan 2023 18:38:24 -0800 Subject: [PATCH 22/55] Fix string-interpolation feature of python-ts-mode (bug#60599) * lisp/progmodes/python.el: (python--treesit-fontify-string-interpolation): New function. (python--treesit-settings): Use the new function for string-interpolation. --- lisp/progmodes/python.el | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index c399bbc64f8..e6ded7a0646 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -1072,6 +1072,20 @@ fontified." (treesit-fontify-with-override string-beg string-end face override start end))) +(defun python--treesit-fontify-string-interpolation + (node _ start end &rest _) + "Fontify string interpolation. +NODE is the string node. Do not fontify the initial f for +f-strings. START and END mark the region to be +fontified." + ;; This is kind of a hack, it basically removes the face applied by + ;; the string feature, so that following features can apply their + ;; face. + (let ((n-start (treesit-node-start node)) + (n-end (treesit-node-end node))) + (remove-text-properties + (max start n-start) (min end n-end) '(face)))) + (defvar python--treesit-settings (treesit-font-lock-rules :feature 'comment @@ -1082,10 +1096,12 @@ fontified." :language 'python '((string) @python--treesit-fontify-string) + ;; HACK: This feature must come after the string feature and before + ;; other features. Maybe we should make string-interpolation an + ;; option rather than a feature. :feature 'string-interpolation :language 'python - :override t - '((interpolation (identifier) @font-lock-variable-name-face)) + '((interpolation) @python--treesit-fontify-string-interpolation) :feature 'definition :language 'python From e3d806b4172f16c446bb3c5b31a160ed24fa5244 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 7 Jan 2023 18:41:28 -0800 Subject: [PATCH 23/55] Fix string fontification on python-ts-mode (bug#60599) * lisp/progmodes/python.el: (python--treesit-fontify-string): Generalize and skip anything before the first quote character. --- lisp/progmodes/python.el | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index e6ded7a0646..21d16db287c 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -1067,8 +1067,11 @@ fontified." "expression_statement")) 'font-lock-doc-face 'font-lock-string-face))) - (when (eq (char-after string-beg) ?f) - (cl-incf string-beg)) + ;; Don't highlight string prefixes like f/r/b. + (save-excursion + (goto-char string-beg) + (when (search-forward "\"" string-end t) + (setq string-beg (match-beginning 0)))) (treesit-fontify-with-override string-beg string-end face override start end))) From e04b3d41bb41ccca3d403345b12b9a614213d488 Mon Sep 17 00:00:00 2001 From: Kyle Meyer Date: Sat, 7 Jan 2023 23:50:54 -0500 Subject: [PATCH 24/55] Update to Org 9.6-90-ga6523f --- doc/misc/org.org | 11 ++++++----- lisp/org/ob-core.el | 14 ++++---------- lisp/org/ob-shell.el | 2 +- lisp/org/org-macs.el | 11 ++++++++--- lisp/org/org-persist.el | 2 +- lisp/org/org-table.el | 1 + lisp/org/org-version.el | 2 +- lisp/org/org.el | 22 +++++++++++++--------- lisp/org/ox.el | 1 - 9 files changed, 35 insertions(+), 31 deletions(-) diff --git a/doc/misc/org.org b/doc/misc/org.org index ed3eb0626f2..7ca2cce9e7f 100644 --- a/doc/misc/org.org +++ b/doc/misc/org.org @@ -1249,11 +1249,12 @@ After the drawer. #+findex: org-insert-drawer You can interactively insert a drawer at point by calling ~org-insert-drawer~, which is bound to {{{kbd(C-c C-x d)}}}. With an -active region, this command puts the region inside the drawer. With -a prefix argument, this command calls ~org-insert-property-drawer~, -which creates a =PROPERTIES= drawer right below the current headline. -Org mode uses this special drawer for storing properties (see -[[*Properties and Columns]]). You cannot use it for anything else. +active region, this command puts the region inside the drawer. With a +prefix argument, this command calls non-interactive function +~org-insert-property-drawer~, which creates a =PROPERTIES= drawer +right below the current headline. Org mode uses this special drawer +for storing properties (see [[*Properties and Columns]]). You cannot use +it for anything else. Completion over drawer keywords is also possible using {{{kbd(M-TAB)}}}[fn:6]. diff --git a/lisp/org/ob-core.el b/lisp/org/ob-core.el index 9bb77f7920b..93cdf6ae868 100644 --- a/lisp/org/ob-core.el +++ b/lisp/org/ob-core.el @@ -1690,6 +1690,7 @@ shown below. (append (split-string (if (stringp raw-result) raw-result + ;; FIXME: Arbitrary code evaluation. (eval raw-result t))) (cdr (assq :result-params params)))))) (append @@ -2860,6 +2861,7 @@ parameters when merging lists." (split-string (cond ((stringp value) value) ((functionp value) (funcall value)) + ;; FIXME: Arbitrary code evaluation. (t (eval value t))))))) (`(:exports . ,value) (setq exports (funcall merge @@ -3188,16 +3190,8 @@ situations in which is it not appropriate." ((and (not inhibit-lisp-eval) (or (memq (string-to-char cell) '(?\( ?' ?` ?\[)) (string= cell "*this*"))) - ;; Prevent arbitrary function calls. - (if (and (memq (string-to-char cell) '(?\( ?`)) - (not (org-babel-confirm-evaluate - ;; See `org-babel-get-src-block-info'. - (list "emacs-lisp" cell - '((:eval . yes)) nil (format "%s" cell) - nil nil)))) - ;; Not allowed. - (user-error "Evaluation of elisp code %S aborted." cell) - (eval (read cell) t))) + ;; FIXME: Arbitrary code evaluation. + (eval (read cell) t)) ((save-match-data (and (string-match "^[[:space:]]*\"\\(.*\\)\"[[:space:]]*$" cell) (not (string-match "[^\\]\"" (match-string 1 cell))))) diff --git a/lisp/org/ob-shell.el b/lisp/org/ob-shell.el index 4a60186cd5d..2c30a26056b 100644 --- a/lisp/org/ob-shell.el +++ b/lisp/org/ob-shell.el @@ -79,7 +79,7 @@ is modified outside the Customize interface." ,(format "Execute a block of %s commands with Babel." name) (let ((shell-file-name ,name) (org-babel-prompt-command - (or (alist-get ,name org-babel-shell-set-prompt-commands) + (or (cdr (assoc ,name org-babel-shell-set-prompt-commands)) (alist-get t org-babel-shell-set-prompt-commands)))) (org-babel-execute:shell body params)))) (eval `(defalias ',(intern (concat "org-babel-variable-assignments:" name)) diff --git a/lisp/org/org-macs.el b/lisp/org/org-macs.el index 72929cdd26c..07c668a807d 100644 --- a/lisp/org/org-macs.el +++ b/lisp/org/org-macs.el @@ -372,18 +372,23 @@ be set to a buffer or a buffer name. `shell-command' then uses it for output." (let* ((base-name (file-name-base source)) (full-name (file-truename source)) - (out-dir (or (file-name-directory source) "./")) + (relative-name (file-relative-name source)) + (out-dir (if (file-name-directory source) + ;; Expand "~". Shell expansion will be disabled + ;; in the shell command call. + (file-name-directory full-name) + "./")) (output (expand-file-name (concat base-name "." ext) out-dir)) (time (file-attribute-modification-time (file-attributes output))) (err-msg (if (stringp err-msg) (concat ". " err-msg) ""))) (save-window-excursion (pcase process - ((pred functionp) (funcall process (shell-quote-argument source))) + ((pred functionp) (funcall process (shell-quote-argument relative-name))) ((pred consp) (let ((log-buf (and log-buf (get-buffer-create log-buf))) (spec (append spec `((?b . ,(shell-quote-argument base-name)) - (?f . ,(shell-quote-argument source)) + (?f . ,(shell-quote-argument relative-name)) (?F . ,(shell-quote-argument full-name)) (?o . ,(shell-quote-argument out-dir)) (?O . ,(shell-quote-argument output)))))) diff --git a/lisp/org/org-persist.el b/lisp/org/org-persist.el index c3650c167e2..336496efbfb 100644 --- a/lisp/org/org-persist.el +++ b/lisp/org/org-persist.el @@ -753,12 +753,12 @@ with `org-persist-write'." When ASSOCIATED is `all', unregister CONTAINER everywhere." (unless org-persist--index (org-persist--load-index)) (setq container (org-persist--normalize-container container)) - (setq associated (org-persist--normalize-associated associated)) (if (eq associated 'all) (mapc (lambda (collection) (when (member container (plist-get collection :container)) (org-persist-unregister container (plist-get collection :associated)))) org-persist--index) + (setq associated (org-persist--normalize-associated associated)) (let ((collection (org-persist--find-index `(:container ,container :associated ,associated)))) (when collection (if (= (length (plist-get collection :container)) 1) diff --git a/lisp/org/org-table.el b/lisp/org/org-table.el index 06cf919db76..fac9e68c124 100644 --- a/lisp/org/org-table.el +++ b/lisp/org/org-table.el @@ -2614,6 +2614,7 @@ location of point." (if lispp (setq ev (condition-case nil + ;; FIXME: Arbitrary code evaluation. (eval (eval (read form))) (error "#ERROR")) ev (if (numberp ev) (number-to-string ev) ev) diff --git a/lisp/org/org-version.el b/lisp/org/org-version.el index dd6d92d8e58..942cc4eae8b 100644 --- a/lisp/org/org-version.el +++ b/lisp/org/org-version.el @@ -11,7 +11,7 @@ Inserted by installing Org mode or when a release is made." (defun org-git-version () "The Git version of Org mode. Inserted by installing Org or when a release is made." - (let ((org-git-version "release_9.6-81-g563a43")) + (let ((org-git-version "release_9.6-90-ga6523f")) org-git-version)) (provide 'org-version) diff --git a/lisp/org/org.el b/lisp/org/org.el index 21764f3d434..8d226c2c5ab 100644 --- a/lisp/org/org.el +++ b/lisp/org/org.el @@ -4898,16 +4898,20 @@ The following commands are available: (= (point-min) (point-max))) (insert "# -*- mode: org -*-\n\n")) (unless org-inhibit-startup + (when (or org-startup-align-all-tables org-startup-shrink-all-tables) + (org-table-map-tables + (cond ((and org-startup-align-all-tables + org-startup-shrink-all-tables) + (lambda () (org-table-align) (org-table-shrink))) + (org-startup-align-all-tables #'org-table-align) + (t #'org-table-shrink)) + t)) + ;; Suppress modification hooks to speed up the startup. + ;; However, do it only when text properties/overlays, but not + ;; buffer text are actually modified. We still need to track text + ;; modifications to make cache updates work reliably. (org-unmodified (when org-startup-with-beamer-mode (org-beamer-mode)) - (when (or org-startup-align-all-tables org-startup-shrink-all-tables) - (org-table-map-tables - (cond ((and org-startup-align-all-tables - org-startup-shrink-all-tables) - (lambda () (org-table-align) (org-table-shrink))) - (org-startup-align-all-tables #'org-table-align) - (t #'org-table-shrink)) - t)) (when org-startup-with-inline-images (org-display-inline-images)) (when org-startup-with-latex-preview (org-latex-preview '(16))) (unless org-inhibit-startup-visibility-stuff (org-cycle-set-startup-visibility)) @@ -8855,7 +8859,7 @@ keywords relative to each registered export back-end." "EXCLUDE_TAGS:" "FILETAGS:" "INCLUDE:" "INDEX:" "KEYWORDS:" "LANGUAGE:" "MACRO:" "OPTIONS:" "PROPERTY:" "PRINT_BIBLIOGRAPHY" "PRIORITIES:" "SELECT_TAGS:" "SEQ_TODO:" "SETUPFILE:" "STARTUP:" "TAGS:" "TITLE:" "TODO:" - "TYP_TODO:" "SELECT_TAGS:" "EXCLUDE_TAGS:")) + "TYP_TODO:" "SELECT_TAGS:" "EXCLUDE_TAGS:" "EXPORT_FILE_NAME:")) (defcustom org-structure-template-alist '(("a" . "export ascii") diff --git a/lisp/org/ox.el b/lisp/org/ox.el index 62fc8d583e4..12767267a71 100644 --- a/lisp/org/ox.el +++ b/lisp/org/ox.el @@ -6757,7 +6757,6 @@ Return file name as a string." (cond (pub-dir (concat (file-name-as-directory pub-dir) (file-name-nondirectory base-name))) - ((file-name-absolute-p base-name) base-name) (t base-name)))) ;; If writing to OUTPUT-FILE would overwrite original file, append ;; EXTENSION another time to final name. From fef4f18cc33754c1c06be3100563e2b0b690c067 Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Sun, 8 Jan 2023 10:56:06 +0100 Subject: [PATCH 25/55] ; Fix NEWS --- etc/NEWS | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index c7cfead5fd0..e9366fe8dd4 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -797,10 +797,10 @@ filter/sentinel error has been handled. ** New faces for font-lock. These faces are primarily meant for use with tree-sitter. They are: 'font-lock-bracket-face', 'font-lock-delimiter-face', -'font-lock-escape-face', 'font-lock-number-face', -'font-lock-regexp-face', -'font-lock-misc-punctuation-face', 'font-lock-operator-face', -'font-lock-property-face', and 'font-lock-punctuation-face'. +'font-lock-escape-face', 'font-lock-misc-punctuation-face', +'font-lock-number-face', 'font-lock-operator-face', +'font-lock-property-face', and 'font-lock-punctuation-face', +'font-lock-regexp-face'. +++ ** New face 'variable-pitch-text'. @@ -3211,8 +3211,8 @@ An optional major mode based on the tree-sitter library for editing programs in the C++ language. +++ -*** New major mode 'c-or-c++-ts-mode'. -A function that automatically guesses the language of a header file, +*** New command 'c-or-c++-ts-mode'. +A command that automatically guesses the language of a header file, and enables either 'c-ts-mode' or 'c++-ts-mode' accordingly. +++ From 53e64cfb852e8c953e90448970f7d48b3872bc1e Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 8 Jan 2023 12:23:26 +0200 Subject: [PATCH 26/55] Improve options and docs of M-x command completion * lisp/simple.el (read-extended-command-predicate): Expand the doc string. Add 2 more selectable values. (command-completion-using-modes-and-keymaps-p): New function. (execute-extended-command): Mention 'read-extended-command-predicate' in the doc string. (Bug#60645) --- lisp/simple.el | 67 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 5 deletions(-) diff --git a/lisp/simple.el b/lisp/simple.el index 63479e9ce0a..24df86c80c2 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -2207,15 +2207,39 @@ to get different commands to edit and resubmit." "Predicate to use to determine which commands to include when completing. If it's nil, include all the commands. If it's a function, it will be called with two parameters: the -symbol of the command and a buffer. The predicate should return -non-nil if the command should be present when doing \\`M-x TAB' -in that buffer." +symbol of the command and the current buffer. The predicate should +return non-nil if the command should be considered as a completion +candidate for \\`M-x' in that buffer. + +Several predicate functions suitable for various optional behaviors +are available: + + `command-completion-default-include-p' + This excludes from completion candidates those commands + which have been marked specific to modes other than the + current buffer's mode. Commands that are not specific + to any mode are included. + + `command-completion-using-modes-p' + This includes in completion candidates only commands + marked as specific to the current buffer's mode. + + `command-completion-using-modes-and-keymaps-p' + This includes commands marked as specific to the current + buffer's modes and commands that have keybindings in the + current buffer's active local keymaps. It also includes + several commands, like Cuztomize commands, which should + always be avaliable." :version "28.1" :group 'completion :type '(choice (const :tag "Don't exclude any commands" nil) (const :tag "Exclude commands irrelevant to current buffer's mode" command-completion-default-include-p) - (function :tag "Other function"))) + (const :tag "Include only commands relevant to current buffer's mode" + command-completion-using-modes-p) + (const :tag "Commands relevant to current buffer's mode or bound in its keymaps" + command-completion-using-modes-and-keymaps-p) + (function :tag "Other predicate function"))) (defun execute-extended-command-cycle () "Choose the next version of the extended command predicates. @@ -2401,6 +2425,35 @@ or (if one of MODES is a minor mode), if it is switched on in BUFFER." #'eq) (seq-intersection modes global-minor-modes #'eq))) +(defun command-completion-using-modes-and-keymaps-p (symbol buffer) + "Return non-nil if SYMBOL is marked for BUFFER's mode or bound in its keymaps." + (with-current-buffer buffer + (let ((keymaps + ;; The major mode's keymap and any active minor modes. + (nconc + (and (current-local-map) (list (current-local-map))) + (mapcar + #'cdr + (seq-filter + (lambda (elem) + (symbol-value (car elem))) + minor-mode-map-alist))))) + (or (command-completion-using-modes-p symbol buffer) + ;; Include commands that are bound in a keymap in the + ;; current buffer. + (and (where-is-internal symbol keymaps) + ;; But not if they have a command predicate that + ;; says that they shouldn't. (This is the case + ;; for `ignore' and `undefined' and similar + ;; commands commonly found in keymaps.) + (or (null (get symbol 'completion-predicate)) + (funcall (get symbol 'completion-predicate) + symbol buffer))) + ;; Include customize-* commands (do we need a list of such + ;; "always available" commands? customizable?) + (string-match-p "customize-" (symbol-name symbol)))))) + + (defun command-completion-button-p (category buffer) "Return non-nil if there's a button of CATEGORY at point in BUFFER." (with-current-buffer buffer @@ -2502,7 +2555,11 @@ Also see `suggest-key-bindings'." (defun execute-extended-command (prefixarg &optional command-name typed) "Read a command name, then read the arguments and call the command. To pass a prefix argument to the command you are -invoking, give a prefix argument to `execute-extended-command'." +invoking, give a prefix argument to `execute-extended-command'. + +This command provides completion when reading the command name. +Which completion candidates are shown can be controlled by +customizing `read-extended-command-predicate'." (declare (interactive-only command-execute)) ;; FIXME: Remember the actual text typed by the user before completion, ;; so that we don't later on suggest the same shortening. From 5cb01ac5d78e52d276857b45cd1f17e5d53b7899 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 8 Jan 2023 12:43:56 +0200 Subject: [PATCH 27/55] ; * src/callint.c (Finteractive): Fix the doc string (bug#60645). --- src/callint.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/callint.c b/src/callint.c index c60a376b958..04bd64535c9 100644 --- a/src/callint.c +++ b/src/callint.c @@ -107,9 +107,12 @@ You may use `@', `*', and `^' together. They are processed in the If MODES is present, it should be a list of mode names (symbols) that this command is applicable for. The main effect of this is that -`M-x TAB' (by default) won't list this command if the current buffer's -mode doesn't match the list. That is, if either the major mode isn't -derived from them, or (when it's a minor mode) the mode isn't in effect. +`M-x TAB' will be able to exclude this command from the list of +completion candidates if the current buffer's mode doesn't match the list. +That is, if either the major mode isn't derived from them, or (when it's +a minor mode) the mode isn't in effect. Which commands are excluded +from the list of completion candidates is controlled by the value +of `read-extended-command-predicate', which see. usage: (interactive &optional ARG-DESCRIPTOR &rest MODES) */ attributes: const) From b1aa720671efc37b85f222179d8ebc97d6d9baad Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 8 Jan 2023 12:56:13 +0200 Subject: [PATCH 28/55] ; * lisp/progmodes/ruby-ts-mode.el: Fix compilation warnings (bug#60647). --- lisp/progmodes/ruby-ts-mode.el | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el index 9ec771e2fff..d68b57966ba 100644 --- a/lisp/progmodes/ruby-ts-mode.el +++ b/lisp/progmodes/ruby-ts-mode.el @@ -82,6 +82,16 @@ (require 'ruby-mode) (declare-function treesit-parser-create "treesit.c") +(declare-function treesit-induce-sparse-tree "treesit.c") +(declare-function treesit-node-child-by-field-name "treesit.c") +(declare-function treesit-search-subtree "treesit.c") +(declare-function treesit-node-parent "treesit.c") +(declare-function treesit-node-next-sibling "treesit.c") +(declare-function treesit-node-type "treesit.c") +(declare-function treesit-node-child "treesit.c") +(declare-function treesit-node-end "treesit.c") +(declare-function treesit-node-start "treesit.c") +(declare-function treesit-node-string "treesit.c") (defgroup ruby-ts nil "Major mode for editing Ruby code." From da96a1fd74189106c065e65002c7a4ac416fb5bb Mon Sep 17 00:00:00 2001 From: Benson Chu Date: Sat, 31 Dec 2022 19:45:43 -0600 Subject: [PATCH 29/55] Add back renamed function 'font-lock-fontify-syntactically-region' A more accurate replacement for font-lock-fontify-syntactically-region would be a function that funcalls the font-lock-fontify-syntactically-function variable. That way, callers of the function can inherit new behavior, if the value of that variable changes. * lisp/font-lock.el (font-lock-fontify-syntactically-region): Add function back, remove its obsolete alias. Copyright-paperwork-exempt: yes --- lisp/font-lock.el | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lisp/font-lock.el b/lisp/font-lock.el index 99df8fb9e06..1fa45379b9f 100644 --- a/lisp/font-lock.el +++ b/lisp/font-lock.el @@ -1183,7 +1183,7 @@ This function is the default `font-lock-fontify-region-function'." (setq font-lock-syntactically-fontified end)) (font-lock-fontify-syntactic-keywords-region start end))) (unless font-lock-keywords-only - (funcall font-lock-fontify-syntactically-function beg end loudly)) + (font-lock-fontify-syntactically-region beg end loudly)) (font-lock-fontify-keywords-region beg end loudly) `(jit-lock-bounds ,beg . ,end)))) @@ -1531,6 +1531,12 @@ START should be at the beginning of a line." (defvar font-lock-comment-end-skip nil "If non-nil, Font Lock mode uses this instead of `comment-end-skip'.") +(defun font-lock-fontify-syntactically-region (beg end &optional loudly) + "Syntactically fontify the text between BEG and END. +If LOUDLY is non-nil, print status messages while fontifying. +This works by calling `font-lock-fontify-syntactically-function'." + (funcall font-lock-fontify-syntactically-function beg end loudly)) + (defun font-lock-default-fontify-syntactically (start end &optional loudly) "Put proper face on each string and comment between START and END. START should be at the beginning of a line." @@ -2369,7 +2375,6 @@ in which C preprocessor directives are used, e.g. `asm-mode' and (define-obsolete-function-alias 'font-lock-after-fontify-buffer #'ignore "29.1") (define-obsolete-function-alias 'font-lock-after-unfontify-buffer #'ignore "29.1") -(define-obsolete-function-alias 'font-lock-fontify-syntactically-region #'font-lock-default-fontify-syntactically "29.1") (provide 'font-lock) From 1469aac20d8ebcd3c5cca898b814c305278d4c27 Mon Sep 17 00:00:00 2001 From: Tad Fisher Date: Wed, 4 Jan 2023 13:40:17 -0800 Subject: [PATCH 30/55] ; * src/pgtkfns.c (parse_resource_key): Use recursive schema lookup XDG_DATA_DIRS may consist of multiple directories, and g_settings_schema_source_get_default composes these into a recursive schema source. One must pass TRUE to g_settings_schema_source_lookup, otherwise only the first directory in XDG_DATA_DIRS is searched. It follows that in the case that the directory containing the compiled GSettings schema for Emacs is not the first in XDG_DATA_DIRS, parse_resource_key will not accept any resource key, which causes pgtk_get_defaults_value and pgtk_set_defaults_value to fail. This impacts systems that compose multiple GSettings schema sources via XDG_DATA_DIRS, such Flatpak and NixOS. Supporting GIO documentation for g_settings_schema_source_get_default: > The returned source may actually consist of multiple schema sources > from different directories, depending on which directories were given > in `XDG_DATA_DIRS` and `GSETTINGS_SCHEMA_DIR`. For this reason, all > lookups performed against the default source should probably be done > recursively. Bug#60565 Copyright-paperwork-exempt: yes --- src/pgtkfns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pgtkfns.c b/src/pgtkfns.c index 6b3a0459d36..6e5bb22375a 100644 --- a/src/pgtkfns.c +++ b/src/pgtkfns.c @@ -1902,7 +1902,7 @@ parse_resource_key (const char *res_key, char *setting_key) /* check existence of setting_key */ GSettingsSchemaSource *ssrc = g_settings_schema_source_get_default (); - GSettingsSchema *scm = g_settings_schema_source_lookup (ssrc, SCHEMA_ID, FALSE); + GSettingsSchema *scm = g_settings_schema_source_lookup (ssrc, SCHEMA_ID, TRUE); if (!scm) return NULL; /* *.schema.xml is not installed. */ if (!g_settings_schema_has_key (scm, setting_key)) From d46f7f4edcce14e6cbd8e2d7091dbabbe08defc1 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sun, 8 Jan 2023 09:40:49 -0800 Subject: [PATCH 31/55] Revert "Add c-or-c++-ts-mode (bug#59613)" This reverts commit 1df2826639c912396fac0af108301533dac71406. I forgot about the feature freeze, sorry :-) --- etc/NEWS | 5 ----- lisp/progmodes/c-ts-mode.el | 44 ------------------------------------- 2 files changed, 49 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index e9366fe8dd4..a28f5c9a65a 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -3210,11 +3210,6 @@ programs in the C language. An optional major mode based on the tree-sitter library for editing programs in the C++ language. -+++ -*** New command 'c-or-c++-ts-mode'. -A command that automatically guesses the language of a header file, -and enables either 'c-ts-mode' or 'c++-ts-mode' accordingly. - +++ *** New major mode 'java-ts-mode'. An optional major mode based on the tree-sitter library for editing diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 66f179f2f7f..e1b45b06e1a 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -858,50 +858,6 @@ This mode is independent from the classic cc-mode.el based (setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'cpp)) (treesit-major-mode-setup))) -;; We could alternatively use parsers, but if this works well, I don't -;; see the need to change. This is copied verbatim from cc-guess.el. -(defconst c-ts-mode--c-or-c++-regexp - (eval-when-compile - (let ((id "[a-zA-Z_][a-zA-Z0-9_]*") (ws "[ \t]+") (ws-maybe "[ \t]*") - (headers '("string" "string_view" "iostream" "map" "unordered_map" - "set" "unordered_set" "vector" "tuple"))) - (concat "^" ws-maybe "\\(?:" - "using" ws "\\(?:namespace" ws - "\\|" id "::" - "\\|" id ws-maybe "=\\)" - "\\|" "\\(?:inline" ws "\\)?namespace" - "\\(:?" ws "\\(?:" id "::\\)*" id "\\)?" ws-maybe "{" - "\\|" "class" ws id - "\\(?:" ws "final" "\\)?" ws-maybe "[:{;\n]" - "\\|" "struct" ws id "\\(?:" ws "final" ws-maybe "[:{\n]" - "\\|" ws-maybe ":\\)" - "\\|" "template" ws-maybe "<.*?>" - "\\|" "#include" ws-maybe "<" (regexp-opt headers) ">" - "\\)"))) - "A regexp applied to C header files to check if they are really C++.") - -;;;###autoload -(defun c-or-c++-ts-mode () - "Analyze buffer and enable either C or C++ mode. - -Some people and projects use .h extension for C++ header files -which is also the one used for C header files. This makes -matching on file name insufficient for detecting major mode that -should be used. - -This function attempts to use file contents to determine whether -the code is C or C++ and based on that chooses whether to enable -`c-ts-mode' or `c++-ts-mode'." - (interactive) - (if (save-excursion - (save-restriction - (save-match-data ; Why `save-match-data'? - (widen) - (goto-char (point-min)) - (re-search-forward c-ts-mode--c-or-c++-regexp nil t)))) - (c++-ts-mode) - (c-ts-mode))) - (provide 'c-ts-mode) ;;; c-ts-mode.el ends here From ec105a45c9f8b56ade9e76324960a726eaf24038 Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Sun, 8 Jan 2023 19:24:17 +0100 Subject: [PATCH 32/55] Add remote-file-name-inhibit-delete-by-moving-to-trash * doc/emacs/files.texi (Misc File Ops): * doc/lispref/files.texi (Changing Files): * doc/misc/tramp.texi (Frequently Asked Questions): * etc/NEWS: Explain remote-file-name-inhibit-delete-by-moving-to-trash. * lisp/files.el (remote-file-name-inhibit-delete-by-moving-to-trash): New defcustom. (Bug#60460) * lisp/net/ange-ftp.el (ange-ftp-delete-file): * lisp/net/tramp.el (tramp-skeleton-delete-directory): Handle `remote-file-name-inhibit-delete-by-moving-to-trash'. (tramp-skeleton-delete-file): New defmacro. * lisp/net/tramp-adb.el (tramp-adb-handle-delete-file): * lisp/net/tramp-fuse.el (tramp-fuse-handle-delete-file): * lisp/net/tramp-gvfs.el (tramp-gvfs-handle-delete-file): * lisp/net/tramp-sh.el (tramp-sh-handle-delete-file): * lisp/net/tramp-smb.el (tramp-smb-handle-delete-file): * lisp/net/tramp-sudoedit.el (tramp-sudoedit-handle-delete-file): Use it. * lisp/net/tramp-crypt.el (tramp-crypt-handle-delete-directory) (tramp-crypt-handle-delete-file): Rearrange. * lisp/net/tramp-fuse.el (tramp-fuse-handle-delete-directory): Use `tramp-skeleton-delete-directory'. * test/lisp/net/tramp-tests.el (remote-file-name-inhibit-delete-by-moving-to-trash): Declare. (tramp-test07-file-exists-p, tramp-test14-delete-directory) (tramp-test48-unload): Extend tests. --- doc/emacs/files.texi | 5 ++++ doc/lispref/files.texi | 5 ++++ doc/misc/tramp.texi | 7 +++--- etc/NEWS | 5 ++++ lisp/files.el | 6 +++++ lisp/net/ange-ftp.el | 3 ++- lisp/net/tramp-adb.el | 12 ++++------ lisp/net/tramp-crypt.el | 8 +++---- lisp/net/tramp-fuse.el | 8 +++---- lisp/net/tramp-gvfs.el | 21 ++++++++--------- lisp/net/tramp-sh.el | 12 ++++------ lisp/net/tramp-smb.el | 29 +++++++++--------------- lisp/net/tramp-sudoedit.el | 19 +++++++--------- lisp/net/tramp.el | 38 +++++++++++++++++++++++-------- test/lisp/net/tramp-tests.el | 44 ++++++++++++++++++++++++++++++++++-- 15 files changed, 141 insertions(+), 81 deletions(-) diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi index 6a9103d3a09..42e252c417b 100644 --- a/doc/emacs/files.texi +++ b/doc/emacs/files.texi @@ -1888,6 +1888,11 @@ following in the Trash directory: liable to also delete this @code{.dir-locals.el} file, so this should only be done if you delete files from the Trash directory manually. +@vindex remote-file-name-inhibit-delete-by-moving-to-trash + If the variable @code{remote-file-name-inhibit-delete-by-moving-to-trash} +is non-@code{nil}, remote files are never moved to the Trash. They +are deleted instead. + @ifnottex If a file is under version control (@pxref{Version Control}), you should delete it using @kbd{M-x vc-delete-file} instead of @kbd{M-x diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index 91643530f7f..5cc4c1e7ddf 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi @@ -1871,6 +1871,11 @@ no prefix argument is given, and @code{nil} otherwise. See also @code{delete-directory} in @ref{Create/Delete Dirs}. @end deffn +@defopt remote-file-name-inhibit-delete-by-moving-to-trash +If this variable is non-@code{nil}, remote files are never moved to +the Trash. They are deleted instead. +@end defopt + @cindex file permissions, setting @cindex permissions, file @cindex file modes, setting diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi index 7f66dc9e849..a8a59f982fc 100644 --- a/doc/misc/tramp.texi +++ b/doc/misc/tramp.texi @@ -5215,9 +5215,10 @@ them, @ref{Misc File Ops, Trashing , , emacs}. @ifnotinfo them. @end ifnotinfo -Remote files are always trashed to the local trash, except remote -encrypted files (@pxref{Keeping files encrypted}), which are deleted -anyway. +Remote files are always trashed to the local trash, except the user +option @code{remote-file-name-inhibit-delete-by-moving-to-trash} is +non-@code{nil}, or it is a remote encrypted file (@pxref{Keeping files +encrypted}), which are deleted anyway. If Emacs is configured to use the XDG conventions for the trash directory, remote files cannot be restored with the respective tools, diff --git a/etc/NEWS b/etc/NEWS index 690e9c3faa9..60dab575da6 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -45,6 +45,11 @@ example, as part of preview for iconified frames. ** 'write-region-inhibit-fsync' now defaults to t in interactive mode, as it has in batch mode since Emacs 24. ++++ +** New user option 'remote-file-name-inhibit-delete-by-moving-to-trash'. +When non-nil, this option suppresses moving remote files to the local +trash when deleting. Default is nil. + * Editing Changes in Emacs 30.1 diff --git a/lisp/files.el b/lisp/files.el index e1b7a990b15..d0167bf3814 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -6336,6 +6336,12 @@ RECURSIVE if DIRECTORY is nonempty." directory-exists)) (files--force recursive #'delete-directory-internal directory)))))) +(defcustom remote-file-name-inhibit-delete-by-moving-to-trash nil + "Whether remote files shall be moved to the Trash. +This overrules any setting of `delete-by-moving-to-trash'." + :version "30.1" + :type 'boolean) + (defun file-equal-p (file1 file2) "Return non-nil if files FILE1 and FILE2 name the same file. If FILE1 or FILE2 does not exist, the return value is unspecified." diff --git a/lisp/net/ange-ftp.el b/lisp/net/ange-ftp.el index 41c28672aae..a14122f815a 100644 --- a/lisp/net/ange-ftp.el +++ b/lisp/net/ange-ftp.el @@ -3534,7 +3534,8 @@ system TYPE.") (setq file (expand-file-name file)) (let ((parsed (ange-ftp-ftp-name file))) (if parsed - (if (and delete-by-moving-to-trash trash) + (if (and delete-by-moving-to-trash trash + (not remote-file-name-inhibit-delete-by-moving-to-trash)) (move-file-to-trash file) (let* ((host (nth 0 parsed)) (user (nth 1 parsed)) diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el index 619d29bb4d6..493a9fb39a9 100644 --- a/lisp/net/tramp-adb.el +++ b/lisp/net/tramp-adb.el @@ -424,14 +424,10 @@ Emacs dired can't find files." (defun tramp-adb-handle-delete-file (filename &optional trash) "Like `delete-file' for Tramp files." - (setq filename (expand-file-name filename)) - (with-parsed-tramp-file-name filename nil - (tramp-flush-file-properties v localname) - (if (and delete-by-moving-to-trash trash) - (move-file-to-trash filename) - (tramp-adb-barf-unless-okay - v (format "rm %s" (tramp-shell-quote-argument localname)) - "Couldn't delete %s" filename)))) + (tramp-skeleton-delete-file filename trash + (tramp-adb-barf-unless-okay + v (format "rm %s" (tramp-shell-quote-argument localname)) + "Couldn't delete %s" filename))) (defun tramp-adb-handle-file-name-all-completions (filename directory) "Like `file-name-all-completions' for Tramp files." diff --git a/lisp/net/tramp-crypt.el b/lisp/net/tramp-crypt.el index 61d1c529619..507fd432419 100644 --- a/lisp/net/tramp-crypt.el +++ b/lisp/net/tramp-crypt.el @@ -689,17 +689,17 @@ absolute file names." (directory &optional recursive _trash) "Like `delete-directory' for Tramp files." (with-parsed-tramp-file-name (expand-file-name directory) nil - (tramp-flush-directory-properties v localname) (let (tramp-crypt-enabled) - (delete-directory (tramp-crypt-encrypt-file-name directory) recursive)))) + (delete-directory (tramp-crypt-encrypt-file-name directory) recursive)) + (tramp-flush-directory-properties v localname))) ;; Encrypted files won't be trashed. (defun tramp-crypt-handle-delete-file (filename &optional _trash) "Like `delete-file' for Tramp files." (with-parsed-tramp-file-name (expand-file-name filename) nil - (tramp-flush-file-properties v localname) (let (tramp-crypt-enabled) - (delete-file (tramp-crypt-encrypt-file-name filename))))) + (delete-file (tramp-crypt-encrypt-file-name filename))) + (tramp-flush-file-properties v localname))) (defun tramp-crypt-handle-directory-files (directory &optional full match nosort count) diff --git a/lisp/net/tramp-fuse.el b/lisp/net/tramp-fuse.el index c8754e2b03d..b846caadc18 100644 --- a/lisp/net/tramp-fuse.el +++ b/lisp/net/tramp-fuse.el @@ -34,15 +34,13 @@ (defun tramp-fuse-handle-delete-directory (directory &optional recursive trash) "Like `delete-directory' for Tramp files." - (with-parsed-tramp-file-name (expand-file-name directory) nil - (tramp-flush-directory-properties v localname) + (tramp-skeleton-delete-directory directory recursive trash (delete-directory (tramp-fuse-local-file-name directory) recursive trash))) (defun tramp-fuse-handle-delete-file (filename &optional trash) "Like `delete-file' for Tramp files." - (with-parsed-tramp-file-name (expand-file-name filename) nil - (delete-file (tramp-fuse-local-file-name filename) trash) - (tramp-flush-file-properties v localname))) + (tramp-skeleton-delete-file filename trash + (delete-file (tramp-fuse-local-file-name filename) trash))) (defvar tramp-fuse-remove-hidden-files nil "Remove hidden files from directory listings.") diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el index bb81b3eb66c..cca7a5fe247 100644 --- a/lisp/net/tramp-gvfs.el +++ b/lisp/net/tramp-gvfs.el @@ -1139,18 +1139,15 @@ file names." (defun tramp-gvfs-handle-delete-file (filename &optional trash) "Like `delete-file' for Tramp files." - (with-parsed-tramp-file-name (expand-file-name filename) nil - (tramp-flush-file-properties v localname) - (if (and delete-by-moving-to-trash trash) - (move-file-to-trash filename) - (unless (and (tramp-gvfs-send-command - v "gvfs-rm" (tramp-gvfs-url-file-name filename)) - (not (tramp-gvfs-info filename))) - ;; Propagate the error. - (with-current-buffer (tramp-get-connection-buffer v) - (goto-char (point-min)) - (tramp-error-with-buffer - nil v 'file-error "Couldn't delete %s" filename)))))) + (tramp-skeleton-delete-file filename trash + (unless (and (tramp-gvfs-send-command + v "gvfs-rm" (tramp-gvfs-url-file-name filename)) + (not (tramp-gvfs-info filename))) + ;; Propagate the error. + (with-current-buffer (tramp-get-connection-buffer v) + (goto-char (point-min)) + (tramp-error-with-buffer + nil v 'file-error "Couldn't delete %s" filename))))) (defun tramp-gvfs-handle-expand-file-name (name &optional dir) "Like `expand-file-name' for Tramp files." diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index fbdd40dd1d2..4647600071c 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -2567,14 +2567,10 @@ The method used must be an out-of-band method." (defun tramp-sh-handle-delete-file (filename &optional trash) "Like `delete-file' for Tramp files." - (setq filename (expand-file-name (expand-file-name filename))) - (with-parsed-tramp-file-name filename nil - (if (and delete-by-moving-to-trash trash) - (move-file-to-trash filename) - (tramp-barf-unless-okay - v (format "rm -f %s" (tramp-shell-quote-argument localname)) - "Couldn't delete %s" filename)) - (tramp-flush-file-properties v localname))) + (tramp-skeleton-delete-file filename trash + (tramp-barf-unless-okay + v (format "rm -f %s" (tramp-shell-quote-argument localname)) + "Couldn't delete %s" filename))) ;; Dired. diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el index f31865d498d..d6f3cca9733 100644 --- a/lisp/net/tramp-smb.el +++ b/lisp/net/tramp-smb.el @@ -695,24 +695,17 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (defun tramp-smb-handle-delete-file (filename &optional trash) "Like `delete-file' for Tramp files." - (setq filename (expand-file-name filename)) - (when (file-exists-p filename) - (with-parsed-tramp-file-name filename nil - ;; We must also flush the cache of the directory, because - ;; `file-attributes' reads the values from there. - (tramp-flush-file-properties v localname) - (if (and delete-by-moving-to-trash trash) - (move-file-to-trash filename) - (unless (tramp-smb-send-command - v (format - "%s %s" - (if (tramp-smb-get-cifs-capabilities v) "posix_unlink" "rm") - (tramp-smb-shell-quote-localname v))) - ;; Error. - (with-current-buffer (tramp-get-connection-buffer v) - (goto-char (point-min)) - (search-forward-regexp tramp-smb-errors nil t) - (tramp-error v 'file-error "%s `%s'" (match-string 0) filename))))))) + (tramp-skeleton-delete-file filename trash + (unless (tramp-smb-send-command + v (format + "%s %s" + (if (tramp-smb-get-cifs-capabilities v) "posix_unlink" "rm") + (tramp-smb-shell-quote-localname v))) + ;; Error. + (with-current-buffer (tramp-get-connection-buffer v) + (goto-char (point-min)) + (search-forward-regexp tramp-smb-errors nil t) + (tramp-error v 'file-error "%s `%s'" (match-string 0) filename))))) (defun tramp-smb-handle-expand-file-name (name &optional dir) "Like `expand-file-name' for Tramp files." diff --git a/lisp/net/tramp-sudoedit.el b/lisp/net/tramp-sudoedit.el index c4e1d32f525..2660dbb1fac 100644 --- a/lisp/net/tramp-sudoedit.el +++ b/lisp/net/tramp-sudoedit.el @@ -347,17 +347,14 @@ absolute file names." (defun tramp-sudoedit-handle-delete-file (filename &optional trash) "Like `delete-file' for Tramp files." - (with-parsed-tramp-file-name (expand-file-name filename) nil - (tramp-flush-file-properties v localname) - (if (and delete-by-moving-to-trash trash) - (move-file-to-trash filename) - (unless (tramp-sudoedit-send-command - v "rm" "-f" (file-name-unquote localname)) - ;; Propagate the error. - (with-current-buffer (tramp-get-connection-buffer v) - (goto-char (point-min)) - (tramp-error-with-buffer - nil v 'file-error "Couldn't delete %s" filename)))))) + (tramp-skeleton-delete-file filename trash + (unless (tramp-sudoedit-send-command + v "rm" "-f" (file-name-unquote localname)) + ;; Propagate the error. + (with-current-buffer (tramp-get-connection-buffer v) + (goto-char (point-min)) + (tramp-error-with-buffer + nil v 'file-error "Couldn't delete %s" filename))))) (defun tramp-sudoedit-handle-expand-file-name (name &optional dir) "Like `expand-file-name' for Tramp files. diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index 4bf0fdefc0b..b8475b7cb48 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -3399,15 +3399,35 @@ BODY is the backend specific code." BODY is the backend specific code." (declare (indent 3) (debug t)) `(with-parsed-tramp-file-name (expand-file-name ,directory) nil - (if (and delete-by-moving-to-trash ,trash) - ;; Move non-empty dir to trash only if recursive deletion was - ;; requested. - (if (not (or ,recursive (tramp-compat-directory-empty-p ,directory))) - (tramp-error - v 'file-error "Directory is not empty, not moving to trash") - (move-file-to-trash ,directory)) - ,@body) - (tramp-flush-directory-properties v localname))) + (let ((delete-by-moving-to-trash + (and delete-by-moving-to-trash + ;; This variable exists since Emacs 30.1. + (not (bound-and-true-p + remote-file-name-inhibit-delete-by-moving-to-trash))))) + (if (and delete-by-moving-to-trash ,trash) + ;; Move non-empty dir to trash only if recursive deletion was + ;; requested. + (if (not (or ,recursive (tramp-compat-directory-empty-p ,directory))) + (tramp-error + v 'file-error "Directory is not empty, not moving to trash") + (move-file-to-trash ,directory)) + ,@body) + (tramp-flush-directory-properties v localname)))) + +(defmacro tramp-skeleton-delete-file (filename &optional trash &rest body) + "Skeleton for `tramp-*-handle-delete-file'. +BODY is the backend specific code." + (declare (indent 2) (debug t)) + `(with-parsed-tramp-file-name (expand-file-name ,filename) nil + (let ((delete-by-moving-to-trash + (and delete-by-moving-to-trash + ;; This variable exists since Emacs 30.1. + (not (bound-and-true-p + remote-file-name-inhibit-delete-by-moving-to-trash))))) + (if (and delete-by-moving-to-trash ,trash) + (move-file-to-trash ,filename) + ,@body) + (tramp-flush-file-properties v localname)))) (defmacro tramp-skeleton-directory-files (directory &optional full match nosort count &rest body) diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el index 90f6fcd6b15..dd3de27d3b9 100644 --- a/test/lisp/net/tramp-tests.el +++ b/test/lisp/net/tramp-tests.el @@ -80,6 +80,9 @@ (defvar remote-file-name-inhibit-locks) (defvar dired-copy-dereference) +;; Declared in Emacs 30. +(defvar remote-file-name-inhibit-delete-by-moving-to-trash) + ;; `ert-resource-file' was introduced in Emacs 28.1. (unless (macrop 'ert-resource-file) (eval-and-compile @@ -2345,7 +2348,24 @@ This checks also `file-name-as-directory', `file-name-directory', (expand-file-name (file-name-nondirectory tmp-name) trash-directory)))) (delete-directory trash-directory 'recursive) - (should-not (file-exists-p trash-directory))))))) + (should-not (file-exists-p trash-directory)))) + + ;; Setting `remote-file-name-inhibit-delete-by-moving-to-trash' + ;; prevents trashing remote files. + (let ((trash-directory (tramp--test-make-temp-name 'local quoted)) + (delete-by-moving-to-trash t) + (remote-file-name-inhibit-delete-by-moving-to-trash t)) + (make-directory trash-directory) + (should-not (file-exists-p tmp-name)) + (write-region "foo" nil tmp-name) + (should (file-exists-p tmp-name)) + (delete-file tmp-name 'trash) + (should-not (file-exists-p tmp-name)) + (should-not + (file-exists-p + (expand-file-name (file-name-nondirectory tmp-name) trash-directory))) + (delete-directory trash-directory 'recursive) + (should-not (file-exists-p trash-directory)))))) (ert-deftest tramp-test08-file-local-copy () "Check `file-local-copy'." @@ -2953,7 +2973,23 @@ This tests also `file-directory-p' and `file-accessible-directory-p'." "%s/%s/%s/bla" trash-directory (file-name-nondirectory tmp-name1) (file-name-nondirectory tmp-name2)))) (delete-directory trash-directory 'recursive) - (should-not (file-exists-p trash-directory))))))) + (should-not (file-exists-p trash-directory)))) + + ;; Setting `remote-file-name-inhibit-delete-by-moving-to-trash' + ;; prevents trashing remote files. + (let ((trash-directory (tramp--test-make-temp-name 'local quoted)) + (delete-by-moving-to-trash t) + (remote-file-name-inhibit-delete-by-moving-to-trash t)) + (make-directory trash-directory) + (make-directory tmp-name1) + (should (file-directory-p tmp-name1)) + (delete-directory tmp-name1 nil 'trash) + (should-not (file-exists-p tmp-name1)) + (should-not + (file-exists-p + (expand-file-name (file-name-nondirectory tmp-name1) trash-directory))) + (delete-directory trash-directory 'recursive) + (should-not (file-exists-p trash-directory)))))) (ert-deftest tramp-test15-copy-directory () "Check `copy-directory'." @@ -7518,6 +7554,8 @@ Since it unloads Tramp, it shall be the last test to run." ;; `tramp-register-archive-file-name-handler' is autoloaded ;; in Emacs < 29.1. (not (eq 'tramp-register-archive-file-name-handler x)) + ;; `tramp-compat-rx' is autoloaded in Emacs 29.1. + (not (eq 'tramp-compat-rx x)) (not (string-match-p (rx bol "tramp" (? "-archive") (** 1 2 "-") "test") (symbol-name x))) @@ -7577,6 +7615,8 @@ If INTERACTIVE is non-nil, the tests are run interactively." ;; * file-equal-p (partly done in `tramp-test21-file-links') ;; * file-in-directory-p ;; * file-name-case-insensitive-p +;; * memory-info +;; * tramp-get-home-directory ;; * tramp-get-remote-gid ;; * tramp-get-remote-groups ;; * tramp-get-remote-uid From 20f36c8f6f98478dd86ddfe93da2803de2518ea2 Mon Sep 17 00:00:00 2001 From: Dmitry Gutov Date: Mon, 9 Jan 2023 00:57:36 +0200 Subject: [PATCH 33/55] ; ruby.rb: Fix pattern matching syntax and extend the example --- test/lisp/progmodes/ruby-mode-resources/ruby.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lisp/progmodes/ruby-mode-resources/ruby.rb b/test/lisp/progmodes/ruby-mode-resources/ruby.rb index bfae948b259..3f0dfdf68ba 100644 --- a/test/lisp/progmodes/ruby-mode-resources/ruby.rb +++ b/test/lisp/progmodes/ruby-mode-resources/ruby.rb @@ -513,7 +513,7 @@ foo bar, { case translation in ['th', orig_text, 'en', trans_text] puts "English translation: #{orig_text} => #{trans_text}" -in {'th' => orig_text, 'ja' => trans_text} +in {th: orig_text, ja: trans_text} => whole puts "Japanese translation: #{orig_text} => #{trans_text}" end From dc911e4ba5ccfc99d66504b6e99c9abcf3e617f3 Mon Sep 17 00:00:00 2001 From: Evgeni Kolev Date: Thu, 29 Dec 2022 17:49:40 +0200 Subject: [PATCH 34/55] Improve go-ts-mode Imenu, navigation and electric pair (bug#60407) The Imenu items are extended to support "Method", "Struct", "Interface", "Alias" and "Type". go-ts-mode is updated to use the Imenu facility added in commit b39dc7ab27a696a8607ab859aeff3c71509231f5. Variable electric-indent-chars is set in order to improve integration with Electric Pair mode. * lisp/progmodes/go-ts-mode.el (go-ts-mode--imenu-1) (go-ts-mode--imenu): Remove functions. (go-ts-mode--defun-name, go-ts-mode--interface-node-p) (go-ts-mode--struct-node-p, go-ts-mode--other-type-node-p) (go-ts-mode--alias-node-p): New functions. (go-ts-mode): Improve Imenu settings, navigation, add Electric Pair mode settings. --- lisp/progmodes/go-ts-mode.el | 107 ++++++++++++++++++++++------------- 1 file changed, 67 insertions(+), 40 deletions(-) diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el index 1d6a8a30db5..64e761d2f72 100644 --- a/lisp/progmodes/go-ts-mode.el +++ b/lisp/progmodes/go-ts-mode.el @@ -36,6 +36,7 @@ (declare-function treesit-node-child-by-field-name "treesit.c") (declare-function treesit-node-start "treesit.c") (declare-function treesit-node-type "treesit.c") +(declare-function treesit-search-subtree "treesit.c") (defcustom go-ts-mode-indent-offset 4 "Number of spaces for each indentation step in `go-ts-mode'." @@ -173,44 +174,6 @@ '((ERROR) @font-lock-warning-face)) "Tree-sitter font-lock settings for `go-ts-mode'.") -(defun go-ts-mode--imenu () - "Return Imenu alist for the current buffer." - (let* ((node (treesit-buffer-root-node)) - (func-tree (treesit-induce-sparse-tree - node "function_declaration" nil 1000)) - (type-tree (treesit-induce-sparse-tree - node "type_spec" nil 1000)) - (func-index (go-ts-mode--imenu-1 func-tree)) - (type-index (go-ts-mode--imenu-1 type-tree))) - (append - (when func-index `(("Function" . ,func-index))) - (when type-index `(("Type" . ,type-index)))))) - -(defun go-ts-mode--imenu-1 (node) - "Helper for `go-ts-mode--imenu'. -Find string representation for NODE and set marker, then recurse -the subtrees." - (let* ((ts-node (car node)) - (children (cdr node)) - (subtrees (mapcan #'go-ts-mode--imenu-1 - children)) - (name (when ts-node - (treesit-node-text - (pcase (treesit-node-type ts-node) - ("function_declaration" - (treesit-node-child-by-field-name ts-node "name")) - ("type_spec" - (treesit-node-child-by-field-name ts-node "name")))))) - (marker (when ts-node - (set-marker (make-marker) - (treesit-node-start ts-node))))) - (cond - ((or (null ts-node) (null name)) subtrees) - (subtrees - `((,name ,(cons name marker) ,@subtrees))) - (t - `((,name . ,marker)))))) - ;;;###autoload (add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode)) @@ -228,14 +191,30 @@ the subtrees." (setq-local comment-end "") (setq-local comment-start-skip (rx "//" (* (syntax whitespace)))) + ;; Navigation. + (setq-local treesit-defun-type-regexp + (regexp-opt '("method_declaration" + "function_declaration" + "type_declaration"))) + (setq-local treesit-defun-name-function #'go-ts-mode--defun-name) + ;; Imenu. - (setq-local imenu-create-index-function #'go-ts-mode--imenu) - (setq-local which-func-functions nil) + (setq-local treesit-simple-imenu-settings + `(("Function" "\\`function_declaration\\'" nil nil) + ("Method" "\\`method_declaration\\'" nil nil) + ("Struct" "\\`type_declaration\\'" go-ts-mode--struct-node-p nil) + ("Interface" "\\`type_declaration\\'" go-ts-mode--interface-node-p nil) + ("Type" "\\`type_declaration\\'" go-ts-mode--other-type-node-p nil) + ("Alias" "\\`type_declaration\\'" go-ts-mode--alias-node-p nil))) ;; Indent. (setq-local indent-tabs-mode t treesit-simple-indent-rules go-ts-mode--indent-rules) + ;; Electric + (setq-local electric-indent-chars + (append "{}()" electric-indent-chars)) + ;; Font-lock. (setq-local treesit-font-lock-settings go-ts-mode--font-lock-settings) (setq-local treesit-font-lock-feature-list @@ -247,6 +226,54 @@ the subtrees." (treesit-major-mode-setup))) +(defun go-ts-mode--defun-name (node) + "Return the defun name of NODE. +Return nil if there is no name or if NODE is not a defun node." + (pcase (treesit-node-type node) + ("function_declaration" + (treesit-node-text + (treesit-node-child-by-field-name + node "name") + t)) + ("method_declaration" + (let* ((receiver-node (treesit-node-child-by-field-name node "receiver")) + (type-node (treesit-search-subtree receiver-node "type_identifier")) + (name-node (treesit-node-child-by-field-name node "name"))) + (concat + "(" (treesit-node-text type-node) ")." + (treesit-node-text name-node)))) + ("type_declaration" + (treesit-node-text + (treesit-node-child-by-field-name + (treesit-node-child node 0 t) "name") + t)))) + +(defun go-ts-mode--interface-node-p (node) + "Return t if NODE is an interface." + (and + (string-equal "type_declaration" (treesit-node-type node)) + (treesit-search-subtree node "interface_type" nil nil 2))) + +(defun go-ts-mode--struct-node-p (node) + "Return t if NODE is a struct." + (and + (string-equal "type_declaration" (treesit-node-type node)) + (treesit-search-subtree node "struct_type" nil nil 2))) + +(defun go-ts-mode--alias-node-p (node) + "Return t if NODE is a type alias." + (and + (string-equal "type_declaration" (treesit-node-type node)) + (treesit-search-subtree node "type_alias" nil nil 1))) + +(defun go-ts-mode--other-type-node-p (node) + "Return t if NODE is a type, other than interface, struct or alias." + (and + (string-equal "type_declaration" (treesit-node-type node)) + (not (go-ts-mode--interface-node-p node)) + (not (go-ts-mode--struct-node-p node)) + (not (go-ts-mode--alias-node-p node)))) + ;; go.mod support. (defvar go-mod-ts-mode--syntax-table From 1238fa8e49bdb12db66d856dcb4b192db5d026ff Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sun, 8 Jan 2023 16:57:29 -0800 Subject: [PATCH 35/55] Fix label indent of GNU and Linux style in c-ts-mode (bug#60543) The previous fix isn't correct. * lisp/progmodes/c-ts-mode.el: (c-ts-mode--indent-styles): New indent rule. Fix the rule for Linux style. (c-ts-mode--top-level-label-matcher): New function. --- lisp/progmodes/c-ts-mode.el | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index e1b45b06e1a..772b259d59e 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -125,6 +125,7 @@ MODE is either `c' or `cpp'." ((and (parent-is "comment") c-ts-mode--looking-at-star) c-ts-mode--comment-start-after-first-star -1) ((parent-is "comment") prev-adaptive-prefix 0) + (c-ts-mode--top-level-label-matcher point-min 1) ((node-is "labeled_statement") parent-bol 0) ((parent-is "labeled_statement") parent-bol c-ts-mode-indent-offset) ((match "preproc_ifdef" "compound_statement") point-min 0) @@ -171,7 +172,10 @@ MODE is either `c' or `cpp'." ,@common) (k&r ,@common) (linux - ((node-is "labeled_statement") point-min 1) + ;; Reference: + ;; https://www.kernel.org/doc/html/latest/process/coding-style.html, + ;; and script/Lindent in Linux kernel repository. + ((node-is "labeled_statement") point-min 0) ,@common) (bsd ((parent-is "if_statement") parent-bol 0) @@ -195,6 +199,17 @@ MODE is either `c' or `cpp'." ('linux (alist-get 'linux (c-ts-mode--indent-styles mode))))))) `((,mode ,@style)))) +(defun c-ts-mode--top-level-label-matcher (node &rest _) + "A matcher that matches a top-level label. +NODE should be a labeled_statement." + (let ((func (treesit-parent-until + node (lambda (n) + (equal (treesit-node-type n) + "function_definition"))))) + (and (equal (treesit-node-type node) + "labeled_statement") + (not (treesit-node-top-level func "function_definition"))))) + (defun c-ts-mode--bracket-children-anchor (_n parent &rest _) "This anchor is used for children of a compound_statement. So anything inside a {} block. PARENT should be the From ef87c75566018b546e56f64f66f665ebfd8da305 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sun, 8 Jan 2023 19:05:19 -0800 Subject: [PATCH 36/55] Make sure NODE is not the root node in tree-sitter indent (bug#60602) There are two possible ways to solve the problem raised in the bug report: either make sure NODE is never the root (so that parent is never nil), or allow parent to be nil. If we go with the latter, a lot of matcher and anchor functions need change (they need to guard against a null parent). I tried it, and needing to check for null parent is pretty annoying. In comparison, if NODE is never the root, it is very convenient for the user, and it doesn't complicate the rule that much (and it's rather intuitive, people usually don't think of the case where NODE is the root node). So that's what I choose. * doc/lispref/modes.texi (Parser-based Indentation): Update manual. * lisp/treesit.el (treesit-indent-function): Update docstring. (treesit--indent-1): Make sure NODE is not the root. --- doc/lispref/modes.texi | 8 ++++---- lisp/treesit.el | 13 ++++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi index b2dd294ea28..ff372edb3ff 100644 --- a/doc/lispref/modes.texi +++ b/doc/lispref/modes.texi @@ -4936,10 +4936,10 @@ Each @var{matcher} or @var{anchor} is a function that takes three arguments: @var{node}, @var{parent}, and @var{bol}. The argument @var{bol} is the buffer position whose indentation is required: the position of the first non-whitespace character after the beginning of -the line. The argument @var{node} is the largest (highest-in-tree) -node that starts at that position; and @var{parent} is the parent of -@var{node}. However, when that position is in a whitespace or inside -a multi-line string, no node can start at that position, so +the line. The argument @var{node} is the largest node that starts at +that position (and is not a root node); and @var{parent} is the parent +of @var{node}. However, when that position is in a whitespace or +inside a multi-line string, no node can start at that position, so @var{node} is @code{nil}. In that case, @var{parent} would be the smallest node that spans that position. diff --git a/lisp/treesit.el b/lisp/treesit.el index 7205e43916d..e53d5d53bd0 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -1341,10 +1341,10 @@ and returns (ANCHOR . OFFSET). BOL is the position of the beginning of the line; NODE is the -\"largest\" node that starts at BOL; PARENT is its parent; ANCHOR -is a point (not a node), and OFFSET is a number. Emacs finds the -column of ANCHOR and adds OFFSET to it as the final indentation -of the current line.") +\"largest\" node that starts at BOL (and isn't a root node); +PARENT is its parent; ANCHOR is a point (not a node), and OFFSET +is a number. Emacs finds the column of ANCHOR and adds OFFSET to +it as the final indentation of the current line.") (defun treesit--indent-1 () "Indent the current line. @@ -1362,10 +1362,13 @@ Return (ANCHOR . OFFSET). This function is used by ((treesit-language-at (point)) (treesit-node-at bol (treesit-language-at (point)))) (t (treesit-node-at bol)))) + (root (treesit-parser-root-node + (treesit-node-parser smallest-node))) (node (treesit-parent-while smallest-node (lambda (node) - (eq bol (treesit-node-start node)))))) + (and (eq bol (treesit-node-start node)) + (not (treesit-node-eq node root))))))) (let* ((parser (if smallest-node (treesit-node-parser smallest-node) From 1f8ad353d9fbf8fb7706e91dda336dfd650b57cc Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sun, 8 Jan 2023 20:30:07 -0800 Subject: [PATCH 37/55] Minor improvement for tree-sitter explorer If you open an empty python buffer and type 1 + 2 a b Currently the explorer only displays the top-level node at point, ie, only 1 + 2, only a, or only b. That's kind of awkward, so if the buffer is small, show the entire parse tree. * lisp/treesit.el (treesit--explorer-refresh): See above. --- lisp/treesit.el | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lisp/treesit.el b/lisp/treesit.el index e53d5d53bd0..7a604121c4e 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -2415,11 +2415,15 @@ in the region." (window-start) (window-end) treesit--explorer-language)) ;; Only highlight the current top-level construct. ;; Highlighting the whole buffer is slow and unnecessary. - (top-level (treesit-node-first-child-for-pos - root (if (eolp) - (max (point-min) (1- (point))) - (point)) - t)) + ;; But if the buffer is small (ie, used in playground + ;; style), just highlight the whole buffer. + (top-level (if (< (buffer-size) 4000) + root + (treesit-node-first-child-for-pos + root (if (eolp) + (max (point-min) (1- (point))) + (point)) + t))) ;; Only highlight node when region is active, if we ;; highlight node at point the syntax tree is too jumpy. (nodes-hl From c1401d1c6c834c4b264cc2435f562b28bc9c83a8 Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Mon, 9 Jan 2023 09:54:19 +0200 Subject: [PATCH 38/55] * lisp/vc/diff-mode.el (diff-font-lock-keywords): Check for limit. This check is necessary since 'diff-beginning-of-hunk' can move not only backwards, but also forwards (bug#60660). --- lisp/vc/diff-mode.el | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el index acfd2c30f0c..eb01dede56e 100644 --- a/lisp/vc/diff-mode.el +++ b/lisp/vc/diff-mode.el @@ -485,17 +485,19 @@ use the face `diff-removed' for removed lines, and the face ;; if below, use `diff-added'. (save-match-data (let ((limit (save-excursion (diff-beginning-of-hunk)))) - (if (save-excursion (re-search-backward diff-context-mid-hunk-header-re limit t)) - diff-indicator-added-face - diff-indicator-removed-face))))) + (when (< limit (point)) + (if (save-excursion (re-search-backward diff-context-mid-hunk-header-re limit t)) + diff-indicator-added-face + diff-indicator-removed-face)))))) (2 (if diff-use-changed-face 'diff-changed-unspecified ;; Otherwise, use the same method as above. (save-match-data (let ((limit (save-excursion (diff-beginning-of-hunk)))) - (if (save-excursion (re-search-backward diff-context-mid-hunk-header-re limit t)) - 'diff-added - 'diff-removed)))))) + (when (< limit (point)) + (if (save-excursion (re-search-backward diff-context-mid-hunk-header-re limit t)) + 'diff-added + 'diff-removed))))))) ("^\\(?:Index\\|revno\\): \\(.+\\).*\n" (0 'diff-header) (1 'diff-index prepend)) ("^\\(?:index .*\\.\\.\\|diff \\).*\n" . 'diff-header) From ebc5263667b17af30d8e91b47aba0cdd67a389d4 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 9 Jan 2023 14:03:04 +0200 Subject: [PATCH 39/55] ; * src/callint.c (Finteractive): Doc string clarification. --- src/callint.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/callint.c b/src/callint.c index 04bd64535c9..d8d2b278458 100644 --- a/src/callint.c +++ b/src/callint.c @@ -105,13 +105,12 @@ If the string begins with `^' and `shift-select-mode' is non-nil, You may use `@', `*', and `^' together. They are processed in the order that they appear, before reading any arguments. -If MODES is present, it should be a list of mode names (symbols) that -this command is applicable for. The main effect of this is that -`M-x TAB' will be able to exclude this command from the list of -completion candidates if the current buffer's mode doesn't match the list. -That is, if either the major mode isn't derived from them, or (when it's -a minor mode) the mode isn't in effect. Which commands are excluded -from the list of completion candidates is controlled by the value +If MODES is present, it should be one or more mode names (symbols) +for which this command is applicable. This is so that `M-x TAB' +will be able to exclude this command from the list of completion +candidates if the current buffer's mode doesn't match the list. +Which commands are excluded from the list of completion +candidates based on this information is controlled by the value of `read-extended-command-predicate', which see. usage: (interactive &optional ARG-DESCRIPTOR &rest MODES) */ From 5259f144d95d92dbda3d8db06b4f870bcfbb4a93 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 9 Jan 2023 22:05:40 +0200 Subject: [PATCH 40/55] Remove unneeded restriction in using AEAD ciphers with GnuTLS * src/gnutls.c (gnutls_symmetric_aead): Disable the enforcement of block size on input data. (Bug#60693) --- src/gnutls.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gnutls.c b/src/gnutls.c index e8528381efd..ca7e9fc4c73 100644 --- a/src/gnutls.c +++ b/src/gnutls.c @@ -2405,6 +2405,9 @@ gnutls_symmetric_aead (bool encrypting, gnutls_cipher_algorithm_t gca, aead_auth_size = aend_byte - astart_byte; } + /* Only block ciphers require that ISIZE be a multiple of the block + size, and AEAD ciphers are not block ciphers. */ +#if 0 ptrdiff_t expected_remainder = encrypting ? 0 : cipher_tag_size; ptrdiff_t cipher_block_size = gnutls_cipher_get_block_size (gca); @@ -2414,6 +2417,7 @@ gnutls_symmetric_aead (bool encrypting, gnutls_cipher_algorithm_t gca, "is not %"pD"d greater than a multiple of the required %"pD"d"), gnutls_cipher_get_name (gca), desc, isize, expected_remainder, cipher_block_size); +#endif ret = ((encrypting ? gnutls_aead_cipher_encrypt : gnutls_aead_cipher_decrypt) (acipher, vdata, vsize, aead_auth_data, aead_auth_size, From 4d1d43e41fafaa5beecba57686f5d5f4146746c8 Mon Sep 17 00:00:00 2001 From: Theodor Thornhill Date: Mon, 9 Jan 2023 07:52:38 +0100 Subject: [PATCH 41/55] Add named defun for transpose-sexps-default-function (bug#60654) * lisp/simple.el (transpose-sexps-default-function): Move the lambda into its own function. (transpose-sexps-function): Refer to it by name. * etc/NEWS: Mention the change. --- etc/NEWS | 4 ++++ lisp/simple.el | 64 ++++++++++++++++++++++++++------------------------ 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 60dab575da6..3aa8f2abb77 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -57,6 +57,10 @@ trash when deleting. Default is nil. Emacs now can set this variable to customize the behavior of the 'transpose-sexps' function. +** New function 'transpose-sexps-default-function'. +The previous implementation is moved into its own function, to be +bound by transpose-sexps-function'. + ** New function 'treesit-transpose-sexps'. treesit.el now unconditionally sets 'transpose-sexps-function' for all Tree-sitter modes. This functionality utilizes the new diff --git a/lisp/simple.el b/lisp/simple.el index 690968ca938..c8c5542caee 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -8436,37 +8436,39 @@ are interchanged." (interactive "*p") (transpose-subr 'forward-word arg)) -(defvar transpose-sexps-function - (lambda (arg) - ;; Here we should try to simulate the behavior of - ;; (cons (progn (forward-sexp x) (point)) - ;; (progn (forward-sexp (- x)) (point))) - ;; Except that we don't want to rely on the second forward-sexp - ;; putting us back to where we want to be, since forward-sexp-function - ;; might do funny things like infix-precedence. - (if (if (> arg 0) - (looking-at "\\sw\\|\\s_") - (and (not (bobp)) - (save-excursion - (forward-char -1) - (looking-at "\\sw\\|\\s_")))) - ;; Jumping over a symbol. We might be inside it, mind you. - (progn (funcall (if (> arg 0) - #'skip-syntax-backward #'skip-syntax-forward) - "w_") - (cons (save-excursion (forward-sexp arg) (point)) (point))) - ;; Otherwise, we're between sexps. Take a step back before jumping - ;; to make sure we'll obey the same precedence no matter which - ;; direction we're going. - (funcall (if (> arg 0) #'skip-syntax-backward #'skip-syntax-forward) - " .") - (cons (save-excursion (forward-sexp arg) (point)) - (progn (while (or (forward-comment (if (> arg 0) 1 -1)) - (not (zerop (funcall (if (> arg 0) - #'skip-syntax-forward - #'skip-syntax-backward) - "."))))) - (point))))) +(defun transpose-sexps-default-function (arg) + "Default method to locate a pair of points for transpose-sexps." + ;; Here we should try to simulate the behavior of + ;; (cons (progn (forward-sexp x) (point)) + ;; (progn (forward-sexp (- x)) (point))) + ;; Except that we don't want to rely on the second forward-sexp + ;; putting us back to where we want to be, since forward-sexp-function + ;; might do funny things like infix-precedence. + (if (if (> arg 0) + (looking-at "\\sw\\|\\s_") + (and (not (bobp)) + (save-excursion + (forward-char -1) + (looking-at "\\sw\\|\\s_")))) + ;; Jumping over a symbol. We might be inside it, mind you. + (progn (funcall (if (> arg 0) + #'skip-syntax-backward #'skip-syntax-forward) + "w_") + (cons (save-excursion (forward-sexp arg) (point)) (point))) + ;; Otherwise, we're between sexps. Take a step back before jumping + ;; to make sure we'll obey the same precedence no matter which + ;; direction we're going. + (funcall (if (> arg 0) #'skip-syntax-backward #'skip-syntax-forward) + " .") + (cons (save-excursion (forward-sexp arg) (point)) + (progn (while (or (forward-comment (if (> arg 0) 1 -1)) + (not (zerop (funcall (if (> arg 0) + #'skip-syntax-forward + #'skip-syntax-backward) + "."))))) + (point))))) + +(defvar transpose-sexps-function #'transpose-sexps-default-function "If non-nil, `transpose-sexps' delegates to this function. This function takes one argument ARG, a number. Its expected From f16cc7c49c7f341558fda08bd14e2c1b7e80baf5 Mon Sep 17 00:00:00 2001 From: Dmitry Gutov Date: Tue, 10 Jan 2023 02:00:29 +0200 Subject: [PATCH 42/55] ; project.el: Bump version --- lisp/progmodes/project.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index 730998727ce..dc87cb8e15d 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -1,7 +1,7 @@ ;;; project.el --- Operations on the current project -*- lexical-binding: t; -*- ;; Copyright (C) 2015-2023 Free Software Foundation, Inc. -;; Version: 0.9.3 +;; Version: 0.9.4 ;; Package-Requires: ((emacs "26.1") (xref "1.4.0")) ;; This is a GNU ELPA :core package. Avoid using functionality that From 8a36a0f44aafc10f1d10e23d5371bf19ee344b41 Mon Sep 17 00:00:00 2001 From: Dmitry Gutov Date: Tue, 10 Jan 2023 02:02:09 +0200 Subject: [PATCH 43/55] ; xref.el: Bump version --- lisp/progmodes/xref.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index d5cee9fa84f..916d83d407b 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -1,7 +1,7 @@ ;;; xref.el --- Cross-referencing commands -*-lexical-binding:t-*- ;; Copyright (C) 2014-2023 Free Software Foundation, Inc. -;; Version: 1.6.0 +;; Version: 1.6.1 ;; Package-Requires: ((emacs "26.1")) ;; This is a GNU ELPA :core package. Avoid functionality that is not From 28dd60213846a04d3f8c4006bd4ec252bd883ed0 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Mon, 9 Jan 2023 01:44:44 -0800 Subject: [PATCH 44/55] Fix c-ts-mode indentation for 2nd line in block comment (bug#60270) If the first line is "/*" or "/* ", indent like this: /* aaa If the first line is "/* some text", indent like this: /* some text aaa * lisp/progmodes/c-ts-mode.el (c-ts-mode--indent-styles): (c-ts-mode--looking-at-star): Minor refactor. (c-ts-mode--comment-2nd-line-matcher) (c-ts-mode--comment-2nd-line-anchor): New functions. * lisp/treesit.el (treesit-simple-indent-presets): prev-adaptive-prefix doesn't handle the comment-start-skip case (i.e, 2nd line) anymore. (Handled by the new matcher.) --- lisp/progmodes/c-ts-mode.el | 38 ++++++++++++++++++++++++++++++++----- lisp/treesit.el | 25 +++++++++++------------- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 772b259d59e..898b89b9fce 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -122,6 +122,9 @@ MODE is either `c' or `cpp'." ((node-is "else") parent-bol 0) ((node-is "case") parent-bol 0) ((node-is "preproc_arg") no-indent) + (c-ts-mode--comment-2nd-line-matcher + c-ts-mode--comment-2nd-line-anchor + 1) ((and (parent-is "comment") c-ts-mode--looking-at-star) c-ts-mode--comment-start-after-first-star -1) ((parent-is "comment") prev-adaptive-prefix 0) @@ -227,11 +230,8 @@ beginning of grandparent." (defun c-ts-mode--looking-at-star (_n _p bol &rest _) "A tree-sitter simple indent matcher. -Matches if there is a \"*\" after point (ignoring whitespace in -between)." - (save-excursion - (goto-char bol) - (looking-at (rx (* (syntax whitespace)) "*")))) +Matches if there is a \"*\" after BOL." + (eq (char-after bol) ?*)) (defun c-ts-mode--comment-start-after-first-star (_n parent &rest _) "A tree-sitter simple indent anchor. @@ -243,6 +243,34 @@ Assumes PARENT is a comment node." (match-end 0) (point)))) +(defun c-ts-mode--comment-2nd-line-matcher (_n parent &rest _) + "Matches if point is at the second line of a block comment. +PARENT should be a comment node." + (save-excursion + (forward-line -1) + (back-to-indentation) + (eq (point) (treesit-node-start parent)))) + +(defun c-ts-mode--comment-2nd-line-anchor (&rest _) + "Return appropriate anchor for the second line of a comment. + +If the first line is /* alone, return the position right after +the star; if the first line is /* followed by some text, return +the position right before the text minus 1. + +Use an offset of 1 with this anchor." + (save-excursion + (forward-line -1) + (back-to-indentation) + (when (looking-at comment-start-skip) + (goto-char (match-end 0)) + (if (looking-at (rx (* (or " " "\t")) eol)) + ;; Only /* at the first line. + (progn (skip-chars-backward " \t") + (point)) + ;; There is something after /* at the first line. + (1- (point)))))) + ;;; Font-lock (defvar c-ts-mode--preproc-keywords diff --git a/lisp/treesit.el b/lisp/treesit.el index 7a604121c4e..5b306354465 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -1143,20 +1143,17 @@ See `treesit-simple-indent-presets'.") (point)))) (cons 'prev-adaptive-prefix (lambda (_n parent &rest _) - (save-excursion - (re-search-backward - (rx (not (or " " "\t" "\n"))) nil t) - (beginning-of-line) - (and (>= (point) (treesit-node-start parent)) - ;; `adaptive-fill-regexp' will not match "/*", - ;; so we need to also try `comment-start-skip'. - (or (and adaptive-fill-regexp - (looking-at adaptive-fill-regexp) - (> (- (match-end 0) (match-beginning 0)) 0) - (match-end 0)) - (and comment-start-skip - (looking-at comment-start-skip) - (match-end 0))))))) + (let ((comment-start-bol + (save-excursion + (goto-char (treesit-node-start parent)) + (line-beginning-position)))) + (save-excursion + (forward-line -1) + (and (>= (point) comment-start-bol) + adaptive-fill-regexp + (looking-at adaptive-fill-regexp) + (> (match-end 0) (match-beginning 0)) + (match-end 0)))))) ;; TODO: Document. (cons 'grand-parent (lambda (_n parent &rest _) From e385c099b8c3eda3c7e3ad397c1b4a8ff2be4010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jostein=20Kj=C3=B8nigsen?= Date: Mon, 9 Jan 2023 11:17:53 +0100 Subject: [PATCH 45/55] Improve fontification for import-statements in typescript-ts-mode (bug#60689) * lisp/progmodes/typescript-ts-mode.el: (typescript-ts-mode--font-lock-settings): Add rules to highlight the actual imports in import-statements. --- lisp/progmodes/typescript-ts-mode.el | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index b26dca101db..037d5c8e87e 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -197,7 +197,10 @@ Argument LANGUAGE is either `typescript' or `tsx'." value: (array (number) (function))) (catch_clause - parameter: (identifier) @font-lock-variable-name-face)) + parameter: (identifier) @font-lock-variable-name-face) + + (import_clause (identifier) @font-lock-variable-name-face) + (import_clause (named_imports (import_specifier (identifier)) @font-lock-variable-name-face))) :language language :override t From aa9df1260c3fe5e872bef926288ce345bedbe1bb Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Mon, 9 Jan 2023 20:15:12 -0800 Subject: [PATCH 46/55] Don't print named tree-sitter nodes with parenthesizes (bug#60696) * src/print.c (print_vectorlike): Use empty string as delimiters if the node is named. --- src/print.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/print.c b/src/print.c index d4a9ff89246..e65b4c40b0e 100644 --- a/src/print.c +++ b/src/print.c @@ -2034,8 +2034,13 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag, /* Now the node must be up-to-date, and calling functions like Ftreesit_node_start will not signal. */ bool named = treesit_named_node_p (XTS_NODE (obj)->node); - const char *delim1 = named ? "(" : "\""; - const char *delim2 = named ? ")" : "\""; + /* We used to use () as delimiters for named nodes, but that + confuses pretty-printing a tad bit. There might be more + little breakages here and there if we print parenthesizes + inside an object, so I guess better not do it. + (bug#60696) */ + const char *delim1 = named ? "" : "\""; + const char *delim2 = named ? "" : "\""; print_c_string (delim1, printcharfun); print_string (Ftreesit_node_type (obj), printcharfun); print_c_string (delim2, printcharfun); From 8377ed5298f0529512294956269dcd06a8e6ed18 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Mon, 9 Jan 2023 21:31:38 -0800 Subject: [PATCH 47/55] Highlight identifier in import statements in js-ts-mode Follow-up on bug#60689. This commit just copied the change in e385c099b8c to js-ts-mode. * lisp/progmodes/js.el: (js--treesit-font-lock-settings): Add import query. --- lisp/progmodes/js.el | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index fe483f220da..058c8907bb5 100644 --- a/lisp/progmodes/js.el +++ b/lisp/progmodes/js.el @@ -3542,7 +3542,10 @@ This function is intended for use in `after-change-functions'." (identifier) (identifier) @font-lock-function-name-face) - value: (array (number) (function)))) + value: (array (number) (function))) + (import_clause (identifier) @font-lock-variable-name-face) + (import_clause (named_imports (import_specifier (identifier)) + @font-lock-variable-name-face))) :language 'javascript :feature 'property From 55aabfea4accd04aed9424b5cdbe304d12be6224 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Mon, 9 Jan 2023 21:46:07 -0800 Subject: [PATCH 48/55] Fix c-ts-mode comment indent * lisp/progmodes/c-ts-mode.el: (c-ts-mode--comment-2nd-line-matcher): Also make sure PARENT is a comment node. --- lisp/progmodes/c-ts-mode.el | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 898b89b9fce..5c7df4b2141 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -246,10 +246,11 @@ Assumes PARENT is a comment node." (defun c-ts-mode--comment-2nd-line-matcher (_n parent &rest _) "Matches if point is at the second line of a block comment. PARENT should be a comment node." - (save-excursion - (forward-line -1) - (back-to-indentation) - (eq (point) (treesit-node-start parent)))) + (and (equal (treesit-node-type parent) "comment") + (save-excursion + (forward-line -1) + (back-to-indentation) + (eq (point) (treesit-node-start parent))))) (defun c-ts-mode--comment-2nd-line-anchor (&rest _) "Return appropriate anchor for the second line of a comment. From f31e65694caf7bd7aa981e13969e2c86fde59a13 Mon Sep 17 00:00:00 2001 From: Manuel Uberti Date: Tue, 10 Jan 2023 14:24:04 +0100 Subject: [PATCH 49/55] Fix completion-auto-help docstring (bug#60709) * lisp/minibuffer.el (completion-auto-help): Remove extra period. --- lisp/minibuffer.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index f47299bd0da..21d4607e7cf 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -986,7 +986,7 @@ already visible. If the value is `visible', the *Completions* buffer is displayed whenever completion is requested but cannot be done for the first time, but remains visible thereafter, and the list of completions in it is -updated for subsequent attempts to complete.." +updated for subsequent attempts to complete." :type '(choice (const :tag "Don't show" nil) (const :tag "Show only when cannot complete" t) (const :tag "Show after second failed completion attempt" lazy) From c267cd01517bca9570faf13c4454793e7fb0c97b Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Tue, 3 Jan 2023 23:10:53 -0800 Subject: [PATCH 50/55] ; Kill some stray buffers left behind by ERC tests * test/lisp/erc/erc-services-tests.el (erc--auth-source-search--plstore-standard, erc--auth-source-search--plstore-announced, erc--auth-source-search--plstore-overrides): Kill buffer renamed by plstore. In the future, try using the `:buffer' keyword introduced in Emacs 29. * test/lisp/erc/resources/erc-d/erc-d-t.el (erc-d-t-kill-related-buffers): Don't forget about `erc-dcc-chat-mode' buffers. --- test/lisp/erc/erc-services-tests.el | 9 ++++++--- test/lisp/erc/resources/erc-d/erc-d-t.el | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/test/lisp/erc/erc-services-tests.el b/test/lisp/erc/erc-services-tests.el index b1d36d868eb..9181a47ee3b 100644 --- a/test/lisp/erc/erc-services-tests.el +++ b/test/lisp/erc/erc-services-tests.el @@ -248,7 +248,8 @@ (let ((auth-sources (list plstore-file)) (auth-source-do-cache nil)) (erc-services-tests--auth-source-standard - #'erc-services-test--call-with-plstore)))) + #'erc-services-test--call-with-plstore)) + (kill-buffer (get-file-buffer plstore-file)))) (ert-deftest erc--auth-source-search--plstore-announced () (ert-with-temp-file plstore-file @@ -264,7 +265,8 @@ (let ((auth-sources (list plstore-file)) (auth-source-do-cache nil)) (erc-services-tests--auth-source-announced - #'erc-services-test--call-with-plstore)))) + #'erc-services-test--call-with-plstore)) + (kill-buffer (get-file-buffer plstore-file)))) (ert-deftest erc--auth-source-search--plstore-overrides () (ert-with-temp-file plstore-file @@ -296,7 +298,8 @@ (let ((auth-sources (list plstore-file)) (auth-source-do-cache nil)) (erc-services-tests--auth-source-overrides - #'erc-services-test--call-with-plstore)))) + #'erc-services-test--call-with-plstore)) + (kill-buffer (get-file-buffer plstore-file)))) ;; auth-source JSON backend diff --git a/test/lisp/erc/resources/erc-d/erc-d-t.el b/test/lisp/erc/resources/erc-d/erc-d-t.el index 282c193b707..7b2adf4f07b 100644 --- a/test/lisp/erc/resources/erc-d/erc-d-t.el +++ b/test/lisp/erc/resources/erc-d/erc-d-t.el @@ -32,7 +32,7 @@ (dolist (buf (buffer-list)) (with-current-buffer buf (when (or erc-d-u--process-buffer - (derived-mode-p 'erc-mode)) + (derived-mode-p 'erc-mode 'erc-dcc-chat-mode)) (push buf buflist)))) (dolist (buf buflist) (when (and (boundp 'erc-server-flood-timer) From bb98666d03f2898f52f8b03f6056f8f8c9368131 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Mon, 2 Jan 2023 18:13:08 -0800 Subject: [PATCH 51/55] ; Fix wrong type in erc-ignore hide-list options * lisp/erc/erc.el (erc-network-hide-list, erc-channel-hide-list): Fix type in custom definition. --- lisp/erc/erc.el | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 6315d5aa482..ba7db15cf8c 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -323,7 +323,8 @@ A typical value would be \((\"Libera.Chat\" \"MODE\") \(\"OFTC\" \"JOIN\" \"QUIT\"))." :version "25.1" :group 'erc-ignore - :type 'erc-message-type) + :type '(alist :key-type string :value-type erc-message-type + :options ("Libera.Chat"))) (defcustom erc-channel-hide-list nil "A list of IRC channels to hide message types from. @@ -331,7 +332,8 @@ A typical value would be \((\"#emacs\" \"QUIT\" \"JOIN\") \(\"#erc\" \"NICK\")." :version "25.1" :group 'erc-ignore - :type 'erc-message-type) + :type '(alist :key-type string :value-type erc-message-type + :options ("#emacs"))) (defcustom erc-disconnected-hook nil "Run this hook with arguments (NICK IP REASON) when disconnected. From fda1ad4a9ec030d013fc16c92d8494bc755b3763 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Tue, 3 Jan 2023 23:10:53 -0800 Subject: [PATCH 52/55] Remove obsolete server buffers on MOTD in erc-track * lisp/erc/erc-networks.el (erc-networks--copy-server-buffer-functions): New internal hook through which modules can perform housekeeping when server buffers belonging to the same network context are merged. (erc-networks--copy-over-server-buffer-contents): Run new internal hook `erc-networks--copy-server-buffer-functions'. * lisp/erc/erc-track.el (erc-track-enable, erc-track-disable): Manage membership in `erc-networks--copy-server-buffer-functions' hook. (erc-track--replace-killed-buffer): New function to replace server buffer being killed in `erc-modified-channels-alist'. * test/lisp/erc/erc-scenarios-base-association.el (erc-scenarios-networks-merge-server-track): New test. * test/lisp/erc/resources/networks/merge-server/track.eld: New test data. (Bug#60560.) --- lisp/erc/erc-networks.el | 6 +++ lisp/erc/erc-track.el | 12 ++++- .../erc/erc-scenarios-base-association.el | 49 +++++++++++++++++++ .../resources/networks/merge-server/track.eld | 44 +++++++++++++++++ 4 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 test/lisp/erc/resources/networks/merge-server/track.eld diff --git a/lisp/erc/erc-networks.el b/lisp/erc/erc-networks.el index 4044be08f92..95fd8990c99 100644 --- a/lisp/erc/erc-networks.el +++ b/lisp/erc/erc-networks.el @@ -1366,6 +1366,11 @@ ANNOUNCED is the server's reported host name." erc-server-connected t erc-networks--id nid)))))) +(defvar erc-networks--copy-server-buffer-functions nil + "Abnormal hook run in new server buffers when deduping. +Passed the existing buffer to be killed, whose contents have +already been copied over to the current, replacement buffer.") + (defun erc-networks--copy-over-server-buffer-contents (existing name) "Kill off existing server buffer after copying its contents. Must be called from the replacement buffer." @@ -1386,6 +1391,7 @@ Must be called from the replacement buffer." erc-kill-server-hook erc-kill-buffer-hook) (erc-networks--insert-transplanted-content text) + (run-hook-with-args 'erc-networks--copy-server-buffer-functions existing) (kill-buffer name))) ;; This stands alone for testing purposes diff --git a/lisp/erc/erc-track.el b/lisp/erc/erc-track.el index 61c0c66abfb..7fd7b53602e 100644 --- a/lisp/erc/erc-track.el +++ b/lisp/erc/erc-track.el @@ -521,7 +521,9 @@ keybindings will not do anything useful." (add-hook 'erc-disconnected-hook #'erc-modified-channels-update)) ;; enable the tracking keybindings (add-hook 'erc-connect-pre-hook #'erc-track-minor-mode-maybe) - (erc-track-minor-mode-maybe))) + (erc-track-minor-mode-maybe)) + (add-hook 'erc-networks--copy-server-buffer-functions + #'erc-track--replace-killed-buffer)) ;; Disable: ((when (boundp 'erc-track-when-inactive) (erc-track-remove-from-mode-line) @@ -539,7 +541,9 @@ keybindings will not do anything useful." ;; disable the tracking keybindings (remove-hook 'erc-connect-pre-hook #'erc-track-minor-mode-maybe) (when erc-track-minor-mode - (erc-track-minor-mode -1))))) + (erc-track-minor-mode -1))) + (remove-hook 'erc-networks--copy-server-buffer-functions + #'erc-track--replace-killed-buffer))) (defcustom erc-track-when-inactive nil "Enable channel tracking even for visible buffers, if you are inactive." @@ -942,6 +946,10 @@ reverse it." (interactive "p") (erc-track--switch-buffer 'switch-to-buffer-other-window arg)) +(defun erc-track--replace-killed-buffer (existing) + (when-let ((found (assq existing erc-modified-channels-alist))) + (setcar found (current-buffer)))) + (provide 'erc-track) ;;; erc-track.el ends here diff --git a/test/lisp/erc/erc-scenarios-base-association.el b/test/lisp/erc/erc-scenarios-base-association.el index 1e280d0fdd7..a40a4cb7550 100644 --- a/test/lisp/erc/erc-scenarios-base-association.el +++ b/test/lisp/erc/erc-scenarios-base-association.el @@ -26,7 +26,9 @@ (declare-function erc-network-name "erc-networks") (declare-function erc-network "erc-networks") +(declare-function erc-track-get-active-buffer "erc-track" (arg)) (defvar erc-autojoin-channels-alist) +(defvar erc-track-mode) (defvar erc-network) ;; Two networks, same channel name, no confusion (no bouncer). Some @@ -190,4 +192,51 @@ (with-current-buffer "#chan@barnet" (erc-d-t-search-for 10 "I'll bid adieu"))))) +;; Some modules may need to perform housekeeping when a newly +;; connected server buffer is deemed a duplicate after its persistent +;; network context is discovered on MOTD end. One such module is +;; `track', which needs to rid its list of modified channels of the +;; buffer being killed. Without this, a user may encounter an +;; "Attempt to display deleted buffer" error when they try switching +;; to it. + +(ert-deftest erc-scenarios-networks-merge-server-track () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "networks/merge-server") + (dumb-server (erc-d-run "localhost" t 'track 'track)) + (port (process-contact dumb-server :service)) + (erc-server-flood-penalty 0.1) + (expect (erc-d-t-make-expecter))) + + (ert-info ("Connect") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester") + (should (string= (buffer-name) (format "127.0.0.1:%d" port))) + (should erc-track-mode) + (funcall expect 5 "changed mode for tester") + (erc-cmd-JOIN "#chan"))) + + (ert-info ("Join channel and quit") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 5 "The hour that fools should ask") + (erc-cmd-QUIT "")) + (with-current-buffer "FooNet" + (funcall expect 5 "finished"))) + + (ert-info ("Reconnect") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester") + (should (string= (buffer-name) (format "127.0.0.1:%d" port))) + (funcall expect 5 "changed mode for tester"))) + + (with-current-buffer "#chan" + (funcall expect 5 "The hour that fools should ask") + ;; Simulate the old `erc-track-switch-buffer' + (switch-to-buffer (erc-track-get-active-buffer 1)) + (erc-d-t-wait-for 10 (eq (get-buffer "FooNet") (current-buffer))) + (erc-cmd-QUIT "")))) + ;;; erc-scenarios-base-association.el ends here diff --git a/test/lisp/erc/resources/networks/merge-server/track.eld b/test/lisp/erc/resources/networks/merge-server/track.eld new file mode 100644 index 00000000000..4a97f92f722 --- /dev/null +++ b/test/lisp/erc/resources/networks/merge-server/track.eld @@ -0,0 +1,44 @@ +;; -*- mode: lisp-data; -*- +((nick 10 "NICK tester")) +((user 10 "USER user 0 * :unknown") + (0.00 ":irc.example.net NOTICE * :*** Looking up your hostname...") + (0.01 ":irc.example.net NOTICE tester :*** Could not resolve your hostname: Domain not found; using your IP address (10.0.2.100) instead.") + (0.10 ":irc.example.net 001 tester :Welcome to the FooNet IRC Network tester!user@10.0.2.100") + (0.02 ":irc.example.net 002 tester :Your host is irc.example.net, running version InspIRCd-3") + (0.02 ":irc.example.net 003 tester :This server was created 05:58:57 Jan 04 2023") + (0.01 ":irc.example.net 004 tester irc.example.net InspIRCd-3 BIRcgikorsw ACHIKMORTXabcefghijklmnopqrstvz :HIXabefghjkloqv") + (0.00 ":irc.example.net 005 tester ACCEPT=30 AWAYLEN=200 BOT=B CALLERID=g CASEMAPPING=ascii CHANLIMIT=#:20 CHANMODES=IXbeg,k,Hfjl,ACKMORTcimnprstz CHANNELLEN=64 CHANTYPES=# ELIST=CMNTU ESILENCE=CcdiNnPpTtx EXCEPTS=e :are supported by this server") + (0.02 ":irc.example.net 005 tester EXTBAN=,ACORTUacjrwz HOSTLEN=64 INVEX=I KEYLEN=32 KICKLEN=255 LINELEN=512 MAXLIST=I:100,X:100,b:100,e:100,g:100 MAXTARGETS=20 MODES=20 MONITOR=30 NAMELEN=128 NAMESX NETWORK=FooNet :are supported by this server") + (0.01 ":irc.example.net 005 tester NICKLEN=30 PREFIX=(qaohv)~&@%+ SAFELIST SILENCE=32 STATUSMSG=~&@%+ TOPICLEN=307 UHNAMES USERIP USERLEN=10 USERMODES=,,s,BIRcgikorw WHOX :are supported by this server") + (0.01 ":irc.example.net 251 tester :There are 2 users and 0 invisible on 2 servers") + (0.01 ":irc.example.net 253 tester 1 :unknown connections") + (0.01 ":irc.example.net 254 tester 1 :channels formed") + (0.00 ":irc.example.net 255 tester :I have 2 clients and 1 servers") + (0.00 ":irc.example.net 265 tester :Current local users: 2 Max: 3") + (0.00 ":irc.example.net 266 tester :Current global users: 2 Max: 3") + (0.00 ":irc.example.net 375 tester :irc.example.net message of the day") + (0.00 ":irc.example.net 372 tester : Have fun with the image!") + (0.00 ":irc.example.net 376 tester :End of message of the day.")) + +((mode 10 "MODE tester +i") + (0.00 ":irc.example.net 501 tester x :is not a recognised user mode.") + (0.00 ":NickServ!NickServ@services.int NOTICE tester :Welcome to FooNet, tester! Here on FooNet, we provide services to enable the registration of nicknames and channels! For details, type \2/msg NickServ help\2 and \2/msg ChanServ help\2.") + (0.02 ":tester!user@10.0.2.100 MODE tester :+i")) + +((join 10 "JOIN #chan") + (0.01 ":tester!user@10.0.2.100 JOIN :#chan")) + +((mode 10 "MODE #chan") + (0.01 ":irc.example.net 353 tester = #chan :@alice bob tester") + (0.01 ":irc.example.net 366 tester #chan :End of /NAMES list.") + (0.00 ":alice!alice@0::1 PRIVMSG #chan :tester, welcome!") + (0.02 ":bob!bob@0::1 PRIVMSG #chan :tester, welcome!") + (0.02 ":irc.example.net 324 tester #chan :+nt") + (0.01 ":irc.example.net 329 tester #chan :1672811954") + (0.07 ":alice!alice@0::1 PRIVMSG #chan :bob: This afternoon, sir ? well, she shall be there.") + (0.05 ":bob!bob@0::1 PRIVMSG #chan :alice: The hour that fools should ask.")) + +((quit 10 "QUIT :\2ERC\2") + (0.04 "ERROR :Closing link: (user@10.0.2.100) [Quit: \2ERC\2]")) + +((drop 1 DROP)) From 64fe6bdb618ff37336b3a8c635f23fc807785ef2 Mon Sep 17 00:00:00 2001 From: Robert Pluim Date: Tue, 10 Jan 2023 15:22:34 +0100 Subject: [PATCH 53/55] Improve 'describe-char-fold-equivalences' docstring * lisp/char-fold.el (describe-char-fold-equivalences): Explain what the output looks like. --- lisp/char-fold.el | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/lisp/char-fold.el b/lisp/char-fold.el index eff2f5558b3..6da2dae8471 100644 --- a/lisp/char-fold.el +++ b/lisp/char-fold.el @@ -436,7 +436,23 @@ specify the character). With no input, i.e. when CHAR is nil, describe all available character equivalences of `char-fold-to-regexp'. Optional argument LAX (interactively, the prefix argument), if non-nil, means also include partially matching ligatures and -non-canonical equivalences." +non-canonical equivalences. + +Each line of the display shows the equivalences in two different +ways separated by a colon: + + - as the literal character or sequence + - using an ASCII-only escape syntax + +For example, for the letter \\='r\\=', the first line is + + r: ?\\N{LATIN SMALL LETTER R} + +which is for the requested character itself, and a later line has + + ṟ: ?\\N{LATIN SMALL LETTER R}?\\N{COMBINING MACRON BELOW} + +which clearly shows what the constituent characters are." (interactive (list (ignore-errors (read-char-by-name (format-prompt "Unicode name, single char, or hex" From 136c0272215e167fe1cc4fc713c814c6c6cd8d7d Mon Sep 17 00:00:00 2001 From: Manuel Uberti Date: Tue, 10 Jan 2023 15:51:46 +0100 Subject: [PATCH 54/55] Fix reftex-citation docstring (bug#60710) * lisp/textmodes/reftex-cite.el (reftex-citation): Fix spelling. --- lisp/textmodes/reftex-cite.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/textmodes/reftex-cite.el b/lisp/textmodes/reftex-cite.el index 77373707d65..6beae816257 100644 --- a/lisp/textmodes/reftex-cite.el +++ b/lisp/textmodes/reftex-cite.el @@ -636,7 +636,7 @@ command, it will add another key, ignoring the value of The regular expression uses an expanded syntax: && is interpreted as `and'. Thus, `aaaa&&bbb' matches entries which contain both `aaaa' and `bbb'. -While entering the regexp, completion on knows citation keys is possible. +While entering the regexp, completion on known citation keys is possible. `=' is a good regular expression to match all entries in all files." (interactive) From 1cbc22b9c7f836f5b3311213dca8afa853513442 Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Tue, 10 Jan 2023 20:29:37 +0000 Subject: [PATCH 55/55] CC Mode: partially revert commit from 2022-10-04 This reversion is of an ill-advised optimization, which resulted in non-type identifiers getting fontified as types. * lisp/progmodes/cc-fonts.el (c-fontify-new-found-type): Rather than writing the expected face directly to the text, instead remove the `fontified' property. This allows the full font-lock mechanism to fontify the buffer correctly. --- lisp/progmodes/cc-fonts.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el index d84c4f8ad8a..4dcc3e0ade9 100644 --- a/lisp/progmodes/cc-fonts.el +++ b/lisp/progmodes/cc-fonts.el @@ -2530,8 +2530,8 @@ higher." (get-text-property (match-beginning 0) 'fontified) (not (memq (c-get-char-property (match-beginning 0) 'face) c-literal-faces))) - (c-put-font-lock-face (match-beginning 0) (match-end 0) - font-lock-type-face)) + (put-text-property (match-beginning 0) (match-end 0) + 'fontified nil)) (dolist (win-boundary window-boundaries) (when (and (< (match-beginning 0) (cdr win-boundary)) (> (match-end 0) (car win-boundary))