commit 1e40be0ab830852ff5e2330c50f8b047d9ebe338 (HEAD, refs/remotes/origin/master) Author: Stefan Kangas Date: Wed Dec 25 04:35:50 2024 +0100 Improve dictionary-switch-tooltip-mode docstring * lisp/net/dictionary.el (dictionary-switch-tooltip-mode): Fix docstring and argument name. diff --git a/lisp/net/dictionary.el b/lisp/net/dictionary.el index 543a98f8de3..7add1db3099 100644 --- a/lisp/net/dictionary.el +++ b/lisp/net/dictionary.el @@ -1453,16 +1453,15 @@ via `dictionary-dictionaries'." (setq dictionary-tooltip-mouse-event (copy-sequence event)) (tooltip-start-delayed-tip))) -(defun dictionary-switch-tooltip-mode (on) - "Turn dictionary tooltip mode off or ON. - -It is normally internally called with 1 to enable support for the -tooltip mode. The hook function will check the value of the -variable `dictionary-tooltip-mode' to decide if some action must be -taken. When disabling the tooltip mode the value of this variable -will be set to nil." - (tooltip-mode on) - (if on +(defun dictionary-switch-tooltip-mode (state) + "Turn dictionary tooltip mode on or off depending on STATE. + +It is normally called internally with a non-nil value to enable the +tooltip mode. The hook function uses the value of the variable +`dictionary-tooltip-mode' to decide if some action must be taken. +When disabling the tooltip mode, that variable will be set to nil." + (tooltip-mode state) + (if state (add-hook 'tooltip-functions #'dictionary-display-tooltip) (remove-hook 'tooltip-functions #'dictionary-display-tooltip))) commit 7cda5e7f0272d766bd2090a274faeb7776303f46 Author: Nicholas Vollmer Date: Tue Jan 23 09:39:02 2024 -0500 Fix checkdoc warnings in dictionary.el * lisp/net/dictionary.el (dictionary-tool-bar-map): Add missing period. (dictionary-process-popup-replies) (dictionary-read-definition) (dictionary-display-tooltip): Rename ignored parameters. (dictionary-tooltip-track-mouse): Describe what function does, not just when. (dictionary-switch-tooltip-mode): Reword docstring in terms of ON parameter. (Bug#68684) diff --git a/lisp/net/dictionary.el b/lisp/net/dictionary.el index 8c7d87f56a5..543a98f8de3 100644 --- a/lisp/net/dictionary.el +++ b/lisp/net/dictionary.el @@ -1340,7 +1340,7 @@ prompt for DICTIONARY." dictionary-default-popup-strategy 'dictionary-process-popup-replies)) -(defun dictionary-process-popup-replies (&ignore) +(defun dictionary-process-popup-replies (_) (let ((list (dictionary-simple-split-string (dictionary-read-answer) "\n+"))) (let ((result (mapcar (lambda (item) @@ -1395,7 +1395,7 @@ via `dictionary-dictionaries'." (dictionary-do-search word dictionary 'dictionary-read-definition t)) nil)) -(defun dictionary-read-definition (&ignore) +(defun dictionary-read-definition (_) (let ((list (dictionary-simple-split-string (dictionary-read-answer) "\n+"))) (mapconcat #'identity (cdr list) "\n"))) @@ -1422,7 +1422,7 @@ via `dictionary-dictionaries'." (defvar dictionary-tooltip-mouse-event nil "Event that triggered the tooltip mode.") -(defun dictionary-display-tooltip (&ignore) +(defun dictionary-display-tooltip (_) "Search the current word in the `dictionary-tooltip-dictionary'." (interactive "e") (if (and dictionary-tooltip-mode dictionary-tooltip-dictionary) @@ -1446,7 +1446,7 @@ via `dictionary-dictionaries'." nil))) (defun dictionary-tooltip-track-mouse (event) - "Called whenever a dictionary tooltip display is about to be triggered." + "Hide current tooltip and setup next tooltip in response to mouse movement EVENT." (interactive "e") (tooltip-hide) (when dictionary-tooltip-mode @@ -1454,7 +1454,7 @@ via `dictionary-dictionaries'." (tooltip-start-delayed-tip))) (defun dictionary-switch-tooltip-mode (on) - "Turn off or on support for the dictionary tooltip mode. + "Turn dictionary tooltip mode off or ON. It is normally internally called with 1 to enable support for the tooltip mode. The hook function will check the value of the commit 8c7db480ead8ef623a382fcd990dd91486616dca Author: Yuan Fu Date: Tue Dec 24 13:52:03 2024 -0800 ; * etc/NEWS: Update tree-sitter NEWS. diff --git a/etc/NEWS b/etc/NEWS index 9754322b1bf..ca107bb4938 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -999,6 +999,22 @@ For example, 'cpp' is translated to "C++". Also adds a new variable 'treesit-language-display-name-alist' that the function uses to translate display names. ++++ +*** New command 'treesit-explore' +This command replaces 'treesit-explore-mode'. It turns on +'treesit-explore-mode' if it’s not on, and pops up the explorer buffer +if it’s already on. + ++++ +*** 'treesit-explore-mode' now supports local parsers +Now 'treesit-explore-mode' (or 'treesit-explore') prompts for a parser +rather than a language, and it’s now possible to select a local parser +at point to explore. + ++++ +*** New variable 'treesit-aggregated-simple-imenu-settings' +This variable allows major modes to setup Imenu for multiple languages. + +++ ** New optional BUFFER argument for 'string-pixel-width'. If supplied, 'string-pixel-width' will use any face remappings from commit e2a9af431191d5c71e2ca7a4347ce9e435e8cca0 Author: Yuan Fu Date: Tue Dec 24 13:17:51 2024 -0800 Add treesit-aggregated-simple-imenu-settings Now we support setting up Imenu for multiple languages * doc/lispref/modes.texi: Update manual. * lisp/treesit.el: (treesit-aggregated-simple-imenu-settings): New variable. (treesit--imenu-merge-entries): New function. (treesit--generate-simple-imenu): This was previously treesit-simple-imenu. (treesit-simple-imenu): Support treesit-aggregated-simple-imenu-settings. (treesit-major-mode-setup): Recognize treesit-aggregated-simple-imenu-settings. * test/src/treesit-tests.el (treesit-imenu): New test. diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi index 73edb688c85..f227bdc635f 100644 --- a/doc/lispref/modes.texi +++ b/doc/lispref/modes.texi @@ -3109,6 +3109,15 @@ instead. automatically sets up Imenu if this variable is non-@code{nil}. @end defvar +@defvar treesit-aggregated-simple-imenu-settings +This variable allows major modes to configure Imenu for multiple +languages. Its value is an alist mapping language symbols to Imenu +settings described in @var{treesit-simple-imenu-settings}. + +If both this variable and @var{treesit-simple-imenu-settings} is +non-@code{nil}, Emacs uses this variable for setting up Imenu. +@end defvar + @node Outline Minor Mode @section Outline Minor Mode diff --git a/lisp/treesit.el b/lisp/treesit.el index 2cf7bccdeed..464b7e688be 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -3123,6 +3123,31 @@ node and returns the name of that defun node. If NAME-FN is nil, `treesit-major-mode-setup' automatically sets up Imenu if this variable is non-nil.") +;; `treesit-simple-imenu-settings' doesn't support multiple languages, +;; and we need to add multi-lang support for Imenu. One option is to +;; extend treesit-simple-imenu-settings to specify language, either by +;; making it optionally an alist (just like +;; `treesit-aggregated-simple-imenu-settings'), or add a fifth element +;; to each setting. But either way makes borrowing Imenu settings from +;; other modes difficult: with the alist approach, you'd need to check +;; whether other mode uses a plain list or an alist; with the fifth +;; element approach, again, you need to check if each setting has the +;; fifth element, and add it if not. +;; +;; OTOH, with `treesit-aggregated-simple-imenu-settings', borrowing +;; Imenu settings is easy: if `treesit-aggregated-simple-imenu-settings' +;; is non-nil, copy everything over; if `treesit-simple-imenu-settings' +;; is non-nil, copy the settings and put them under a language symbol. +(defvar treesit-aggregated-simple-imenu-settings nil + "Settings that configure `treesit-simple-imenu' for multi-language modes. + +The value should be an alist of (LANG . SETTINGS), where LANG is a +language symbol, and SETTINGS has the same form as +`treesit-simple-imenu-settings'. + +When both this variable and `treesit-simple-imenu-settings' are non-nil, +this variable takes priority.") + (defun treesit--simple-imenu-1 (node pred name-fn) "Given a sparse tree, create an Imenu index. @@ -3170,20 +3195,69 @@ ENTRY. MARKER marks the start of each tree-sitter node." ;; Leaf node, return a (list of) plain index entry. (t (list (cons name marker)))))) +(defun treesit--imenu-merge-entries (entries) + "Merge ENTRIES by category. + +ENTRIES is a list of (CATEGORY . SUB-ENTRIES...). Merge them so there's +no duplicate CATEGORY. CATEGORY's are strings. The merge is stable, +meaning the order of elements are kept." + (let ((return-entries nil)) + (dolist (entry entries) + (let* ((category (car entry)) + (sub-entries (cdr entry)) + (existing-entries + (alist-get category return-entries nil nil #'equal))) + (if (not existing-entries) + (push entry return-entries) + (setf (alist-get category return-entries nil nil #'equal) + (append existing-entries sub-entries))))) + (nreverse return-entries))) + +(defun treesit--generate-simple-imenu (node settings) + "Return an Imenu index for NODE with SETTINGS. + +NODE usually should be a root node of a parser. SETTINGS is described +by `treesit-simple-imenu-settings'." + (mapcan (lambda (setting) + (pcase-let ((`(,category ,regexp ,pred ,name-fn) + setting)) + (when-let* ((tree (treesit-induce-sparse-tree + node regexp)) + (index (treesit--simple-imenu-1 + tree pred name-fn))) + (if category + (list (cons category index)) + index)))) + settings)) + (defun treesit-simple-imenu () "Return an Imenu index for the current buffer." - (let ((root (treesit-buffer-root-node))) - (mapcan (lambda (setting) - (pcase-let ((`(,category ,regexp ,pred ,name-fn) - setting)) - (when-let* ((tree (treesit-induce-sparse-tree - root regexp)) - (index (treesit--simple-imenu-1 - tree pred name-fn))) - (if category - (list (cons category index)) - index)))) - treesit-simple-imenu-settings))) + (if (not treesit-aggregated-simple-imenu-settings) + (treesit--generate-simple-imenu + (treesit-parser-root-node treesit-primary-parser) + treesit-simple-imenu-settings) + ;; Use `treesit-aggregated-simple-imenu-settings'. Remove languages + ;; that doesn't have any Imenu entries. + (seq-filter + #'cdr + (mapcar + (lambda (entry) + (let* ((lang (car entry)) + (settings (cdr entry)) + (global-parser (car (treesit-parser-list nil lang))) + (local-parsers + (treesit-parser-list nil lang 'embedded))) + (cons (treesit-language-display-name lang) + ;; No one says you can't have both global and local + ;; parsers for the same language. E.g., Rust uses + ;; local parsers for the same language to handle + ;; macros. + (treesit--imenu-merge-entries + (mapcan (lambda (parser) + (treesit--generate-simple-imenu + (treesit-parser-root-node parser) settings)) + (cons global-parser local-parsers)))))) + treesit-aggregated-simple-imenu-settings)))) ;;; Outline minor mode @@ -3321,7 +3395,8 @@ and `end-of-defun-function'. If `treesit-defun-name-function' is non-nil, set up `add-log-current-defun'. -If `treesit-simple-imenu-settings' is non-nil, set up Imenu. +If `treesit-simple-imenu-settings' or +`treesit-aggregated-simple-imenu-settings' is non-nil, set up Imenu. If either `treesit-outline-predicate' or `treesit-simple-imenu-settings' are non-nil, and Outline minor mode settings don't already exist, setup @@ -3395,7 +3470,8 @@ before calling this function." (setq-local forward-sentence-function #'treesit-forward-sentence)) ;; Imenu. - (when treesit-simple-imenu-settings + (when (or treesit-aggregated-simple-imenu-settings + treesit-simple-imenu-settings) (setq-local imenu-create-index-function #'treesit-simple-imenu)) diff --git a/test/src/treesit-tests.el b/test/src/treesit-tests.el index 50f205421d7..43102fc97e0 100644 --- a/test/src/treesit-tests.el +++ b/test/src/treesit-tests.el @@ -1270,6 +1270,20 @@ This tests bug#60355." (should node) (should (equal (treesit-node-text node) "2")))) +;;; Imenu + +(ert-deftest treesit-imenu () + "Test imenu functions." + (should (equal (treesit--imenu-merge-entries + '(("Function" . (f1 f2)) + ("Function" . (f3 f4 f5)) + ("Class" . (c1 c2 c3)) + ("Variables" . (v1 v2)) + ("Class" . (c4)))) + '(("Function" . (f1 f2 f3 f4 f5)) + ("Class" . (c1 c2 c3 c4)) + ("Variables" . (v1 v2)))))) + ;; TODO ;; - Functions in treesit.el commit 833494d4b00a837be8ceaa09b37f54ce17d0a062 Author: Yuan Fu Date: Mon Dec 23 21:20:18 2024 -0800 ; Add some shortdoc examples for treesit entry * lisp/treesit.el: Add some shortdoc examples. diff --git a/lisp/treesit.el b/lisp/treesit.el index be264b4292a..2cf7bccdeed 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -4376,6 +4376,22 @@ generated by \"git describe\". It only works when :eval (treesit-pattern-expand '(identifier)) :eval (treesit-pattern-expand :equal)) + "Tree-sitter things and navigation" + (treesit-thing-defined-p + :no-eval (treesit-thing-defined-p 'sexp) + :eg-result nil) + (treesit-thing-definition + :no-eval (treesit-thing-defined 'sexp) + :eg-result (not ,(rx (or "{" "}" "[" "]" "(" ")" ",")))) + (treesit-thing-at + :no-eval (treesit-thing-at 3943) + :eg-result-string "#") + (treesit-thing-next + :no-eval (treesit-thing-next 3943 'sexp)) + (treesit-navigate-thing + :no-eval (treesit-navigate-thing 3943 1 'beg 'sexp)) + (treesit-beginning-of-thing + :no-eval (treesit-beginning-of-thing 'defun 1 'nested)) "Parsing a string" (treesit-parse-string @@ -4388,7 +4404,15 @@ generated by \"git describe\". It only works when "Misc" (treesit-subtree-stat :no-eval (treesit-subtree-stat node) - :eg-result (6 33 487))) + :eg-result (6 33 487)) + (treesit-language-abi-version + :no-eval (treesit-language-abi-version 'c) + :eg-result 14) + (treesit-grammar-location + :no-eval (treesit-language-abi-version 'c)) + (treesit-language-display-name + :no-eval (treesit-language-display-name 'cpp) + :eg-result "C++")) (provide 'treesit) commit 251b4c8c39535fee9f6da89420483304274ac03e Author: Yuan Fu Date: Mon Dec 23 21:19:32 2024 -0800 Add treesit-language-display-name * lisp/treesit.el: (treesit-language-display-name-alist): New variable. (treesit-language-display-name): New function. * doc/lispref/parsing.texi (Language Grammar): Add to manual. * etc/NEWS: Add to NEWS. diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi index 7f21c3864fc..fc56c20304b 100644 --- a/doc/lispref/parsing.texi +++ b/doc/lispref/parsing.texi @@ -160,6 +160,22 @@ grammar library loaded by Emacs for @var{language}. If @var{language} is unavailable, this function returns @code{nil}. @end defun +@vindex treesit-language-display-name-alist +@defun treesit-language-display-name language +This function translates @var{language} to an appropriate display name. +For example, it translates @code{ruby} to ``Ruby'', @code{cpp} to +``C++''. + +Most languages has ``regular'' names, and their display name is simply +the symbol name with first letter capitalized. For languages that has +``irregular'' names, @var{treesit-language-display-name-alist} maps +language symbols to their display names. + +If a major mode package uses a langauge with ``irregular'' name, they +should add a mapping into @var{treesit-language-display-name-alist} on +load. +@end defun + @heading Concrete syntax tree @cindex syntax tree, concrete diff --git a/etc/NEWS b/etc/NEWS index 847cc39ce96..9754322b1bf 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -992,6 +992,13 @@ The new function 'treesit-forward-sexp-list' uses 'sexp-list' to move across lists. But to move across atoms inside the list it uses `forward-sexp-default-function'. ++++ +*** New function 'treesit-language-display-name'. +New function that returns the display name given the language symbol. +For example, 'cpp' is translated to "C++". Also adds a new variable +'treesit-language-display-name-alist' that the function uses to +translate display names. + +++ ** New optional BUFFER argument for 'string-pixel-width'. If supplied, 'string-pixel-width' will use any face remappings from diff --git a/lisp/treesit.el b/lisp/treesit.el index e37ea85ebbe..be264b4292a 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -835,6 +835,36 @@ omitted, default END to BEG." return rng finally return nil)))) +;;; Language display name + +;; The entries are sorted by `sort-lines'. +(defvar treesit-language-display-name-alist + '( + (charp . "C#") + (cmake . "CMake") + (cpp . "C++") + (gomod . "Go Mod") + (heex . "HEEx") + (json . "JSON") + (php . "PHP") + (tsx . "TSX") + ) + "An alist mapping language symbols to their display names. + +Used by `treesit-language-display-name'. If there's no mapping in this +alist, `treesit-language-display-name' converts the symbol to display +name by capitalizing the first letter. So languages like Java, +Javascript, Rust don't need an entry in this variable.") + +(defun treesit-language-display-name (language) + "Returns the display name (a string) of LANGUAGE. + +If LANGUAGE has an entry in `treesit-language-display-name-alist', use +the display name in their. Otherwise, capitalize the first letter of +LANGUAGE and return the string." + (or (alist-get language treesit-language-display-name-alist) + (capitalize (symbol-name language)))) + ;;; Fontification (define-error 'treesit-font-lock-error commit 563e5868f6dbab59937ad247b45b488f5523ad3c Author: Juri Linkov Date: Tue Dec 24 19:39:30 2024 +0200 Add treesit thing 'sexp-list' to c++-ts-mode (bug#73404) * lisp/progmodes/c-ts-mode.el (c-ts-mode--thing-settings): Add C++ 'sexp-list' nodes for 'treesit-thing-settings'. diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 90e73260b9b..5537439004e 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -1170,7 +1170,18 @@ if `c-ts-mode-emacs-sources-support' is non-nil." "initializer_list" "subscript_designator" "subscript_range_designator" - "string_literal") + "string_literal" + "system_lib_string" + ;; C++ + "template_parameter_list" + "structured_binding_declarator" + "template_argument_list" + "condition_clause" + "subscript_argument_list" + "requirement_seq" + "requires_parameter_list" + "lambda_capture_specifier" + "fold_expression") 'symbols)) ;; compound_statement makes us jump over too big units ;; of code, so skip that one, and include the other commit b061c01607aa43b8ffa1b5c4a90c3602497cf823 Author: Juri Linkov Date: Tue Dec 24 19:24:11 2024 +0200 Add treesit thing 'sexp-list' to tsx-ts-mode (bug#73404, bug#73978) * lisp/progmodes/typescript-ts-mode.el (tsx-ts-mode): Add 'sexp-list' to 'treesit-thing-settings' with "jsx" things. (typescript-ts-mode--sexp-list-nodes): Remove "jsx" things. diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index 5c3c9a24ff4..df41c179e30 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -470,8 +470,6 @@ See `treesit-thing-settings' for more information.") "object_pattern" "array" "array_pattern" - "jsx_expression" - "_jsx_string" "string" "regex" "arguments" @@ -599,8 +597,15 @@ at least 3 (which is the default value)." `((tsx (sexp ,(regexp-opt (append typescript-ts-mode--sexp-nodes - '("jsx")) - 'symbols)) + '("jsx")))) + (sexp-list ,(concat "^" + (regexp-opt + (append typescript-ts-mode--sexp-list-nodes + '( + "jsx_element" + "jsx_self_closing_element" + "jsx_expression"))) + "$")) (sentence ,(regexp-opt (append typescript-ts-mode--sentence-nodes '("jsx_element" commit f0afebb99158be3db1d9623758321622a1026c8d Author: Juri Linkov Date: Tue Dec 24 09:40:21 2024 +0200 * lisp/progmodes/typescript-ts-mode.el: Fix regexp-opt of treesit-thing. (typescript-ts-base-mode): Add arg 'symbols' to regexp-opt of 'sexp', 'sexp-list', 'sentence', 'text' (bug#73404, bug#74366, bug#74963). (tsx-ts-mode): Add arg 'symbols' to regexp-opt of 'sexp', 'sentence'. This avoids such mismatches as "string_fragment" by "string". diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index 08c8a71c18e..5c3c9a24ff4 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -514,12 +514,14 @@ This mode is intended to be inherited by concrete major modes." (setq-local treesit-thing-settings `((typescript - (sexp ,(regexp-opt typescript-ts-mode--sexp-nodes)) - (sexp-list ,(regexp-opt typescript-ts-mode--sexp-list-nodes)) + (sexp ,(regexp-opt typescript-ts-mode--sexp-nodes 'symbols)) + (sexp-list ,(regexp-opt typescript-ts-mode--sexp-list-nodes + 'symbols)) (sentence ,(regexp-opt - typescript-ts-mode--sentence-nodes)) + typescript-ts-mode--sentence-nodes 'symbols)) (text ,(regexp-opt '("comment" - "template_string")))))) + "template_string") + 'symbols))))) ;; Imenu (same as in `js-ts-mode'). (setq-local treesit-simple-imenu-settings @@ -597,11 +599,13 @@ at least 3 (which is the default value)." `((tsx (sexp ,(regexp-opt (append typescript-ts-mode--sexp-nodes - '("jsx")))) + '("jsx")) + 'symbols)) (sentence ,(regexp-opt (append typescript-ts-mode--sentence-nodes '("jsx_element" - "jsx_self_closing_element"))))))) + "jsx_self_closing_element")) + 'symbols))))) ;; Font-lock. (setq-local treesit-font-lock-settings commit 7ac7ebef6cde9942905c45126cc6ef2bab01dc10 Author: Yuan Fu Date: Mon Dec 23 18:51:51 2024 -0800 ; Update c-ts-mode and c++-ts-mode's verified revision * lisp/progmodes/c-ts-mode.el: Update revision. diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 67ccbb8594b..90e73260b9b 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -25,10 +25,10 @@ ;;; Tree-sitter language versions ;; ;; c-ts-mode is known to work with the following languages and version: -;; - tree-sitter-c: v0.20.8-61-g3efee11 +;; - tree-sitter-c: v0.23.4 ;; ;; c++-ts-mode is known to work with the following languages and version: -;; - tree-sitter-cpp: v0.20.5-49-gf41b4f6 +;; - tree-sitter-cpp: v0.23.4-1-gf41b4f6 ;; ;; We try our best to make builtin modes work with latest grammar ;; versions, so a more recent grammar version has a good chance to work. commit 32ad7342893833058ca2f7f8eca667bd32d42ea0 Author: Yuan Fu Date: Mon Dec 23 18:50:08 2024 -0800 Include lightweight tags in treesit-admin--verify-major-mode-queries * lisp/treesit.el (treesit--language-git-revision): Include lightweight tags as well. diff --git a/lisp/treesit.el b/lisp/treesit.el index 69b800cb271..e37ea85ebbe 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -4013,7 +4013,7 @@ Return the output of \"git describe\". If anything goes wrong, return nil." (with-temp-buffer (cond - ((eq 0 (call-process "git" nil t nil "describe")) + ((eq 0 (call-process "git" nil t nil "describe" "--tags")) (string-trim (buffer-string))) ((eq 0 (progn (erase-buffer) (call-process "git" nil t nil "rev-parse" "HEAD"))) commit 4def541bbfe67b1a492e8a3b6041a1d8f76d680b Author: Yuan Fu Date: Mon Dec 23 18:43:11 2024 -0800 Fix cmake-ts-mode font-lock queries This commit in tree-sitter-cmake removed angle brackets: https://github.com/uyha/tree-sitter-cmake/commit/a414a4c83d54388f596269639c175a5b84bfa929 * lisp/progmodes/cmake-ts-mode.el (cmake-ts-mode--font-lock-settings): Remove angle brackets. diff --git a/lisp/progmodes/cmake-ts-mode.el b/lisp/progmodes/cmake-ts-mode.el index 3ec239e89bb..1871ea39a47 100644 --- a/lisp/progmodes/cmake-ts-mode.el +++ b/lisp/progmodes/cmake-ts-mode.el @@ -22,6 +22,15 @@ ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . +;;; Tree-sitter language versions +;; +;; cmake-ts-mode is known to work with the following languages and version: +;; - tree-sitter-cmake: e409ae33f00e04cde30f2bcffb979caf1a33562a +;; +;; We try our best to make builtin modes work with latest grammar +;; versions, so a more recent grammar version has a good chance to work. +;; Send us a bug report if it doesn't. + ;;; Commentary: ;; @@ -175,7 +184,7 @@ Check if a node type is available, then return the right font lock rules." :feature 'misc-punctuation ;; Don't override strings. :override 'nil - '((["$" "{" "}" "<" ">"]) @font-lock-misc-punctuation-face) + '((["$" "{" "}"]) @font-lock-misc-punctuation-face) :language 'cmake :feature 'variable commit 93755ea1a6113e115ac3349b67e58e2f3fd03894 Author: Yuan Fu Date: Mon Dec 23 17:12:39 2024 -0800 Create a blobless clone in treesit-admin--verify-major-mode-queries * admin/treesit-admin.el (treesit-admin--verify-major-mode-queries): Create a blobless clone. * lisp/treesit.el (treesit--install-language-grammar-blobless): New variable. (treesit--git-clone-repo): Support blobless clone. diff --git a/admin/treesit-admin.el b/admin/treesit-admin.el index 3c0798a29f2..440056aff21 100644 --- a/admin/treesit-admin.el +++ b/admin/treesit-admin.el @@ -96,6 +96,7 @@ queries that has problems with latest grammar." (let ((treesit-extra-load-path (list grammar-dir)) (treesit-language-source-alist treesit-admin--builtin-language-sources) (treesit--install-language-grammar-full-clone t) + (treesit--install-language-grammar-blobless t) (version-alist nil) (invalid-feature-list nil) (valid-modes nil) diff --git a/lisp/treesit.el b/lisp/treesit.el index 7b7f4842505..69b800cb271 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -3925,6 +3925,9 @@ See `treesit-language-source-alist' for details." (defvar treesit--install-language-grammar-full-clone nil "If non-nil, do a full clone when cloning git repos.") +(defvar treesit--install-language-grammar-blobless nil + "If non-nil, create a blobless clone when cloning git repos.") + ;;;###autoload (defun treesit-install-language-grammar (lang &optional out-dir) "Build and install the tree-sitter language grammar library for LANG. @@ -4048,6 +4051,8 @@ Use shallow clone by default. Do a full clone when (let ((args (list "git" nil t nil "clone" url "--quiet"))) (when (not treesit--install-language-grammar-full-clone) (setq args (append args (list "--depth" "1")))) + (when treesit--install-language-grammar-blobless + (setq args (append args (list "--filter=blob:none")))) (when revision (setq args (append args (list "-b" revision)))) (setq args (append args (list workdir))) commit 8d7cba7bbf8fe83bbf9a9d8cae963983f3bca8cf Author: Yuan Fu Date: Fri Dec 20 22:46:31 2024 -0800 ; Minor comment improvement in c-ts-common--adaptive-fill-prefix * lisp/progmodes/c-ts-common.el (c-ts-common--adaptive-fill-prefix): Improve comment. diff --git a/lisp/progmodes/c-ts-common.el b/lisp/progmodes/c-ts-common.el index 137ff37a661..25b386cbaa7 100644 --- a/lisp/progmodes/c-ts-common.el +++ b/lisp/progmodes/c-ts-common.el @@ -249,9 +249,12 @@ This function should be called at BOL. Used by ;; (3) ;; Current line: *, |, - ;; Prefix: same. - ;; This branch must return the same prefix as branch (1), as the - ;; second line in the paragraph; then the whole paragraph will use * - ;; as the prefix. + ;; Adaptive fill looks at the first and second line of a paragraph, + ;; only when both lines return the same prefix does it use that + ;; prefix for the following lines. If the first lines matches branch + ;; (1) and returns * as prefix, and the second line matches this + ;; branch (3), and returns * as prefix, then the whole paragraph will + ;; use * as prefix. ((looking-at (rx (* (syntax whitespace)) (or "*" "|" "-") (* (syntax whitespace)))) commit 6ac38396898e6324d4c6dddb2ad05d1ad0dc5e7c Author: Stefan Kangas Date: Tue Dec 24 00:04:51 2024 +0100 ; * .mailmap: Fix UTF-8 issue. diff --git a/.mailmap b/.mailmap index bbfe4bceba1..56876a30fbe 100644 --- a/.mailmap +++ b/.mailmap @@ -27,6 +27,7 @@ Andrew G Cohen Arash Esbati Arash Esbati Arni Magnusson +Arsen Arsenović Artur Malabarba Artur Malabarba Artur Malabarba Basil L. Contovounesios commit 28c420afab6a0944a192c30ff2d5d9e40c88f14f Author: Paul Eggert Date: Mon Dec 23 13:38:51 2024 -0800 Avoid U+FFFD in commit messages * build-aux/git-hooks/commit-msg: Also check against U+FFFD REPLACEMENT CHARACTER in commit messages. diff --git a/build-aux/git-hooks/commit-msg b/build-aux/git-hooks/commit-msg index 1eb2560bba2..dace4c7fb66 100755 --- a/build-aux/git-hooks/commit-msg +++ b/build-aux/git-hooks/commit-msg @@ -31,6 +31,8 @@ fi # Use U+00A2 CENT SIGN to test whether the locale works. cent_sign_utf8_format='\302\242\n' cent_sign=`printf "$cent_sign_utf8_format"` +replacement_character_utf8_format='\357\277\275\n' +replacement_character=`printf "$replacement_character_utf8_format"` print_at_sign='BEGIN {print substr("'$cent_sign'@", 2)}' at_sign=`$awk "$print_at_sign" /dev/null` if test "$at_sign" != @; then @@ -44,7 +46,12 @@ if test "$at_sign" != @; then fi # Check the log entry. -exec $awk -v at_sign="$at_sign" -v cent_sign="$cent_sign" -v file="$1" ' +exec $awk \ + -v at_sign="$at_sign" \ + -v cent_sign="$cent_sign" \ + -v file="$1" \ + -v replacement_character="$replacement_character" \ +' BEGIN { # These regular expressions assume traditional Unix unibyte behavior. # They are needed for old or broken versions of awk, e.g., @@ -137,6 +144,10 @@ exec $awk -v at_sign="$at_sign" -v cent_sign="$cent_sign" -v file="$1" ' print "Unprintable character in commit message" status = 1 } + $0 ~ replacement_character { + print "Replacement character in commit message" + status = 1 + } END { if (nlines == 0) { commit b1de495eeae9afc8abccd908e5c53c463afdb7dc Author: Michael Albinus Date: Mon Dec 23 12:46:23 2024 +0100 * configure.ac (dbus): Default to ifavailable. (Bug#75004) diff --git a/configure.ac b/configure.ac index 1c7545ef984..18cbb42b0ef 100644 --- a/configure.ac +++ b/configure.ac @@ -578,7 +578,7 @@ OPTION_DEFAULT_OFF([w32], [use native MS Windows GUI in a Cygwin build]) OPTION_DEFAULT_OFF([pgtk], [use GTK to support window systems other than X]) OPTION_DEFAULT_ON([gpm],[don't use -lgpm for mouse support on a GNU/Linux console]) -OPTION_DEFAULT_ON([dbus],[don't compile with D-Bus support]) +OPTION_DEFAULT_IFAVAILABLE([dbus],[compile with D-Bus support]) AC_ARG_WITH([gconf],[AS_HELP_STRING([--with-gconf], [compile with Gconf support (Gsettings replaces this)])],[], [if test $with_features = yes; then @@ -3969,8 +3969,8 @@ dnl D-Bus has been tested under GNU/Linux only. Must be adapted for dnl other platforms. HAVE_DBUS=no DBUS_OBJ= -if test "${with_dbus}" = "yes"; then - EMACS_CHECK_MODULES([DBUS], [dbus-1 >= 1.0]) +if test "${with_dbus}" != "no" ; then + EMACS_CHECK_MODULES([DBUS], [dbus-1 >= 1.0], [HAVE_DBUS=yes], [HAVE_DBUS=no]) if test "$HAVE_DBUS" = yes; then AC_DEFINE([HAVE_DBUS], [1], [Define to 1 if using D-Bus.]) dnl dbus_watch_get_unix_fd has been introduced in D-Bus 1.1.1. @@ -5564,6 +5564,11 @@ if test "${HAVE_X11}" = "yes"; then WITH_IFAVAILABLE="$WITH_IFAVAILABLE --with-tiff=ifavailable";; esac fi +case $with_dbus,$HAVE_DBUS in + no,* | ifavailable,* | *,yes) ;; + *) MISSING="$MISSING dbus-1" + WITH_IFAVAILABLE="$WITH_IFAVAILABLE --with-dbus=ifavailable";; +esac case $with_gnutls,$HAVE_GNUTLS in no,* | ifavailable,* | *,yes) ;; *) MISSING="$MISSING gnutls" commit 6017c6a986fd958732facb1bb6ea2c040981b023 Author: Martin Rudalics Date: Mon Dec 23 10:59:11 2024 +0100 Make 'fit-frame-to-buffer' work around size hints (Bug#74866) * lisp/window.el (fit-frame-to-buffer-1): When 'frame-resize-pixelwise' is nil, round up requested sizes to avoid that lines get wrapped (Bug#74866). * doc/lispref/windows.texi (Resizing Windows): Mention that with size hints one may have to set 'frame-resize-pixelwise' to make 'fit-frame-to-buffer' fit the buffer exactly. diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index adc294e4c99..3ff78b599de 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -1166,7 +1166,9 @@ frame to its buffer using the command @code{fit-frame-to-buffer}. This command adjusts the size of @var{frame} to display the contents of its buffer exactly. @var{frame} can be any live frame and defaults to the selected one. Fitting is done only if @var{frame}'s root window is -live. +a live window. On window systems that use size hints, exact fitting can +be often achieved if and only if @code{frame-resize-pixelwise} +(@pxref{Frame Size}) is non-@code{nil}. The arguments @var{max-height}, @var{min-height}, @var{max-width} and @var{min-width}, if non-@code{nil}, specify bounds on the new body size diff --git a/lisp/window.el b/lisp/window.el index e9d57652ec6..cd19fd73849 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -9921,6 +9921,26 @@ for `fit-frame-to-buffer'." ;; Move frame down. (setq top top-margin))))) ;; Apply our changes. + (unless frame-resize-pixelwise + ;; When 'frame-resize-pixelwise' is nil, a frame cannot be + ;; necessarily fit completely even if the window's calculated + ;; width and height are integral multiples of the frame's + ;; character width and height. The size hints Emacs produces + ;; are inept to handle that when the combined sizes of the + ;; frame's fringes, scroll bar and internal border are not an + ;; integral multiple of the frame's character width (Bug#74866). + ;; Consequently, the window manager will round sizes down and + ;; this may cause lines getting wrapped. To avoid that, round + ;; sizes up here which will, however, leave a blank space at the + ;; end of the longest line(s). + (setq text-minus-body-width + (+ text-minus-body-width + (- char-width + (% text-minus-body-width char-width)))) + (setq text-minus-body-height + (+ text-minus-body-height + (- char-height + (% text-minus-body-height char-height))))) (setq text-width (if width (+ width text-minus-body-width) commit 39380e1bd3bfc26e355445590e243fcfa940fc9f Author: Arsen Arsenović Date: Sun Dec 22 19:33:29 2024 +0000 Java Mode: introduce the keyword `assert'. * lisp/progmodes/cc-langs.el (c-simple-stmt-kwds): Put `assert' into the java value. diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el index a256371f850..8d3d0ed3a3b 100644 --- a/lisp/progmodes/cc-langs.el +++ b/lisp/progmodes/cc-langs.el @@ -3251,7 +3251,7 @@ Such a keyword is a member of `c-paren-clause-kwds." c++ '("break" "continue" "goto" "return" "co_return") objc '("break" "continue" "goto" "return" "@throw") ;; Note: `goto' is not valid in Java, but the keyword is still reserved. - java '("break" "continue" "goto" "return" "throw") + java '("assert" "break" "continue" "goto" "return" "throw") idl nil pike '("break" "continue" "return") awk '(;; Not sure about "delete", "exit", "getline", etc. ; ACM 2002/5/30 commit 423e1ee7d6d6f34c0bc249a8dfb14a4a25eae08a Author: Juri Linkov Date: Sun Dec 22 21:15:18 2024 +0200 Add treesit thing 'sexp-list' to typescript-ts-mode (bug#73404) * lisp/progmodes/typescript-ts-mode.el (typescript-ts-base-mode): Add 'sexp-list' to 'treesit-thing-settings'. (typescript-ts-mode--sexp-list-nodes): New variable. diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index edca89e5c3a..08c8a71c18e 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -459,6 +459,35 @@ See `treesit-thing-settings' for more information.") "Nodes that designate sexps in TypeScript. See `treesit-thing-settings' for more information.") +(defvar typescript-ts-mode--sexp-list-nodes + '("export_clause" + "named_imports" + "statement_block" + "_for_header" + "switch_body" + "parenthesized_expression" + "object" + "object_pattern" + "array" + "array_pattern" + "jsx_expression" + "_jsx_string" + "string" + "regex" + "arguments" + "class_body" + "formal_parameters" + "computed_property_name" + "decorator_parenthesized_expression" + "enum_body" + "parenthesized_type" + "type_arguments" + "object_type" + "type_parameters" + "tuple_type") + "Nodes that designate lists in TypeScript. +See `treesit-thing-settings' for more information.") + ;;;###autoload (define-derived-mode typescript-ts-base-mode prog-mode "TypeScript" "Generic major mode for editing TypeScript. @@ -486,6 +515,7 @@ This mode is intended to be inherited by concrete major modes." (setq-local treesit-thing-settings `((typescript (sexp ,(regexp-opt typescript-ts-mode--sexp-nodes)) + (sexp-list ,(regexp-opt typescript-ts-mode--sexp-list-nodes)) (sentence ,(regexp-opt typescript-ts-mode--sentence-nodes)) (text ,(regexp-opt '("comment" commit ec39f669f902143a68a99fb42dd05716a27736be Author: Augusto Stoffel Date: Tue Nov 5 15:07:27 2024 +0100 Handle ':noquery' in 'open-gnutls-stream' * lisp/net/gnutls.el (open-gnutls-stream): Extract and use ':noquery' keyword. (Bug#74193). diff --git a/lisp/net/gnutls.el b/lisp/net/gnutls.el index b5fb4d47d57..2261ccc7e30 100644 --- a/lisp/net/gnutls.el +++ b/lisp/net/gnutls.el @@ -166,7 +166,7 @@ Third arg HOST is the name of the host to connect to, or its IP address. Fourth arg SERVICE is the name of the service desired, or an integer specifying a port number to connect to. Fifth arg PARAMETERS is an optional list of keyword/value pairs. -Only :client-certificate, :nowait, and :coding keywords are +Only :client-certificate, :nowait, :noquery, and :coding keywords are recognized, and have the same meaning as for `open-network-stream'. For historical reasons PARAMETERS can also be a symbol, which is @@ -197,9 +197,11 @@ trust and key files, and priority string." (cert (network-stream-certificate host service parameters)) (keylist (and cert (list cert))) (nowait (plist-get parameters :nowait)) + (noquery (plist-get parameters :noquery)) (process (open-network-stream name buffer host service :nowait nowait + :noquery noquery :tls-parameters (and nowait (cons 'gnutls-x509pki commit fb7bf20a9c129a97ceeabad00523ecafaa58697c Author: Michael Albinus Date: Sun Dec 22 10:20:15 2024 +0100 * test/lisp/files-tests.el (sh-shell): Move down declaration. diff --git a/test/lisp/files-tests.el b/test/lisp/files-tests.el index 78fc139025c..9dbf42ee603 100644 --- a/test/lisp/files-tests.el +++ b/test/lisp/files-tests.el @@ -1659,8 +1659,6 @@ The door of all subtleties! (should (equal (file-name-base "foo") "foo")) (should (equal (file-name-base "foo/bar") "bar"))) -(defvar sh-shell) - (defun files-tests--check-mode (filename) "Return the major mode found in `auto-mode-alist' for FILENAME." (set-auto-mode--find-matching-alist-entry @@ -1682,6 +1680,8 @@ The door of all subtleties! (should-not (eq (files-tests--check-mode "gdbinit.5") #'gdb-script-mode)) (should-not (eq (files-tests--check-mode ".gdbinit.py.in") #'gdb-script-mode))) +(defvar sh-shell) + (defun files-tests--check-shebang (shebang expected-mode &optional expected-dialect) "Assert that mode for SHEBANG derives from EXPECTED-MODE. commit 78eb102bc3d25aafb9a2d6756b956f7a2321a715 Author: Antero Mejr Date: Mon May 15 23:15:33 2023 +0000 Allow viewing .dcm images via image-convert * lisp/files.el (auto-mode-alist): Support the DICOM .dcm image format. (Bug#63531) diff --git a/lisp/files.el b/lisp/files.el index c7c2e7206b2..9144aaf0553 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -3221,6 +3221,7 @@ ARC\\|ZIP\\|LZH\\|LHA\\|ZOO\\|[JEW]AR\\|XPI\\|RAR\\|CBR\\|7Z\\|SQUASHFS\\)\\'" . ("\\.cmyk\\'" . image-mode) ("\\.cmyka\\'" . image-mode) ("\\.crw\\'" . image-mode) + ("\\.dcm\\'" . image-mode) ("\\.dcr\\'" . image-mode) ("\\.dcx\\'" . image-mode) ("\\.dng\\'" . image-mode) commit 7d41a23ad3b4c03ea1dea91eb70474f074dc05a4 Author: Antero Mejr Date: Mon May 15 21:21:12 2023 +0000 Allow viewing .six images via image-convert * lisp/files.el (auto-mode-alist): Support the Sixel .six image format. (Bug#63531) * lisp/image.el (imagemagick-enabled-types): Add SIX. diff --git a/lisp/files.el b/lisp/files.el index c92fc0608dd..c7c2e7206b2 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -3250,6 +3250,7 @@ ARC\\|ZIP\\|LZH\\|LHA\\|ZOO\\|[JEW]AR\\|XPI\\|RAR\\|CBR\\|7Z\\|SQUASHFS\\)\\'" . ("\\.pict\\'" . image-mode) ("\\.rgb\\'" . image-mode) ("\\.rgba\\'" . image-mode) + ("\\.six\\'" . image-mode) ("\\.tga\\'" . image-mode) ("\\.wbmp\\'" . image-mode) ("\\.webp\\'" . image-mode) diff --git a/lisp/image.el b/lisp/image.el index ce97eeb3ca1..29467d05678 100644 --- a/lisp/image.el +++ b/lisp/image.el @@ -1174,7 +1174,7 @@ has no effect." KDC MIFF MNG MRW MSL MSVG MTV NEF ORF OTB PBM PCD PCDS PCL PCT PCX PDB PEF PGM PICT PIX PJPEG PNG PNG24 PNG32 PNG8 PNM PPM PSD PTIF PWP RAF RAS RBG RGB RGBA RGBO RLA RLE SCR SCT - SFW SGI SR2 SRF SUN SVG SVGZ TGA TIFF TIFF64 TILE TIM TTF + SFW SGI SIX SR2 SRF SUN SVG SVGZ TGA TIFF TIFF64 TILE TIM TTF UYVY VDA VICAR VID VIFF VST WBMP WPG X3F XBM XC XCF XPM XV XWD YCbCr YCbCrA YUV) "List of ImageMagick types to treat as images. commit 961cff855a9eccb9c2de31edc7d90ce697ebb65d Author: Stefan Monnier Date: Sat Dec 21 21:45:41 2024 -0500 * lisp/vc/smerge-mode.el (smerge-extend): New command (bug#74509) diff --git a/etc/NEWS b/etc/NEWS index 12a318f5ed7..847cc39ce96 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -311,6 +311,9 @@ modal editing packages. * Changes in Specialized Modes and Packages in Emacs 31.1 +** Smerge +*** New command 'smerge-extend' extends a conflict over surrounding lines. + ** Browse URL *** New user option 'browse-url-transform-alist'. diff --git a/lisp/vc/smerge-mode.el b/lisp/vc/smerge-mode.el index 09d9ebda21b..a64ad2e0ec3 100644 --- a/lisp/vc/smerge-mode.el +++ b/lisp/vc/smerge-mode.el @@ -311,7 +311,7 @@ Can be nil if the style is undecided, or else: (let ((ends nil)) (dolist (i '(3 2 1 0)) (push (if (match-end i) (copy-marker (match-end i) t)) ends)) - (setq ends (apply 'vector ends)) + (setq ends (apply #'vector ends)) (goto-char (aref ends 0)) (if (not (re-search-forward smerge-begin-re nil t)) (error "No next conflict") @@ -701,7 +701,7 @@ this keeps \"LLL\"." (smerge-keep-n 3) (smerge-auto-leave)) -(define-obsolete-function-alias 'smerge-keep-other 'smerge-keep-lower "26.1") +(define-obsolete-function-alias 'smerge-keep-other #'smerge-keep-lower "26.1") (defun smerge-keep-upper () "Keep the \"upper\" version of a merge conflict. @@ -718,7 +718,7 @@ this keeps \"UUU\"." (smerge-keep-n 1) (smerge-auto-leave)) -(define-obsolete-function-alias 'smerge-keep-mine 'smerge-keep-upper "26.1") +(define-obsolete-function-alias 'smerge-keep-mine #'smerge-keep-upper "26.1") (defun smerge-get-current () (let ((i 3)) @@ -759,7 +759,7 @@ this keeps \"UUU\"." (smerge-diff 2 1)) (define-obsolete-function-alias 'smerge-diff-base-mine - 'smerge-diff-base-upper "26.1") + #'smerge-diff-base-upper "26.1") (defun smerge-diff-base-lower () "Diff `base' and `lower' version in current conflict region." @@ -767,7 +767,7 @@ this keeps \"UUU\"." (smerge-diff 2 3)) (define-obsolete-function-alias 'smerge-diff-base-other - 'smerge-diff-base-lower "26.1") + #'smerge-diff-base-lower "26.1") (defun smerge-diff-upper-lower () "Diff `upper' and `lower' version in current conflict region." @@ -775,7 +775,7 @@ this keeps \"UUU\"." (smerge-diff 1 3)) (define-obsolete-function-alias 'smerge-diff-mine-other - 'smerge-diff-upper-lower "26.1") + #'smerge-diff-upper-lower "26.1") (defun smerge-match-conflict () "Get info about the conflict. Puts the info in the `match-data'. @@ -1207,6 +1207,7 @@ repeating the command will highlight other two parts." '((smerge . refine) (font-lock-face . smerge-refined-added)))))) (defun smerge-swap () + ;; FIXME: Extend for diff3 to allow swapping the middle end as well. "Swap the \"Upper\" and the \"Lower\" chunks. Can be used before things like `smerge-keep-all' or `smerge-resolve' where the ordering can have some subtle influence on the result, such as preferring the @@ -1219,6 +1220,49 @@ spacing of the \"Lower\" chunk." (goto-char (match-beginning 1)) (insert txt3))) +(defun smerge-extend (otherpos) + "Extend current conflict with some of the surrounding text. +Point should be inside a conflict and OTHERPOS should be either a marker +indicating the position until which to extend the conflict (either before +or after the current conflict), +OTHERPOS can also be an integer indicating the number of lines over which +to extend the conflict. If positive, it extends over the lines following +the conflict and other, it extends over the lines preceding the conflict. +When used interactively, you can specify OTHERPOS either using an active +region, or with a numeric prefix. By default it uses a numeric prefix of 1." + (interactive + (list (if (use-region-p) (mark-marker) + (prefix-numeric-value current-prefix-arg)))) + ;; FIXME: If OTHERPOS is inside (or next to) another conflict + ;; or if there are conflicts between the current conflict and OTHERPOS, + ;; we end up messing up the conflict markers. We should merge the + ;; conflicts instead! + (condition-case err + (smerge-match-conflict) + (error (if (not (markerp otherpos)) (signal (car err) (cdr err)) + (goto-char (prog1 otherpos (setq otherpos (point-marker)))) + (smerge-match-conflict)))) + (let ((beg (match-beginning 0)) + (end (copy-marker (match-end 0))) + text) + (when (integerp otherpos) + (goto-char (if (>= otherpos 0) end beg)) + (setq otherpos (copy-marker (line-beginning-position (+ otherpos 1))))) + (setq text (cond + ((<= end otherpos) + (buffer-substring end otherpos)) + ((<= otherpos beg) + (buffer-substring otherpos beg)) + (t (user-error "The other end should be outside the conflict")))) + (dotimes (i 3) + (let* ((mn (- 3 i)) + (me (funcall (if (<= end otherpos) #'match-end #'match-beginning) + mn))) + (when me + (goto-char me) + (insert text)))) + (delete-region (if (<= end otherpos) end beg) otherpos))) + (defun smerge-diff (n1 n2) (smerge-match-conflict) (smerge-ensure-match n1) @@ -1252,7 +1296,7 @@ spacing of the \"Lower\" chunk." (let ((inhibit-read-only t)) (erase-buffer) (let ((status - (apply 'call-process diff-command nil t nil + (apply #'call-process diff-command nil t nil (append smerge-diff-switches (and (diff-check-labels) (list "--label" @@ -1394,7 +1438,7 @@ with a \\[universal-argument] prefix, makes up a 3-way conflict." (when current-prefix-arg (pop-mark) (mark)))) ;; Start from the end so as to avoid problems with pos-changes. (pcase-let ((`(,pt1 ,pt2 ,pt3 ,pt4) - (sort `(,pt1 ,pt2 ,pt3 ,@(if pt4 (list pt4))) '>=))) + (sort `(,pt1 ,pt2 ,pt3 ,@(if pt4 (list pt4))) #'>=))) (goto-char pt1) (beginning-of-line) (insert ">>>>>>> LOWER\n") (goto-char pt2) (beginning-of-line) commit 86a8b24bdea52a7aab45abcc51db2dd47308c11f Author: Stefan Kangas Date: Sun Dec 22 02:57:45 2024 +0100 Match more gdbinit files in auto-mode-alist * lisp/files.el (auto-mode-alist): Match more gdbinit files, including XDG, and MS-Windows. Avoid false positives. (set-auto-mode--find-matching-alist-entry): Break out function... (set-auto-mode--apply-alist): ...from here. (Bug#74946) * test/lisp/files-tests.el (files-tests--check-mode): New function. (files-tests-auto-mode-alist): New test. diff --git a/lisp/files.el b/lisp/files.el index c790d4add6f..c92fc0608dd 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -3056,7 +3056,7 @@ since only a single case-insensitive search through the alist is made." ;; files, cross-debuggers can use something like ;; .PROCESSORNAME-gdbinit so that the host and target gdbinit files ;; don't interfere with each other. - ("/\\.[a-z0-9-]*gdbinit" . gdb-script-mode) + ("/[._]?[A-Za-z0-9-]*\\(?:gdbinit\\(?:\\.\\(?:ini?\\|loader\\)\\)?\\|gdb\\.ini\\)\\'" . gdb-script-mode) ;; GDB 7.5 introduced OBJFILE-gdb.gdb script files; e.g. a file ;; named 'emacs-gdb.gdb', if it exists, will be automatically ;; loaded when GDB reads an objfile called 'emacs'. @@ -3455,6 +3455,35 @@ If FUNCTION is nil, then it is not called.") "Upper limit on `magic-mode-alist' regexp matches. Also applies to `magic-fallback-mode-alist'.") +(defun set-auto-mode--find-matching-alist-entry (alist name case-insensitive) + "Find first matching entry in ALIST for file NAME. + +If CASE-INSENSITIVE, the file system of file NAME is case-insensitive." + (let (mode) + (while name + (setq mode + (if case-insensitive + ;; Filesystem is case-insensitive. + (let ((case-fold-search t)) + (assoc-default name alist 'string-match)) + ;; Filesystem is case-sensitive. + (or + ;; First match case-sensitively. + (let ((case-fold-search nil)) + (assoc-default name alist 'string-match)) + ;; Fallback to case-insensitive match. + (and auto-mode-case-fold + (let ((case-fold-search t)) + (assoc-default name alist 'string-match)))))) + (if (and mode + (not (functionp mode)) + (consp mode) + (cadr mode)) + (setq mode (car mode) + name (substring name 0 (match-beginning 0))) + (setq name nil))) + mode)) + (defun set-auto-mode--apply-alist (alist keep-mode-if-same dir-local) "Helper function for `set-auto-mode'. This function takes an alist of the same form as @@ -3476,29 +3505,8 @@ extra checks should be done." (when (and (stringp remote-id) (string-match (regexp-quote remote-id) name)) (setq name (substring name (match-end 0)))) - (while name - ;; Find first matching alist entry. - (setq mode - (if case-insensitive-p - ;; Filesystem is case-insensitive. - (let ((case-fold-search t)) - (assoc-default name alist 'string-match)) - ;; Filesystem is case-sensitive. - (or - ;; First match case-sensitively. - (let ((case-fold-search nil)) - (assoc-default name alist 'string-match)) - ;; Fallback to case-insensitive match. - (and auto-mode-case-fold - (let ((case-fold-search t)) - (assoc-default name alist 'string-match)))))) - (if (and mode - (not (functionp mode)) - (consp mode) - (cadr mode)) - (setq mode (car mode) - name (substring name 0 (match-beginning 0))) - (setq name nil))) + (setq mode (set-auto-mode--find-matching-alist-entry + alist name case-insensitive-p)) (when (and dir-local mode (not (set-auto-mode--dir-local-valid-p mode))) (message "Ignoring invalid mode `%s'" mode) diff --git a/test/lisp/files-tests.el b/test/lisp/files-tests.el index ad54addf06b..78fc139025c 100644 --- a/test/lisp/files-tests.el +++ b/test/lisp/files-tests.el @@ -1661,6 +1661,27 @@ The door of all subtleties! (defvar sh-shell) +(defun files-tests--check-mode (filename) + "Return the major mode found in `auto-mode-alist' for FILENAME." + (set-auto-mode--find-matching-alist-entry + auto-mode-alist + (concat "/home/jrhacker/" filename) + nil)) + +(ert-deftest files-tests-auto-mode-alist () + (should (eq (files-tests--check-mode ".gdbinit.in") #'gdb-script-mode)) + (should (eq (files-tests--check-mode ".gdbinit") #'gdb-script-mode)) + (should (eq (files-tests--check-mode "_gdbinit") #'gdb-script-mode)) ; for MS-DOS + (should (eq (files-tests--check-mode "gdb.ini") #'gdb-script-mode)) ; likewise + (should (eq (files-tests--check-mode "gdbinit") #'gdb-script-mode)) + (should (eq (files-tests--check-mode "gdbinit.in") #'gdb-script-mode)) + (should (eq (files-tests--check-mode "SOMETHING-gdbinit") #'gdb-script-mode)) + (should (eq (files-tests--check-mode ".gdbinit.loader") #'gdb-script-mode)) + (should-not (eq (files-tests--check-mode "gdbinit-history.exp") #'gdb-script-mode)) + (should-not (eq (files-tests--check-mode "gdbinit.c") #'gdb-script-mode)) + (should-not (eq (files-tests--check-mode "gdbinit.5") #'gdb-script-mode)) + (should-not (eq (files-tests--check-mode ".gdbinit.py.in") #'gdb-script-mode))) + (defun files-tests--check-shebang (shebang expected-mode &optional expected-dialect) "Assert that mode for SHEBANG derives from EXPECTED-MODE. commit d89d8715eeae775305d4c5790b60793e3e57a474 Author: Stefan Kangas Date: Sun Dec 22 02:13:07 2024 +0100 Prefer defvar-keymap in gud.el * lisp/progmodes/gud.el (gud-gdb-repeat-map, gud-sdb-repeat-map) (gud-dbx-repeat-map, gud-xdb-repeat-map, gud-perldb-repeat-map) (gud-pdb-repeat-map, gud-guiler-repeat-map, gud-jdb-repeat-map): Convert to defvar-keymap. diff --git a/lisp/progmodes/gud.el b/lisp/progmodes/gud.el index 70daa087c2b..a38378886c0 100644 --- a/lisp/progmodes/gud.el +++ b/lisp/progmodes/gud.el @@ -331,20 +331,17 @@ Check it when `gud-running' is t") (tool-bar-local-item-from-menu (car x) (cdr x) map gud-menu-mode-map)))) -(defvar gud-gdb-repeat-map - (let ((map (make-sparse-keymap))) - (pcase-dolist (`(,key . ,cmd) '(("n" . gud-next) - ("s" . gud-step) - ("i" . gud-stepi) - ("c" . gud-cont) - ("l" . gud-refresh) - ("f" . gud-finish) - ("<" . gud-up) - (">" . gud-down))) - (define-key map key cmd)) - map) - "Keymap to repeat `gud-gdb' stepping instructions \\`C-x C-a C-n n n'. -Used in `repeat-mode'.") +(defvar-keymap gud-gdb-repeat-map + :doc "Keymap to repeat `gud-gdb' stepping instructions \\`C-x C-a C-n n n'. +Used in `repeat-mode'." + "n" #'gud-next + "s" #'gud-step + "i" #'gud-stepi + "c" #'gud-cont + "l" #'gud-refresh + "f" #'gud-finish + "<" #'gud-up + ">" #'gud-down) (defun gud-set-repeat-map-property (keymap-symbol) "Set the `repeat-map' property of relevant gud commands to KEYMAP-SYMBOL. @@ -1062,17 +1059,14 @@ SKIP is the number of chars to skip on each line, it defaults to 0." (defvar gud-sdb-lastfile nil) -(defvar gud-sdb-repeat-map - (let ((map (make-sparse-keymap))) - (pcase-dolist (`(,key . ,cmd) '(("n" . gud-next) - ("s" . gud-step) - ("i" . gud-stepi) - ("c" . gud-cont) - ("l" . gud-refresh))) - (define-key map key cmd)) - map) - "Keymap to repeat `sdb' stepping instructions \\`C-x C-a C-n n n'. -Used in `repeat-mode'.") +(defvar-keymap gud-sdb-repeat-map + :doc "Keymap to repeat `sdb' stepping instructions \\`C-x C-a C-n n n'. +Used in `repeat-mode'." + "n" #'gud-next + "s" #'gud-step + "i" #'gud-stepi + "c" #'gud-cont + "l" #'gud-refresh) (defun gud-sdb-marker-filter (string) (setq gud-marker-acc @@ -1304,22 +1298,21 @@ whereby $stopformat=1 produces an output format compatible with ;; whereby `set $stopformat=1' reportedly produces output compatible ;; with `gud-dbx-marker-filter', which we prefer. -(defvar gud-dbx-repeat-map - (let ((map (make-sparse-keymap))) - (pcase-dolist (`(,key . ,cmd) '(("n" . gud-next) - ("s" . gud-step) - ("i" . gud-stepi) - ("c" . gud-cont) - ("l" . gud-refresh) - ("<" . gud-up) - (">" . gud-down))) - (define-key map key cmd)) - (when (or gud-mips-p - gud-irix-p) - (define-key map "f" #'gud-finish)) - map) - "Keymap to repeat `dbx' stepping instructions \\`C-x C-a C-n n n'. -Used in `repeat-mode'.") +(defvar-keymap gud-dbx-repeat-map + :doc "Keymap to repeat `dbx' stepping instructions \\`C-x C-a C-n n n'. +Used in `repeat-mode'." + "n" #'gud-next + "s" #'gud-step + "i" #'gud-stepi + "c" #'gud-cont + "l" #'gud-refresh + "<" #'gud-up + ">" #'gud-down) + +(when (or gud-mips-p + gud-irix-p) + (keymap-set gud-dbx-repeat-map "f" #'gud-finish)) + ;; The process filter is also somewhat ;; unreliable, sometimes not spotting the markers; I don't know @@ -1481,20 +1474,17 @@ and source-file directory for your debugger." ;; History of argument lists passed to xdb. (defvar gud-xdb-history nil) -(defvar gud-xdb-repeat-map - (let ((map (make-sparse-keymap))) - (pcase-dolist (`(,key . ,cmd) '(("n" . gud-next) - ("s" . gud-step) - ("i" . gud-stepi) - ("c" . gud-cont) - ("l" . gud-refresh) - ("f" . gud-finish) - ("<" . gud-up) - (">" . gud-down))) - (define-key map key cmd)) - map) - "Keymap to repeat `xdb' stepping instructions \\`C-x C-a C-n n n'. -Used in `repeat-mode'.") +(defvar-keymap gud-xdb-repeat-map + :doc "Keymap to repeat `xdb' stepping instructions \\`C-x C-a C-n n n'. +Used in `repeat-mode'." + "n" #'gud-next + "s" #'gud-step + "i" #'gud-stepi + "c" #'gud-cont + "l" #'gud-refresh + "f" #'gud-finish + "<" #'gud-up + ">" #'gud-down) (defcustom gud-xdb-directories nil "A list of directories that xdb should search for source code. @@ -1573,16 +1563,13 @@ directories if your program contains sources from more than one directory." ;; History of argument lists passed to perldb. (defvar gud-perldb-history nil) -(defvar gud-perldb-repeat-map - (let ((map (make-sparse-keymap))) - (pcase-dolist (`(,key . ,cmd) '(("n" . gud-next) - ("s" . gud-step) - ("c" . gud-cont) - ("l" . gud-refresh))) - (define-key map key cmd)) - map) - "Keymap to repeat `perldb' stepping instructions \\`C-x C-a C-n n n'. -Used in `repeat-mode'.") +(defvar-keymap gud-perldb-repeat-map + :doc "Keymap to repeat `perldb' stepping instructions \\`C-x C-a C-n n n'. +Used in `repeat-mode'." + "n" #'gud-next + "s" #'gud-step + "c" #'gud-cont + "l" #'gud-refresh) (defun gud-perldb-massage-args (_file args) "Convert a command line as would be typed normally to run perldb @@ -1761,19 +1748,16 @@ working directory and source-file directory for your debugger." (defvar gud-pdb-marker-regexp-start "^> ") -(defvar gud-pdb-repeat-map - (let ((map (make-sparse-keymap))) - (pcase-dolist (`(,key . ,cmd) '(("n" . gud-next) - ("s" . gud-step) - ("c" . gud-cont) - ("l" . gud-refresh) - ("f" . gud-finish) - ("<" . gud-up) - (">" . gud-down))) - (define-key map key cmd)) - map) - "Keymap to repeat `pdb' stepping instructions \\`C-x C-a C-n n n'. -Used in `repeat-mode'.") +(defvar-keymap gud-pdb-repeat-map + :doc "Keymap to repeat `pdb' stepping instructions \\`C-x C-a C-n n n'. +Used in `repeat-mode'." + "n" #'gud-next + "s" #'gud-step + "c" #'gud-cont + "l" #'gud-refresh + "f" #'gud-finish + "<" #'gud-up + ">" #'gud-down) ;; There's no guarantee that Emacs will hand the filter the entire ;; marker at once; it could be broken up across several strings. We @@ -1879,18 +1863,15 @@ directory and source-file directory for your debugger." (defvar gud-guiler-lastfile nil) -(defvar gud-guiler-repeat-map - (let ((map (make-sparse-keymap))) - (pcase-dolist (`(,key . ,cmd) '(("n" . gud-next) - ("s" . gud-step) - ("l" . gud-refresh) - ("f" . gud-finish) - ("<" . gud-up) - (">" . gud-down))) - (define-key map key cmd)) - map) - "Keymap to repeat `guiler' stepping instructions \\`C-x C-a C-n n n'. -Used in `repeat-mode'.") +(defvar-keymap gud-guiler-repeat-map + :doc "Keymap to repeat `guiler' stepping instructions \\`C-x C-a C-n n n'. +Used in `repeat-mode'." + "n" #'gud-next + "s" #'gud-step + "l" #'gud-refresh + "f" #'gud-finish + "<" #'gud-up + ">" #'gud-down) (defun gud-guiler-marker-filter (string) (setq gud-marker-acc (if gud-marker-acc (concat gud-marker-acc string) string)) @@ -2404,20 +2385,17 @@ extension EXTN. Normally EXTN is given as the regular expression ;; Note: Reset to this value every time a prompt is seen (defvar gud-jdb-lowest-stack-level 999) -(defvar gud-jdb-repeat-map - (let ((map (make-sparse-keymap))) - (pcase-dolist (`(,key . ,cmd) '(("n" . gud-next) - ("s" . gud-step) - ("i" . gud-stepi) - ("c" . gud-cont) - ("f" . gud-finish) - ("<" . gud-up) - (">" . gud-down) - ("l" . gud-refresh))) - (define-key map key cmd)) - map) - "Keymap to repeat `jdb' stepping instructions \\`C-x C-a C-n n n'. -Used in `repeat-mode'.") +(defvar-keymap gud-jdb-repeat-map + :doc "Keymap to repeat `jdb' stepping instructions \\`C-x C-a C-n n n'. +Used in `repeat-mode'." + "n" #'gud-next + "s" #'gud-step + "i" #'gud-stepi + "c" #'gud-cont + "f" #'gud-finish + "<" #'gud-up + ">" #'gud-down + "l" #'gud-refresh) (defun gud-jdb-find-source-using-classpath (p) "Find source file corresponding to fully qualified class P. commit e59e7278924cd0dca49d4333dba188530721f5a3 Author: Michael Albinus Date: Sat Dec 21 18:12:45 2024 +0100 * lisp/net/tramp-gvfs.el (tramp-gvfs-local-file-name): New defun. diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el index 683f8cc12bd..f96581c1510 100644 --- a/lisp/net/tramp-gvfs.el +++ b/lisp/net/tramp-gvfs.el @@ -1772,6 +1772,24 @@ a downcased host name only." (string-match (rx bol (+ alnum) "://" (group (+ (not (any "/:"))))) url) (match-string 1 url))) +;; This is used in GNU ELPA package tramp-locproc.el. +(defun tramp-gvfs-local-file-name (filename) + "Return local mount name of FILENAME." + (setq filename (file-name-unquote (expand-file-name filename))) + (with-parsed-tramp-file-name filename nil + (with-tramp-file-property v localname "local-file-name" + ;; As long as we call `tramp-gvfs-maybe-open-connection' here, + ;; we cache the result. + (tramp-gvfs-maybe-open-connection v) + (let ((quoted (file-name-quoted-p localname)) + (localname (file-name-unquote localname))) + (funcall + (if quoted #'file-name-quote #'identity) + (expand-file-name + (if (file-name-absolute-p localname) + (substring localname 1) localname) + (tramp-get-file-property v "/" "fuse-mountpoint"))))))) + ;; D-Bus GVFS functions. commit 476426168106dbcee67d8ea667e11ebe80c7aaed Author: Stefan Monnier Date: Sat Dec 21 11:13:07 2024 -0500 (cl-flet, cl-labels): Fix bug#74870 * lisp/emacs-lisp/cl-macs.el (cl-flet, cl-labels): Wrap function bodies in `cl-block`. * test/lisp/emacs-lisp/cl-macs-tests.el (cl-macs--test-flet-block): New test. diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el index 65bc2cb9173..b1c42a23acd 100644 --- a/lisp/emacs-lisp/cl-macs.el +++ b/lisp/emacs-lisp/cl-macs.el @@ -2071,7 +2071,8 @@ Each definition can take the form (FUNC EXP) where FUNC is the function name, and EXP is an expression that returns the function value to which it should be bound, or it can take the more common form (FUNC ARGLIST BODY...) which is a shorthand -for (FUNC (lambda ARGLIST BODY)). +for (FUNC (lambda ARGLIST BODY)) where BODY is wrapped in +a `cl-block' named FUNC. FUNC is defined only within FORM, not BODY, so you can't write recursive function definitions. Use `cl-labels' for that. See @@ -2096,15 +2097,22 @@ info node `(cl) Function Bindings' for details. cl-declarations body))) (let ((binds ()) (newenv macroexpand-all-environment)) (dolist (binding bindings) - (let ((var (make-symbol (format "--cl-%s--" (car binding)))) - (args-and-body (cdr binding))) - (if (and (= (length args-and-body) 1) - (macroexp-copyable-p (car args-and-body))) + (let* ((var (make-symbol (format "--cl-%s--" (car binding)))) + (args-and-body (cdr binding)) + (args (car args-and-body)) + (body (cdr args-and-body))) + (if (and (null body) + (macroexp-copyable-p args)) ;; Optimize (cl-flet ((fun var)) body). - (setq var (car args-and-body)) - (push (list var (if (= (length args-and-body) 1) - (car args-and-body) - `(cl-function (lambda . ,args-and-body)))) + (setq var args) + (push (list var (if (null body) + args + (let ((parsed-body (macroexp-parse-body body))) + `(cl-function + (lambda ,args + ,@(car parsed-body) + (cl-block ,(car binding) + ,@(cdr parsed-body))))))) binds)) (push (cons (car binding) (lambda (&rest args) @@ -2271,10 +2279,11 @@ BINDINGS is a list of definitions of the form either (FUNC EXP) where EXP is a form that should return the function to bind to the function name FUNC, or (FUNC ARGLIST BODY...) where FUNC is the function name, ARGLIST its arguments, and BODY the -forms of the function body. FUNC is in scope in any BODY or EXP, as well -as FORM, so you can write recursive and mutually recursive -function definitions, with the caveat that EXPs are evaluated in sequence -and you cannot call a FUNC before its EXP has been evaluated. +forms of the function body. BODY is wrapped in a `cl-block' named FUNC. +FUNC is in scope in any BODY or EXP, as well as in FORM, so you can write +recursive and mutually recursive function definitions, with the caveat +that EXPs are evaluated in sequence and you cannot call a FUNC before its +EXP has been evaluated. See info node `(cl) Function Bindings' for details. \(fn ((FUNC ARGLIST BODY...) ...) FORM...)" @@ -2282,7 +2291,7 @@ See info node `(cl) Function Bindings' for details. (let ((binds ()) (newenv macroexpand-all-environment)) (dolist (binding bindings) (let ((var (make-symbol (format "--cl-%s--" (car binding))))) - (push (cons var (cdr binding)) binds) + (push (cons var binding) binds) (push (cons (car binding) (lambda (&rest args) (if (eq (car args) cl--labels-magic) @@ -2295,12 +2304,18 @@ See info node `(cl) Function Bindings' for details. ;; Perform self-tail call elimination. `(letrec ,(mapcar (lambda (bind) - (pcase-let* ((`(,var ,sargs . ,sbody) bind)) + (pcase-let* ((`(,var ,fun ,sargs . ,sbody) bind)) `(,var ,(cl--self-tco-on-form var (macroexpand-all (if (null sbody) sargs ;A (FUNC EXP) definition. - `(cl-function (lambda ,sargs . ,sbody))) + (let ((parsed-body + (macroexp-parse-body sbody))) + `(cl-function + (lambda ,sargs + ,@(car parsed-body) + (cl-block ,fun + ,@(cdr parsed-body)))))) newenv))))) (nreverse binds)) . ,(macroexp-unprogn diff --git a/test/lisp/emacs-lisp/cl-macs-tests.el b/test/lisp/emacs-lisp/cl-macs-tests.el index 4baf5428101..e1a521dca79 100644 --- a/test/lisp/emacs-lisp/cl-macs-tests.el +++ b/test/lisp/emacs-lisp/cl-macs-tests.el @@ -718,6 +718,16 @@ collection clause." (f lex-var))))) (should (equal (f nil) 'a))))) +(ert-deftest cl-macs--test-flet-block () + (should (equal (cl-block f1 + (cl-flet ((f1 (a) (cons (cl-return-from f1 a) 6))) + (cons (f1 5) 6))) + '(5 . 6))) + (should (equal (cl-block f1 + (cl-labels ((f1 (a) (cons (cl-return-from f1 a) 6))) + (cons (f1 7) 8))) + '(7 . 8)))) + (ert-deftest cl-flet/edebug () "Check that we can instrument `cl-flet' forms (bug#65344)." (with-temp-buffer commit a1d08d2c13497937475bf453c66a22a61f4e8631 Merge: b6d9183e7dd 5e97079cc75 Author: Eli Zaretskii Date: Sat Dec 21 07:56:28 2024 -0500 Merge from origin/emacs-30 5e97079cc75 ; Fix call to 'decode_string_utf_8' in #ifdef'ed-away code 6902673b5b9 ; Improve commentary in calendar.el 08b62132dde Add 'lua-ts-mode' to 'interpreter-mode-alist' d8ffcf2fbac Document representation of dates in calendar.el faaa13ec762 Autoload 'shortdoc-help-fns-examples-function' commit b6d9183e7dd160be902530044e6fe1ec7d467234 Merge: 3617940f322 68bcabf58af Author: Eli Zaretskii Date: Sat Dec 21 07:56:28 2024 -0500 ; Merge from origin/emacs-30 The following commits were skipped: 68bcabf58af * Update 'ldefs-boot.el' (don't merge) 9d93d717d58 * Bump Emacs version to 30.0.93 commit 3617940f322c381dee8b3c1f970b8eeda13d1c11 Merge: fd529bbd076 8f8da2d7854 Author: Eli Zaretskii Date: Sat Dec 21 07:56:08 2024 -0500 Merge from origin/emacs-30 8f8da2d7854 ; * ChangeLog.4: Update. 49adcf30b01 ; * etc/AUTHORS: Update. 1381c6f9591 * Update authors.el 5c0f3f5826e ; * etc/NEWS: Mark unmarked entries. 8a0c9c234f1 Document 'trusted-content c6ce11b2a48 Mention network-interface-list in network-interface-info ... a7905145f70 ; * lisp/emacs-lisp/re-builder.el (reb-change-syntax): Fi... cde22c02011 Move NEWS items from unreleased 28.3 to released 29.1 5686bb5b428 Improve browse-url-android-share docstring 92041e15f4a Minor doc fix for url-handler-regexp 9fd96e2ab95 Improve reb-change-syntax docstring b9dc337ea74 * lisp/files.el (trusted-content-p): Make `:all` work in ... 4b685bc4fcd ; * src/process.c (Fnetwork_interface_list): Fix typo. c14c4895719 ; * lisp/net/nsm.el (nsm-trust-local-network): Fix typo. 10f976300d0 ; Add some tree-sitter thing content to the manual 55303a6bc0a * lisp/org/ox-texinfo.el (org-texinfo-template): Fix Info... 8b6c6cffd1f trusted-content: Adjust the last patch based on prelimina... 69b16e5c638 ; * etc/NEWS: Fix typos. 5c6dbc65f36 ; * doc/lispref/frames.texi (Multiple Terminals): Add ind... 856a58e2827 Update documentation of 'etags' regexps some more 4c68846223b Update documentation of 'etags' regexps b5158bd1914 elisp-mode.el: Disable Flymake byte-compile backend in un... # Conflicts: # doc/man/etags.1 # etc/NEWS # lisp/org/ox-texinfo.el commit 5e97079cc7587ce338679ed237efb911723e4367 Author: Eli Zaretskii Date: Sat Dec 21 14:12:14 2024 +0200 ; Fix call to 'decode_string_utf_8' in #ifdef'ed-away code * src/coding.c (Finternal_decode_string_utf_8): Fix calling sequence of 'decode_string_utf_8' to adapt to changes in the latter's signature. diff --git a/src/coding.c b/src/coding.c index 5591b7fed45..aee5eed4f73 100644 --- a/src/coding.c +++ b/src/coding.c @@ -10407,7 +10407,7 @@ DEFUN ("internal-decode-string-utf-8", Finternal_decode_string_utf_8, if (NILP (decode_method)) { for (int i = 0; i < repeat_count; i++) - val = decode_string_utf_8 (string, buffer, ! NILP (nocopy), + val = decode_string_utf_8 (string, NULL, -1, buffer, ! NILP (nocopy), handle_8_bit, handle_over_uni); } else if (EQ (decode_method, Qt)) commit 6902673b5b9c641fd2df3881533d6fc343124371 Author: Eli Zaretskii Date: Sat Dec 21 13:00:05 2024 +0200 ; Improve commentary in calendar.el * lisp/calendar/calendar.el: Expand the commentary. Suggested by Richard Lawrence . (Bug#74965) diff --git a/lisp/calendar/calendar.el b/lisp/calendar/calendar.el index f5066c61ae2..a2382f3dd1a 100644 --- a/lisp/calendar/calendar.el +++ b/lisp/calendar/calendar.el @@ -96,10 +96,13 @@ ;; list of integers (MONTH DAY YEAR) -- see the functions ;; `calendar-extract-year', `calendar-extract-month', and ;; `calendar-extract-day'. Internally it also uses an "absolute" format -;; which is an integer number of days since December 31, 1BC (see -;; e.g. `calendar-absolute-from-gregorian'), and converts between -;; different calendar scales by converting to and from the absolute -;; format (see e.g. `calendar-iso-from-absolute' in cal-iso.el). +;; which is an integer number of days since December 31, 1BC on the +;; Gregorian calendar (see e.g. `calendar-absolute-from-gregorian'), and +;; converts between different calendar scales by converting to and from +;; the absolute format (see e.g. `calendar-iso-from-absolute' in +;; cal-iso.el). This representation is also useful for certain +;; calculations; e.g. `calendar-day-of-week' is simply the absolute +;; represention modulo 7, because December 31, 1BC is a Sunday. ;; A note on free variables: commit 08b62132ddee01f0c84bc478b718370b51fade6a Author: john muhl Date: Wed Dec 18 10:59:19 2024 -0600 Add 'lua-ts-mode' to 'interpreter-mode-alist' * lisp/progmodes/lua-ts-mode.el: Enable 'lua-ts-mode' for Lua scripts based on their interpreter line. (Bug#74951) diff --git a/lisp/progmodes/lua-ts-mode.el b/lisp/progmodes/lua-ts-mode.el index 9d06517a97d..641ea4261b0 100644 --- a/lisp/progmodes/lua-ts-mode.el +++ b/lisp/progmodes/lua-ts-mode.el @@ -853,7 +853,8 @@ Calls REPORT-FN directly." (derived-mode-add-parents 'lua-ts-mode '(lua-mode)) (when (treesit-ready-p 'lua) - (add-to-list 'auto-mode-alist '("\\.lua\\'" . lua-ts-mode))) + (add-to-list 'auto-mode-alist '("\\.lua\\'" . lua-ts-mode)) + (add-to-list 'interpreter-mode-alist '("\\ Date: Mon Dec 16 20:46:34 2024 +0100 Document representation of dates in calendar.el * lisp/calendar/calendar.el: Add a comment in file header explaining how dates are represented. diff --git a/lisp/calendar/calendar.el b/lisp/calendar/calendar.el index 345687d1775..f5066c61ae2 100644 --- a/lisp/calendar/calendar.el +++ b/lisp/calendar/calendar.el @@ -90,6 +90,16 @@ ;; ;; +;; A note on how dates are represented: + +;; The standard format for a (Gregorian) calendar date in this file is a +;; list of integers (MONTH DAY YEAR) -- see the functions +;; `calendar-extract-year', `calendar-extract-month', and +;; `calendar-extract-day'. Internally it also uses an "absolute" format +;; which is an integer number of days since December 31, 1BC (see +;; e.g. `calendar-absolute-from-gregorian'), and converts between +;; different calendar scales by converting to and from the absolute +;; format (see e.g. `calendar-iso-from-absolute' in cal-iso.el). ;; A note on free variables: commit fd529bbd076d14087d70c50d94bc9ef231cf1997 Author: Cecilio Pardo Date: Sun Dec 15 01:13:16 2024 +0100 Add support for the ':data' keyword for play-sound in MS-Windows. * src/sound.c (parse_sound) [WINDOWSNT]: Check that either :file or :data is present. (do_play_sound): Added parameter to select file or data, and code to play from data. (Fplay_sound_internal): Fixed volume format, and send file or data to 'do_play_sound'. (Bug#74863) * etc/NEWS: Add entry for this change. * etc/PROBLEMS: Remove entry about missing support for :data. diff --git a/etc/NEWS b/etc/NEWS index 5b0c89b6b20..12a318f5ed7 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1111,6 +1111,11 @@ current buffer, if the major mode supports it. (Support for Transformed images are smoothed using the bilinear interpolation by means of the GDI+ library. +--- +** Emacs on MS-Windows now supports the ':data' keyword for 'play-sound'. +In addition to ':file FILE' for playing a sound from a file, ':data +DATA' can now be used to play a sound from memory. + ---------------------------------------------------------------------- This file is part of GNU Emacs. diff --git a/etc/PROBLEMS b/etc/PROBLEMS index 8de12a78613..c1745e8d18f 100644 --- a/etc/PROBLEMS +++ b/etc/PROBLEMS @@ -3278,11 +3278,6 @@ Files larger than 4GB cause overflow in the size (represented as a well, since the Windows port uses a Lisp emulation of 'ls', which relies on 'file-attributes'. -** Playing sound doesn't support the :data method - -Sound playing is not supported with the ':data DATA' key-value pair. -You _must_ use the ':file FILE' method. - ** Typing Alt-Shift has strange effects on MS-Windows. This combination of keys is a command to change keyboard layout. If diff --git a/src/sound.c b/src/sound.c index 004015fc936..843d05d2349 100644 --- a/src/sound.c +++ b/src/sound.c @@ -26,14 +26,12 @@ along with GNU Emacs. If not, see . */ implementation of the play-sound specification for Windows. Notes: - In the Windows implementation of play-sound-internal only the - :file and :volume keywords are supported. The :device keyword, - if present, is ignored. The :data keyword, if present, will - cause an error to be generated. + In the Windows implementation of play-sound-internal the :device + keyword, if present, is ignored. The Windows implementation of play-sound is implemented via the - Windows API functions mciSendString, waveOutGetVolume, and - waveOutSetVolume which are exported by Winmm.dll. + Windows API functions mciSendString, waveOutGetVolume, + waveOutSetVolume and PlaySound which are exported by Winmm.dll. */ #include @@ -91,6 +89,11 @@ along with GNU Emacs. If not, see . */ #include "w32.h" /* END: Windows Specific Includes */ +/* Missing in mingw32. */ +#ifndef SND_SENTRY +#define SND_SENTRY 0x00080000 +#endif + #endif /* WINDOWSNT */ /* BEGIN: Common Definitions */ @@ -278,7 +281,7 @@ static void au_play (struct sound *, struct sound_device *); #else /* WINDOWSNT */ /* BEGIN: Windows Specific Definitions */ -static int do_play_sound (const char *, unsigned long); +static int do_play_sound (const char *, unsigned long, bool); /* END: Windows Specific Definitions */ #endif /* WINDOWSNT */ @@ -366,21 +369,10 @@ parse_sound (Lisp_Object sound, Lisp_Object *attrs) attrs[SOUND_DEVICE] = plist_get (sound, QCdevice); attrs[SOUND_VOLUME] = plist_get (sound, QCvolume); -#ifndef WINDOWSNT /* File name or data must be specified. */ if (!STRINGP (attrs[SOUND_FILE]) && !STRINGP (attrs[SOUND_DATA])) return 0; -#else /* WINDOWSNT */ - /* - Data is not supported in Windows. Therefore a - File name MUST be supplied. - */ - if (!STRINGP (attrs[SOUND_FILE])) - { - return 0; - } -#endif /* WINDOWSNT */ /* Volume must be in the range 0..100 or unspecified. */ if (!NILP (attrs[SOUND_VOLUME])) @@ -1225,7 +1217,7 @@ alsa_init (struct sound_device *sd) } while (0) static int -do_play_sound (const char *psz_file, unsigned long ui_volume) +do_play_sound (const char *psz_file_or_data, unsigned long ui_volume, bool in_memory) { int i_result = 0; MCIERROR mci_error = 0; @@ -1236,65 +1228,7 @@ do_play_sound (const char *psz_file, unsigned long ui_volume) BOOL b_reset_volume = FALSE; char warn_text[560]; - /* Since UNICOWS.DLL includes only a stub for mciSendStringW, we - need to encode the file in the ANSI codepage on Windows 9X even - if w32_unicode_filenames is non-zero. */ - if (w32_major_version <= 4 || !w32_unicode_filenames) - { - char fname_a[MAX_PATH], shortname[MAX_PATH], *fname_to_use; - - filename_to_ansi (psz_file, fname_a); - fname_to_use = fname_a; - /* If the file name is not encodable in ANSI, try its short 8+3 - alias. This will only work if w32_unicode_filenames is - non-zero. */ - if (_mbspbrk ((const unsigned char *)fname_a, - (const unsigned char *)"?")) - { - if (w32_get_short_filename (psz_file, shortname, MAX_PATH)) - fname_to_use = shortname; - else - mci_error = MCIERR_FILE_NOT_FOUND; - } - - if (!mci_error) - { - memset (sz_cmd_buf_a, 0, sizeof (sz_cmd_buf_a)); - memset (sz_ret_buf_a, 0, sizeof (sz_ret_buf_a)); - sprintf (sz_cmd_buf_a, - "open \"%s\" alias GNUEmacs_PlaySound_Device wait", - fname_to_use); - mci_error = mciSendStringA (sz_cmd_buf_a, - sz_ret_buf_a, sizeof (sz_ret_buf_a), NULL); - } - } - else - { - wchar_t sz_cmd_buf_w[520]; - wchar_t sz_ret_buf_w[520]; - wchar_t fname_w[MAX_PATH]; - - filename_to_utf16 (psz_file, fname_w); - memset (sz_cmd_buf_w, 0, sizeof (sz_cmd_buf_w)); - memset (sz_ret_buf_w, 0, sizeof (sz_ret_buf_w)); - /* _swprintf is not available on Windows 9X, so we construct the - UTF-16 command string by hand. */ - wcscpy (sz_cmd_buf_w, L"open \""); - wcscat (sz_cmd_buf_w, fname_w); - wcscat (sz_cmd_buf_w, L"\" alias GNUEmacs_PlaySound_Device wait"); - mci_error = mciSendStringW (sz_cmd_buf_w, - sz_ret_buf_w, ARRAYELTS (sz_ret_buf_w) , NULL); - } - if (mci_error != 0) - { - strcpy (warn_text, - "mciSendString: 'open' command failed to open sound file "); - strcat (warn_text, psz_file); - SOUND_WARNING (mciGetErrorString, mci_error, warn_text); - i_result = (int) mci_error; - return i_result; - } - if ((ui_volume > 0) && (ui_volume != UINT_MAX)) + if (ui_volume > 0) { mm_result = waveOutGetVolume ((HWAVEOUT) WAVE_MAPPER, &ui_volume_org); if (mm_result == MMSYSERR_NOERROR) @@ -1319,34 +1253,105 @@ do_play_sound (const char *psz_file, unsigned long ui_volume) " not be used."); } } - memset (sz_cmd_buf_a, 0, sizeof (sz_cmd_buf_a)); - memset (sz_ret_buf_a, 0, sizeof (sz_ret_buf_a)); - strcpy (sz_cmd_buf_a, "play GNUEmacs_PlaySound_Device wait"); - mci_error = mciSendStringA (sz_cmd_buf_a, sz_ret_buf_a, sizeof (sz_ret_buf_a), - NULL); - if (mci_error != 0) + + if (in_memory) { - strcpy (warn_text, - "mciSendString: 'play' command failed to play sound file "); - strcat (warn_text, psz_file); - SOUND_WARNING (mciGetErrorString, mci_error, warn_text); - i_result = (int) mci_error; + int flags = SND_MEMORY; + if (w32_major_version >= 6) /* Vista and later */ + flags |= SND_SENTRY; + i_result = !PlaySound (psz_file_or_data, NULL, flags); } - memset (sz_cmd_buf_a, 0, sizeof (sz_cmd_buf_a)); - memset (sz_ret_buf_a, 0, sizeof (sz_ret_buf_a)); - strcpy (sz_cmd_buf_a, "close GNUEmacs_PlaySound_Device wait"); - mci_error = mciSendStringA (sz_cmd_buf_a, sz_ret_buf_a, sizeof (sz_ret_buf_a), - NULL); + else + { + /* Since UNICOWS.DLL includes only a stub for mciSendStringW, we + need to encode the file in the ANSI codepage on Windows 9X even + if w32_unicode_filenames is non-zero. */ + if (w32_major_version <= 4 || !w32_unicode_filenames) + { + char fname_a[MAX_PATH], shortname[MAX_PATH], *fname_to_use; + + filename_to_ansi (psz_file_or_data, fname_a); + fname_to_use = fname_a; + /* If the file name is not encodable in ANSI, try its short 8+3 + alias. This will only work if w32_unicode_filenames is + non-zero. */ + if (_mbspbrk ((const unsigned char *)fname_a, + (const unsigned char *)"?")) + { + if (w32_get_short_filename (psz_file_or_data, shortname, MAX_PATH)) + fname_to_use = shortname; + else + mci_error = MCIERR_FILE_NOT_FOUND; + } + + if (!mci_error) + { + memset (sz_cmd_buf_a, 0, sizeof (sz_cmd_buf_a)); + memset (sz_ret_buf_a, 0, sizeof (sz_ret_buf_a)); + sprintf (sz_cmd_buf_a, + "open \"%s\" alias GNUEmacs_PlaySound_Device wait", + fname_to_use); + mci_error = mciSendStringA (sz_cmd_buf_a, + sz_ret_buf_a, sizeof (sz_ret_buf_a), NULL); + } + } + else + { + wchar_t sz_cmd_buf_w[520]; + wchar_t sz_ret_buf_w[520]; + wchar_t fname_w[MAX_PATH]; + + filename_to_utf16 (psz_file_or_data, fname_w); + memset (sz_cmd_buf_w, 0, sizeof (sz_cmd_buf_w)); + memset (sz_ret_buf_w, 0, sizeof (sz_ret_buf_w)); + /* _swprintf is not available on Windows 9X, so we construct the + UTF-16 command string by hand. */ + wcscpy (sz_cmd_buf_w, L"open \""); + wcscat (sz_cmd_buf_w, fname_w); + wcscat (sz_cmd_buf_w, L"\" alias GNUEmacs_PlaySound_Device wait"); + mci_error = mciSendStringW (sz_cmd_buf_w, + sz_ret_buf_w, ARRAYELTS (sz_ret_buf_w) , NULL); + } + if (mci_error != 0) + { + strcpy (warn_text, + "mciSendString: 'open' command failed to open sound file "); + strcat (warn_text, psz_file_or_data); + SOUND_WARNING (mciGetErrorString, mci_error, warn_text); + i_result = (int) mci_error; + return i_result; + } + memset (sz_cmd_buf_a, 0, sizeof (sz_cmd_buf_a)); + memset (sz_ret_buf_a, 0, sizeof (sz_ret_buf_a)); + strcpy (sz_cmd_buf_a, "play GNUEmacs_PlaySound_Device wait"); + mci_error = mciSendStringA (sz_cmd_buf_a, sz_ret_buf_a, sizeof (sz_ret_buf_a), + NULL); + if (mci_error != 0) + { + strcpy (warn_text, + "mciSendString: 'play' command failed to play sound file "); + strcat (warn_text, psz_file_or_data); + SOUND_WARNING (mciGetErrorString, mci_error, warn_text); + i_result = (int) mci_error; + } + memset (sz_cmd_buf_a, 0, sizeof (sz_cmd_buf_a)); + memset (sz_ret_buf_a, 0, sizeof (sz_ret_buf_a)); + strcpy (sz_cmd_buf_a, "close GNUEmacs_PlaySound_Device wait"); + mci_error = mciSendStringA (sz_cmd_buf_a, sz_ret_buf_a, sizeof (sz_ret_buf_a), + NULL); + } + if (b_reset_volume == TRUE) { mm_result = waveOutSetVolume ((HWAVEOUT) WAVE_MAPPER, ui_volume_org); if (mm_result != MMSYSERR_NOERROR) - { - SOUND_WARNING (waveOutGetErrorText, mm_result, + { + SOUND_WARNING (waveOutGetErrorText, mm_result, "waveOutSetVolume: failed to reset the original" - " volume level of the WAVE_MAPPER device."); - } + " volume level of the WAVE_MAPPER device."); + } } + return i_result; } @@ -1364,8 +1369,7 @@ Internal use only, use `play-sound' instead. */) specpdl_ref count = SPECPDL_INDEX (); #ifdef WINDOWSNT - unsigned long ui_volume_tmp = UINT_MAX; - unsigned long ui_volume = UINT_MAX; + unsigned long ui_volume = 0; #endif /* WINDOWSNT */ /* Parse the sound specification. Give up if it is invalid. */ @@ -1432,33 +1436,31 @@ Internal use only, use `play-sound' instead. */) #else /* WINDOWSNT */ - file = Fexpand_file_name (attrs[SOUND_FILE], Vdata_directory); - file = ENCODE_FILE (file); + if (FIXNUMP (attrs[SOUND_VOLUME])) - { - ui_volume_tmp = XFIXNAT (attrs[SOUND_VOLUME]); - } + ui_volume = XFIXNAT (attrs[SOUND_VOLUME]); else if (FLOATP (attrs[SOUND_VOLUME])) - { - ui_volume_tmp = XFLOAT_DATA (attrs[SOUND_VOLUME]) * 100; - } + ui_volume = XFLOAT_DATA (attrs[SOUND_VOLUME]) * 100; + + if (ui_volume > 100) + ui_volume = 100; + + /* For volume (32 bits), low order 16 bits are the value for left + channel, and high order 16 bits for the right channel. We use the + specified volume on both channels. */ + ui_volume = ui_volume * 0xFFFF / 100; + ui_volume = (ui_volume << 16) + ui_volume; CALLN (Frun_hook_with_args, Qplay_sound_functions, sound); - /* - Based on some experiments I have conducted, a value of 100 or less - for the sound volume is much too low. You cannot even hear it. - A value of UINT_MAX indicates that you wish for the sound to played - at the maximum possible volume. A value of UINT_MAX/2 plays the - sound at 50% maximum volume. Therefore the value passed to do_play_sound - (and thus to waveOutSetVolume) must be some fraction of UINT_MAX. - The following code adjusts the user specified volume level appropriately. - */ - if ((ui_volume_tmp > 0) && (ui_volume_tmp <= 100)) + if (STRINGP (attrs[SOUND_FILE])) { - ui_volume = ui_volume_tmp * (UINT_MAX / 100); + file = Fexpand_file_name (attrs[SOUND_FILE], Vdata_directory); + file = ENCODE_FILE (file); + do_play_sound (SSDATA (file), ui_volume, false); } - (void)do_play_sound (SSDATA (file), ui_volume); + else + do_play_sound (SDATA (attrs[SOUND_DATA]), ui_volume, true); #endif /* WINDOWSNT */ commit b6852b67b0d462c7ba0012e5ac3b79a245f4b7e5 Author: Eli Zaretskii Date: Sat Dec 21 12:30:44 2024 +0200 ; Fix last change * doc/lispref/os.texi (Time Calculations): Extend documentation of 'seconds-to-string'; add missing @end defun. (Bug#71572) diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi index a3ba27bdf24..2b96417f136 100644 --- a/doc/lispref/os.texi +++ b/doc/lispref/os.texi @@ -2205,10 +2205,26 @@ structure. For instance, the 120th day in 2004 is April 29th. @end defun @defun seconds-to-string delay &optional readable abbrev precision -Return a string describing a given @var{delay} (in seconds). Optional -arguments can be used to configure a human readable delay using various -formats. For example, a delay of 9861.5 seconds with @var{readable} set -to the symbol @code{expanded} returns @samp{2 hours 44 minutes}. +Return a string describing a given @var{delay} (in seconds). By +default, this function formats the returned string as a floating-point +number in units selected according to the value of @var{delay}. For +example, a delay of 9861.5 seconds yields @samp{2.74h}, since the value +of @var{delay} is longer than 1 hour, but shorter than 1 day. The +output formatting can be further controlled by the optional arguments, +if optional argument @var{readable} is non-@code{nil}. If +@var{readable}'s value is @code{expanded}, the returned string will +describe @var{delay} using two units; for example, a delay of 9861.5 +seconds with @var{readable} set to the symbol @code{expanded} returns +@samp{2 hours 44 minutes}, but if @var{readable} is @code{t}, the +function returns @samp{3 hours}. Optional argument @var{abbrev}, if +non-@code{nil}, means to abbreviate the units: use @samp{h} instead of +@samp{hours}, @samp{m} instead of @samp{minutes}, etc. If +@var{precision} is a whole integer number, the function rounds the value +of the smallest unit it produces to that many digits after the decimal +point; thus, 9861.5 with @var{precision} set to 3 yields @samp{2.739 +hours}. If @var{precision} is a non-negative float smaller than 1, the +function rounds to that value. +@end defun @node Timers @section Timers for Delayed Execution commit 308d5d54737917d449bfc0bf80815537eef69446 Author: JD Smith <93749+jdtsmith@users.noreply.github.com> Date: Thu Jul 11 16:24:17 2024 -0400 'seconds-to-string': new optional arguments for readable strings * lisp/calendar/time-date.el (seconds-to-string): Accept new optional arguments READABLE, ABBREV, and PRECISION, and format the output string accordingly. (Bug#71572) * doc/lispref/os.texi (Time Calculations): * etc/NEWS: Document the new arguments of 'seconds-to-string'. diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi index be26fb5063c..a3ba27bdf24 100644 --- a/doc/lispref/os.texi +++ b/doc/lispref/os.texi @@ -2204,6 +2204,12 @@ Return the date of @var{ordinal} in @var{year} as a decoded time structure. For instance, the 120th day in 2004 is April 29th. @end defun +@defun seconds-to-string delay &optional readable abbrev precision +Return a string describing a given @var{delay} (in seconds). Optional +arguments can be used to configure a human readable delay using various +formats. For example, a delay of 9861.5 seconds with @var{readable} set +to the symbol @code{expanded} returns @samp{2 hours 44 minutes}. + @node Timers @section Timers for Delayed Execution @cindex timers diff --git a/etc/NEWS b/etc/NEWS index 9a7b320acdb..5b0c89b6b20 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -883,6 +883,9 @@ destination window is chosen using 'display-buffer-alist'. Example: ** Nested backquotes are not supported any more in Pcase patterns. +--- +** The obsolete variable `redisplay-dont-pause' has been removed. + ** The 'rx' category name 'chinese-two-byte' must now be spelled correctly. An old alternative name (without the first 'e') has been removed. @@ -919,8 +922,13 @@ restore the old behavior, you can set 'eshell-pwd-convert-function' to * Lisp Changes in Emacs 31.1 ---- -** The obsolete variable `redisplay-dont-pause' has been removed. +** Time & Date + ++++ +*** 'seconds-to-string' supports new formatting options. +Optional arguments are provided to produce human-readable time-duration +strings in a variety of formats, for example "6 months 3 weeks" or "5m +52.5s". ** New function 'native-compile-directory'. This function natively-compiles all Lisp files in a directory and in its diff --git a/lisp/calendar/time-date.el b/lisp/calendar/time-date.el index 9a2fb45e3bc..9b85acf1dd0 100644 --- a/lisp/calendar/time-date.el +++ b/lisp/calendar/time-date.el @@ -403,11 +403,85 @@ right of \"%x\", trailing zero units are not output." (list (* 3600 24 400) "d" (* 3600.0 24.0)) (list nil "y" (* 365.25 24 3600))) "Formatting used by the function `seconds-to-string'.") + +(defvar seconds-to-string-readable + `(("Y" "year" "years" ,(round (* 60 60 24 365.2425))) + ("M" "month" "months" ,(round (* 60 60 24 30.436875))) + ("w" "week" "weeks" ,(* 60 60 24 7)) + ("d" "day" "days" ,(* 60 60 24)) + ("h" "hour" "hours" ,(* 60 60)) + ("m" "minute" "minutes" 60) + ("s" "second" "seconds" 1)) + "Formatting used by the function `seconds-to-string' with READABLE set. +The format is an alist, with string keys ABBREV-UNIT, and elements like: + + (ABBREV-UNIT UNIT UNIT-PLURAL SECS) + +where UNIT is a unit of time, ABBREV-UNIT is the abreviated form of +UNIT, UNIT-PLURAL is the plural form of UNIT, and SECS is the number of +seconds per UNIT.") + ;;;###autoload -(defun seconds-to-string (delay) - ;; FIXME: There's a similar (tho fancier) function in mastodon.el! - "Convert the time interval in seconds to a short string." - (cond ((> 0 delay) (concat "-" (seconds-to-string (- delay)))) +(defun seconds-to-string (delay &optional readable abbrev precision) + "Convert time interval DELAY (in seconds) to a string. +By default, the returned string is formatted as a float in the smallest +unit from the variable `seconds-to-string' that is longer than DELAY, +and a precision of two. If READABLE is non-nil, convert DELAY into a +readable string, using the information provided in the variable +`seconds-to-string-readable'. If it is the symbol `expanded', use two +units to describe DELAY, if appropriate. E.g. \"1 hour 32 minutes\". +If ABBREV is non-nil, abbreviate the readable units. If PRECISION is a +whole number, round the value associated with the smallest displayed +unit to that many digits after the decimal. If it is a non-negative +float less than 1.0, round to that value." + (cond ((< delay 0) + (concat "-" (seconds-to-string (- delay) readable precision))) + (readable + (let* ((stsa seconds-to-string-readable) + (expanded (eq readable 'expanded)) + digits + (round-to (cond ((wholenump precision) + (setq digits precision) + (expt 10 (- precision))) + ((and (floatp precision) (< precision 1.)) + (setq digits (- (floor (log precision 10)))) + precision) + (t (setq digits 0) 1))) + (dformat (if (> digits 0) (format "%%0.%df" digits))) + (padding (if abbrev "" " ")) + here cnt cnt-pre here-pre cnt-val isfloatp) + (if (= (round delay round-to) 0) + (format "0%s" (if abbrev "s" " seconds")) + (while (and (setq here (pop stsa)) stsa + (< (/ delay (nth 3 here)) 1))) + (or (and + expanded stsa ; smaller unit remains + (progn + (setq + here-pre here here (car stsa) + cnt-pre (floor (/ (float delay) (nth 3 here-pre))) + cnt (round + (/ (- (float delay) (* cnt-pre (nth 3 here-pre))) + (nth 3 here)) + round-to)) + (if (> cnt 0) t (setq cnt cnt-pre here here-pre here-pre nil)))) + (setq cnt (round (/ (float delay) (nth 3 here)) round-to))) + (setq cnt-val (* cnt round-to) + isfloatp (and (> digits 0) + (> (- cnt-val (floor cnt-val)) 0.))) + (cl-labels + ((unit (val here &optional plural) + (cond (abbrev (car here)) + ((and (not plural) (<= (floor val) 1)) (nth 1 here)) + (t (nth 2 here))))) + (concat + (when here-pre + (concat (number-to-string cnt-pre) padding + (unit cnt-pre here-pre) " ")) + (if isfloatp (format dformat cnt-val) + (number-to-string (floor cnt-val))) + padding + (unit cnt-val here isfloatp)))))) ; float formats are always plural ((= 0 delay) "0s") (t (let ((sts seconds-to-string) here) (while (and (car (setq here (pop sts))) commit bf41ff24b9ab9c7426b3b3f1c1902b301e9f08a4 Author: Eli Zaretskii Date: Sat Dec 21 11:33:47 2024 +0200 ; * lisp/net/browse-url.el (browse-url-with-browser-kind): Doc fix. diff --git a/lisp/net/browse-url.el b/lisp/net/browse-url.el index ab6f8f8aff3..0fae30b09d1 100644 --- a/lisp/net/browse-url.el +++ b/lisp/net/browse-url.el @@ -976,11 +976,11 @@ Optional prefix argument ARG non-nil inverts the value of the option "Browse URL with a browser of the given browser KIND. KIND is either `internal' or `external'. In order to find an -appropriate browser for the given KIND, first the `browse-url-handlers' -and `browse-url-default-handlers' lists are consulted. If no handler is -found, the functions `browse-url-browser-function', +appropriate browser for the given KIND, first consult the `browse-url-handlers' +and `browse-url-default-handlers' lists. If no handler is found, try the +functions `browse-url-browser-function', `browse-url-secondary-browser-function', `browse-url-default-browser' -and `eww' are tried in that order. +and `eww', in that order. When called interactively, the default browser kind is the opposite of the browser kind of `browse-url-browser-function'." commit 0f645b92ed3e82f149de468df7ebe0eda5104aca Author: Daniel Mendler Date: Thu Dec 12 12:15:10 2024 +0100 browse-url-with-browser-kind: Improve browser function selection In order to find an appropriate browser function for the given kind, first the browser handler lists are consulted. If no handler is found, the `browse-url-browser-function', `browse-url-secondary-browser-function`, `browse-url-default-browser' and `eww' are tried in that order until a browser function with a matching kind is found. This way the user customization of `browse-url-browser-function' and `browse-url-secondary-browser-function` is respected by `browse-url-with-browser-kind'. * lisp/net/browse-url.el (browse-url-with-browser-kind): Try the browser functions in the aforementioned order. (Bug#74820) diff --git a/lisp/net/browse-url.el b/lisp/net/browse-url.el index eea7dac2f97..ab6f8f8aff3 100644 --- a/lisp/net/browse-url.el +++ b/lisp/net/browse-url.el @@ -974,7 +974,13 @@ Optional prefix argument ARG non-nil inverts the value of the option ;;;###autoload (defun browse-url-with-browser-kind (kind url &optional arg) "Browse URL with a browser of the given browser KIND. -KIND is either `internal' or `external'. + +KIND is either `internal' or `external'. In order to find an +appropriate browser for the given KIND, first the `browse-url-handlers' +and `browse-url-default-handlers' lists are consulted. If no handler is +found, the functions `browse-url-browser-function', +`browse-url-secondary-browser-function', `browse-url-default-browser' +and `eww' are tried in that order. When called interactively, the default browser kind is the opposite of the browser kind of `browse-url-browser-function'." @@ -994,9 +1000,14 @@ opposite of the browser kind of `browse-url-browser-function'." (cons k url-arg))) (let ((function (browse-url-select-handler url kind))) (unless function - (setq function (if (eq kind 'external) - #'browse-url-default-browser - #'eww))) + (setq function + (seq-find + (lambda (fun) + (eq kind (browse-url--browser-kind fun url))) + (list browse-url-browser-function + browse-url-secondary-browser-function + #'browse-url-default-browser + #'eww)))) (funcall function url arg))) ;;;###autoload commit 40145ba971942eb8b2b9db1e28b513b1f3fdda6f Author: Eli Zaretskii Date: Sat Dec 21 10:57:47 2024 +0200 ; Improve last change * lisp/net/eww.el (eww-search-confirm-send-region) (eww-search-words): Doc fix. (eww-search-words): Improve wording of confirmation request. (Bug#74218) diff --git a/lisp/net/eww.el b/lisp/net/eww.el index 319b1e72fbb..842db3f27f4 100644 --- a/lisp/net/eww.el +++ b/lisp/net/eww.el @@ -53,8 +53,8 @@ :type 'string) (defcustom eww-search-confirm-send-region t - "Whether to confirm before sending a region to a search engine. -Non-nil if EWW should ask confirmation before sending the + "Whether to ask for confirmation before sending the region to a search engine. +Non-nil if EWW should ask for confirmation before sending the selected region to the configured search engine. This is the default to mitigate the risk of accidental data leak. Set this variable to nil to send the region to the search engine @@ -608,8 +608,9 @@ new buffer instead of reusing the default EWW buffer." ;;;###autoload (defun eww-search-words () "Search the web for the text in the region. -If region is active (and not whitespace), search the web for -the text between region beginning and end. Else, prompt the +If region is active (and not whitespace), search the web for the +text between region beginning and end, subject to user's confirmation +controlled by `eww-search-confirm-send-region'. Else, prompt the user for a search string. See the variable `eww-search-prefix' for the search engine used." (interactive) @@ -620,7 +621,7 @@ for the search engine used." (or (not eww-search-confirm-send-region) (yes-or-no-p (format-message - "Really send the entire region to the search engine? "))) + "Really send the region to the search engine? "))) (eww region-string)) (call-interactively #'eww))) (call-interactively #'eww))) commit 31f3a760c504e76ae06805e5cc5c325b06e4a9ad Author: Fabio Natali Date: Tue Nov 5 23:52:30 2024 +0000 Ask confirmation before EWW sends region to a search engine With 'eww-search-words' (by default bound to 'M-s M-w') a user can type in some search terms and get back the results of a web search from a predefined search engine. If a region is selected, 'eww-search-words' will use that for the web search instead of prompting the user. In its current form, 'eww-search-words' presents a security and usability problem. It is relatively too easy to mistakenly launch the function and, if a region of text is selected, have potentially sensitive data sent out to a third-party service. This commit changes the search function's default behaviour so that explicit confirmation is required before a region is sent to a search engine. The behaviour can be adjusted via the newly-introduced 'eww-search-confirm-send-region' variable, which is set to true by default. * lisp/net/eww.el (eww-search-confirm-send-region): Add. (eww-search-words): Update default 'eww-search-words' behaviour so as to ask confirmation before sending the region to a search engine. (Bug#74218) diff --git a/lisp/net/eww.el b/lisp/net/eww.el index 9b4bbca2e3e..319b1e72fbb 100644 --- a/lisp/net/eww.el +++ b/lisp/net/eww.el @@ -52,6 +52,17 @@ :group 'eww :type 'string) +(defcustom eww-search-confirm-send-region t + "Whether to confirm before sending a region to a search engine. +Non-nil if EWW should ask confirmation before sending the +selected region to the configured search engine. This is the +default to mitigate the risk of accidental data leak. Set this +variable to nil to send the region to the search engine +straightaway." + :version "31.1" + :group 'eww + :type 'boolean) + (defcustom eww-search-prefix "https://duckduckgo.com/html/?q=" "Prefix URL to search engine." :version "24.4" @@ -605,7 +616,12 @@ for the search engine used." (if (use-region-p) (let ((region-string (buffer-substring (region-beginning) (region-end)))) (if (not (string-match-p "\\`[ \n\t\r\v\f]*\\'" region-string)) - (eww region-string) + (when + (or (not eww-search-confirm-send-region) + (yes-or-no-p + (format-message + "Really send the entire region to the search engine? "))) + (eww region-string)) (call-interactively #'eww))) (call-interactively #'eww))) commit 1c960bda91237c92f9f602bcb8538ad500c0bc49 Author: F. Jason Park Date: Fri Nov 29 15:56:47 2024 -0800 Use smarter default for erc-server-reconnect-function * doc/misc/erc.texi (Sample Configuration): Remove customization in `use-package' declaration for `erc-server-reconnect-function' as well as related language in the customization walk-through. Do this because the new default incorporates `erc-server-delayed-check-reconnect' behavior for compatible connect functions. * etc/ERC-NEWS: Announce new default for `erc-server-reconnect-function'. * lisp/erc/erc-backend.el (erc-server-reconnect-function): Change default to `erc-server-prefer-check-reconnect'. (erc-server-delayed-check-reconnect): Use `process-send-string' instead of `send-string'. (erc--server-delayed-check-connectors): New variable. (erc-server-prefer-check-reconnect): New function. * test/lisp/erc/erc-scenarios-base-auto-recon.el (erc-scenarios-base-auto-recon-unavailable) (erc-scenarios-base-auto-recon-no-proto): Remove unnecessary `erc-server-reconnect-function' binding because the new default incorporates the behavior being tested for. * test/lisp/erc/erc-scenarios-base-buffer-display.el (erc-scenarios-base-buffer-display--reconnect-common): * test/lisp/erc/erc-scenarios-base-compat-rename-bouncer.el (erc-scenarios-common--base-compat-no-rename-bouncer): * test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-base.el (erc-scenarios-base-netid-bouncer--recon-base): * test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-both.el (erc-scenarios-base-netid-bouncer--recon-both): * test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-id.el (erc-scenarios-base-netid-bouncer--reconnect-id-foo) (erc-scenarios-base-netid-bouncer--reconnect-id-bar): * test/lisp/erc/erc-scenarios-base-reconnect.el (erc-scenarios-base-reconnect-timer) (erc-scenarios-base-cancel-reconnect): * test/lisp/erc/erc-scenarios-services-misc.el (erc-scenarios-services-misc--reconnect-retry-nick): * test/lisp/erc/erc-scenarios-stamp.el (erc-scenarios-stamp--date-mode/reconnect): Explicitly bind `erc-server-reconnect-function' to `erc-server-delayed-reconnect', the former default, which does not do any probing. (Bug#62044) diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi index 0f6b6b8c5be..b5838b3b0ce 100644 --- a/doc/misc/erc.texi +++ b/doc/misc/erc.texi @@ -1340,8 +1340,7 @@ settings (@pxref{Sample configuration via Customize}). ;; Scroll all windows to prompt when submitting input. (erc-scrolltobottom-all t) - ;; Reconnect automatically using a fancy strategy. - (erc-server-reconnect-function #'erc-server-delayed-check-reconnect) + ;; Wait a bit longer between automatic reconnect attempts. (erc-server-reconnect-timeout 30) ;; Show new buffers in the current window instead of a split. @@ -1444,30 +1443,18 @@ descriptions just in case you want to disable them later. When finished, hit @kbd{C-x C-s} or click @samp{[Apply and Save]} atop the buffer. -Now do the same for another couple options, this time having to do -with automatic reconnection. But instead of searching for their print -names, try running @kbd{M-x customize-option @key{RET} @samp{