commit b0a0127880e01d8b35468269ac03fad45c900b61 (HEAD, refs/remotes/origin/master) Author: Sean Whitton Date: Mon Dec 1 22:00:42 2025 +0000 vc-dir-headers: Use ngettext, move the newline out of 'propertize' * lisp/vc/vc-dir.el (vc-dir-headers): Use ngettext, move the newline out of 'propertize'. diff --git a/lisp/vc/vc-dir.el b/lisp/vc/vc-dir.el index 937c33a2db4..28690583ba1 100644 --- a/lisp/vc/vc-dir.el +++ b/lisp/vc/vc-dir.el @@ -1353,12 +1353,16 @@ specific headers." (_ (plusp count))) (concat (propertize "Outgoing : " 'face 'vc-dir-header) - (propertize (format "%d unpushed revisions\n" count) + (propertize (format (ngettext "%d unpushed revision" + "%d unpushed revisions" + count) + count) 'face 'vc-dir-header-urgent-value 'mouse-face 'highlight 'keymap vc-dir-outgoing-revisions-map 'help-echo "\\\ -\\[vc-log-outgoing]: List outgoing revisions"))))) +\\[vc-log-outgoing]: List outgoing revisions") + "\n")))) (defun vc-dir-refresh-files (files) "Refresh some FILES in the *VC-Dir* buffer." commit 49611cce303c136d3ff6bd27aba66dfb68d60eb4 Author: Elías Gabriel Pérez Date: Thu Sep 18 19:24:53 2025 -0600 hideshow.el: New commands 'hs-cycle' and 'hs-toggle-all'. (Bug#79877) * etc/NEWS: Announce features. * doc/emacs/programs.texi (Hideshow): Document it. * lisp/progmodes/hideshow.el (hs-prefix-map): Bind the new commands. (hs-hide-level-recursive): Simplify. (hs--toggle-all-state): New variable. (hs-toggle-all, hs-cycle): New commands. (hs-get-near-block): New function. (hs-hide-block): Simplify. Co-authored-by: Karthik Chikmagalur diff --git a/doc/emacs/programs.texi b/doc/emacs/programs.texi index 0adb90b36cb..6acd04d0bae 100644 --- a/doc/emacs/programs.texi +++ b/doc/emacs/programs.texi @@ -1699,6 +1699,7 @@ count as blocks. @findex hs-show-region @findex hs-hide-level @findex hs-toggle-hiding +@findex hs-cycle @kindex C-c @@ C-h @kindex C-c @@ C-s @kindex C-c @@ C-c @@ -1706,6 +1707,8 @@ count as blocks. @kindex C-c @@ C-M-s @kindex C-c @@ C-r @kindex C-c @@ C-l +@kindex C-c @@ TAB +@kindex C-c @@ @kindex S-mouse-2 @table @kbd @item C-c @@ C-h @@ -1726,6 +1729,10 @@ Show all blocks in the buffer (@code{hs-show-all}). @item C-u @var{n} C-c @@ C-l Hide all blocks @var{n} levels below this block (@code{hs-hide-level}). +@item C-c @@ TAB +Cycle the visibility state of the current block (@code{hs-cycle}). +@item C-c @@ +Either hide or show all the blocks in the current buffer. (@code{hs-toggle-all}). @end table @vindex hs-hide-comments-when-hiding-all diff --git a/etc/NEWS b/etc/NEWS index 5623f1f5825..ed5efced52c 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1092,6 +1092,16 @@ convention (regexp arg second) and Emacs convention (regexp arg first). ** Hideshow ++++ +*** New command 'hs-cycle'. +This command cycles the visibility state of the current block between +hide the parent block, hide the nested blocks only and show all the +blocks. + ++++ +*** New command 'hs-toggle-all'. +This command hide or show all the blocks in the current buffer. + +++ *** New user option 'hs-display-lines-hidden'. If this option is non-nil, Hideshow displays the number of hidden lines diff --git a/lisp/progmodes/hideshow.el b/lisp/progmodes/hideshow.el index ac0c68a0410..e916d2091c5 100644 --- a/lisp/progmodes/hideshow.el +++ b/lisp/progmodes/hideshow.el @@ -39,6 +39,8 @@ ;; `hs-toggle-hiding' C-c @ C-c ;; `hs-toggle-hiding' S- ;; `hs-hide-initial-comment-block' +;; `hs-cycle' C-c @ TAB +;; `hs-toggle-all' C-c @ ;; ;; All these commands are defined in `hs-prefix-map', ;; `hs-minor-mode-map' and `hs-indicators-map'. @@ -504,16 +506,18 @@ Use the command `hs-minor-mode' to toggle or set this variable.") :doc "Keymap for hideshow commands." :prefix t ;; These bindings roughly imitate those used by Outline mode. - "C-h" #'hs-hide-block - "C-s" #'hs-show-block - "C-M-h" #'hs-hide-all - "C-M-s" #'hs-show-all - "C-l" #'hs-hide-level - "C-c" #'hs-toggle-hiding - "C-a" #'hs-show-all - "C-t" #'hs-hide-all - "C-d" #'hs-hide-block - "C-e" #'hs-toggle-hiding) + "C-h" #'hs-hide-block + "C-d" #'hs-hide-block + "C-s" #'hs-show-block + "C-M-h" #'hs-hide-all + "C-t" #'hs-hide-all + "C-M-s" #'hs-show-all + "C-a" #'hs-show-all + "C-l" #'hs-hide-level + "C-c" #'hs-toggle-hiding + "C-e" #'hs-toggle-hiding + "TAB" #'hs-cycle + "" #'hs-toggle-all) (defvar-keymap hs-minor-mode-map :doc "Keymap for hideshow minor mode." @@ -589,6 +593,8 @@ to the variable `mode-line-format'. For example, Note that `mode-line-format' is buffer-local.") +(defvar-local hs--toggle-all-state) + ;;--------------------------------------------------------------------------- ;; API variables @@ -1057,6 +1063,34 @@ first block found. Otherwise, if no block is found, it returns nil." t)))) exit)) +(defun hs-get-near-block (&optional include-comment) + "Reposition point to a near block around point. +It search for a valid block before and after point and return t if one +is found. + +If INCLUDE-COMMENT is non-nil, it also searches for a comment block, +returning `comment' if one is found." + (let ((c-reg (when include-comment (funcall hs-inside-comment-predicate))) + pos) + (cond + ((and c-reg (car c-reg) (hs-hideable-region-p + (car c-reg) (cadr c-reg))) + (goto-char (car c-reg)) + 'comment) + + ((and (eq hs-hide-block-behavior 'after-bol) + (save-excursion + (goto-char (line-beginning-position)) + (setq pos (hs-get-first-block)))) + (goto-char pos) + t) + + ((and (or (funcall hs-looking-at-block-start-predicate) + (and (goto-char (line-beginning-position)) + (funcall hs-find-block-beginning-function))) + (hs-hideable-region-p)) + t)))) + (defun hs-inside-comment-p () (declare (obsolete "Call `hs-inside-comment-predicate' instead." "31.1")) (funcall hs-inside-comment-predicate)) @@ -1184,26 +1218,35 @@ region (point MAXP)." (and (< (point) maxp) (re-search-forward regexp maxp t))) -(defun hs-hide-level-recursive (arg minp maxp) - "Recursively hide blocks ARG levels below point in region (MINP MAXP)." +(defun hs-hide-level-recursive (arg &optional beg end) + "Recursively hide blocks between BEG and END that are ARG levels below point. +If BEG and END are not specified, it will search for a near block and +use its position instead. + +If point is inside a block, it will use the current block positions +instead of BEG and END." + ;; If we are near of a block, set BEG and END according to that + ;; block positions. (when (funcall hs-find-block-beginning-function) - (setq minp (1+ (point))) - (funcall hs-forward-sexp-function 1) - (setq maxp (1- (point)))) - (unless hs-allow-nesting - (hs-discard-overlays minp maxp)) - (goto-char minp) - (while (funcall hs-find-next-block-function hs-block-start-regexp maxp nil) - (when (save-match-data - (not (nth 8 (syntax-ppss)))) ; not inside comments or strings - (if (> arg 1) - (hs-hide-level-recursive (1- arg) minp maxp) - ;; `hs-hide-block-at-point' already moves the cursor, but if it - ;; fails, return to the previous position where we were. - (unless (and (goto-char (match-beginning hs-block-start-mdata-select)) - (hs-hide-block-at-point t)) - (goto-char (match-end hs-block-start-mdata-select)))))) - (goto-char maxp)) + (let ((block (hs-block-positions))) + (setq beg (point) end (cadr block)))) + + ;; Show all blocks in that region + (unless hs-allow-nesting (hs-discard-overlays beg end)) + + ;; Skip initial block + (goto-char (1+ beg)) + + (while (funcall hs-find-next-block-function hs-block-start-regexp end nil) + (if (> arg 1) + (hs-hide-level-recursive (1- arg)) + ;; `hs-hide-block-at-point' already moves the cursor, but if it + ;; fails, return to the previous position where we were. + (unless (and (goto-char (match-beginning hs-block-start-mdata-select)) + (hs-hide-block-at-point t)) + (goto-char (match-end hs-block-start-mdata-select))))) + + (goto-char end)) (defmacro hs-life-goes-on (&rest body) "Evaluate BODY forms if variable `hs-minor-mode' is non-nil. @@ -1331,17 +1374,7 @@ Upon completion, point is repositioned and the normal hook (c-reg (hs-hide-block-at-point end c-reg)) - ((save-excursion - (and-let* ((_ (eq hs-hide-block-behavior 'after-bol)) - (_ (goto-char (line-beginning-position))) - (pos (hs-get-first-block)) - (_ (goto-char pos)) - (_ (hs-hide-block-at-point end)))))) - - ((or (funcall hs-looking-at-block-start-predicate) - (and (goto-char (line-beginning-position)) - (funcall hs-find-block-beginning-function))) - (hs-hide-block-at-point end))) + ((hs-get-near-block) (hs-hide-block-at-point))) (run-hooks 'hs-hide-hook)))) @@ -1442,6 +1475,56 @@ This can be useful if you have huge RCS logs in those comments." (when (hs-hideable-region-p beg end) (hs-hide-comment-region beg end))))))) +(defun hs-cycle (&optional level) + "Cycle the visibility state of the current block. +This cycles the visibility of the current block between hide the parent +block, hide the nested blocks only, and show the parent and nested +blocks. + +If LEVEL is specified (interactively, the prefix numeric argument), hide +only blocks which are that many levels below the level of point." + (interactive "p") + (hs-life-goes-on + (when-let* ((ret (hs-get-near-block :include-comments))) + (cond ((eq ret 'comment) + (hs-toggle-hiding) + (message "Toggle visibility")) + ((> level 1) + (hs-hide-level-recursive level) + (message "Hide %d level" level)) + (t + (let* (hs-allow-nesting + (block (hs-block-positions)) + (ov (seq-find + (lambda (o) + (and (eq (overlay-get o 'invisible) 'hs))) + (overlays-in (car block) (cadr block))))) + (cond + ;; Hide all if there are no hidden blocks + ((not ov) + (hs-hide-block) + (message "Hide block and nested blocks")) + ;; Hide the children blocks if the parent block is hidden + ((and (= (overlay-start ov) (car block)) + (= (overlay-end ov) (cadr block))) + (hs-hide-level-recursive 1) + (message "Hide first nested blocks")) + ;; Otherwise show all in the parent block, we cannot use + ;; `hs-show-block' here because we already know the + ;; positions. + (ov (hs-discard-overlays (car block) (cadr block)) + (message "Show block and nested blocks") + (run-hooks 'hs-show-hook))))))))) + +(defun hs-toggle-all () + "Hide or show all the blocks in the current buffer." + (interactive) + (if hs--toggle-all-state + (let (hs-allow-nesting) + (hs-discard-overlays (point-min) (point-max))) + (hs-hide-all)) + (setq-local hs--toggle-all-state (not hs--toggle-all-state))) + ;;;###autoload (define-minor-mode hs-minor-mode "Minor mode to selectively hide/show code and comment blocks. commit 481977f5970e71d0c0575d48dbd5b1b0ea1bc63f Author: Juri Linkov Date: Mon Dec 1 19:29:11 2025 +0200 Override 'display-buffer-overriding-action' conditionally in perform-replace * lisp/replace.el (perform-replace): For 'diff' display, override 'display-buffer-overriding-action' only when it has the default value. https://lists.gnu.org/archive/html/emacs-devel/2025-11/msg01077.html diff --git a/lisp/replace.el b/lisp/replace.el index 5ef16b9df68..e4709040dff 100644 --- a/lisp/replace.el +++ b/lisp/replace.el @@ -3341,9 +3341,12 @@ characters." (setq replaced t)) ((eq def 'diff) - (let ((display-buffer-overriding-action - '(nil (inhibit-same-window . t)))) - (save-selected-window + (let ((display-buffer-overriding-action + ;; Override only the default value. + (if (equal display-buffer-overriding-action '(nil)) + '(nil (inhibit-same-window . t)) + display-buffer-overriding-action))) + (save-selected-window (multi-file-replace-as-diff (list (or buffer-file-name (current-buffer))) from-string (or replacements next-replacement) commit 310ec706484bfc9cd1bd93f61a673239b01e3ffe Author: Mattias Engdegård Date: Sun Nov 30 19:38:39 2025 +0100 Deduplicate bytecode strings in each top-level form This cheap device enables sharing of byte-code for local functions that only differ in their constant vectors (and/or doc strings etc). It makes the .elc files smaller by about 150 KB, and should reduce in-memory usage a little as well. * lisp/emacs-lisp/bytecomp.el (bytecomp--code-strings): New. (byte-compile-from-buffer, byte-compile-flush-pending) (byte-compile-lambda): Hash-cons byte-code locally. diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 58f00af8be9..66b1bd4f54e 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el @@ -495,6 +495,9 @@ Filled in `cconv-analyze-form' but initialized and consulted here.") (defvar byte-compiler-error-flag) +(defvar bytecomp--code-strings nil + "List of unique bytecode strings in this top-level form, for deduplication.") + (defun byte-compile-recurse-toplevel (form non-toplevel-case) "Implement `eval-when-compile' and `eval-and-compile'. Return the compile-time value of FORM." @@ -2417,6 +2420,7 @@ With argument ARG, insert value in current buffer after the form." (byte-compile-depth 0) (byte-compile-maxdepth 0) (byte-compile-output nil) + (bytecomp--code-strings nil) ;; #### This is bound in b-c-close-variables. ;; (byte-compile-warnings byte-compile-warnings) (symbols-with-pos-enabled t)) @@ -2580,6 +2584,7 @@ Call from the source buffer." byte-compile-depth 0 byte-compile-maxdepth 0 byte-compile-output nil + bytecomp--code-strings nil byte-compile-jump-tables nil)))) (defun byte-compile-preprocess (form &optional _for-effect) @@ -3162,9 +3167,16 @@ lambda-expression." (if lexical-binding (byte-compile-make-args-desc arglist) bare-arglist) + ;; code string, deduplicated + (let* ((code (cadr compiled)) + (prev (member code bytecomp--code-strings))) + (if prev + (car prev) + (push code bytecomp--code-strings) + code)) (append - ;; byte-string, constants-vector, stack depth - (cdr compiled) + ;; constants-vector and stack depth + (drop 2 compiled) ;; optionally, the doc string. (when (or doc int) (list doc)) ;; optionally, the interactive spec (and the modes the commit 4b55e5623229fcb6f1c74c9a2dcc22dc9269a9e0 Author: Eli Zaretskii Date: Mon Dec 1 15:16:49 2025 +0200 Fix whitespace in remember.el * lisp/textmodes/remember.el (remember-mode): Remove redundant whitespace. Patch by Huang Jing (bug#79928). diff --git a/lisp/textmodes/remember.el b/lisp/textmodes/remember.el index d04d811d78f..ee2bf5c5631 100644 --- a/lisp/textmodes/remember.el +++ b/lisp/textmodes/remember.el @@ -605,7 +605,7 @@ the data away for latter retrieval, and possible indexing. (setq header-line-format (substitute-command-keys "Edit, then exit with `\\[remember-finalize]' or abort with \ - `\\[remember-destroy]'"))) +`\\[remember-destroy]'"))) ;; Notes buffer showing the notes: commit 4271fc0daac9c546febe7f44e486ca6a8b97558c Author: Sean Whitton Date: Mon Dec 1 12:19:20 2025 +0000 * lisp/vc/vc-dir.el (vc-dir-headers): Put newlines in better places. diff --git a/lisp/vc/vc-dir.el b/lisp/vc/vc-dir.el index 0b237e91974..937c33a2db4 100644 --- a/lisp/vc/vc-dir.el +++ b/lisp/vc/vc-dir.el @@ -1348,17 +1348,17 @@ specific headers." (propertize (format "%s\n" (abbreviate-file-name dir)) 'face 'vc-dir-header-value) (vc-call-backend backend 'dir-extra-headers dir) + "\n" (and-let* ((count (ignore-errors (vc--count-outgoing backend))) (_ (plusp count))) - (concat (propertize "\nOutgoing : " + (concat (propertize "Outgoing : " 'face 'vc-dir-header) (propertize (format "%d unpushed revisions\n" count) 'face 'vc-dir-header-urgent-value 'mouse-face 'highlight 'keymap vc-dir-outgoing-revisions-map 'help-echo "\\\ -\\[vc-log-outgoing]: List outgoing revisions"))) - "\n")) +\\[vc-log-outgoing]: List outgoing revisions"))))) (defun vc-dir-refresh-files (files) "Refresh some FILES in the *VC-Dir* buffer." commit 1c3d37a67340df90403003f044ebb2056380d52a Author: Kristoffer Balintona Date: Sat Nov 29 00:57:18 2025 -0600 log-edit-show-files: Respect display-buffer-alist * lisp/vc/log-edit.el (log-edit-show-files): Consolidate the call to cvs-pop-to-buffer-same-frame, shrink-window-if-larger-than-buffer, and set-window-dedicated-p into a single call to display-buffer. diff --git a/lisp/vc/log-edit.el b/lisp/vc/log-edit.el index bf706159cac..66d94cc3de1 100644 --- a/lisp/vc/log-edit.el +++ b/lisp/vc/log-edit.el @@ -915,11 +915,12 @@ visible when the *vc-log* buffer pops up." (cvs-insert-strings files) (special-mode) (goto-char (point-min)) - (save-selected-window - (cvs-pop-to-buffer-same-frame buf) - (shrink-window-if-larger-than-buffer) - (set-window-dedicated-p (selected-window) t) - (selected-window))))) + (display-buffer buf '((display-buffer-below-selected) + (dedicated . t) + (window-height . shrink-window-if-larger-than-buffer) + (inhibit-same-window . t) + (reusable-frames . nil) + (inhibit-switch-frame . t)))))) (defun log-edit-empty-buffer-p () "Return non-nil if the buffer is \"empty\"." commit fd3b74ca083216b1d8f644eb52caa8d39a9c807c Author: Sean Whitton Date: Mon Dec 1 11:18:07 2025 +0000 Fix log-view-vc-fileset in *vc-incoming* and *vc-outgoing* buffers This fixes log-view-modify-change-comment in those buffers. * lisp/vc/vc.el (vc-incoming-outgoing-internal): Pass the VC root to vc-log-internal-common. diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el index 6547e5ebfbd..9a8c80edfcb 100644 --- a/lisp/vc/vc.el +++ b/lisp/vc/vc.el @@ -3906,7 +3906,7 @@ Each function runs in the log output buffer without args.") (defun vc-incoming-outgoing-internal (backend upstream-location buffer-name type) (vc-log-internal-common - backend buffer-name nil type + backend buffer-name (list (vc-root-dir)) type (lambda (bk buf type-arg _files) (vc-call-backend bk type-arg buf upstream-location)) (lambda (_bk _files-arg _ret) nil) commit 5e98195e84c4f52a4368f84cf0d6ae8126d9966d Author: Sean Whitton Date: Mon Dec 1 11:14:55 2025 +0000 log-edit-generate-changelog-from-diff: Special-case Summary field * lisp/vc/add-log.el (log-edit-fill-entry): Delete unused declaration. * lisp/vc/log-edit.el (log-edit-generate-changelog-from-diff): Special-case inserting a single line into the Summary field. diff --git a/lisp/vc/add-log.el b/lisp/vc/add-log.el index 61cfe3833d9..c7d0051fe4b 100644 --- a/lisp/vc/add-log.el +++ b/lisp/vc/add-log.el @@ -314,7 +314,6 @@ as a list of strings." ",[[:blank:]]*" t) finally do (skip-chars-backward "\n[:blank:]"))) -(declare-function log-edit-fill-entry "log-edit") (defun change-log-insert-entries (changelogs) "Format and insert CHANGELOGS into current buffer. CHANGELOGS is a list in the form returned by diff --git a/lisp/vc/log-edit.el b/lisp/vc/log-edit.el index c095c7ab67d..bf706159cac 100644 --- a/lisp/vc/log-edit.el +++ b/lisp/vc/log-edit.el @@ -1057,20 +1057,29 @@ names into a single entry where they all share the same description. Should you need to look at the diffs themselves, they can be found in the \"*vc-diff*\" buffer produced by this command." (interactive) - (change-log-insert-entries - (with-current-buffer - (let* ((diff-buf nil) - ;; Unfortunately, `log-edit-show-diff' doesn't have a - ;; NO-SHOW option, so we try to work around it via - ;; display-buffer machinery. - (display-buffer-overriding-action - `(,(lambda (buf alist) - (setq diff-buf buf) - (display-buffer-no-window buf alist)) - . ((allow-no-window . t))))) - (log-edit-show-diff) - diff-buf) - (diff-add-log-current-defuns)))) + (let* ((entries + (with-current-buffer + (let* ((diff-buf nil) + ;; Unfortunately, `log-edit-show-diff' doesn't have a + ;; NO-SHOW option, so we try to work around it via + ;; display-buffer machinery. + (display-buffer-overriding-action + `(,(lambda (buf alist) + (setq diff-buf buf) + (display-buffer-no-window buf alist)) + . ((allow-no-window . t))))) + (log-edit-show-diff) + diff-buf) + (diff-add-log-current-defuns))) + (single-line-summary + (and (length= entries 1) + (length< (cdar entries) 2) + (< (point) (save-excursion (rfc822-goto-eoh) (point))) + (save-excursion (forward-line 0) (looking-at "Summary:"))))) + (change-log-insert-entries entries) + (when single-line-summary + (delete-char -1) + (insert " ")))) (defun log-edit-insert-changelog (&optional use-first) "Insert a VC commit log message by looking at the ChangeLog.