commit c3d9581f84107c2e137c71bb8fbf386bc20c944c (HEAD, refs/remotes/origin/master) Author: Stefan Monnier Date: Sat May 31 13:29:05 2025 -0400 (load-path-filter-cache-directory-files): Filter only for `must-suffix` Most loads set the `must-suffix` (e.g. `require and `autoload-do-load`), but some don't (e.g. `load-library`). This results in two separate entries in `load-path-filter--cache` with two hash-tables. The entry for `must-suffix=nil` is larger and much less often used than the other, so just skip filtering when `must-suffix=nil`. Reduces the memory size of the cache from ~1MB to ~400kB in my test case. * lisp/startup.el (load-path-filter-cache-directory-files): Don't use a filtering cache when `must-suffix` is nil. diff --git a/lisp/startup.el b/lisp/startup.el index 0e59731d976..3d38f68098b 100644 --- a/lisp/startup.el +++ b/lisp/startup.el @@ -1148,11 +1148,12 @@ the `--debug-init' option to view a complete error backtrace." The value is an alist. The car of each entry is a list of load suffixes, such as returned by `get-load-suffixes'. The cdr of each entry is a -cons whose car is an `regex-opt' optimized regex matching those suffixes +cons whose car is a regex matching those suffixes at the end of a string, and whose cdr is a hash-table mapping directories to files in those directories which end with one of the suffixes. -Since the list of load suffixes usually includes an empty string, the -hash-table will also include subdirectories of those directories. +These can also be nil, in which case no filtering will happen. +The files named in the hash-table can be of any kind, +including subdirectories. The hash-table uses `equal' as its key comparison function.") (defun load-path-filter-cache-directory-files (path file suffixes) @@ -1170,19 +1171,28 @@ This function is called from `load' via `load-path-filter-function'." (if (file-name-directory file) ;; FILE has more than one component, don't bother filtering. path - (seq-filter - (let ((rx-and-ht - (with-memoization (alist-get suffixes load-path-filter--cache nil nil #'equal) - (cons - (concat (regexp-opt suffixes) "\\'") - (make-hash-table :test #'equal))))) - (lambda (dir) - (when (file-directory-p dir) - (try-completion - file - (with-memoization (gethash dir (cdr rx-and-ht)) - (directory-files dir nil (car rx-and-ht) t)))))) - path))) + (pcase-let + ((`(,rx . ,ht) + (with-memoization (alist-get suffixes load-path-filter--cache + nil nil #'equal) + (if (member "" suffixes) + '(nil ;; Optimize the filtering. + ;; Don't bother filtering if "" is among the suffixes. + ;; It's a much less common use-case and it would use + ;; more memory to keep the corresponding info. + . nil) + (cons (concat (regexp-opt suffixes) "\\'") + (make-hash-table :test #'equal)))))) + (if (null ht) + path + (seq-filter + (lambda (dir) + (when (file-directory-p dir) + (try-completion + file + (with-memoization (gethash dir ht) + (directory-files dir nil rx t))))) + path))))) (defun command-line () "A subroutine of `normal-top-level'. commit 4b527088e66fe9f39ca4060cf1bc5918feb37c49 Author: Eli Zaretskii Date: Sat May 31 17:32:49 2025 +0300 ; * src/fns.c (fixnum_float_cmp): Don't use non-ASCII characters. diff --git a/src/fns.c b/src/fns.c index 21916b6fb46..52f911b8de6 100644 --- a/src/fns.c +++ b/src/fns.c @@ -3041,7 +3041,7 @@ fixnum_float_cmp (EMACS_INT a, double b) { /* This doesn't mean that a=b because the conversion may have rounded. However, b must be an integer that fits in an EMACS_INT, - because |b| ≤ 2|a| and EMACS_INT has at least one bit more than + because |b| <= 2|a| and EMACS_INT has at least one bit more than needed to represent any fixnum. Thus we can compare in the integer domain instead. */ EMACS_INT ib = b; /* lossless conversion */ commit 3f8faed9d2e8dbc4da722bbd0553e88eebc969cc Merge: 9d6a4fdd7e4 5ce0e1372bb Author: Eli Zaretskii Date: Sat May 31 17:29:40 2025 +0300 Merge branch 'master' of git.savannah.gnu.org:/srv/git/emacs commit 9d6a4fdd7e4e82ea804a83f428e395ffbbc3e8dd Author: Matthew Tromp Date: Mon May 19 15:45:21 2025 -0400 Add additional keybindings for flymake diagnostics modes This adds keybindings for C-o and C-m, and changes the bindings for n and m, in `flymake-diagnostics-buffer-mode' and `flymake-project-diagnostics-mode' buffers. Previously, `flymake-project-diagnostics-mode' did not use the keybindings for `flymake-diagnostics-buffer-mode'. RET and SPC were never bound in `flymake-project-diagnostics-mode' buffers. This seems to have been an oversight: since the filename and message are buttons which call `flymake-goto-diagnostic', pressing RET still brought users to the diagnostic at point most of the time. This change adds a `flymake-project-diagnostics-mode-map' which inherits from `flymake-diagnostics-buffer-mode-map'. C-o and C-m now show and jump to the diagnostic currently at point, similar to how `compilation-mode' works. n and p now show the diagnostic newly under point after moving up or down a line, which is also intended to make behavior more similar to `compilation-mode'. In order that other next-error buffers do not interfere with navigation in the diagnostics buffers, this change introduces and uses new functions, `next-error-this-buffer-no-select' and `previous-error-this-buffer-no-select'. If we instead used `next-error-no-select' and `previous-error-no-select', then a user who runs `flymake-show-diagnostics-buffer', then e.g. `compile', then returns to the diagnostics buffer and presses 'n', would be navigated to the next error in the compilation buffer. * lisp/progmodes/flymake.el (flymake-diagnostics-buffer-mode-map): Add bindings. (flymake-project-diagnostics-mode-map): Inherit bindings from `flymake-diagnostics-buffer-mode' * lisp/simple.el (next-error-this-buffer-no-select): (previous-error-this-buffer-no-select): Add new commands. (Bug#78619) Copyright-paperwork-exempt: yes diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el index 8a072b94a17..e911faf603d 100644 --- a/lisp/progmodes/flymake.el +++ b/lisp/progmodes/flymake.el @@ -1891,6 +1891,10 @@ TYPE is usually keyword `:error', `:warning' or `:note'." (let ((map (make-sparse-keymap))) (define-key map (kbd "RET") 'flymake-goto-diagnostic) (define-key map (kbd "SPC") 'flymake-show-diagnostic) + (keymap-set map "C-o" #'flymake-show-diagnostic) + (keymap-set map "C-m" #'flymake-goto-diagnostic) + (keymap-set map "n" #'next-error-this-buffer-no-select) + (keymap-set map "p" #'previous-error-this-buffer-no-select) map)) (defun flymake-show-diagnostic (pos &optional other-window) @@ -2187,6 +2191,11 @@ some of this variable's contents the diagnostic listings.") (defvar-local flymake--project-diagnostic-list-project nil) +(defvar flymake-project-diagnostics-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map flymake-diagnostics-buffer-mode-map) + map)) + (define-derived-mode flymake-project-diagnostics-mode tabulated-list-mode "Flymake diagnostics" "A mode for listing Flymake diagnostics in a project." diff --git a/lisp/simple.el b/lisp/simple.el index f686907ad68..fa173b26289 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -478,6 +478,16 @@ select the source buffer." '(nil (inhibit-same-window . t)))) (next-error n)))) +(defun next-error-this-buffer-no-select (&optional n) + "Move point to the next error in the current buffer and highlight match. +Prefix arg N says how many error messages to move forwards (or +backwards, if negative). +Finds and highlights the source line like \\[next-error], but does not +select the source buffer." + (interactive "p") + (next-error-select-buffer (current-buffer)) + (next-error-no-select n)) + (defun previous-error-no-select (&optional n) "Move point to the previous error in the `next-error' buffer and highlight match. Prefix arg N says how many error messages to move backwards (or @@ -487,6 +497,16 @@ select the source buffer." (interactive "p") (next-error-no-select (- (or n 1)))) +(defun previous-error-this-buffer-no-select (&optional n) + "Move point to the previous error in the current buffer and highlight match. +Prefix arg N says how many error messages to move forwards (or +backwards, if negative). +Finds and highlights the source line like \\[previous-error], but does not +select the source buffer." + (interactive "p") + (next-error-select-buffer (current-buffer)) + (previous-error-no-select n)) + ;; Internal variable for `next-error-follow-mode-post-command-hook'. (defvar next-error-follow-last-line nil) commit 5ce0e1372bb41ac83c513a632a57b3ffb643971e Author: Michael Albinus Date: Sat May 31 15:08:06 2025 +0200 Fix Tramp bug#78508 * lisp/net/tramp-container.el (tramp-methods) : * lisp/net/tramp-sh.el (tramp-methods) : * lisp/net/tramp-sshfs.el (tramp-methods) : Set TERM environment. (Bug#78508) * lisp/net/tramp-sh.el (tramp-find-executable): Handle superlong PATH. (tramp-set-remote-path): Simplify command. (tramp-timeout-session): Add ;;;###tramp-autoload cookie. * lisp/net/tramp-smb.el (tramp-smb-errors): Add string. (tramp-smb-winexe-program): Adapt docstring. (tramp-smb-handle-copy-directory, tramp-smb-handle-file-acl) (tramp-smb-handle-set-file-acl, tramp-smb-maybe-open-connection): Simplify argument handling. (tramp-smb-handle-process-file): Flush " process-exit-status" property. (tramp-smb-call-winexe): Set $winsize.Width to 102 only. * lisp/net/tramp.el (tramp-process-sentinel): Adapt docstring. Set " process-exit-status" property. * test/lisp/net/tramp-tests.el (tramp--test-enabled): Make it more robust. (tramp-test18-file-attributes) (tramp-test26-interactive-file-name-completion) (tramp-test26-file-name-completion-boundaries) (tramp-test35-remote-path): Adapt tests. diff --git a/lisp/net/tramp-cache.el b/lisp/net/tramp-cache.el index cbdaa48fc0e..721b7be123f 100644 --- a/lisp/net/tramp-cache.el +++ b/lisp/net/tramp-cache.el @@ -713,5 +713,7 @@ for all methods. Resulting data are derived from connection history." ;;; TODO: ;; ;; * Use multisession.el, starting with Emacs 29.1. +;; +;; Use `with-memoization', starting with Emacs 29.1. ;;; tramp-cache.el ends here diff --git a/lisp/net/tramp-container.el b/lisp/net/tramp-container.el index 8429208b44b..6e82bc67be1 100644 --- a/lisp/net/tramp-container.el +++ b/lisp/net/tramp-container.el @@ -551,6 +551,7 @@ see its function help for a description of the format." (tramp-login-args (("exec") ("-it") ("-u" "%u") + ("-e" ,(format "TERM=%s" tramp-terminal-type)) ("%h") ("%l"))) (tramp-direct-async (,tramp-default-remote-shell "-c")) @@ -565,6 +566,7 @@ see its function help for a description of the format." (tramp-login-args (("exec") ("-it") ("-u" "%u") + ("-e" ,(format "TERM=%s" tramp-terminal-type)) ("%h") ("%l"))) (tramp-direct-async (,tramp-default-remote-shell "-c")) @@ -583,6 +585,7 @@ see its function help for a description of the format." (tramp-login-args (("exec") ("-it") ("-u" "%u") + ("-e" ,(format "TERM=%s" tramp-terminal-type)) ("%h") ("%l"))) (tramp-direct-async (,tramp-default-remote-shell "-c")) @@ -597,6 +600,7 @@ see its function help for a description of the format." (tramp-login-args (("exec") ("-it") ("-u" "%u") + ("-e" ,(format "TERM=%s" tramp-terminal-type)) ("%h") ("%l"))) (tramp-direct-async (,tramp-default-remote-shell "-c")) @@ -754,6 +758,8 @@ see its function help for a description of the format." `(,tramp-apptainer-method (tramp-login-program ,tramp-apptainer-program) (tramp-login-args (("shell") + ("--env" + ,(format "TERM=%s" tramp-terminal-type)) ("instance://%h") ("%h"))) ; Needed for multi-hop check. (tramp-remote-shell ,tramp-default-remote-shell) @@ -777,6 +783,8 @@ see its function help for a description of the format." (tramp-login-args (("shell") ("-q") ("--uid" "%u") + ("-E" + ,(format "TERM=%s" tramp-terminal-type)) ("%h"))) (tramp-remote-shell ,tramp-default-remote-shell) (tramp-remote-shell-login ("-l")) diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index eb446f4e2cd..679d76d0f57 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -190,7 +190,10 @@ The string is used in `tramp-methods'.") `("scp" (tramp-login-program "ssh") (tramp-login-args (("-l" "%u") ("-p" "%p") ("%c") - ("-e" "none") ("%h"))) + ("-e" "none") + ("-o" ,(format "SetEnv=\"TERM=%s\"" + tramp-terminal-type)) + ("%h"))) (tramp-async-args (("-q"))) (tramp-direct-async ("-t" "-t")) (tramp-remote-shell ,tramp-default-remote-shell) @@ -208,6 +211,8 @@ The string is used in `tramp-methods'.") (tramp-login-args (("-l" "%u") ("-p" "%p") ("%c") ("-e" "none") ("-t" "-t") ("-o" "RemoteCommand=\"%l\"") + ("-o" ,(format "SetEnv=\"TERM=%s\"" + tramp-terminal-type)) ("%h"))) (tramp-async-args (("-q"))) (tramp-remote-shell ,tramp-default-remote-shell) @@ -223,7 +228,10 @@ The string is used in `tramp-methods'.") `("rsync" (tramp-login-program "ssh") (tramp-login-args (("-l" "%u") ("-p" "%p") ("%c") - ("-e" "none") ("%h"))) + ("-e" "none") + ("-o" ,(format "SetEnv=\"TERM=%s\"" + tramp-terminal-type)) + ("%h"))) (tramp-async-args (("-q"))) (tramp-direct-async t) (tramp-remote-shell ,tramp-default-remote-shell) @@ -254,7 +262,10 @@ The string is used in `tramp-methods'.") `("ssh" (tramp-login-program "ssh") (tramp-login-args (("-l" "%u") ("-p" "%p") ("%c") - ("-e" "none") ("%h"))) + ("-e" "none") + ("-o" ,(format "SetEnv=\"TERM=%s\"" + tramp-terminal-type)) + ("%h"))) (tramp-async-args (("-q"))) (tramp-direct-async ("-t" "-t")) (tramp-remote-shell ,tramp-default-remote-shell) @@ -265,6 +276,8 @@ The string is used in `tramp-methods'.") (tramp-login-program "ssh") (tramp-login-args (("-l" "%u") ("-p" "%p") ("%c") ("-e" "none") ("-t" "-t") + ("-o" ,(format "SetEnv=\"TERM=%s\"" + tramp-terminal-type)) ("-o" "RemoteCommand=\"%l\"") ("%h"))) (tramp-async-args (("-q"))) @@ -301,6 +314,7 @@ The string is used in `tramp-methods'.") ;; remote host echoes the command. ;; The "-p" argument doesn't work reliably, see Bug#50594. (tramp-login-args (("SUDO_PROMPT=P\"\"a\"\"s\"\"s\"\"w\"\"o\"\"r\"\"d\"\":") + (,(format "TERM=%s" tramp-terminal-type)) ("sudo") ("-u" "%u") ("-s") ("-H") ("%l"))) (tramp-remote-shell ,tramp-default-remote-shell) @@ -4123,12 +4137,33 @@ This function expects to be in the right *tramp* buffer." (unless (char-equal ?~ (aref d 0)) (setq newdl (cons d newdl)))) (setq dirlist (nreverse newdl)))) - (when (tramp-send-command-and-check - vec (format "(unalias %s; %s command -v %s)" - progname - (if dirlist (concat "PATH=" (string-join dirlist ":")) "") - progname)) - (string-trim (tramp-get-buffer-string (tramp-get-connection-buffer vec))))) + (let ((command + (concat + (when dirlist (format "PATH=%s " (string-join dirlist ":"))) + "command -v " progname)) + (pipe-buf (tramp-get-remote-pipe-buf vec)) + tmpfile chunk chunksize) + (when (if (length< command pipe-buf) + (tramp-send-command-and-check vec command) + ;; Use a temporary file. We cannot use `write-region' + ;; because setting the remote path happens in the early + ;; connection handshake, and not all external tools are + ;; determined yet. + (setq command (concat command "\n") + tmpfile (tramp-make-tramp-temp-file vec)) + (while (not (string-empty-p command)) + (setq chunksize (min (length command) (/ pipe-buf 2)) + chunk (substring command 0 chunksize) + command (substring command chunksize)) + (tramp-send-command + vec (format "printf \"%%b\" \"$*\" %s >>%s" + (tramp-shell-quote-argument chunk) + (tramp-shell-quote-argument tmpfile)))) + (tramp-send-command-and-check + vec (format ". %s && rm -f %s" tmpfile tmpfile))) + + (string-trim + (tramp-get-buffer-string (tramp-get-connection-buffer vec)))))) ;; On hydra.nixos.org, the $PATH environment variable is too long to ;; send it. This is likely not due to PATH_MAX, but PIPE_BUF. We @@ -4162,12 +4197,11 @@ variable PATH." (setq chunksize (min (length command) (/ pipe-buf 2)) chunk (substring command 0 chunksize) command (substring command chunksize)) - (tramp-send-command vec (format - "printf \"%%b\" \"$*\" %s >>%s" - (tramp-shell-quote-argument chunk) - (tramp-shell-quote-argument tmpfile)))) - (tramp-send-command vec (format ". %s" tmpfile)) - (tramp-send-command vec (format "rm -f %s" tmpfile)))))) + (tramp-send-command + vec (format "printf \"%%b\" \"$*\" %s >>%s" + (tramp-shell-quote-argument chunk) + (tramp-shell-quote-argument tmpfile)))) + (tramp-send-command vec (format ". %s && rm -f %s" tmpfile tmpfile)))))) ;; ------------------------------------------------------------ ;; -- Communication with external shell -- @@ -5108,6 +5142,7 @@ Goes through the list `tramp-inline-compress-commands'." (t "-3"))) +;;;###tramp-autoload (defun tramp-timeout-session (vec) "Close the connection VEC after a session timeout. If there is just some editing, retry it after 5 seconds." diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el index aeb7c01c03f..db961c97523 100644 --- a/lisp/net/tramp-smb.el +++ b/lisp/net/tramp-smb.el @@ -162,6 +162,7 @@ this variable \"client min protocol=NT1\"." "NT_STATUS_PASSWORD_MUST_CHANGE" "NT_STATUS_RESOURCE_NAME_NOT_FOUND" "NT_STATUS_REVISION_MISMATCH" + "NT_STATUS_RPC_SS_CONTEXT_MISMATCH" "NT_STATUS_SHARING_VIOLATION" "NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE" "NT_STATUS_UNSUCCESSFUL" @@ -316,7 +317,7 @@ Operations not mentioned here will be handled by the default Emacs primitives.") ;; Options for remote processes via winexe. (defcustom tramp-smb-winexe-program "winexe" "Name of winexe client to run. -If it isn't found in the local $PATH, the absolute path of winexe +If it isn't found in the local $PATH, the absolute path of \"winexe\" shall be given. This is needed for remote processes." :group 'tramp :version "24.3" @@ -488,12 +489,13 @@ arguments to pass to the OPERATION." (args (list (concat "//" host "/" share) "-E")) (options tramp-smb-options)) - (if (tramp-string-empty-or-nil-p user) - (setq args (append args (list "-N"))) - (setq args (append args (list "-U" user)))) + (setq args + (append args + (if (tramp-string-empty-or-nil-p user) + (list "-N") + (list "-U" (if domain (concat domain "/" user) user))) + (when port (list "-p" port)))) - (when domain (setq args (append args (list "-W" domain)))) - (when port (setq args (append args (list "-p" port)))) (when tramp-smb-conf (setq args (append args (list "-s" tramp-smb-conf)))) (while options @@ -779,12 +781,13 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (args (list (concat "//" host "/" share) "-E")) (options tramp-smb-options)) - (if (tramp-string-empty-or-nil-p user) - (setq args (append args (list "-N"))) - (setq args (append args (list "-U" user)))) + (setq args + (append args + (if (tramp-string-empty-or-nil-p user) + (list "-N") + (list "-U" (if domain (concat domain "/" user) user))) + (when port (list "-p" port)))) - (when domain (setq args (append args (list "-W" domain)))) - (when port (setq args (append args (list "-p" port)))) (when tramp-smb-conf (setq args (append args (list "-s" tramp-smb-conf)))) (while options @@ -1251,6 +1254,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (tramp-set-connection-property v " process-buffer" (or outbuf (generate-new-buffer tramp-temp-buffer-name))) + (tramp-flush-connection-property v " process-exit-status") (with-current-buffer (tramp-get-connection-buffer v) ;; Preserve buffer contents. (narrow-to-region (point-max) (point-max)) @@ -1366,12 +1370,13 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (string-replace "\n" "," acl-string))) (options tramp-smb-options)) - (if (tramp-string-empty-or-nil-p user) - (setq args (append args (list "-N"))) - (setq args (append args (list "-U" user)))) + (setq args + (append args + (if (tramp-string-empty-or-nil-p user) + (list "-N") + (list "-U" (if domain (concat domain "/" user) user))) + (when port (list "-p" port)))) - (when domain (setq args (append args (list "-W" domain)))) - (when port (setq args (append args (list "-p" port)))) (when tramp-smb-conf (setq args (append args (list "-s" tramp-smb-conf)))) (while options @@ -1906,16 +1911,19 @@ If ARGUMENT is non-nil, use it as argument for (share (setq args (list (concat "//" host "/" share)))) (t (setq args (list "-g" "-L" host )))) - (if (tramp-string-empty-or-nil-p user) - (setq args (append args (list "-N"))) - (setq args (append args (list "-U" user)))) + (setq args + (append args + (if (tramp-string-empty-or-nil-p user) + (list "-N") + (list "-U" (if domain (concat domain "/" user) user))) + (when port (list "-p" port)))) - (when domain (setq args (append args (list "-W" domain)))) - (when port (setq args (append args (list "-p" port)))) (when tramp-smb-conf (setq args (append args (list "-s" tramp-smb-conf)))) (dolist (option options) (setq args (append args (list "--option" option)))) + ;; For debugging. + (setq args (append args (list "-d" "1"))) (when argument (setq args (append args (list argument)))) @@ -2026,6 +2034,8 @@ Removes smb prompt. Returns nil if an error message has appeared." (when (tramp-file-name-port vec) (tramp-error vec 'file-error "Port not supported for remote processes")) + ;; In case of "NT_STATUS_RPC_SS_CONTEXT_MISMATCH", the remote server + ;; is a Samba server. winexe cannot install the respective service there. (tramp-smb-maybe-open-connection vec (format @@ -2037,12 +2047,14 @@ Removes smb prompt. Returns nil if an error message has appeared." ;; Suppress "^M". Shouldn't we specify utf8? (set-process-coding-system (tramp-get-connection-process vec) 'raw-text-dos) - ;; Set width to 128. This avoids mixing prompt and long error messages. + ;; Set width to 128 ($bufsize.Width) or 102 ($winsize.Width), + ;; respectively. $winsize.Width cannot be larger. This avoids + ;; mixing prompt and long error messages. (tramp-smb-send-command vec "$rawui = (Get-Host).UI.RawUI") (tramp-smb-send-command vec "$bufsize = $rawui.BufferSize") (tramp-smb-send-command vec "$winsize = $rawui.WindowSize") (tramp-smb-send-command vec "$bufsize.Width = 128") - (tramp-smb-send-command vec "$winsize.Width = 128") + (tramp-smb-send-command vec "$winsize.Width = 102") (tramp-smb-send-command vec "$rawui.BufferSize = $bufsize") (tramp-smb-send-command vec "$rawui.WindowSize = $winsize")) @@ -2069,5 +2081,7 @@ Removes smb prompt. Returns nil if an error message has appeared." ;; several places, especially in `tramp-smb-handle-insert-directory'. ;; ;; * Keep a separate connection process per share. +;; +;; * Keep a permanent connection process for `process-file'. ;;; tramp-smb.el ends here diff --git a/lisp/net/tramp-sshfs.el b/lisp/net/tramp-sshfs.el index 3176236128a..cbc083a1fe0 100644 --- a/lisp/net/tramp-sshfs.el +++ b/lisp/net/tramp-sshfs.el @@ -62,6 +62,8 @@ (tramp-login-program "ssh") (tramp-login-args (("-q") ("-l" "%u") ("-p" "%p") ("-e" "none") ("%a" "%a") + ("-o" ,(format "SetEnv=\"TERM=%s\"" + tramp-terminal-type)) ("%h") ("%l"))) (tramp-direct-async t) (tramp-remote-shell ,tramp-default-remote-shell) diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index 67aa2cd0fdb..24298e8e09a 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -6255,15 +6255,22 @@ the remote host use line-endings as defined in the variable (process-send-string p string))))))) (defun tramp-process-sentinel (proc event) - "Flush file caches and remove shell prompt." + "Flush file caches and remove shell prompt. +Set exit status of PROC as connection property \" process-exit-status\"." (unless (process-live-p proc) (let ((vec (process-get proc 'tramp-vector)) (buf (process-buffer proc)) (prompt (tramp-get-connection-property proc "prompt"))) (when vec - (tramp-message vec 5 "Sentinel called: `%S' `%s'" proc event) + (tramp-message + vec 5 "Sentinel called: `%S' event: `%s' status: %s" + proc event (process-exit-status proc)) (tramp-flush-connection-properties proc) - (tramp-flush-directory-properties vec "/")) + (tramp-flush-directory-properties vec "/") + ;; Sometimes, the process has been deleted already before we + ;; can retrieve the exit status. + (tramp-set-connection-property + vec " process-exit-status" (process-exit-status proc))) (when (buffer-live-p buf) (with-current-buffer buf (when (and prompt (tramp-search-regexp (rx (literal prompt)))) diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el index 349abdc44c9..b60b29fc3e6 100644 --- a/test/lisp/net/tramp-tests.el +++ b/test/lisp/net/tramp-tests.el @@ -278,9 +278,10 @@ being the result.") (| "rclone" "sshfs") ".") (file-name-nondirectory file))) (tramp--test-message "Delete %s" file) - (if (file-directory-p file) - (delete-directory file 'recursive) - (delete-file file)))))) + (ignore-errors ;; Wrong permissions? + (if (file-directory-p file) + (delete-directory file 'recursive) + (delete-file file))))))) ;; Cleanup connection. (tramp-cleanup-connection tramp-test-vec nil 'keep-password)) @@ -3761,11 +3762,7 @@ This tests also `access-file', `file-readable-p', (tmp-name2 (tramp--test-make-temp-name nil quoted)) ;; File name with "//". (tmp-name3 - (format - "%s%s" - (file-remote-p tmp-name1) - (replace-regexp-in-string - "/" "//" (file-remote-p tmp-name1 'localname)))) + (replace-regexp-in-string "/" "//" (file-local-name tmp-name1))) ;; `file-ownership-preserved-p' is implemented only in tramp-sh.el. (test-file-ownership-preserved-p (tramp--test-sh-p)) attr) @@ -3887,28 +3884,13 @@ This tests also `access-file', `file-readable-p', ;; symlinked files to a non-existing or cyclic target. (when test-file-ownership-preserved-p (should (file-ownership-preserved-p tmp-name2 'group))) - (delete-file tmp-name2))) + (delete-file tmp-name2)) - ;; Check, that "//" in symlinks are handled properly. - (with-temp-buffer - (let ((default-directory ert-remote-temporary-file-directory)) - (shell-command - (format - "ln -s %s %s" - (tramp-file-name-localname - (tramp-dissect-file-name tmp-name3)) - (tramp-file-name-localname - (tramp-dissect-file-name tmp-name2))) - t))) - (when (file-symlink-p tmp-name2) + ;; Check, that "//" in symlinks are handled properly. + (make-symbolic-link tmp-name3 tmp-name2) + (should (file-symlink-p tmp-name2)) (setq attr (file-attributes tmp-name2)) - (should - (string-equal - (file-attribute-type attr) - (funcall - (if (tramp--test-sshfs-p) #'file-name-nondirectory #'identity) - (tramp-file-name-localname - (tramp-dissect-file-name tmp-name3))))) + (should (string-equal (file-attribute-type attr) tmp-name3)) (delete-file tmp-name2)) (when test-file-ownership-preserved-p @@ -5164,7 +5146,8 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." ;; (tramp--test-message "%s" (tramp-get-buffer-string trace-buffer)) ;; (untrace-function #'tramp-completion-file-name-handler) ;; (untrace-function #'completion-file-name-table) - (tramp-change-syntax orig-syntax)))) + (tramp-change-syntax orig-syntax) + (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)))) (defun tramp--test-split-on-boundary (s) "Return completion boundaries for string S." @@ -5177,15 +5160,12 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." ;; boundaries are always incorrect before that. (skip-unless (tramp--test-emacs31-p)) - (should (equal (tramp--test-split-on-boundary "/ssh:user@host:foo") - '("/ssh:user@host:" . "foo"))) - (should (equal (tramp--test-split-on-boundary "/ssh:user@host:/~/foo") - '("/ssh:user@host:/~/" . "foo"))) - (should (equal (tramp--test-split-on-boundary "/ssh:user@host:/usr//usr/foo") - '("/ssh:user@host:/usr//usr/" . "foo"))) - (should (equal (tramp--test-split-on-boundary - "/ssh:user@host:/ssh:user@host://usr/foo") - '("/ssh:user@host:/ssh:user@host://usr/" . "foo")))) + (let ((remote (file-remote-p ert-remote-temporary-file-directory))) + (dolist + (file `(,remote ,(concat remote "/~/") + ,(concat remote "/usr//usr/") ,(concat remote remote "//usr/"))) + (should (equal (tramp--test-split-on-boundary (concat file "foo")) + `(,file . "foo")))))) (ert-deftest tramp-test27-load () "Check `load'." @@ -6511,6 +6491,7 @@ INPUT, if non-nil, is a string sent to the process." (file-remote-p default-directory 'localname))) ;; The shell "sh" shall always exist. (should (executable-find "sh" 'remote)) + ;; Since the last element in `exec-path' is the current ;; directory, an executable file in that directory will be ;; found. @@ -6539,19 +6520,19 @@ INPUT, if non-nil, is a string sent to the process." (skip-unless (tramp--test-sh-p)) (skip-unless (not (tramp--test-crypt-p))) - (let* ((tmp-name (tramp--test-make-temp-name)) + (let* ((tmp-name1 (tramp--test-make-temp-name)) (default-directory ert-remote-temporary-file-directory) (orig-exec-path (exec-path)) (tramp-remote-path tramp-remote-path) (orig-tramp-remote-path tramp-remote-path) - path) + tmp-name2 path) ;; The "flatpak" method modifies `tramp-remote-path'. (skip-unless (not (tramp-compat-connection-local-p tramp-remote-path))) (unwind-protect (progn ;; Non existing directories are removed. (setq tramp-remote-path - (cons (file-remote-p tmp-name 'localname) tramp-remote-path)) + (cons (file-remote-p tmp-name1 'localname) tramp-remote-path)) (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password) (should (equal (exec-path) orig-exec-path)) (setq tramp-remote-path orig-tramp-remote-path) @@ -6564,11 +6545,11 @@ INPUT, if non-nil, is a string sent to the process." ;; We make a super long `tramp-remote-path'. (unless (tramp--test-container-oob-p) - (make-directory tmp-name) - (should (file-directory-p tmp-name)) + (make-directory tmp-name1) + (should (file-directory-p tmp-name1)) (while (length< (string-join orig-exec-path ":") 5000) (let ((dir (make-temp-file - (file-name-as-directory tmp-name) 'dir))) + (file-name-as-directory tmp-name1) 'dir))) (should (file-directory-p dir)) (setq tramp-remote-path (append @@ -6591,12 +6572,33 @@ INPUT, if non-nil, is a string sent to the process." (should (string-equal path (string-join (butlast orig-exec-path) ":")))) ;; The shell "sh" shall always exist. - (should (executable-find "sh" 'remote)))) + (should (executable-find "sh" 'remote)) + + ;; Since the last element in `exec-path' is the current + ;; directory, an executable file in that directory will be + ;; found. + (setq tmp-name2 + (expand-file-name + "foo" + (concat (file-remote-p default-directory) + (car (last orig-exec-path 2))))) + (write-region "foo" nil tmp-name2) + (should (file-exists-p tmp-name2)) + + (set-file-modes tmp-name2 #o777) + (should (file-executable-p tmp-name2)) + (should + (string-equal + (executable-find (file-name-nondirectory tmp-name2) 'remote) + (file-remote-p tmp-name2 'localname))) + (should-not + (executable-find + (concat (file-name-nondirectory tmp-name2) "foo") 'remote)))) ;; Cleanup. + (ignore-errors (delete-directory tmp-name1 'recursive)) (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password) - (setq tramp-remote-path orig-tramp-remote-path) - (ignore-errors (delete-directory tmp-name 'recursive))))) + (setq tramp-remote-path orig-tramp-remote-path)))) (tramp--test-deftest-direct-async-process tramp-test35-remote-path) commit b247b1e0b16a5133ce11c92a110240f4c0217b06 Merge: 6a7f89c4e91 9dc6c21b414 Author: Eli Zaretskii Date: Sat May 31 08:29:51 2025 -0400 Merge from origin/emacs-30 9dc6c21b414 ; * lisp/subr.el (setq-local): Doc fix (bug#78644). 1bb88a86cb3 Revert "; * lisp/subr.el (setq-local): Doc fix (bug#78644)." cb9556d669c ; * lisp/subr.el (setq-local): Doc fix (bug#78644). 8881dca81c9 ; * doc/lispref/searching.texi (Char Classes): Add speedu... 4507b6a9c75 Fix bug in 'todo-jump-to-category' (bug#78608) commit 6a7f89c4e912eb21eec24e35ecc7053c7afca662 Merge: b3a8633dbad 3e57c35323a Author: Eli Zaretskii Date: Sat May 31 08:29:51 2025 -0400 ; Merge from origin/emacs-30 The following commit was skipped: 3e57c35323a Fix gitlab-ci.yml (don't merge to master) commit b3a8633dbad04fbd381ab2c8ea8b4c2b953c809f Merge: 6f8cee03316 1d2ae31b8bc Author: Eli Zaretskii Date: Sat May 31 08:29:50 2025 -0400 Merge from origin/emacs-30 1d2ae31b8bc typescript-ts-mode: Improve function body indentation (bu... 421ecbcf6b4 ; * CONTRIBUTE: Explain the line-width preferences. commit 6f8cee03316e166e4204ba49fbb9964a075968ca Author: Matthias Meulien Date: Thu May 8 16:51:46 2025 +0200 ansi-osc.el: Use marker (bug#78184) * lisp/ansi-osc.el (ansi-osc-apply-on-region) (ansi-osc-filter-region): Use marker to properly handle unfinished escape sequence. * test/lisp/ansi-osc-tests.el (ansi-osc-tests--strings) (ansi-osc-tests-apply-region-no-handlers) (ansi-osc-tests-apply-region-no-handlers-multiple-calls) (ansi-osc-tests-filter-region) (ansi-osc-tests-filter-region-with-multiple-calls): Cover bug#78184. diff --git a/lisp/ansi-osc.el b/lisp/ansi-osc.el index 97d6f6c8754..06359779823 100644 --- a/lisp/ansi-osc.el +++ b/lisp/ansi-osc.el @@ -35,18 +35,32 @@ ;;; Code: -(defconst ansi-osc-control-seq-regexp - ;; See ECMA 48, section 8.3.89 "OSC - OPERATING SYSTEM COMMAND". - "\e\\][\x08-\x0D]*[\x20-\x7E]*\\(\a\\|\e\\\\\\)" - "Regexp matching an OSC control sequence.") +;; According to ECMA 48, section 8.3.89 "OSC - OPERATING SYSTEM COMMAND" +;; OSC control sequences match: +;; "\e\\][\x08-\x0D]*[\x20-\x7E]*\\(\a\\|\e\\\\\\)" + +(defvar-local ansi-osc--marker nil + "Marker pointing to the start of an escape sequence. +Used by `ansi-osc-filter-region' and `ansi-osc-apply-on-region' to store +position of an unfinished escape sequence, for the complete sequence to +be handled in next call.") (defun ansi-osc-filter-region (begin end) - "Filter out all OSC control sequences from region between BEGIN and END." - (save-excursion - (goto-char begin) - ;; Delete escape sequences. - (while (re-search-forward ansi-osc-control-seq-regexp end t) - (delete-region (match-beginning 0) (match-end 0))))) + "Filter out all OSC control sequences from region between BEGIN and END. +When an unfinished escape sequence is found, the start position is saved +to `ansi-osc--marker'. Later call will override BEGIN with the position +pointed by `ansi-osc--marker'." + (let ((end-marker (copy-marker end))) + (save-excursion + (goto-char (or ansi-osc--marker begin)) + (when (eq (char-before) ?\e) (backward-char)) + (while (re-search-forward "\e]" end-marker t) + (let ((pos0 (match-beginning 0))) + (if (re-search-forward + "\\=[\x08-\x0D]*[\x20-\x7E]*\\(\a\\|\e\\\\\\)" + end-marker t) + (delete-region pos0 (point)) + (setq ansi-osc--marker (copy-marker pos0)))))))) (defvar-local ansi-osc-handlers '(("2" . ansi-osc-window-title-handler) ("7" . ansi-osc-directory-tracker) @@ -54,10 +68,6 @@ "Alist of handlers for OSC escape sequences. See `ansi-osc-apply-on-region' for details.") -(defvar-local ansi-osc--marker nil) -;; The function `ansi-osc-apply-on-region' can set `ansi-osc--marker' -;; to the start position of an escape sequence without termination. - (defun ansi-osc-apply-on-region (begin end) "Interpret OSC escape sequences in region between BEGIN and END. This function searches for escape sequences of the forms @@ -65,29 +75,33 @@ This function searches for escape sequences of the forms ESC ] command ; text BEL ESC ] command ; text ESC \\ -Every occurrence of such escape sequences is removed from the -buffer. Then, if `command' is a key in the alist that is the -value of the local variable `ansi-osc-handlers', that key's -value, which should be a function, is called with `command' and -`text' as arguments, with point where the escape sequence was -located." - (save-excursion - (goto-char (or ansi-osc--marker begin)) - (when (eq (char-before) ?\e) (backward-char)) - (while (re-search-forward "\e]" end t) - (let ((pos0 (match-beginning 0)) - (code (and (re-search-forward "\\=\\([0-9A-Za-z]*\\);" end t) - (match-string 1))) - (pos1 (point))) - (if (re-search-forward "\a\\|\e\\\\" end t) - (let ((text (buffer-substring-no-properties - pos1 (match-beginning 0)))) - (setq ansi-osc--marker nil) - (delete-region pos0 (point)) - (when-let* ((fun (cdr (assoc-string code ansi-osc-handlers)))) - (funcall fun code text))) - (put-text-property pos0 end 'invisible t) - (setq ansi-osc--marker (copy-marker pos0))))))) +Every occurrence of such escape sequences is removed from the buffer. +Then, if `command' is a key in the alist that is the value of the local +variable `ansi-osc-handlers', that key's value, which should be a +function, is called with `command' and `text' as arguments, with point +where the escape sequence was located. When an unfinished escape +sequence is identified, it's hidden and the start position is saved to +`ansi-osc--marker'. Later call will override BEGIN with the position +pointed by `ansi-osc--marker'." + (let ((end-marker (copy-marker end))) + (save-excursion + (goto-char (or ansi-osc--marker begin)) + (when (eq (char-before) ?\e) (backward-char)) + (while (re-search-forward "\e]" end-marker t) + (let ((pos0 (match-beginning 0)) + (code (and + (re-search-forward "\\=\\([0-9A-Za-z]*\\);" end-marker t) + (match-string 1))) + (pos1 (point))) + (if (re-search-forward "\a\\|\e\\\\" end-marker t) + (let ((text (buffer-substring-no-properties + pos1 (match-beginning 0)))) + (setq ansi-osc--marker nil) + (delete-region pos0 (point)) + (when-let* ((fun (cdr (assoc-string code ansi-osc-handlers)))) + (funcall fun code text))) + (put-text-property pos0 end-marker 'invisible t) + (setq ansi-osc--marker (copy-marker pos0)))))))) ;; Window title handling (OSC 2) diff --git a/test/lisp/ansi-osc-tests.el b/test/lisp/ansi-osc-tests.el index d2fb130e518..d083626f3f9 100644 --- a/test/lisp/ansi-osc-tests.el +++ b/test/lisp/ansi-osc-tests.el @@ -30,8 +30,7 @@ (require 'ert) (defvar ansi-osc-tests--strings - `( - ("Hello World" "Hello World") + `(("Hello World" "Hello World") ;; window title ("Buffer \e]2;A window title\e\\content" "Buffer content") @@ -44,6 +43,10 @@ ;; hyperlink ("\e]8;;http://example.com\e\\This is a link\e]8;;\e\\" "This is a link") + + ;; multiple sequences + ("Escape \e]2;A window title\e\\sequence followed by \e]2;unfinished sequence" + "Escape sequence followed by \e]2;unfinished sequence") )) ;; Don't output those strings to stdout since they may have ;; side-effects on the environment @@ -54,4 +57,44 @@ (with-temp-buffer (insert input) (ansi-osc-apply-on-region (point-min) (point-max)) - (should (equal (buffer-string) text)))))) + (should (equal + (buffer-substring-no-properties + (point-min) (point-max)) + text)))))) + +(ert-deftest ansi-osc-tests-apply-region-no-handlers-multiple-calls () + (let ((ansi-osc-handlers nil)) + (with-temp-buffer + (insert + (concat "First set the window title \e]2;A window title\e\\" + "then change it\e]2;Another ")) + (ansi-osc-apply-on-region (point-min) (point-max)) + (let ((pos (point))) + (insert "title\e\\, and stop.") + (ansi-osc-apply-on-region pos (point-max))) + (should + (equal + (buffer-substring-no-properties (point-min) (point-max)) + "First set the window title then change it, and stop."))))) + +(ert-deftest ansi-osc-tests-filter-region () + (pcase-dolist (`(,input ,text) ansi-osc-tests--strings) + (with-temp-buffer + (insert input) + (ansi-osc-filter-region (point-min) (point-max)) + (should (equal (buffer-string) text))))) + + +(ert-deftest ansi-osc-tests-filter-region-with-multiple-calls () + (with-temp-buffer + (insert + (concat "First set the window title \e]2;A window title\e\\" + "then change it\e]2;Another ")) + (ansi-osc-filter-region (point-min) (point-max)) + (let ((pos (point))) + (insert "title\e\\, and stop.") + (ansi-osc-filter-region pos (point-max))) + (should + (equal + (buffer-string) + "First set the window title then change it, and stop.")))) commit 32d911cddfd6ccdf288247a5d7eaf3d9a977b87c Author: Eli Zaretskii Date: Sat May 31 15:09:42 2025 +0300 Remove unused user options in sh-script.el * lisp/progmodes/sh-script.el (sh-indent-comment) (sh-first-lines-indent, sh-indent-for-else): Remove variables that are no longer obeyed. (sh-var-list): Likewise. (Bug#78592) diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el index 5075e9a0afc..d10e9fbfb43 100644 --- a/lisp/progmodes/sh-script.el +++ b/lisp/progmodes/sh-script.el @@ -1162,17 +1162,6 @@ are conflicts." (const :tag "Always" t)) :group 'sh-indentation) -(defcustom sh-first-lines-indent 0 - "The indentation of the first non-blank non-comment line. -Usually 0 meaning first column. -Can be set to a number, or to nil which means leave it as is." - :type '(choice - (const :tag "Leave as is" nil) - (integer :tag "Column number" - :menu-tag "Indent to this col (0 means first col)" )) - :group 'sh-indentation) - - (defcustom sh-basic-offset 4 "The default indentation increment. This value is used for the `+' and `-' symbols in an indentation variable." @@ -1180,21 +1169,6 @@ This value is used for the `+' and `-' symbols in an indentation variable." :safe #'integerp :group 'sh-indentation) -(defcustom sh-indent-comment t - "How a comment line is to be indented. -nil means leave it as it is; -t means indent it as a normal line, aligning it to previous non-blank - non-comment line; -a number means align to that column, e.g. 0 means first column." - :type '(choice - (const :tag "Leave as is." nil) - (const :tag "Indent as a normal line." t) - (integer :menu-tag "Indent to this col (0 means first col)." - :tag "Indent to column number.") ) - :version "24.3" - :group 'sh-indentation) - - (defvar sh-debug nil "Enable lots of debug messages - if function `sh-debug' is enabled.") @@ -1220,16 +1194,6 @@ a number means align to that column, e.g. 0 means first column." (const :tag "/ " :value / :menu-tag "/ Indent left half sh-basic-offset"))) -(defcustom sh-indent-for-else 0 - "How much to indent an `else' relative to its `if'. Usually 0." - :type `(choice - (integer :menu-tag "A number (positive=>indent right)" - :tag "A number") - (const :tag "--") ;; separator! - ,@ sh-symbol-list - ) - :group 'sh-indentation) - (defconst sh-number-or-symbol-list (append '((integer :menu-tag "A number (positive=>indent right)" :tag "A number") @@ -1380,19 +1344,17 @@ punctuation characters like `-'." (defconst sh-var-list '( - sh-basic-offset sh-first-lines-indent sh-indent-after-case + sh-basic-offset sh-indent-after-case sh-indent-after-do sh-indent-after-done sh-indent-after-else sh-indent-after-if sh-indent-after-loop-construct sh-indent-after-open - sh-indent-comment sh-indent-for-case-alt sh-indent-for-case-label sh-indent-for-continuation sh-indent-for-do sh-indent-for-done - sh-indent-for-else sh-indent-for-fi sh-indent-for-then ) commit bcc7c4dbbbc1a68a6467c336db2b0910f3362ae0 Author: Eli Zaretskii Date: Sat May 31 14:53:50 2025 +0300 ; * lisp/startup.el (load-path-filter--cache): Doc fix. diff --git a/lisp/startup.el b/lisp/startup.el index c772b4a8596..0e59731d976 100644 --- a/lisp/startup.el +++ b/lisp/startup.el @@ -1151,6 +1151,8 @@ such as returned by `get-load-suffixes'. The cdr of each entry is a cons whose car is an `regex-opt' optimized regex matching those suffixes at the end of a string, and whose cdr is a hash-table mapping directories to files in those directories which end with one of the suffixes. +Since the list of load suffixes usually includes an empty string, the +hash-table will also include subdirectories of those directories. The hash-table uses `equal' as its key comparison function.") (defun load-path-filter-cache-directory-files (path file suffixes) commit 98c3f4c371d2c31745ea056c1286f5f407397bc2 Author: Sean Whitton Date: Sat May 31 09:36:25 2025 +0100 Restore & obsolete vc-finish-logentry-hook * lisp/vc/vc-dispatcher.el (vc-finish-logentry-hook): Declare, document and mark obsolete. (vc-finish-logentry): Call vc-finish-logentry-hook again. diff --git a/lisp/vc/vc-dispatcher.el b/lisp/vc/vc-dispatcher.el index 820c666ca7d..18c0fd5e3ca 100644 --- a/lisp/vc/vc-dispatcher.el +++ b/lisp/vc/vc-dispatcher.el @@ -122,6 +122,15 @@ dispatcher client mode imposes itself." :type 'hook :group 'vc) +;; This hook was undeclared and undocumented until declared obsolete. +;; I believe it can be replaced with `vc-log-after-operation-hook'; if +;; someone can demonstrate a case where this is wanted too, we can +;; unobsolete it. --spwhitton +(defvar vc-finish-logentry-hook nil + "Additional hook run at the end of `vc-finish-logentry'.") +(make-obsolete-variable 'vc-finish-logentry-hook 'vc-log-after-operation-hook + "31.1" 'set) + (defcustom vc-delete-logbuf-window t "If non-nil, delete the log buffer and window after each logical action. If nil, bury that buffer instead. @@ -882,7 +891,7 @@ the buffer contents as a comment." ;; Now make sure we see the expanded headers (mapc (lambda (file) (vc-resynch-buffer file t t)) log-fileset) - (run-hooks after-hook))) + (run-hooks after-hook 'vc-finish-logentry-hook))) (defun vc-dispatcher-browsing () "Are we in a directory browser buffer?" commit 9dc6c21b4148222f404fe5af4dc6a24613a58d7c (refs/remotes/origin/emacs-30) Author: Eli Zaretskii Date: Sat May 31 11:12:58 2025 +0300 ; * lisp/subr.el (setq-local): Doc fix (bug#78644). diff --git a/lisp/subr.el b/lisp/subr.el index 99981848db4..50ebc598e80 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -161,11 +161,12 @@ of previous VARs. `(progn . ,(nreverse exps)))) (defmacro setq-local (&rest pairs) - "Make each VARIABLE buffer-local and assign to it the corresponding VALUE. + "Make each VARIABLE local to current buffer and set it to corresponding VALUE. The arguments are variable/value pairs. For each VARIABLE in a pair, -make VARIABLE buffer-local and assign to it the corresponding VALUE -of the pair. The VARIABLEs are literal symbols and should not be quoted. +make VARIABLE buffer-local in the current buffer and assign to it the +corresponding VALUE of the pair. The VARIABLEs are literal symbols +and should not be quoted. The VALUE of the Nth pair is not computed until after the VARIABLE of the (N-1)th pair is set; thus, each VALUE can use the new VALUEs commit 1bb88a86cb38d47006b257fa18a150f23345ad56 Author: Eli Zaretskii Date: Sat May 31 11:08:45 2025 +0300 Revert "; * lisp/subr.el (setq-local): Doc fix (bug#78644)." This reverts commit cb9556d669c037c4e2f1a9c80adacad55948c706. Some of its parts were not supposed to be installed. diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el index 510c0b99702..2ecae541fed 100644 --- a/lisp/cus-edit.el +++ b/lisp/cus-edit.el @@ -149,8 +149,7 @@ (error nil)) (condition-case nil - (unless (featurep 'cus-start) - (require 'cus-start)) + (require 'cus-start) (error nil)) (put 'custom-define-hook 'custom-type 'hook) diff --git a/lisp/custom.el b/lisp/custom.el index e5ceda87f61..a0dc1945bed 100644 --- a/lisp/custom.el +++ b/lisp/custom.el @@ -699,8 +699,7 @@ The result is that the change is treated as having been made through Custom." (ignore-errors (require 'cus-load)) (ignore-errors - (unless (featurep 'cus-start) - (require 'cus-start))) + (require 'cus-start)) (dolist (load (get symbol 'custom-loads)) (cond ((symbolp load) (ignore-errors (require load))) ;; This is subsumed by the test below, but it's much faster. diff --git a/lisp/subr.el b/lisp/subr.el index 50ebc598e80..99981848db4 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -161,12 +161,11 @@ of previous VARs. `(progn . ,(nreverse exps)))) (defmacro setq-local (&rest pairs) - "Make each VARIABLE local to current buffer and set it to corresponding VALUE. + "Make each VARIABLE buffer-local and assign to it the corresponding VALUE. The arguments are variable/value pairs. For each VARIABLE in a pair, -make VARIABLE buffer-local in the current buffer and assign to it the -corresponding VALUE of the pair. The VARIABLEs are literal symbols -and should not be quoted. +make VARIABLE buffer-local and assign to it the corresponding VALUE +of the pair. The VARIABLEs are literal symbols and should not be quoted. The VALUE of the Nth pair is not computed until after the VARIABLE of the (N-1)th pair is set; thus, each VALUE can use the new VALUEs commit cb9556d669c037c4e2f1a9c80adacad55948c706 Author: Eli Zaretskii Date: Sat May 31 10:05:06 2025 +0300 ; * lisp/subr.el (setq-local): Doc fix (bug#78644). diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el index 2ecae541fed..510c0b99702 100644 --- a/lisp/cus-edit.el +++ b/lisp/cus-edit.el @@ -149,7 +149,8 @@ (error nil)) (condition-case nil - (require 'cus-start) + (unless (featurep 'cus-start) + (require 'cus-start)) (error nil)) (put 'custom-define-hook 'custom-type 'hook) diff --git a/lisp/custom.el b/lisp/custom.el index a0dc1945bed..e5ceda87f61 100644 --- a/lisp/custom.el +++ b/lisp/custom.el @@ -699,7 +699,8 @@ The result is that the change is treated as having been made through Custom." (ignore-errors (require 'cus-load)) (ignore-errors - (require 'cus-start)) + (unless (featurep 'cus-start) + (require 'cus-start))) (dolist (load (get symbol 'custom-loads)) (cond ((symbolp load) (ignore-errors (require load))) ;; This is subsumed by the test below, but it's much faster. diff --git a/lisp/subr.el b/lisp/subr.el index 99981848db4..50ebc598e80 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -161,11 +161,12 @@ of previous VARs. `(progn . ,(nreverse exps)))) (defmacro setq-local (&rest pairs) - "Make each VARIABLE buffer-local and assign to it the corresponding VALUE. + "Make each VARIABLE local to current buffer and set it to corresponding VALUE. The arguments are variable/value pairs. For each VARIABLE in a pair, -make VARIABLE buffer-local and assign to it the corresponding VALUE -of the pair. The VARIABLEs are literal symbols and should not be quoted. +make VARIABLE buffer-local in the current buffer and assign to it the +corresponding VALUE of the pair. The VARIABLEs are literal symbols +and should not be quoted. The VALUE of the Nth pair is not computed until after the VARIABLE of the (N-1)th pair is set; thus, each VALUE can use the new VALUEs commit d25e9f518082f31ab730623eea36da45cd73ac06 Author: Jim Porter Date: Fri May 30 22:21:40 2025 -0700 Add more "safe" display specs to 'visual-wrap-prefix-mode' * lisp/visual-wrap.el (visual-wrap--safe-display-specs): Add 'space-width' and 'min-width'. (visual-wrap--display-property-safe-p): Use 'member' instead of 'memq' to more-closely match the behavior of other code that works with display properties. diff --git a/lisp/visual-wrap.el b/lisp/visual-wrap.el index b921e1f0549..227afe71006 100644 --- a/lisp/visual-wrap.el +++ b/lisp/visual-wrap.el @@ -74,7 +74,7 @@ extra indent = 2 (face-background face nil t))))) (defvar visual-wrap--safe-display-specs - '(height raise) + '(space-width min-width height raise) "A list of display specs that don't interfere with wrap prefixes. A \"safe\" display spec is one that won't interfere with the additional text properties that `visual-wrap-prefix-mode' uses. @@ -98,8 +98,8 @@ members of `visual-wrap--safe-display-specs' (which see)." (when (or (vectorp display) (listp display)) (not (catch 'unsafe (mapc (lambda (spec) - (unless (memq (car-safe spec) - visual-wrap--safe-display-specs) + (unless (member (car-safe spec) + visual-wrap--safe-display-specs) (throw 'unsafe t))) display))))) commit 9e322088b01f45a024827ead350a02f29d197e0b Author: Jeremy Bryant Date: Fri May 16 23:28:13 2025 +0100 ; reftex.el: Checkdoc fixes, comments to docstrings * lisp/textmodes/reftex.el (reftex-next-multifile-index): (reftex-TeX-master-file, reftex-is-multi): (reftex-get-cite-format, reftex-ensure-compiled-variables): (reftex-erase-all-selection-and-index-buffers): (reftex-compile-variables, reftex-parse-args): (reftex-access-scan-info, reftex-check-parse-consistency): (reftex-select-external-document, reftex-find-file-externally): (reftex-access-search-path, reftex-find-file-on-path): (reftex-parse-colon-path, reftex-expand-path): (reftex-recursive-directory-list, reftex-typekey-check): (reftex-check-recursive-edit, reftex-no-props): (reftex-match-string, reftex-kill-buffer): (reftex-erase-buffer, reftex-this-word, reftex-all-assq): (reftex-all-assoc-string, reftex-last-assoc-before-elt): (reftex-sublist-nth, reftex-make-selection-buffer-name): (reftex-make-index-buffer-name, reftex-truncate): (reftex-nearest-match, reftex-auto-mode-alist): (reftex-enlarge-to-fit, reftex-select-with-char): (reftex-make-regexp-allow-for-ctrl-m, reftex-visited-files): (reftex-get-file-buffer-force, reftex-kill-temporary-buffers): (reftex-splice-symbols-into-list, reftex-uniquify): (reftex-uniquify-by-car, reftex-nicify-text, reftex-refontify): (reftex-fontify-select-label-buffer): (reftex-select-font-lock-fontify-region): (reftex-verified-face, reftex-highlight-shall-die): Convert comment to docstring in functions. (reftex-silence-toc-markers): Convert comment to docstring and capitalize argument. (reftex-set-cite-format): Capitalize argument. (AUCTeX bug#77864) diff --git a/lisp/textmodes/reftex.el b/lisp/textmodes/reftex.el index ee217804d8f..946685150af 100644 --- a/lisp/textmodes/reftex.el +++ b/lisp/textmodes/reftex.el @@ -316,7 +316,7 @@ For buffer objects, returns the buffer object itself." (defvar-local reftex-docstruct-symbol nil) (defun reftex-next-multifile-index () - ;; Return the next free index for multifile symbols. + "Return the next free index for multifile symbols." (incf reftex-multifile-index)) (defun reftex--remove-buffer-from-master-index () @@ -372,10 +372,10 @@ If the symbols for the current master file do not exist, they are created." (set symbol nil)))) (defun reftex-TeX-master-file () - ;; Return the name of the master file associated with the current buffer. - ;; When AUCTeX is loaded, we will use it's more sophisticated method. - ;; We also support the default TeX and LaTeX modes by checking for a - ;; variable tex-main-file. + "Return the name of the master file associated with the current buffer. +When AUCTeX is loaded, we will use it's more sophisticated method. +We also support the default TeX and LaTeX modes by checking for a +variable `tex-main-file'." (with-current-buffer (or (buffer-base-buffer) (current-buffer)) (let ;; Set master to a file name (possibly non-existent), or nil: @@ -445,14 +445,14 @@ If the symbols for the current master file do not exist, they are created." (or master (current-buffer)))))) (defun reftex-is-multi () - ;; Tell if this is a multifile document. When not sure, say yes. + "Tell if this is a multifile document. When not sure, say yes." (let ((entry (assq 'is-multi (symbol-value reftex-docstruct-symbol)))) (if entry (nth 1 entry) t))) (defun reftex-set-cite-format (value) - "Set the document-local value of `reftex-cite-format'. + "Set the document-local VALUE of `reftex-cite-format'. When such a value exists, it overwrites the setting given with `reftex-cite-format'. See the documentation of `reftex-cite-format' for possible values. This function should be used from AUCTeX style files." @@ -463,8 +463,9 @@ for possible values. This function should be used from AUCTeX style files." (put reftex-docstruct-symbol 'reftex-cite-format value))) (defun reftex-get-cite-format () - ;; Return the current citation format. Either the document-local value in - ;; reftex-cite-format-symbol, or the global value in reftex-cite-format. + "Return the current citation format. +Either the document-local value in `reftex-cite-format-symbol', or the +global value in `reftex-cite-format'." (if (and reftex-docstruct-symbol (symbolp reftex-docstruct-symbol) (get reftex-docstruct-symbol 'reftex-cite-format)) @@ -697,7 +698,7 @@ will deactivate it." )) (defun reftex-ensure-compiled-variables () - ;; Recompile the label alist when necessary + "Recompile the label alist when necessary." (let* ((mem reftex-memory) (cache (get reftex-docstruct-symbol 'reftex-cache)) (cmem (car cache)) @@ -777,7 +778,7 @@ This enforces rescanning the buffer on next use." (set (symbol-value symbol) nil))))) (defun reftex-erase-all-selection-and-index-buffers () - ;; Remove all selection buffers associated with current document. + "Remove all selection buffers associated with current document." (mapc (lambda (type) (reftex-erase-buffer (reftex-make-selection-buffer-name type))) @@ -789,8 +790,7 @@ This enforces rescanning the buffer on next use." (cdr (assoc 'index-tags (symbol-value reftex-docstruct-symbol))))) (defun reftex-compile-variables () - ;; Compile the information in reftex-label-alist & Co. - + "Compile the information in reftex-label-alist & Co." (message "Compiling label environment definitions...") ;; Update AUCTeX style information @@ -1129,8 +1129,8 @@ This enforces rescanning the buffer on next use." (mapcar #'symbol-value reftex-cache-variables))) (defun reftex-parse-args (macro) - ;; Return a list of macro name, nargs, arg-nr which is label and a list of - ;; optional argument indices. + "Return a list of MACRO name, nargs, arg-nr. +arg-nr is label and a list of optional argument indices." (if (string-match "[[{]\\*?[]}]" macro) (progn (let ((must-match (substring macro 0 (match-beginning 0))) @@ -1152,11 +1152,11 @@ This enforces rescanning the buffer on next use." ;;; Accessing the parse information (defun reftex-access-scan-info (&optional rescan file) - "Ensure access to the scanning info for the current file." - ;; When the multifile symbols are not yet tied, - ;; tie them. When they are empty or RESCAN is non-nil, scan the document. - ;; But, when RESCAN is -1, don't rescan even if docstruct is empty. - ;; When FILE is non-nil, parse only from that file. + "Ensure access to the scanning info for the current file. +When the multifile symbols are not yet tied, tie them. +When they are empty or RESCAN is non-nil, scan the document. +But, when RESCAN is -1, don't rescan even if docstruct is empty. +When FILE is non-nil, parse only from that file." ;; Make sure we have the symbols tied (if (eq reftex-docstruct-symbol nil) @@ -1196,7 +1196,7 @@ This enforces rescanning the buffer on next use." t)) (defun reftex-silence-toc-markers (list n) - ;; Set all toc markers in the first N entries in list to nil + "Set all toc markers in the first N entries in LIST to nil." (while (and list (> (decf n) -1)) (and (eq (car (car list)) 'toc) (markerp (nth 4 (car list))) @@ -1292,7 +1292,7 @@ For non-file buffers, persistence operations are skipped." t)))) (defun reftex-check-parse-consistency () - ;; Check if parse file is consistent, throw an error if not. + "Check if parse file is consistent, throw an error if not." ;; Check if the master is the same: when moving a document, this will see it. (let* ((real-master (reftex-TeX-master-file)) @@ -1316,7 +1316,7 @@ For non-file buffers, persistence operations are skipped." ) (defun reftex-select-external-document (xr-alist xr-index) - ;; Return index of an external document. + "Return index of an external document." (let* ((len (length xr-alist)) (highest (1- (+ ?0 len))) (prompt (format "[%c-%c] Select TAB: Read prefix with completion" ?0 highest)) @@ -1401,9 +1401,9 @@ When FILE is a buffer object, return that buffer." (t (message "No such file: %s (ignored)" file) nil))))) (defun reftex-find-file-externally (file type &optional master-dir) - ;; Use external program to find FILE. - ;; The program is taken from `reftex-external-file-finders'. - ;; Interpret relative path definitions starting from MASTER-DIR. + "Use external program to find FILE. +The program is taken from `reftex-external-file-finders'. +Interpret relative path definitions starting from MASTER-DIR." (let ((default-directory (or master-dir default-directory)) (prg (cdr (assoc type reftex-external-file-finders))) out) @@ -1425,13 +1425,13 @@ When FILE is a buffer object, return that buffer." (apply #'call-process program nil '(t nil) nil args)))))) (defun reftex-access-search-path (type &optional recurse master-dir file) - ;; Access path from environment variables. TYPE is either "tex" or "bib". - ;; When RECURSE is t, expand path elements ending in `//' recursively. - ;; Relative path elements are left as they are. However, relative recursive - ;; elements are expanded with MASTER-DIR as default directory. - ;; The expanded path is cached for the next search. - ;; FILE is just for the progress message. - ;; Returns the derived path. + "Access path from environment variables. TYPE is either \"tex\" or \"bib\". +When RECURSE is t, expand path elements ending in `//' recursively. +Relative path elements are left as they are. However, relative recursive +elements are expanded with MASTER-DIR as default directory. +The expanded path is cached for the next search. +FILE is just for the progress message. +Returns the derived path." (let* ((pathvar (intern (concat "reftex-" type "-path")))) (when (null (get pathvar 'status)) ;; Get basic path @@ -1485,8 +1485,8 @@ When FILE is a buffer object, return that buffer." (symbol-value pathvar)))) (defun reftex-find-file-on-path (file path &optional def-dir) - ;; Find FILE along the directory list PATH. - ;; DEF-DIR is the default directory for expanding relative path elements. + "Find FILE along the directory list PATH. +DEF-DIR is the default directory for expanding relative path elements." (catch 'exit (when (file-name-absolute-p file) (if (file-regular-p file) @@ -1503,8 +1503,8 @@ When FILE is a buffer object, return that buffer." nil))) (defun reftex-parse-colon-path (path) - ;; Like parse-colon-parse, but // or /~ are left alone. - ;; Trailing ! or !! will be converted into `//' (emTeX convention) + "Like parse-colon-parse, but // or /~ are left alone. +Trailing ! or !! will be converted into `//' (emTeX convention)" (mapcar (lambda (dir) (if (string-match "\\(//+\\|/*!+\\)\\'" dir) @@ -1513,8 +1513,8 @@ When FILE is a buffer object, return that buffer." (delete "" (split-string path (concat path-separator "+"))))) (defun reftex-expand-path (path &optional default-dir) - ;; Expand parts of path ending in `//' recursively into directory list. - ;; Relative recursive path elements are expanded relative to DEFAULT-DIR. + "Expand parts of path ending in `//' recursively into directory list. +Relative recursive path elements are expanded relative to DEFAULT-DIR." (let (path1 dir recursive) (while (setq dir (pop path)) (if (setq recursive (string= (substring dir -2) "//")) @@ -1530,7 +1530,7 @@ When FILE is a buffer object, return that buffer." (nreverse path1))) (defun reftex-recursive-directory-list (dir) - ;; Return a list of all directories below DIR, including DIR itself + "Return a list of all directories below DIR, including DIR itself." (let ((path (list dir)) path1 file files) (while (setq dir (pop path)) (when (file-directory-p dir) @@ -1546,7 +1546,7 @@ When FILE is a buffer object, return that buffer." ;;; Some generally useful functions (defun reftex-typekey-check (typekey conf-variable &optional n) - ;; Check if CONF-VARIABLE is true or contains TYPEKEY + "Check if CONF-VARIABLE is true or contains TYPEKEY." (and n (setq conf-variable (nth n conf-variable))) (or (eq conf-variable t) (and (stringp conf-variable) @@ -1554,8 +1554,8 @@ When FILE is a buffer object, return that buffer." (string-match (concat "[" conf-variable "]") typekey))))) (defun reftex-check-recursive-edit () - ;; Check if we are already in a recursive edit. Abort with helpful - ;; message if so. + "Check if we are already in a recursive edit. +Abort with helpful message if so." (if (marker-position reftex-recursive-edit-marker) (error (substitute-command-keys @@ -1576,26 +1576,26 @@ When FILE is a buffer object, return that buffer." pos t))))) (defun reftex-no-props (string) - ;; Return STRING with all text properties removed + "Return STRING with all text properties removed." (and (stringp string) (set-text-properties 0 (length string) nil string)) string) (defun reftex-match-string (n) - ;; Match string without properties + "Match string without properties." (when (match-beginning n) (buffer-substring-no-properties (match-beginning n) (match-end n)))) (define-obsolete-function-alias 'reftex-region-active-p #'use-region-p "28.1") (defun reftex-kill-buffer (buffer) - ;; Kill buffer if it exists. + "Kill BUFFER if it exists." (and (setq buffer (get-buffer buffer)) (kill-buffer buffer))) (defun reftex-erase-buffer (&optional buffer) - ;; Erase BUFFER if it exists. BUFFER defaults to current buffer. - ;; This even erases read-only buffers. + "Erase BUFFER if it exists. BUFFER defaults to current buffer. +This even erases read-only buffers." (cond ((null buffer) ;; erase current buffer @@ -1606,7 +1606,7 @@ When FILE is a buffer object, return that buffer." (let ((inhibit-read-only t)) (erase-buffer)))))) (defun reftex-this-word (&optional class) - ;; Grab the word around point. + "Grab the word around point." (setq class (or class "-a-zA-Z0-9:_/.*;|")) (save-excursion (buffer-substring-no-properties @@ -1619,7 +1619,7 @@ When FILE is a buffer object, return that buffer." "")) (defun reftex-all-assq (key list) - ;; Return a list of all associations of KEY in LIST. Comparison with eq. + "Return a list of all associations of KEY in LIST. Comparison with eq." (let (rtn) (while (setq list (memq (assq key list) list)) (push (car list) rtn) @@ -1627,7 +1627,7 @@ When FILE is a buffer object, return that buffer." (nreverse rtn))) (defun reftex-all-assoc-string (key list) - ;; Return a list of all associations of KEY in LIST. Comparison with string=. + "Return a list of all associations of KEY in LIST. Comparison with string=." (let (rtn) (while list (if (string= (car (car list)) key) @@ -1636,11 +1636,11 @@ When FILE is a buffer object, return that buffer." (nreverse rtn))) (defun reftex-last-assoc-before-elt (key elt list &optional exclusive) - ;; Find the last association of KEY in LIST before or at ELT - ;; ELT is found in LIST with equal, not eq. - ;; Returns nil when either KEY or elt are not found in LIST. - ;; When EXCLUSIVE is non-nil, ELT cannot be the return value. - ;; On success, returns the association. + "Find the last association of KEY in LIST before or at ELT. +ELT is found in LIST with equal, not eq. +Returns nil when either KEY or elt are not found in LIST. +When EXCLUSIVE is non-nil, ELT cannot be the return value. +On success, returns the association." (let* ((elt (car (member elt list))) (ex (not exclusive)) ass last-ass) (while (and (setq ass (assoc key list)) (setq list (memq ass list)) @@ -1651,10 +1651,9 @@ When FILE is a buffer object, return that buffer." last-ass)) (defun reftex-sublist-nth (list nth predicate &optional completion) - ;; Make a list of the NTH elements of all members of LIST which - ;; fulfill PREDICATE. - ;; When COMPLETION is non-nil, make all elements of the resulting - ;; list also a list, so that the result can be used for completion. + "Make a list of the NTH elements of all members of LIST which fulfill PREDICATE. +When COMPLETION is non-nil, make all elements of the resulting +list also a list, so that the result can be used for completion." (let (rtn) (while list (if (funcall predicate (car list)) @@ -1666,20 +1665,20 @@ When FILE is a buffer object, return that buffer." (nreverse rtn))) (defun reftex-make-selection-buffer-name (type &optional index) - ;; Make unique name for a selection buffer. + "Make unique name for a selection buffer." (format " *RefTeX[%s][%d]*" type (or index (get reftex-docstruct-symbol :master-index) 0))) (defun reftex-make-index-buffer-name (tag &optional cnt) - ;; Make unique name for an index buffer. + "Make unique name for an index buffer." (format "*Index[%s][%d]*" tag (or cnt (get reftex-docstruct-symbol :master-index) 0))) (defun reftex-truncate (string ncols &optional ellipses padding) - ;; Truncate STRING to NCOLS characters. - ;; When PADDING is non-nil, and string is shorter than NCOLS, fill with - ;; white space to NCOLS characters. When ELLIPSES is non-nil and the - ;; string needs to be truncated, replace last 3 characters by dots. + "Truncate STRING to NCOLS characters. +When PADDING is non-nil, and string is shorter than NCOLS, fill with +white space to NCOLS characters. When ELLIPSES is non-nil and the +string needs to be truncated, replace last 3 characters by dots." (setq string (if (<= (length string) ncols) string @@ -1691,9 +1690,9 @@ When FILE is a buffer object, return that buffer." string)) (defun reftex-nearest-match (regexp &optional max-length) - ;; Find the nearest match of REGEXP. Set the match data. - ;; If POS is given, calculate distances relative to it. - ;; Return nil if there is no match. + "Find the nearest match of REGEXP. Set the match data. +If POS is given, calculate distances relative to it. +Return nil if there is no match." (let ((pos (point)) (dist (or max-length (length regexp))) match1 match2 match) @@ -1713,8 +1712,8 @@ When FILE is a buffer object, return that buffer." (if match (progn (set-match-data match) t) nil))) (defun reftex-auto-mode-alist () - ;; Return an `auto-mode-alist' with only the .gz (etc) thingies. - ;; Stolen from gnus nnheader. + "Return an `auto-mode-alist' with only the .gz (etc) thingies. +Stolen from gnus nnheader." (let ((alist auto-mode-alist) out) (while alist @@ -1724,8 +1723,8 @@ When FILE is a buffer object, return that buffer." (nreverse out))) (defun reftex-enlarge-to-fit (buf2 &optional keep-current) - ;; Enlarge other window displaying buffer to show whole buffer if possible. - ;; If KEEP-CURRENT in non-nil, current buffer must remain visible. + "Enlarge other window displaying buffer to show whole buffer if possible. +If KEEP-CURRENT in non-nil, current buffer must remain visible." (let* ((win1 (selected-window)) (buf1 (current-buffer)) (win2 (get-buffer-window buf2))) ;; Only on current frame. @@ -1743,9 +1742,9 @@ When FILE is a buffer object, return that buffer." (shrink-window (- (window-height) window-min-height)))))) (defun reftex-select-with-char (prompt help-string &optional delay-time scroll) - ;; Offer to select something with PROMPT and, after DELAY-TIME seconds, - ;; also with HELP-STRING. - ;; When SCROLL is non-nil, use SPC and DEL to scroll help window. + "Offer to select something with PROMPT. +After DELAY-TIME seconds, also with HELP-STRING. When SCROLL is +non-nil, use \\`SPC' and \\`DEL' to scroll help window." (let ((char ?\?)) (save-window-excursion (catch 'exit @@ -1783,7 +1782,7 @@ When FILE is a buffer object, return that buffer." (defun reftex-make-regexp-allow-for-ctrl-m (string) - ;; convert STRING into a regexp, allowing ^M for \n and vice versa + "Convert STRING into a regexp, allowing ^M for \\n and vice versa." (let ((start -2)) (setq string (regexp-quote string)) (while (setq start (string-match "[\n\r]" string (+ 3 start))) @@ -1794,16 +1793,16 @@ When FILE is a buffer object, return that buffer." #'find-buffer-visiting "28.1") (defun reftex-visited-files (list) - ;; Takes a list of filenames and returns the buffers of those already visited + "Takes a list of filenames and returns the buffers of those already visited." (delq nil (mapcar (lambda (x) (if (find-buffer-visiting x) x nil)) list))) (defun reftex-get-file-buffer-force (file &optional mark-to-kill) - ;; Return a buffer visiting file. Make one, if necessary. - ;; If neither such a buffer nor the file exist, return nil. - ;; If MARK-TO-KILL is t and there is no live buffer, visit the file with - ;; initializations according to `reftex-initialize-temporary-buffers', - ;; and mark the buffer to be killed after use. + "Return a buffer visiting file. Make one, if necessary. +If neither such a buffer nor the file exist, return nil. +If MARK-TO-KILL is t and there is no live buffer, visit the file with +initializations according to `reftex-initialize-temporary-buffers', +and mark the buffer to be killed after use." (let ((buf (if (bufferp file) file @@ -1849,7 +1848,7 @@ When FILE is a buffer object, return that buffer." (t nil)))) (defun reftex-kill-temporary-buffers (&optional buffer) - ;; Kill all buffers in the list reftex-kill-temporary-buffers. + "Kill all buffers in the list reftex-kill-temporary-buffers." (cond (buffer (when (member buffer reftex-buffers-to-kill) @@ -1868,8 +1867,8 @@ When FILE is a buffer object, return that buffer." (pop reftex-buffers-to-kill))))) (defun reftex-splice-symbols-into-list (list alist) - ;; Splice the association in ALIST of any symbols in LIST into the list. - ;; Return new list. + "Splice the association in ALIST of any symbols in LIST into the list. +Return new list." (let (rtn tmp) (while list (while (and (not (null (car list))) ;; keep list elements nil @@ -1885,8 +1884,8 @@ When FILE is a buffer object, return that buffer." (nreverse rtn))) (defun reftex-uniquify (list &optional sort) - ;; Return a list of all strings in LIST, but each only once, keeping order - ;; unless SORT is set (faster!). + "Return a list of all strings in LIST, but each only once. +Keep order unless SORT is set (faster!)." (setq list (copy-sequence list)) (if sort (progn @@ -1917,9 +1916,9 @@ When FILE is a buffer object, return that buffer." (delq nil list))) (defun reftex-uniquify-by-car (alist &optional keep-list sort) - ;; Return a list of all elements in ALIST, but each car only once. - ;; Elements of KEEP-LIST are not removed even if duplicate. - ;; The order is kept unless SORT is set (faster!). + "Return a list of all elements in ALIST, but each car only once. +Elements of KEEP-LIST are not removed even if duplicate. +The order is kept unless SORT is set (faster!)." (setq keep-list (sort (copy-sequence keep-list) #'string<) alist (copy-sequence alist)) (if sort @@ -2055,7 +2054,7 @@ IGNORE-WORDS List of words which should be removed from the string." string)) (defun reftex-nicify-text (text) - ;; Make TEXT nice for inclusion as context into label menu. + "Make TEXT nice for inclusion as context into label menu." ;; 1. remove line breaks and extra white space (while (string-match "[\n\r\t]\\|[ \t][ \t]+" text) (setq text (replace-match " " nil t text))) @@ -2080,7 +2079,7 @@ IGNORE-WORDS List of words which should be removed from the string." ;;; Fontification and Highlighting (defun reftex-refontify () - ;; Return t if we need to refontify context + "Return t if we need to refontify context." (and reftex-use-fonts (or (eq t reftex-refontify-context) (and (eq 1 reftex-refontify-context) @@ -2088,8 +2087,9 @@ IGNORE-WORDS List of words which should be removed from the string." (and (featurep 'x-symbol-tex) (not (boundp 'x-symbol-mode))))))) (defun reftex-fontify-select-label-buffer (parent-buffer) - ;; Fontify the `*RefTeX Select*' buffer. Buffer is temporarily renamed to - ;; start with none-SPC char, because Font-Lock otherwise refuses operation. + "Fontify the `*RefTeX Select*' buffer. +Buffer is temporarily renamed to start with none-SPC char, because +Font-Lock otherwise refuses operation." (run-hook-with-args 'reftex-pre-refontification-functions parent-buffer 'reftex-ref) (let* ((oldname (buffer-name)) @@ -2107,7 +2107,7 @@ IGNORE-WORDS List of words which should be removed from the string." (rename-buffer oldname)))) (defun reftex-select-font-lock-fontify-region (beg end &optional _loudly) - ;; Fontify a region, but only lines starting with a dot. + "Fontify a region, but only lines starting with a dot." (let ((func (if (fboundp 'font-lock-default-fontify-region) 'font-lock-default-fontify-region 'font-lock-fontify-region)) @@ -2121,10 +2121,10 @@ IGNORE-WORDS List of words which should be removed from the string." (defun reftex-select-font-lock-unfontify (&rest _ignore) t) (defun reftex-verified-face (&rest faces) - ;; Return the first valid face in FACES, or nil if none is valid. - ;; Also, when finding a nil element in FACES, return nil. This - ;; function is just a safety net to catch name changes of builtin - ;; fonts. Currently it is only used for reftex-label-face. + "Return the first valid face in FACES, or nil if none is valid. +Also, when finding a nil element in FACES, return nil. This +function is just a safety net to catch name changes of builtin +fonts. Currently it is only used for reftex-label-face." (let (face) (catch 'exit (while (setq face (pop faces)) @@ -2159,7 +2159,7 @@ IGNORE-WORDS List of words which should be removed from the string." (delete-overlay (aref reftex-highlight-overlays index))) (defun reftex-highlight-shall-die () - ;; Function used in pre-command-hook to remove highlights. + "Function used in pre-command-hook to remove highlights." (remove-hook 'pre-command-hook #'reftex-highlight-shall-die) (reftex-unhighlight 0)) commit c459ba692ece6ed7c9d4be9cf3821b4efe04cd30 Author: Sean Whitton Date: Fri May 30 13:21:07 2025 +0100 vc-finish-logentry: Don't run vc-finish-logentry-hook * lisp/vc/vc-dispatcher.el (vc-finish-logentry): Don't run undocumented, undeclared 'vc-finish-logentry-hook'. There is already 'vc-log-after-operation-hook'; it is not clear we need both. diff --git a/lisp/vc/vc-dispatcher.el b/lisp/vc/vc-dispatcher.el index 2368cc6512e..820c666ca7d 100644 --- a/lisp/vc/vc-dispatcher.el +++ b/lisp/vc/vc-dispatcher.el @@ -874,19 +874,15 @@ the buffer contents as a comment." (setq vc-log-operation nil) ;; Quit windows on logbuf. - (cond - ((not logbuf)) - (vc-delete-logbuf-window - (quit-windows-on logbuf t (selected-frame))) - (t - (quit-windows-on logbuf nil 0))) + (cond ((not logbuf)) + (vc-delete-logbuf-window + (quit-windows-on logbuf t (selected-frame))) + (t + (quit-windows-on logbuf nil 0))) ;; Now make sure we see the expanded headers - (when log-fileset - (mapc - (lambda (file) (vc-resynch-buffer file t t)) - log-fileset)) - (run-hooks after-hook 'vc-finish-logentry-hook))) + (mapc (lambda (file) (vc-resynch-buffer file t t)) log-fileset) + (run-hooks after-hook))) (defun vc-dispatcher-browsing () "Are we in a directory browser buffer?" commit f699b6e4f409c0cc98703a2cea9b243ff8cb570a Author: Sean Whitton Date: Fri May 30 11:41:06 2025 +0100 Gather variable binding tests in data-tests.el * test/lisp/emacs-lisp/lisp-tests.el (c-e-x, c-e-l): Move to data-tests.el. (core-elisp-tests-2-window-configurations): Rename ... (core-elisp-tests-1-window-configurations): ... to this. (core-elisp-tests-3-backquote): Rename ... (core-elisp-tests-2-backquote): ... to this. (core-elisp-tests-1-defvar-in-let) (core-elisp-tests-4-toplevel-values): Move and rename ... * test/src/data-tests.el (binding-test-defvar-in-let) (binding-test-toplevel-values): ... to these. (c-e-x, c-e-l): Moved from data-tests.el. diff --git a/test/lisp/emacs-lisp/lisp-tests.el b/test/lisp/emacs-lisp/lisp-tests.el index 1ef6bc864a7..d7cdaa3b331 100644 --- a/test/lisp/emacs-lisp/lisp-tests.el +++ b/test/lisp/emacs-lisp/lisp-tests.el @@ -212,21 +212,7 @@ (goto-char (point-min)) (should-error (forward-sexp)))) ;; FIXME: Shouldn't be an error. -;; Test some core Elisp rules. -(defvar c-e-x) -(ert-deftest core-elisp-tests-1-defvar-in-let () - "Test some core Elisp rules." - (with-temp-buffer - ;; Check that when defvar is run within a let-binding, the toplevel default - ;; is properly initialized. - (should (equal (list (let ((c-e-x 1)) (defvar c-e-x 2) c-e-x) c-e-x) - '(1 2))) - (should (equal (list (let ((c-e-x 1)) - (defcustom c-e-x 2 "doc" :group 'blah :type 'integer) c-e-x) - c-e-x) - '(1 2))))) - -(ert-deftest core-elisp-tests-2-window-configurations () +(ert-deftest core-elisp-tests-1-window-configurations () "Test properties of window-configurations." (let ((wc (current-window-configuration))) (with-current-buffer (window-buffer (frame-selected-window)) @@ -235,40 +221,10 @@ (set-window-configuration wc) (should (or (not mark-active) (mark))))) -(ert-deftest core-elisp-tests-3-backquote () +;; For variable binding tests, see src/data-tests.el. +(ert-deftest core-elisp-tests-2-backquote () (should (eq 3 (eval ``,,'(+ 1 2) t)))) -(defvar-local c-e-l 'foo) -(ert-deftest core-elisp-tests-4-toplevel-values () - (setq-default c-e-l 'foo) - (let ((c-e-l 'bar)) - (let ((c-e-l 'baz)) - (setq-default c-e-l 'bar) - (should (eq c-e-l 'bar)) - (should (eq (default-toplevel-value 'c-e-l) 'foo)) - (set-default-toplevel-value 'c-e-l 'baz) - (should (eq c-e-l 'bar)) - (should (eq (default-toplevel-value 'c-e-l) 'baz)))) - (let ((c-e-u 'foo)) - (should (condition-case _ - (default-toplevel-value 'c-e-u) - (void-variable t)))) - (with-temp-buffer - (setq-local c-e-l 'bar) - (should (eq (buffer-local-toplevel-value 'c-e-l) 'bar)) - (let ((c-e-l 'baz)) - (let ((c-e-l 'quux)) - (setq-local c-e-l 'baz) - (should (eq c-e-l 'baz)) - (should (eq (buffer-local-toplevel-value 'c-e-l) 'bar)) - (set-buffer-local-toplevel-value 'c-e-l 'foo) - (should (eq c-e-l 'baz)) - (should (eq (buffer-local-toplevel-value 'c-e-l) 'foo))))) - (with-temp-buffer - (should (condition-case _ - (buffer-local-toplevel-value 'c-e-l) - (void-variable t))))) - ;; Test up-list and backward-up-list. (defun lisp-run-up-list-test (fn data start instructions) (cl-labels ((posof (thing) diff --git a/test/src/data-tests.el b/test/src/data-tests.el index 260bdb281bb..75be9856463 100644 --- a/test/src/data-tests.el +++ b/test/src/data-tests.el @@ -354,6 +354,19 @@ comparing the subr with a much slower Lisp implementation." (setq-default binding-test-some-local 'new-default)) (should (eq binding-test-some-local 'some)))) +(defvar c-e-x) +(ert-deftest binding-test-defvar-in-let () + "Test some core Elisp rules." + (with-temp-buffer + ;; Check that when defvar is run within a let-binding, the toplevel default + ;; is properly initialized. + (should (equal (list (let ((c-e-x 1)) (defvar c-e-x 2) c-e-x) c-e-x) + '(1 2))) + (should (equal (list (let ((c-e-x 1)) + (defcustom c-e-x 2 "doc" :group 'blah :type 'integer) c-e-x) + c-e-x) + '(1 2))))) + (ert-deftest data-tests--let-buffer-local () (let ((blvar (make-symbol "blvar"))) (set-default blvar nil) @@ -396,6 +409,37 @@ comparing the subr with a much slower Lisp implementation." (should (equal (default-value var) def))) ))))) +(defvar-local c-e-l 'foo) +(ert-deftest binding-test-toplevel-values () + (setq-default c-e-l 'foo) + (let ((c-e-l 'bar)) + (let ((c-e-l 'baz)) + (setq-default c-e-l 'bar) + (should (eq c-e-l 'bar)) + (should (eq (default-toplevel-value 'c-e-l) 'foo)) + (set-default-toplevel-value 'c-e-l 'baz) + (should (eq c-e-l 'bar)) + (should (eq (default-toplevel-value 'c-e-l) 'baz)))) + (let ((c-e-u 'foo)) + (should (condition-case _ + (default-toplevel-value 'c-e-u) + (void-variable t)))) + (with-temp-buffer + (setq-local c-e-l 'bar) + (should (eq (buffer-local-toplevel-value 'c-e-l) 'bar)) + (let ((c-e-l 'baz)) + (let ((c-e-l 'quux)) + (setq-local c-e-l 'baz) + (should (eq c-e-l 'baz)) + (should (eq (buffer-local-toplevel-value 'c-e-l) 'bar)) + (set-buffer-local-toplevel-value 'c-e-l 'foo) + (should (eq c-e-l 'baz)) + (should (eq (buffer-local-toplevel-value 'c-e-l) 'foo))))) + (with-temp-buffer + (should (condition-case _ + (buffer-local-toplevel-value 'c-e-l) + (void-variable t))))) + (ert-deftest binding-test-makunbound () "Tests of makunbound, from the manual." (with-current-buffer binding-test-buffer-B commit 30c2ef6d6ab73b913ee5c4da7b6cfc26477f5faa Author: Michael Albinus Date: Fri May 30 12:28:15 2025 +0200 Fix bug in `tramp-find-executable' * lisp/net/tramp-sh.el (tramp-find-executable): Use "command -v", preserving non-standard PATH search. Bug#78633) diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index 64ad3d4996e..eb446f4e2cd 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -4124,7 +4124,7 @@ This function expects to be in the right *tramp* buffer." (setq newdl (cons d newdl)))) (setq dirlist (nreverse newdl)))) (when (tramp-send-command-and-check - vec (format "(unalias %s; %s command -pv %s)" + vec (format "(unalias %s; %s command -v %s)" progname (if dirlist (concat "PATH=" (string-join dirlist ":")) "") progname)) commit 8881dca81c95bac1977aa2c924be173382444c4a Author: Eli Zaretskii Date: Thu May 29 19:02:13 2025 +0300 ; * doc/lispref/searching.texi (Char Classes): Add speedup advice. diff --git a/doc/lispref/searching.texi b/doc/lispref/searching.texi index 09ff6202afa..8434431a74a 100644 --- a/doc/lispref/searching.texi +++ b/doc/lispref/searching.texi @@ -616,7 +616,10 @@ This matches horizontal whitespace, as defined by Annex C of the Unicode Technical Standard #18. In particular, it matches spaces, tabs, and other characters whose Unicode @samp{general-category} property (@pxref{Character Properties}) indicates they are spacing -separators. +separators. (If you only need to look for ASCII whitespace characters, +we suggest using an explicit set of character alternatives, such as +@w{@samp{[ \t]}}, instead, as it will be faster than +@code{[[:blank:]]}.) @item [:cntrl:] This matches any character whose code is in the range 0--31. @item [:digit:] commit 4507b6a9c7587c2b3caa241982db13e999197b1c Author: Stephen Berman Date: Wed May 28 17:17:23 2025 +0200 Fix bug in 'todo-jump-to-category' (bug#78608) * lisp/calendar/todo-mode.el (todo-jump-to-category): Eliminate comparison of the number of Todo categories before and after specifying the category to jump to and replace it by a check of whether there are any items in the category, since an existing category should always have at least one item (perhaps done or archived). diff --git a/lisp/calendar/todo-mode.el b/lisp/calendar/todo-mode.el index 652176af3b1..6fee0ce2950 100644 --- a/lisp/calendar/todo-mode.el +++ b/lisp/calendar/todo-mode.el @@ -952,12 +952,9 @@ Categories mode." todo-current-todo-file) ".toda") ;; Otherwise, jump to the category in the todo file. todo-current-todo-file))) - (len (length todo-categories)) (cat+file (unless cat (todo-read-category "Jump to category: " (if archive 'archive) file))) - (add-item (and todo-add-item-if-new-category - (> (length todo-categories) len))) (category (or cat (car cat+file)))) (unless cat (setq file0 (cdr cat+file))) (with-current-buffer (find-file-noselect file0 'nowarn) @@ -971,7 +968,10 @@ Categories mode." (todo-category-select) (goto-char (point-min)) (if (bound-and-true-p hl-line-mode) (hl-line-highlight)) - (when add-item (todo-insert-item--basic)))))) + (when (and todo-add-item-if-new-category + ;; A new category is empty on creation. + (seq-every-p #'zerop (cdr (assoc category todo-categories)))) + (todo-insert-item--basic)))))) (defun todo-next-item (&optional count) "Move point down to the beginning of the next item. commit 3e57c35323abe0782ba6a70adeecf99c27497e48 Author: Michael Albinus Date: Tue May 27 09:10:51 2025 +0200 Fix gitlab-ci.yml (don't merge to master) * test/infra/gitlab-ci.yml (.job-template): Fix config.log name. (test-filenotify-gio, test-eglot): Fix formatting. diff --git a/test/infra/gitlab-ci.yml b/test/infra/gitlab-ci.yml index caa81b07039..2b443d14c24 100644 --- a/test/infra/gitlab-ci.yml +++ b/test/infra/gitlab-ci.yml @@ -91,7 +91,7 @@ default: # - test -n "$(docker ps -aq -f name=${test_name})" && ( docker export ${test_name} | tar -tvf - ) # Prepare test artifacts. - test -n "$(docker ps -aq -f name=${test_name})" && docker cp ${test_name}:checkout/test ${test_name} - - test -n "$(docker ps -aq -f name=${test_name})" && docker cp ${test_name}:checkout/configure.log ${test_name} || true + - test -n "$(docker ps -aq -f name=${test_name})" && docker cp ${test_name}:checkout/config.log ${test_name} || true - test -n "$(docker ps -aq -f name=${test_name})" && docker rm ${test_name} - find ${test_name} ! \( -name "*.log" -o -name ${EMACS_TEST_JUNIT_REPORT} \) -type f -delete # BusyBox find does not know -empty. @@ -269,8 +269,8 @@ test-filenotify-gio: # This is needed in order to get a JUnit test report. make_params: >- check-expensive - TEST_HOME=/root - LOGFILES="lisp/autorevert-tests.log lisp/filenotify-tests.log" + TEST_HOME=/root + LOGFILES="lisp/autorevert-tests.log lisp/filenotify-tests.log" build-image-eglot: stage: platform-images @@ -288,12 +288,7 @@ test-eglot: target: emacs-eglot # This is needed in order to get a JUnit test report. make_params: >- - check-expensive - TEST_HOME=/root LOGFILES="lisp/progmodes/eglot-tests.log" - # EMACS_EXTRAOPT="--eval \(package-reinstall\ \(quote\ company\)\) - # --eval \(package-reinstall\ \(quote\ yasnippet\)\) - # --eval \(use-package\ company\) - # --eval \(use-package\ yasnippet\)" + check-expensive TEST_HOME=/root LOGFILES="lisp/progmodes/eglot-tests.log" build-image-tree-sitter: stage: platform-images commit 1d2ae31b8bcca5f00c3c707cc7af3a347749c332 Author: Konstantin Kharlamov Date: Tue Apr 29 21:51:18 2025 +0700 typescript-ts-mode: Improve function body indentation (bug#78121) Older code was calculating body indentation depending on function parameters alignment. This is incorrect, because if parameters are misaligned, so will the function body. Instead, use offset of the previous standalone parent. * lisp/progmodes/typescript-ts-mode.el: (typescript-ts-mode--indent-rules): Stop depending on function parameters indentation for calculating body content and the closing `}'. * test/lisp/progmodes/typescript-ts-mode-resources/indent.erts: (Function body with params misindented (bug#78121)): Add new test. diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index 6cc1eb0bea9..72b9d31204c 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -111,7 +111,7 @@ declarations, accounting for the length of keyword (var, let, or const)." Argument LANGUAGE is either `typescript' or `tsx'." `((,language ((parent-is "program") column-0 0) - ((node-is "}") parent-bol 0) + ((node-is "}") standalone-parent 0) ((node-is ")") parent-bol 0) ((node-is "]") parent-bol 0) ((node-is ">") parent-bol 0) @@ -121,7 +121,7 @@ Argument LANGUAGE is either `typescript' or `tsx'." ((parent-is "ternary_expression") standalone-parent typescript-ts-mode-indent-offset) ((parent-is "member_expression") parent-bol typescript-ts-mode-indent-offset) ((parent-is "named_imports") parent-bol typescript-ts-mode-indent-offset) - ((parent-is "statement_block") parent-bol typescript-ts-mode-indent-offset) + ((parent-is "statement_block") standalone-parent typescript-ts-mode-indent-offset) ((or (node-is "case") (node-is "default")) parent-bol typescript-ts-mode-indent-offset) diff --git a/test/lisp/progmodes/typescript-ts-mode-resources/indent.erts b/test/lisp/progmodes/typescript-ts-mode-resources/indent.erts index 8abaa81c627..405566c40f0 100644 --- a/test/lisp/progmodes/typescript-ts-mode-resources/indent.erts +++ b/test/lisp/progmodes/typescript-ts-mode-resources/indent.erts @@ -164,3 +164,28 @@ interface Foo { bar?: boolean; } =-=-= + +Code: + (lambda () + (setq tsx-ts-mode-indent-offset 2) + (tsx-ts-mode) + (setq indent-tabs-mode nil) + (indent-region (line-beginning-position 7) (point-max))) + +Name: Function body with params misindented (bug#78121) + +=-= +const f1 = (a1: string, + a2: number) => { + const f2 = (a1: string, + a2: number) => { + const f3 = (a1: string, + a2: number) => + { + return; + } + return; + } + return; +} +=-=-= commit 421ecbcf6b476c413675e93c074f1399db146fc8 Author: Eli Zaretskii Date: Sun May 25 12:08:02 2025 +0300 ; * CONTRIBUTE: Explain the line-width preferences. diff --git a/CONTRIBUTE b/CONTRIBUTE index 06e6fe45c84..2da47fa35f8 100644 --- a/CONTRIBUTE +++ b/CONTRIBUTE @@ -231,7 +231,9 @@ formatting them: - Lines in ChangeLog entries should preferably be not longer than 63 characters, and must not exceed 78 characters, unless they consist of a single word of at most 140 characters; this 78/140 limit is - enforced by a commit hook. + enforced by a commit hook. (The 63-character preference is to + avoid too-long lines in the ChangeLog file generated from Git logs, + where each entry line is indented by a TAB.) - If only a single file is changed, the summary line can be the normal first line of a ChangeLog entry (starting with the asterisk). Then