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/emacs/misc.texi b/doc/emacs/misc.texi index c706b727e6f..88d4188d144 100644 --- a/doc/emacs/misc.texi +++ b/doc/emacs/misc.texi @@ -2702,40 +2702,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 -@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.) +@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-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 frameset-filter-alist - 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 -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. - -@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 +@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}): @@ -2743,25 +2719,98 @@ sessions, or add this line in your init file (@pxref{Init File}): (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 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 -@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. + 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. - 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-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. 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 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 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 +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 +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; 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. @@ -2773,50 +2822,18 @@ 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. 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. - -@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}). - @node Recursive Edit @section Recursive Editing Levels @cindex recursive editing level 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/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/help.texi b/doc/lispref/help.texi index de5ed76c7f7..59b6b6dab1d 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 @@ -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, 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/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 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}. 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/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..3aa8f2abb77 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 @@ -52,6 +57,10 @@ as it has in batch mode since Emacs 24. 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/etc/NEWS.29 b/etc/NEWS.29 index 5901b2718e9..a28f5c9a65a 100644 --- a/etc/NEWS.29 +++ b/etc/NEWS.29 @@ -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'. 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) 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" 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/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. 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/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) 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) 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/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. diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index e76966e7660..e929fe1dd81 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -122,9 +122,13 @@ 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) + (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) @@ -138,6 +142,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) @@ -151,7 +156,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) @@ -167,7 +174,12 @@ MODE is either `c' or `cpp'." ((match "while" "do_statement") parent 0) ,@common) (k&r ,@common) - (linux ,@common) + (linux + ;; 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) ((parent-is "for_statement") parent-bol 0) @@ -190,6 +202,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 @@ -205,11 +228,10 @@ 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)) "*"))) +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. @@ -221,6 +243,35 @@ 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." + (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. + +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 @@ -419,20 +470,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))) @@ -534,9 +594,11 @@ 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") + "union_specifier" "class_specifier" + "namespace_definition") (treesit-node-child-by-field-name node "name"))) t)) @@ -568,6 +630,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 @@ -741,7 +820,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) @@ -772,7 +852,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) @@ -782,49 +862,49 @@ 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) - (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++" "Major mode for editing C++, powered by tree-sitter." :group 'c++ - (unless (treesit-ready-p 'cpp) - (error "Tree-sitter for C++ isn't available")) + (when (treesit-ready-p 'cpp) + (setq-local treesit-text-type-regexp + (regexp-opt '("comment" + "raw_string_literal"))) - (setq-local treesit-text-type-regexp - (regexp-opt '("comment" - "raw_string_literal"))) + (treesit-parser-create 'cpp) - (treesit-parser-create 'cpp) - (setq-local syntax-propertize-function - #'c-ts-mode--syntax-propertize) + ;; Syntax. + (setq-local syntax-propertize-function + #'c-ts-mode--syntax-propertize) - (setq-local treesit-simple-indent-rules - (c-ts-mode--set-indent-style 'cpp)) + ;; 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)) + ;; Font-lock. + (setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'cpp)) - (treesit-major-mode-setup)) + (treesit-major-mode-setup))) (provide 'c-ts-mode) 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)) 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 diff --git a/lisp/progmodes/gud.el b/lisp/progmodes/gud.el index 20692d6c8df..92e018aaec1 100644 --- a/lisp/progmodes/gud.el +++ b/lisp/progmodes/gud.el @@ -3561,8 +3561,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) diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index 881f4a83b17..902d4fa7ab3 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 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 diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 59164d7d50c..21d16db287c 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -1067,11 +1067,28 @@ 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))) +(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 +1099,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 @@ -3766,15 +3785,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/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el index 5f5de500435..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." @@ -304,7 +314,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)) diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index 0a79ae01248..0786150d906 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -194,7 +194,13 @@ 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) + + (import_clause (identifier) @font-lock-variable-name-face) + (import_clause (named_imports (import_specifier (identifier)) @font-lock-variable-name-face))) :language language :override t @@ -223,17 +229,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 +241,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) 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 diff --git a/lisp/simple.el b/lisp/simple.el index 690968ca938..f5712177234 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. @@ -8436,37 +8493,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 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) diff --git a/lisp/treesit.el b/lisp/treesit.el index a7f453a8899..25b2c70ce0a 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 _) @@ -1187,9 +1184,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))))) @@ -1338,10 +1338,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. @@ -1359,10 +1359,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) @@ -2447,11 +2450,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 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) diff --git a/src/callint.c b/src/callint.c index c60a376b958..d8d2b278458 100644 --- a/src/callint.c +++ b/src/callint.c @@ -105,11 +105,13 @@ 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' (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. +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) */ attributes: const) 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, 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)) diff --git a/src/print.c b/src/print.c index bc6d5487c13..d656774b9cd 100644 --- a/src/print.c +++ b/src/print.c @@ -2039,8 +2039,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); 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/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) 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)) 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 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 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