commit e58efac78eed96842e4b6cbc64a1633e74edd6c1 (HEAD, refs/remotes/origin/master) Author: Juri Linkov Date: Mon Sep 22 09:20:27 2025 +0300 * lisp/keymap.el (read-only-keymap-bind): The remaining fix. Replace 'browse-url-keymap-filter' with 'read-only-keymap-filter'. diff --git a/lisp/keymap.el b/lisp/keymap.el index 54760fd1207..2dcc1db080c 100644 --- a/lisp/keymap.el +++ b/lisp/keymap.el @@ -798,7 +798,7 @@ They are considered active only in read-only buffers." "Use BINDING according to `read-only-keymap-filter'." `(menu-item "" ,binding - :filter ,#'browse-url-keymap-filter)) + :filter ,#'read-only-keymap-filter)) (provide 'keymap) commit 36635b934e9451939b4812141ff229f3f4749bac Author: Po Lu Date: Mon Sep 22 09:42:34 2025 +0800 Fix bootstrap and prevent browse-url from preloading numerous files * lisp/keymap.el (read-only-keymap-filter) (read-only-keymap-bind): New functions, removed from browse-url.el. * lisp/net/browse-url.el (browse-url-keymap-filter) (browse-url-keymap-bind): Move to keymap.el. All callers changed. diff --git a/lisp/ansi-osc.el b/lisp/ansi-osc.el index d3c066cfdba..1facd9aa205 100644 --- a/lisp/ansi-osc.el +++ b/lisp/ansi-osc.el @@ -146,7 +146,7 @@ and `shell-dirtrack-mode'." (defvar-keymap ansi-osc-hyperlink-map :doc "Keymap used by OSC 8 hyperlink buttons." - "RET" (browse-url-keymap-bind #'browse-url-button-open) + "RET" (read-only-keymap-bind #'browse-url-button-open) "C-c RET" #'browse-url-button-open "" #'browse-url-button-open "" 'mouse-face) diff --git a/lisp/keymap.el b/lisp/keymap.el index 2cd62ab6498..54760fd1207 100644 --- a/lisp/keymap.el +++ b/lisp/keymap.el @@ -787,6 +787,19 @@ in the echo area. (put symbol 'non-key-event t) symbol) + + +(defun read-only-keymap-filter (cmd) + "Return CMD if `browse-url' and similar button bindings should be active. +They are considered active only in read-only buffers." + (when buffer-read-only cmd)) + +(defun read-only-keymap-bind (binding) + "Use BINDING according to `read-only-keymap-filter'." + `(menu-item + "" ,binding + :filter ,#'browse-url-keymap-filter)) + (provide 'keymap) ;;; keymap.el ends here diff --git a/lisp/net/browse-url.el b/lisp/net/browse-url.el index 162a2c578b4..cd0a88b1a16 100644 --- a/lisp/net/browse-url.el +++ b/lisp/net/browse-url.el @@ -1759,23 +1759,9 @@ from `browse-url-elinks-wrapper'." ;;; Adding buttons to a buffer to call `browse-url' when you hit them. -;;;###autoload -(defun browse-url-keymap-filter (cmd) - "Return CMD if `browse-url' button bindings should be active. -By default they are active only in read-only buffers." - (when buffer-read-only - cmd)) - -;;;###autoload -(defun browse-url-keymap-bind (binding) - "Use BINDING according to `browse-url-keymap-filter'." - `(menu-item - "" ,binding - :filter ,#'browse-url-keymap-filter)) - (defvar-keymap browse-url-button-map :doc "The keymap used for `browse-url' buttons." - "RET" (browse-url-keymap-bind #'browse-url-button-open) + "RET" (read-only-keymap-bind #'browse-url-button-open) "C-c RET" #'browse-url-button-open "" #'browse-url-button-open "w" #'browse-url-button-copy) diff --git a/lisp/net/goto-addr.el b/lisp/net/goto-addr.el index b603cc04f8d..c1f8b72f137 100644 --- a/lisp/net/goto-addr.el +++ b/lisp/net/goto-addr.el @@ -121,7 +121,7 @@ will have no effect.") (defvar-keymap goto-address-highlight-keymap :doc "Keymap to hold goto-addr's mouse key defs under highlighted URLs." "" #'goto-address-at-point - "RET" (browse-url-keymap-bind #'goto-address-at-point) + "RET" (read-only-keymap-bind #'goto-address-at-point) "C-c RET" #'goto-address-at-point) (defun goto-address-context-menu (menu click) diff --git a/lisp/progmodes/bug-reference.el b/lisp/progmodes/bug-reference.el index f91e7536c6d..0b5c36d0ed2 100644 --- a/lisp/progmodes/bug-reference.el +++ b/lisp/progmodes/bug-reference.el @@ -45,7 +45,7 @@ (defvar-keymap bug-reference-map :doc "Keymap used by bug reference buttons." "" #'bug-reference-push-button - "RET" (browse-url-keymap-bind #'bug-reference-push-button) + "RET" (read-only-keymap-bind #'bug-reference-push-button) "C-c RET" #'bug-reference-push-button) ;; E.g., "https://gcc.gnu.org/PR%s" commit 8310795babf5699438b6ea416672194e4e0bb933 Author: Sean Whitton Date: Sun Sep 21 21:39:42 2025 +0100 VC checkin-patch: Support extracting commit metadata from patches * lisp/vc/vc-git.el (vc-git--mailinfo): New function. (vc-git-checkin-patch): Use it to extract authorship, date and log message information from patches. (vc-git--call): New INFILE argument. All uses changed. * lisp/vc/vc-hg.el (vc-hg--checkin): When COMMENT is nil, take authorship, date and log message information from the patch. * lisp/vc/vc.el (checkin-patch): Specify to use authorship, date and comment information in PATCH-STRING (bug#79408). (prepare-patch): Specify that patch should include authorship identity, date and log message information for REV if supported. (diff-bounds-of-hunk): Declare. (vc-default-checkin-patch): Warn if it looks like we will ignore patch authorship information. * test/lisp/vc/vc-tests/vc-tests.el (vc-hg-command) (vc-git--out-str): Declare. (vc-test--checkin-patch): New function. (vc-test-git08-checkin-patch, vc-test-hg08-checkin-patch): New tests. diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el index 8e0629a802a..868948c3a35 100644 --- a/lisp/vc/vc-git.el +++ b/lisp/vc/vc-git.el @@ -978,7 +978,7 @@ or an empty string if none." "Return the existing branches, as a list of strings. The car of the list is the current branch." (with-temp-buffer - (vc-git--call t "branch") + (vc-git--call nil t "branch") (goto-char (point-min)) (let (current-branch branches) (while (not (eobp)) @@ -1139,7 +1139,7 @@ It is based on `log-edit-mode', and has Git-specific extensions." (defun vc-git--checkin (comment &optional files patch-string) "Workhorse routine for `vc-git-checkin' and `vc-git-checkin-patch'. -COMMENT is the commit message. +COMMENT is the commit message; must be non-nil. For a regular checkin, FILES is the list of files to check in. To check in a patch, PATCH-STRING is the patch text. It is an error to supply both or neither." @@ -1279,9 +1279,84 @@ It is an error to supply both or neither." (apply #'vc-git-command nil 0 files args) (funcall post))))) +(defun vc-git--mailinfo (patch-string) + "Pipe PATCH-STRING to git-mailinfo(1) and return an alist of its output. + +The alist always contains an entry with key `message'. +This contains the commit log message. +In the case that there is also an alist entry with key \"Subject\", the +first line of the commit message is missing from the `message' entry. +To recover the full commit message, concatenate the \"Subject\" and +`message' entries, interpolating two newline characters. + +The alist also always contains an entry with key `patch'. +This contains the patch extracted from PATCH-STRING. +If there is text in PATCH-STRING occurring before the actual hunks but +after the commit message, separated from the latter with a line +consisting of three hyphens, then that extra text is included in this +alist entry. (This space between the line of three hyphens and the +hunks is conventionally used for a diffstat, and/or additional +explanatory text submitted with the patch but not to be included in the +commit log message.) + +The remaining entries in the alist correspond to the information +returned by git-mailinfo(1) on standard output. These specify the +authorship and date information for the commit, and sometimes the first +line of the commit message in an entry with key \"Subject\"." + (let ((input-file (make-nearby-temp-file "git-mailinfo-input")) + (msg-file (make-nearby-temp-file "git-mailinfo-msg")) + (patch-file (make-nearby-temp-file "git-mailinfo-patch")) + (coding-system-for-read (or coding-system-for-read + vc-git-log-output-coding-system)) + res) + (unwind-protect + (with-temp-buffer + (let ((coding-system-for-write + ;; Git expects Unix line endings here even on Windows. + (coding-system-change-eol-conversion + (or coding-system-for-write vc-git-commits-coding-system) + 'unix))) + (with-temp-file input-file + (insert patch-string))) + (let ((coding-system-for-write + ;; On MS-Windows, we must encode command-line arguments + ;; in the system codepage. + (if (eq system-type 'windows-nt) + locale-coding-system + coding-system-for-write))) + (vc-git--call input-file t "mailinfo" msg-file patch-file)) + (goto-char (point-min)) + ;; git-mailinfo joins up any header continuation lines for us. + (while (re-search-forward "^\\([^\t\n\s:]+\\):\\(.*\\)$" nil t) + (push (cons (match-string 1) (string-trim (match-string 2))) + res)) + (erase-buffer) + (insert-file-contents-literally patch-file) + (push (cons 'patch (buffer-string)) res) + (erase-buffer) + (insert-file-contents-literally msg-file) + (push (cons 'message (string-trim (buffer-string))) res)) + (dolist (file (list input-file msg-file patch-file)) + (when (file-exists-p file) + (delete-file file)))) + res)) + (defun vc-git-checkin-patch (patch-string comment) "Git-specific version of `vc-BACKEND-checkin-patch'." - (vc-git--checkin comment nil patch-string)) + (let ((mailinfo (vc-git--mailinfo patch-string))) + (unless comment + (setq comment (if-let* ((subject (assoc "Subject" mailinfo))) + (format "Summary: %s\n\n%s" + (cdr subject) + (cdr (assq 'message mailinfo))) + (cdr (assq 'message mailinfo))))) + (when-let* ((date (assoc "Date" mailinfo))) + (setq comment (format "Date: %s\n%s" (cdr date) comment))) + (when-let* ((author (assoc "Author" mailinfo)) + (email (assoc "Email" mailinfo))) + (setq comment (format "Author: %s <%s>\n%s" + (cdr author) (cdr email) comment))) + (vc-git--checkin comment nil (cdr (assq 'patch mailinfo))))) (defun vc-git-checkin (files comment &optional _rev) "Git-specific version of `vc-BACKEND-checkin'. @@ -2081,7 +2156,7 @@ Will not rewrite likely-public history; see option `vc-allow-rewriting-published (defun vc-git-modify-change-comment (files rev comment) (vc-git--assert-allowed-rewrite rev) - (when (zerop (vc-git--call nil "rev-parse" (format "%s^2" rev))) + (when (zerop (vc-git--call nil nil "rev-parse" (format "%s^2" rev))) ;; This amend! approach doesn't work for merge commits. ;; Error out now instead of leaving an amend! commit hanging. (error "Cannot modify merge commit comments")) @@ -2286,7 +2361,7 @@ In other modes, call `vc-deduce-fileset' to determine files to stash." (interactive "sStash name: ") (let ((root (vc-git-root default-directory))) (when root - (apply #'vc-git--call nil "stash" "push" "-m" name + (apply #'vc-git--call nil nil "stash" "push" "-m" name (vc-git--deduce-files-for-stash)) (vc-resynch-buffer root t t)))) @@ -2353,7 +2428,7 @@ In `vc-dir-mode', if there are files marked, stash the changes to those. If no files are marked, stash all uncommitted changes to tracked files. In other modes, call `vc-deduce-fileset' to determine files to stash." (interactive) - (apply #'vc-git--call nil "stash" "push" "-m" + (apply #'vc-git--call nil nil "stash" "push" "-m" (format-time-string "Snapshot on %Y-%m-%d at %H:%M") (vc-git--deduce-files-for-stash)) (vc-git-command "*vc-git-stash*" 0 nil "stash" "apply" "-q" "stash@{0}") @@ -2543,9 +2618,9 @@ The difference to `vc-do-command' is that this function always invokes (defun vc-git--empty-db-p () "Check if the git db is empty (no commit done yet)." (let (process-file-side-effects) - (not (eq 0 (vc-git--call nil "rev-parse" "--verify" "HEAD"))))) + (not (zerop (vc-git--call nil nil "rev-parse" "--verify" "HEAD"))))) -(defun vc-git--call (buffer command &rest args) +(defun vc-git--call (infile buffer command &rest args) ;; We don't need to care the arguments. If there is a file name, it ;; is always a relative one. This works also for remote ;; directories. We enable `inhibit-null-byte-detection', otherwise @@ -2565,12 +2640,13 @@ The difference to `vc-do-command' is that this function always invokes ,@(when revert-buffer-in-progress '("GIT_OPTIONAL_LOCKS=0"))) process-environment))) - (apply #'process-file vc-git-program nil buffer nil "--no-pager" command args))) + (apply #'process-file vc-git-program infile buffer nil + "--no-pager" command args))) (defun vc-git--out-ok (command &rest args) "Run `git COMMAND ARGS...' and insert standard output in current buffer. Return whether the process exited with status zero." - (zerop (apply #'vc-git--call '(t nil) command args))) + (zerop (apply #'vc-git--call nil '(t nil) command args))) (defun vc-git--out-str (command &rest args) "Run `git COMMAND ARGS...' and return standard output as a string. diff --git a/lisp/vc/vc-hg.el b/lisp/vc/vc-hg.el index 5c9df6bf287..ce1abbe3d88 100644 --- a/lisp/vc/vc-hg.el +++ b/lisp/vc/vc-hg.el @@ -1215,13 +1215,13 @@ It is based on `log-edit-mode', and has Hg-specific extensions.") (defun vc-hg--checkin (comment &optional files patch-string) "Workhorse routine for `vc-hg-checkin' and `vc-hg-checkin-patch'. -COMMENT is the commit message. +COMMENT is the commit message; nil if it should come from PATCH-STRING. For a regular checkin, FILES is the list of files to check in. To check in a patch, PATCH-STRING is the patch text. It is an error to supply both or neither." (unless (xor files patch-string) (error "Invalid call to `vc-hg--checkin'")) - (let* ((args (vc-hg--extract-headers comment)) + (let* ((args (and comment (vc-hg--extract-headers comment))) (temps-dir (or (file-name-directory (or (car files) default-directory)) default-directory)) @@ -1231,7 +1231,7 @@ It is an error to supply both or neither." ;; must be in the system codepage, and therefore might not ;; support non-ASCII characters in the log message. ;; Also handle remote files. - (and (eq system-type 'windows-nt) + (and args (eq system-type 'windows-nt) (let ((default-directory temps-dir)) (make-nearby-temp-file "hg-msg")))) (patch-file (and patch-string @@ -1252,9 +1252,9 @@ It is an error to supply both or neither." (nconc (if patch-file (list "import" "--bypass" patch-file) (list "commit" "-A")) - (if msg-file - (cl-list* "-l" (file-local-name msg-file) (cdr args)) - (cl-list* "-m" args)))) + (cond (msg-file (cl-list* "-l" (file-local-name msg-file) + (cdr args))) + (args (cons "-m" args))))) (post (lambda () (when (and msg-file (file-exists-p msg-file)) (delete-file msg-file)) diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el index ee8d901e4b6..efb28501c21 100644 --- a/lisp/vc/vc.el +++ b/lisp/vc/vc.el @@ -269,8 +269,15 @@ ;; ;; - checkin-patch (patch-string comment) ;; -;; Commit a single patch PATCH-STRING to this backend, bypassing -;; the changes in filesets. COMMENT is used as a check-in comment. +;; Commit a single patch PATCH-STRING to this backend, bypassing any +;; changes to the fileset. COMMENT is used as a check-in comment. +;; If PATCH-STRING contains authorship and date information in a +;; format commonly used with the backend, it should be used as the +;; commit authorship identity and date; in particular, this should +;; always occur if PATCH-STRING was generated by the backend's +;; prepare-patch function (see below). Similarly, if COMMENT is nil +;; and PATCH-STRING contains a log message, that log message should be +;; used as the check-in comment. ;; ;; * find-revision (file rev buffer) ;; @@ -669,7 +676,9 @@ ;; `:body-start' and `:body-end' demarcating what part of said ;; buffer should be inserted into an inline patch. If the two last ;; properties are omitted, `point-min' and `point-max' will -;; respectively be used instead. +;; respectively be used instead. If supported by the backend, the +;; patch should contain authorship identity and date information, and +;; REV's log message. ;; ;; - clone (remote directory rev) ;; @@ -2083,10 +2092,23 @@ have changed; continue with old fileset?" (current-buffer)))) backend patch-string))) +(declare-function diff-bounds-of-hunk "diff-mode") + (defun vc-default-checkin-patch (_backend patch-string comment) - (pcase-let* ((`(,backend ,files) (with-temp-buffer - (insert patch-string) - (diff-vc-deduce-fileset))) + (pcase-let* ((`(,backend ,files) + (with-temp-buffer + (diff-mode) + (insert patch-string) + (goto-char (point-min)) + (when (and (re-search-forward + "^\\(?:Date\\|From\\|Author\\):[\t\s]*[^\t\n\s]" + (car (diff-bounds-of-hunk)) + t) + (not (yes-or-no-p "Patch appears to contain \ +authorship information but this will be ignored when checking in; \ +proceed anyway?"))) + (user-error "Aborted")) + (diff-vc-deduce-fileset))) (tmpdir (make-temp-file "vc-checkin-patch" t))) (dolist (f files) (make-directory (file-name-directory (expand-file-name f tmpdir)) t) diff --git a/test/lisp/vc/vc-tests/vc-tests.el b/test/lisp/vc/vc-tests/vc-tests.el index c9e2a4cac09..26da67e20aa 100644 --- a/test/lisp/vc/vc-tests/vc-tests.el +++ b/test/lisp/vc/vc-tests/vc-tests.el @@ -783,6 +783,120 @@ This checks also `vc-backend' and `vc-responsible-backend'." (ignore-errors (run-hooks 'vc-test--cleanup-hook))))))) +(declare-function vc-hg-command "vc-hg") +(declare-function vc-git--out-str "vc-git") + +(defun vc-test--checkin-patch (backend) + "Test preparing and checking in patches." + (ert-with-temp-directory _tempdir + (let ((vc-handled-backends `(,backend)) + (default-directory + (file-name-as-directory + (expand-file-name + (make-temp-name "vc-test") temporary-file-directory))) + (file "foo") + (author "VC user ") + (date "Fri, 19 Sep 2025 15:00:00 +0100") + (desc1 "Make a modification") + (desc2 "Make a modification redux") + vc-test--cleanup-hook buf) + (vc-test--with-author-identity backend + (unwind-protect + (cl-flet + ((get-patch-string () + "Get patch corresponding to most recent commit to FILE." + (let* ((rev (vc-call-backend backend 'working-revision file)) + (patch (vc-call-backend backend 'prepare-patch rev))) + (with-current-buffer (plist-get patch :buffer) + (buffer-substring-no-properties (point-min) + (point-max))))) + (revert (msg) + "Make a commit reverting the most recent change to FILE." + (with-current-buffer buf + (undo-boundary) + (revert-buffer-quick) + (undo-boundary) + (undo) + (basic-save-buffer) + (vc-checkin (list file) backend) + (insert msg) + (let (vc-async-checkin) + (log-edit-done)))) + (check (author date desc) + "Assert that most recent commit has AUTHOR, DATE and DESC." + (should + (equal + (string-trim-right + (cl-case backend + (Git + (vc-git--out-str "log" "-n1" + "--pretty=%an <%ae>%n%aD%n%B")) + (Hg + (with-output-to-string + (vc-hg-command standard-output 0 nil "log" "--limit=1" + "--template" + "{user}\n{date|rfc822date}\n{desc}"))))) + (format "%s\n%s\n%s" author date desc))))) + ;; (1) Cleanup. + (add-hook 'vc-test--cleanup-hook + (let ((dir default-directory)) + (lambda () + (delete-directory dir 'recursive)))) + + ;; (2) Basic setup. + (make-directory default-directory) + (vc-test--create-repo-function backend) + (write-region "foo\n" nil file nil 'nomessage) + (vc-register `(,backend (,file))) + (setq buf (find-file-noselect file)) + (with-current-buffer buf + (vc-checkin (list file) backend) + (insert "Initial commit") + (let (vc-async-checkin) + (log-edit-done))) + + ;; (3) Prepare a commit with a known Author & Date. + (with-current-buffer buf + (insert "bar\n") + (basic-save-buffer) + (vc-root-diff nil) + (vc-next-action nil) + (insert desc1) + (goto-char (point-min)) + (insert (format "Author: %s\n" author)) + (insert (format "Date: %s\n" date)) + (let (vc-async-checkin) + (log-edit-done))) + + ;; (4) Revert it, then test applying it with + ;; checkin-patch, passing nil as COMMENT. Should take the + ;; author, date and comment from PATCH-STRING. + (let ((patch-string (get-patch-string))) + (revert "Revert modification, first time") + (vc-call-backend backend 'checkin-patch patch-string nil)) + (check author date desc1) + + ;; (5) Revert it again and try applying it with + ;; checkin-patch again, but passing non-nil COMMENT. + ;; Should take the author, date but not the comment from + ;; PATCH-STRING. + (let ((patch-string (get-patch-string))) + ;; FIXME: We shouldn't need to branch here. Git should + ;; update the working tree after making the commit. + (cl-case backend + (Git (with-current-buffer buf + (vc-checkin (list file) backend) + (insert "Revert modification, second time") + (let (vc-async-checkin) + (log-edit-done)))) + (t (revert "Revert modification, second time"))) + (vc-call-backend backend 'checkin-patch patch-string desc2)) + (check author date desc2)) + + ;; Save exit. + (ignore-errors + (run-hooks 'vc-test--cleanup-hook))))))) + ;; Create the test cases. (defun vc-test--rcs-enabled () @@ -944,7 +1058,20 @@ This checks also `vc-backend' and `vc-responsible-backend'." (version< (vc-git--program-version) "2.17"))) (let ((vc-hg-global-switches (cons "--config=extensions.share=" vc-hg-global-switches))) - (vc-test--other-working-trees ',backend))))))) + (vc-test--other-working-trees ',backend))) + + (ert-deftest + ,(intern (format "vc-test-%s08-checkin-patch" backend-string)) () + ,(format "Check preparing and checking in patches with the %s backend." + backend-string) + (skip-unless + (ert-test-passed-p + (ert-test-most-recent-result + (ert-get-test + ',(intern + (format "vc-test-%s01-register" backend-string)))))) + (skip-unless (memq ',backend '(Git Hg))) + (vc-test--checkin-patch ',backend)))))) (provide 'vc-tests) ;;; vc-tests.el ends here commit 0109b4a758fad1467b83c0631066e15c046669a9 Author: Sean Whitton Date: Fri Sep 19 16:26:16 2025 +0100 * lisp/vc/vc-git.el (vc-git--checkin): Validate parameters. diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el index e9539616765..8e0629a802a 100644 --- a/lisp/vc/vc-git.el +++ b/lisp/vc/vc-git.el @@ -1143,6 +1143,8 @@ COMMENT is the commit message. For a regular checkin, FILES is the list of files to check in. To check in a patch, PATCH-STRING is the patch text. It is an error to supply both or neither." + (unless (xor files patch-string) + (error "Invalid call to `vc-hg--checkin'")) (let* ((file1 (or (car files) default-directory)) (root (vc-git-root file1)) (default-directory (expand-file-name root)) commit 8a501c47a46dddb55d3c9bd9608662f1ea6ba4b5 Author: Juri Linkov Date: Sun Sep 21 20:52:02 2025 +0300 Support 'RET' for visiting URLs in read-only buffers (bug#74792) * lisp/net/browse-url.el (browse-url-keymap-filter) (browse-url-keymap-bind): New functions. (browse-url-button-map): Bind "C-c RET" to 'browse-url-button-open' and rebind "RET" with the filter 'browse-url-keymap-bind'. * lisp/ansi-osc.el (ansi-osc-hyperlink-map): * lisp/net/goto-addr.el (goto-address-highlight-keymap): * lisp/progmodes/bug-reference.el (bug-reference-map): Bind "RET" with the filter 'browse-url-keymap-bind'. diff --git a/etc/NEWS b/etc/NEWS index 059270bff46..d3e25bf5d5d 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1262,6 +1262,11 @@ are browsed from a PGTK frame. For other frames, we fall back to the default URL launch function. This change allows us to properly raise browser windows under Wayland using the xdg_activation_v1 protocol. +*** 'RET' can visit URLs in read-only buffers. +In some keymaps such as 'ansi-osc-hyperlink-map', 'browse-url-button-map', +'goto-address-highlight-keymap', 'bug-reference-map' it's possible now +to visit URLs by typing just 'RET' instead of 'C-c RET' in read-only buffers. + *** Removed support for some obsolete web browsers. Conkeror (obsolete since Emacs 28.1), gnome-moz-remote (obsolete since Emacs 25.1), and gnudoit (obsolete since Emacs 25.1). diff --git a/lisp/ansi-osc.el b/lisp/ansi-osc.el index 83fcd0d184a..d3c066cfdba 100644 --- a/lisp/ansi-osc.el +++ b/lisp/ansi-osc.el @@ -146,6 +146,7 @@ and `shell-dirtrack-mode'." (defvar-keymap ansi-osc-hyperlink-map :doc "Keymap used by OSC 8 hyperlink buttons." + "RET" (browse-url-keymap-bind #'browse-url-button-open) "C-c RET" #'browse-url-button-open "" #'browse-url-button-open "" 'mouse-face) diff --git a/lisp/net/browse-url.el b/lisp/net/browse-url.el index 63ed7283949..162a2c578b4 100644 --- a/lisp/net/browse-url.el +++ b/lisp/net/browse-url.el @@ -1759,9 +1759,24 @@ from `browse-url-elinks-wrapper'." ;;; Adding buttons to a buffer to call `browse-url' when you hit them. +;;;###autoload +(defun browse-url-keymap-filter (cmd) + "Return CMD if `browse-url' button bindings should be active. +By default they are active only in read-only buffers." + (when buffer-read-only + cmd)) + +;;;###autoload +(defun browse-url-keymap-bind (binding) + "Use BINDING according to `browse-url-keymap-filter'." + `(menu-item + "" ,binding + :filter ,#'browse-url-keymap-filter)) + (defvar-keymap browse-url-button-map :doc "The keymap used for `browse-url' buttons." - "RET" #'browse-url-button-open + "RET" (browse-url-keymap-bind #'browse-url-button-open) + "C-c RET" #'browse-url-button-open "" #'browse-url-button-open "w" #'browse-url-button-copy) diff --git a/lisp/net/goto-addr.el b/lisp/net/goto-addr.el index d803a050e90..b603cc04f8d 100644 --- a/lisp/net/goto-addr.el +++ b/lisp/net/goto-addr.el @@ -121,6 +121,7 @@ will have no effect.") (defvar-keymap goto-address-highlight-keymap :doc "Keymap to hold goto-addr's mouse key defs under highlighted URLs." "" #'goto-address-at-point + "RET" (browse-url-keymap-bind #'goto-address-at-point) "C-c RET" #'goto-address-at-point) (defun goto-address-context-menu (menu click) diff --git a/lisp/progmodes/bug-reference.el b/lisp/progmodes/bug-reference.el index 9901d5df245..f91e7536c6d 100644 --- a/lisp/progmodes/bug-reference.el +++ b/lisp/progmodes/bug-reference.el @@ -45,6 +45,7 @@ (defvar-keymap bug-reference-map :doc "Keymap used by bug reference buttons." "" #'bug-reference-push-button + "RET" (browse-url-keymap-bind #'bug-reference-push-button) "C-c RET" #'bug-reference-push-button) ;; E.g., "https://gcc.gnu.org/PR%s" commit 203faa6e42f49a6428e34dfb52ac755d4095b968 Author: Roi Martin Date: Sun Sep 21 12:18:03 2025 +0200 Suffix tree-sitter cache variables with "-cached" * lisp/progmodes/cmake-ts-mode.el (cmake-ts-mode--indent-rules) (cmake-ts-mode--indent-rules-cached, cmake-ts-mode--font-lock-settings) (cmake-ts-mode--font-lock-settings-cached): * lisp/progmodes/go-ts-mode.el (go-ts-mode--font-lock-settings) (go-ts-mode--font-lock-settings-cached): * lisp/progmodes/js.el (js--treesit-indent-rules) (js--treesit-indent-rules-cached, js--treesit-font-lock-settings) (js--treesit-font-lock-settings-cached): Suffix tree-sitter cache variables with "-cached" (bug#79363). diff --git a/lisp/progmodes/cmake-ts-mode.el b/lisp/progmodes/cmake-ts-mode.el index 8e49b18f731..9625b0f0330 100644 --- a/lisp/progmodes/cmake-ts-mode.el +++ b/lisp/progmodes/cmake-ts-mode.el @@ -61,16 +61,16 @@ table) "Syntax table for `cmake-ts-mode'.") -(defvar cmake-ts-mode--indent-rules nil - "Tree-sitter indent rules for `cmake-ts-mode'.") +(defvar cmake-ts-mode--indent-rules-cached nil + "Cached tree-sitter indent rules for `cmake-ts-mode'.") (defun cmake-ts-mode--indent-rules () "Return tree-sitter indent rules for `cmake-ts-mode'. -Tree-sitter indent rules are evaluated the first time this function -is called. Subsequent calls return the first evaluated value." - (or cmake-ts-mode--indent-rules - (setq cmake-ts-mode--indent-rules +Tree-sitter indent rules are evaluated the first time this function is +called. Subsequent calls return the first evaluated value." + (or cmake-ts-mode--indent-rules-cached + (setq cmake-ts-mode--indent-rules-cached `((cmake ((node-is ")") parent-bol 0) ((node-is "else_command") parent-bol 0) @@ -148,16 +148,16 @@ Check if a node type is available, then return the right font lock rules." eol)) @font-lock-constant-face)))))))) -(defvar cmake-ts-mode--font-lock-settings nil - "Tree-sitter font-lock settings for `cmake-ts-mode'.") +(defvar cmake-ts-mode--font-lock-settings-cached nil + "Cached tree-sitter font-lock settings for `cmake-ts-mode'.") (defun cmake-ts-mode--font-lock-settings () "Return tree-sitter font-lock settings for `cmake-ts-mode'. -Tree-sitter font-lock rules are evaluated the first time this function -is called. Subsequent calls return the first evaluated value." - (or cmake-ts-mode--font-lock-settings - (setq cmake-ts-mode--font-lock-settings +Tree-sitter font-lock settings are evaluated the first time this +function is called. Subsequent calls return the first evaluated value." + (or cmake-ts-mode--font-lock-settings-cached + (setq cmake-ts-mode--font-lock-settings-cached (treesit-font-lock-rules :language 'cmake :feature 'bracket diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el index 1b44478f41a..91664a4de48 100644 --- a/lisp/progmodes/go-ts-mode.el +++ b/lisp/progmodes/go-ts-mode.el @@ -162,16 +162,16 @@ (ignore-errors (or (treesit-query-string "" '((method_elem) @cap) 'go) t))) -(defvar go-ts-mode--font-lock-settings nil - "Tree-sitter font-lock settings for `go-ts-mode'.") +(defvar go-ts-mode--font-lock-settings-cached nil + "Cached tree-sitter font-lock settings for `go-ts-mode'.") (defun go-ts-mode--font-lock-settings () "Return tree-sitter font-lock settings for `go-ts-mode'. -Tree-sitter font-lock rules are evaluated the first time this function -is called. Subsequent calls return the first evaluated value." - (or go-ts-mode--font-lock-settings - (setq go-ts-mode--font-lock-settings +Tree-sitter font-lock settings are evaluated the first time this +function is called. Subsequent calls return the first evaluated value." + (or go-ts-mode--font-lock-settings-cached + (setq go-ts-mode--font-lock-settings-cached (treesit-font-lock-rules :language 'go :feature 'bracket diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index 0fda7d62145..5e54383cd9f 100644 --- a/lisp/progmodes/js.el +++ b/lisp/progmodes/js.el @@ -3513,16 +3513,16 @@ characters of the current line." node parent bol args) js-indent-level))) -(defvar js--treesit-indent-rules nil - "Tree-sitter indent rules for `js-ts-mode'.") +(defvar js--treesit-indent-rules-cached nil + "Cached tree-sitter indent rules for `js-ts-mode'.") (defun js--treesit-indent-rules () "Return tree-sitter indent rules for `js-ts-mode'. -Tree-sitter indent rules are evaluated the first time this function -is called. Subsequent calls return the first evaluated value." - (or js--treesit-indent-rules - (setq js--treesit-indent-rules +Tree-sitter indent rules are evaluated the first time this function is +called. Subsequent calls return the first evaluated value." + (or js--treesit-indent-rules-cached + (setq js--treesit-indent-rules-cached `((javascript ((parent-is "program") parent-bol 0) ((node-is "}") standalone-parent 0) @@ -3595,16 +3595,16 @@ is called. Subsequent calls return the first evaluated value." "&&" "||" "!") "JavaScript operators for tree-sitter font-locking.") -(defvar js--treesit-font-lock-settings nil - "Tree-sitter font-lock settings for `js-ts-mode'.") +(defvar js--treesit-font-lock-settings-cached nil + "Cached tree-sitter font-lock settings for `js-ts-mode'.") (defun js--treesit-font-lock-settings () "Return tree-sitter font-lock settings for `js-ts-mode'. -Tree-sitter font-lock rules are evaluated the first time this function -is called. Subsequent calls return the first evaluated value." - (or js--treesit-font-lock-settings - (setq js--treesit-font-lock-settings +Tree-sitter font-lock settings are evaluated the first time this +function is called. Subsequent calls return the first evaluated value." + (or js--treesit-font-lock-settings-cached + (setq js--treesit-font-lock-settings-cached (treesit-font-lock-rules :language 'javascript commit 2ae54a8b17f42329c69c3d9d3c4bd8895b35f81c Author: Roi Martin Date: Thu Sep 18 18:37:54 2025 +0200 Fix font lock and cache indent rules in mhtml-ts-mode Fix font lock in mhtml-ts-mode when the required tree-sitter grammars are automatically installed (bug#79363). Also, cache tree-sitter indent rules. * lisp/textmodes/mhtml-ts-mode.el (mhtml-ts-mode--treesit-font-lock-settings): Evaluate the rules only after the tree-sitter grammars are installed. (mhtml-ts-mode--treesit-indent-rules): Cache indent rules. (mhtml-ts-mode): Call the new `mhtml-ts-mode--treesit-font-lock-settings' function. diff --git a/lisp/textmodes/mhtml-ts-mode.el b/lisp/textmodes/mhtml-ts-mode.el index 94350d6d304..355c3201946 100644 --- a/lisp/textmodes/mhtml-ts-mode.el +++ b/lisp/textmodes/mhtml-ts-mode.el @@ -259,20 +259,28 @@ NODE and PARENT are ignored." css--treesit-font-lock-feature-list)) "Settings for `treesit-font-lock-feature-list'.") -(defvar mhtml-ts-mode--treesit-font-lock-settings - (append html-ts-mode--font-lock-settings - (js--treesit-font-lock-settings) - ;; Let's replace a css rule with a new one that adds color to - ;; the css value. - (treesit-replace-font-lock-feature-settings - (treesit-font-lock-rules - :language 'css - :override t - :feature 'variable - '((plain_value) @mhtml-ts-mode--colorize-css-value - (color_value) @mhtml-ts-mode--colorize-css-value)) - css--treesit-settings)) - "Settings for `treesit-font-lock-settings'.") +(defvar mhtml-ts-mode--treesit-font-lock-settings-cached nil + "Cached tree-sitter font-lock settings for `mhtml-ts-mode'.") + +(defun mhtml-ts-mode--treesit-font-lock-settings () + "Return tree-sitter font-lock settings for `mhtml-ts-mode'. + +Tree-sitter font-lock settings are evaluated the first time this +function is called. Subsequent calls return the first evaluated value." + (or mhtml-ts-mode--treesit-font-lock-settings-cached + (setq mhtml-ts-mode--treesit-font-lock-settings-cached + (append html-ts-mode--font-lock-settings + (js--treesit-font-lock-settings) + ;; Let's replace a css rule with a new one that adds + ;; color to the css value. + (treesit-replace-font-lock-feature-settings + (treesit-font-lock-rules + :language 'css + :override t + :feature 'variable + '((plain_value) @mhtml-ts-mode--colorize-css-value + (color_value) @mhtml-ts-mode--colorize-css-value)) + css--treesit-settings))))) (defvar mhtml-ts-mode--treesit-thing-settings ;; In addition to putting together the various definitions, we need to @@ -292,31 +300,34 @@ NODE and PARENT are ignored." `((defun ,css--treesit-defun-type-regexp)))) "Settings for `treesit-thing-settings'.") -;; We use a function instead of a variable, because -;; `js--treesit-indent-rules' and `css--treesit-indent-rules' doesn't -;; exist when at compile time (unless we `eval-when-compile', but that -;; doesn't feel like the right solution to me). +(defvar mhtml-ts-mode--treesit-indent-rules-cached nil + "Cached tree-sitter indent rules for `mhtml-ts-mode'.") + (defun mhtml-ts-mode--treesit-indent-rules () - "Return intent rules for `mhtml-ts-mode'." - (treesit--indent-rules-optimize - (append html-ts-mode--indent-rules - ;; Extended rules for js and css, to - ;; indent appropriately when injected - ;; into html - (treesit-simple-indent-modify-rules - 'javascript - `((javascript ((parent-is "program") - mhtml-ts-mode--js-css-tag-bol - mhtml-ts-mode--js-css-indent-offset))) - (js--treesit-indent-rules) - :replace) - (treesit-simple-indent-modify-rules - 'css - `((css ((parent-is "stylesheet") - mhtml-ts-mode--js-css-tag-bol - mhtml-ts-mode--js-css-indent-offset))) - css--treesit-indent-rules - :prepend)))) + "Return tree-sitter indent rules for `mhtml-ts-mode'. + +Tree-sitter indent rules are evaluated the first time this function +is called. Subsequent calls return the first evaluated value." + (or mhtml-ts-mode--treesit-indent-rules-cached + (setq mhtml-ts-mode--treesit-indent-rules-cached + (treesit--indent-rules-optimize + (append html-ts-mode--indent-rules + ;; Extended rules for js and css, to indent + ;; appropriately when injected into html + (treesit-simple-indent-modify-rules + 'javascript + `((javascript ((parent-is "program") + mhtml-ts-mode--js-css-tag-bol + mhtml-ts-mode--js-css-indent-offset))) + (js--treesit-indent-rules) + :replace) + (treesit-simple-indent-modify-rules + 'css + `((css ((parent-is "stylesheet") + mhtml-ts-mode--js-css-tag-bol + mhtml-ts-mode--js-css-indent-offset))) + css--treesit-indent-rules + :prepend)))))) (defvar mhtml-ts-mode--treesit-aggregated-simple-imenu-settings `((html ,@html-ts-mode--treesit-simple-imenu-settings) @@ -561,7 +572,7 @@ Powered by tree-sitter." ;; to extend/modify the default rule or use a different set of ;; rules. See `php-ts-mode--custom-html-font-lock-settings' for more ;; advanced usage. - (setq-local treesit-font-lock-settings mhtml-ts-mode--treesit-font-lock-settings) + (setq-local treesit-font-lock-settings (mhtml-ts-mode--treesit-font-lock-settings)) ;; Tells treesit the list of features to fontify. (setq-local treesit-font-lock-feature-list mhtml-ts-mode--treesit-font-lock-feature-list) commit ae32e2541918bf8baecc457e25953a89cbe04e68 Author: Steven Allen Date: Fri Sep 19 10:34:47 2025 -0700 Fix minibuffer-nonselected-mode when using recursive minibuffers * lisp/minibuffer.el (minibuffer-nonselected-setup): Use window-buffer-change-functions in addition to window-selection-change-functions to detect changes from one recursive minibuffer to another within the same minibuffer-window. (minibuffer-nonselected-check): Ensure that the target minibuffer is current before checking/deleting the overlay (bug#79472). diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index ff1b68b49a4..70ad0c7abc5 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -5612,8 +5612,9 @@ Use overlay to highlight the minibuffer window when another window is selected. But don't warn in case when the *Completions* window becomes selected." (if (eq window (selected-window)) - (when (overlayp minibuffer-nonselected-overlay) - (delete-overlay minibuffer-nonselected-overlay)) + (with-current-buffer (window-buffer window) + (when (overlayp minibuffer-nonselected-overlay) + (delete-overlay minibuffer-nonselected-overlay))) (unless (eq major-mode 'completion-list-mode) (with-current-buffer (window-buffer window) (let ((ov (make-overlay (point-min) (point-max)))) @@ -5623,6 +5624,8 @@ becomes selected." (setq minibuffer-nonselected-overlay ov)))))) (defun minibuffer-nonselected-setup () + (add-hook 'window-buffer-change-functions + 'minibuffer-nonselected-check nil t) (add-hook 'window-selection-change-functions 'minibuffer-nonselected-check nil t)) commit 33e61769329d289e452c380cc0aca1886fb60f03 Author: Eli Zaretskii Date: Sun Sep 21 13:03:16 2025 +0300 ; * lisp/international/textsec-check.el (textsec-suspicious-p): Doc fix. diff --git a/lisp/international/textsec-check.el b/lisp/international/textsec-check.el index 0da1a39170b..f728591b209 100644 --- a/lisp/international/textsec-check.el +++ b/lisp/international/textsec-check.el @@ -58,7 +58,7 @@ Available values of TYPE and corresponding OBJECTs are: `name' -- the \"display name\" part of an email address; OBJECT should be a string. -`email-address' -- a full email address; OBJECT should be a string. + `email-address' -- a full email address; OBJECT should be a string. `email-address-header' -- a raw email address header in RFC 2822 format; OBJECT should be a string.