From 4e0cb960dbd95c8001b08c62682b085292184b87 Mon Sep 17 00:00:00 2001 From: Vincenzo Pupillo Date: Thu, 10 Oct 2024 16:06:37 +0200 Subject: [PATCH 01/11] Fix 'php-ts-mode': better indentation and font locking Incomplete compound_statement or colon_block (statement-group without a closing brace or closing keyword) that are not inside a function or method are not recognized as such by tree-sitter-php. A new function 'php-ts-mode--open-statement-group-heuristic' handles this case. Font locking of magic methods and better support for alternative control structure syntax. Support for latest grammar version. * lisp/progmodes/php-ts-mode.el (php-ts-mode--language-source-alist): Updated grammar version. (php-ts-mode--possibly-braceless-keyword-re): Regular expression for braceless keyword. (php-ts-mode--open-statement-group-heuristic): New function. (php-ts-mode--parent-html-bol): Use the new function and doc fix. (php-ts-mode--parent-html-heuristic): Use the new function and doc fix. (php-ts-mode--indent-styles): Use the new function and add 'colon_block' support. (php-ts-mode--class-magic-methods): New predefined magic methods list. (php-ts-mode--test-namespace-name-as-prefix-p): Doc fix. (php-ts-mode--test-namespace-aliasing-clause-p): Fix the test and doc. (php-ts-mode--test-namespace-use-group-clause-p): Doc fix. (php-ts-mode--test-visibility-modifier-operation-clause-p): New function for the new asymmetric property visibility feature of PHP 8.4. (php-ts-mode--font-lock-settings): Font lock for class magic methods and alternative syntax. Better font lock for 'instanceof'. Use 'font-lock-function-call-face' for scoped and member call expression. (bug#73779) --- lisp/progmodes/php-ts-mode.el | 168 ++++++++++++++++++++++------------ 1 file changed, 112 insertions(+), 56 deletions(-) diff --git a/lisp/progmodes/php-ts-mode.el b/lisp/progmodes/php-ts-mode.el index d2559e5a45f..1c5fdb6f617 100644 --- a/lisp/progmodes/php-ts-mode.el +++ b/lisp/progmodes/php-ts-mode.el @@ -84,7 +84,7 @@ ;;; Install treesitter language parsers (defvar php-ts-mode--language-source-alist - '((php . ("https://github.com/tree-sitter/tree-sitter-php" "v0.23.0" "php/src")) + '((php . ("https://github.com/tree-sitter/tree-sitter-php" "v0.23.4" "php/src")) (phpdoc . ("https://github.com/claytonrcarter/tree-sitter-phpdoc")) (html . ("https://github.com/tree-sitter/tree-sitter-html" "v0.23.0")) (javascript . ("https://github.com/tree-sitter/tree-sitter-javascript" "v0.23.0")) @@ -428,6 +428,27 @@ Useful for debugging." ;;; Indent +(defconst php-ts-mode--possibly-braceless-keyword-re + (regexp-opt '("if" "for" "foreach" "while" "do") 'symbols) + "Regexp matching keywords optionally followed by an opening brace.") + +(defun php-ts-mode--open-statement-group-heuristic (node _parent bol &rest _) + "Heuristic matcher for statement-group without closing bracket. + +Return `php-ts-mode-indent-offset' plus 1 when BOL is after +`php-ts-mode--possibly-braceless-keyword-re', otherwise return 0. It's +usefull for matching incomplete compound_statement or colon_block. +PARENT is NODE's parent, BOL is the beginning of non-whitespace +characters of the current line." + (and (null node) + (save-excursion + (forward-line -1) + (if (re-search-forward + php-ts-mode--possibly-braceless-keyword-re + bol t) + (+ 1 php-ts-mode-indent-offset) + 0)))) + ;; taken from c-ts-mode (defun php-ts-mode--else-heuristic (node parent bol &rest _) "Heuristic matcher for when \"else\" is followed by a closing bracket. @@ -475,43 +496,50 @@ NODE is the node to match and PARENT is its parent." (goto-char (treesit-node-start parent)) (line-end-position))) -(defun php-ts-mode--parent-html-bol (node parent _bol &rest _) +(defun php-ts-mode--parent-html-bol (node parent bol &rest _) "Find the first non-space characters of the HTML tags before NODE. +When NODE is nil call `php-ts-mode--open-statement-group-heuristic'. PARENT is NODE's parent, BOL is the beginning of non-whitespace characters of the current line." - (save-excursion - (let ((html-node (treesit-search-forward node "text" t))) - (if html-node - (let ((end-html (treesit-node-end html-node))) - (goto-char end-html) - (backward-word) - (back-to-indentation) - (point)) - (treesit-node-start parent))))) + (if (null node) + ;; If NODE is nil it could be an open statement-group. + (php-ts-mode--open-statement-group-heuristic node parent bol) + (save-excursion + (let ((html-node (treesit-search-forward node "text" t))) + (if html-node + (let ((end-html (treesit-node-end html-node))) + (goto-char end-html) + (backward-word) + (back-to-indentation) + (point)) + (treesit-node-start parent)))))) -(defun php-ts-mode--parent-html-heuristic (node parent _bol &rest _) +(defun php-ts-mode--parent-html-heuristic (node parent bol &rest _) "Return position based on html indentation. Returns 0 if the NODE is after the , otherwise returns the -indentation point of the last word before the NODE, plus the -indentation offset. If there is no HTML tag, it returns the beginning -of the parent. +indentation point of the last word before the NODE, plus the indentation +offset. If there is no HTML tag, it returns the beginning of the +parent. When NODE is nil call `php-ts-mode--open-statement-group-heuristic'. It can be used when you want to indent PHP code relative to the HTML. PARENT is NODE's parent, BOL is the beginning of non-whitespace characters of the current line." - (let ((html-node (treesit-search-forward node "text" t))) - (if html-node - (let ((end-html (treesit-node-end html-node))) - (save-excursion - (goto-char end-html) - (backward-word) - (back-to-indentation) - (if (search-forward "" end-html t 1) - 0 - (+ (point) php-ts-mode-indent-offset)))) - ;; Maybe it's better to use bol? - (treesit-node-start parent)))) + (if (null node) + ;; If NODE is nil it could be an open statement-group. + (php-ts-mode--open-statement-group-heuristic node parent bol) + (let ((html-node (treesit-search-forward node "text" t))) + (if html-node + (let ((end-html (treesit-node-end html-node))) + (save-excursion + (goto-char end-html) + (backward-word) + (back-to-indentation) + (if (search-forward "" end-html t 1) + 0 + (+ (point) php-ts-mode-indent-offset)))) + ;; Maybe it's better to use bol? + (treesit-node-start parent))))) (defun php-ts-mode--array-element-heuristic (_node parent _bol &rest _) "Return of the position of the first element of the array. @@ -648,16 +676,22 @@ characters of the current line." ((parent-is "initializer_list") parent-bol php-ts-mode-indent-offset) ;; Statement in {} blocks. - ((or (and (parent-is "compound_statement") + ((or (and (or (parent-is "compound_statement") + (parent-is "colon_block")) ;; If the previous sibling(s) are not on their ;; own line, indent as if this node is the first ;; sibling php-ts-mode--first-sibling) - (match null "compound_statement")) + (or (match null "compound_statement") + (match null "colon_block"))) standalone-parent php-ts-mode-indent-offset) - ((parent-is "compound_statement") parent-bol php-ts-mode-indent-offset) + ((or (parent-is "compound_statement") + (parent-is "colon_block")) + parent-bol php-ts-mode-indent-offset) ;; Opening bracket. - ((node-is "compound_statement") standalone-parent php-ts-mode-indent-offset) + ((or (node-is "compound_statement") + (node-is "colon_block")) + standalone-parent php-ts-mode-indent-offset) ((parent-is "match_block") parent-bol php-ts-mode-indent-offset) ((parent-is "switch_block") parent-bol 0) @@ -667,6 +701,7 @@ characters of the current line." ;; rule for PHP alternative syntax ((or (node-is "else_if_clause") (node-is "endif") + (node-is "endfor") (node-is "endforeach") (node-is "endwhile")) parent-bol 0) @@ -679,9 +714,13 @@ characters of the current line." (parent-is "switch_statement") (parent-is "case_statement") (parent-is "empty_statement")) - parent-bol php-ts-mode-indent-offset)))) + parent-bol php-ts-mode-indent-offset) + + ;; Workaround: handle "for" open statement group. Currently + ;; the grammar handles it differently than other control structures. + (no-node php-ts-mode--open-statement-group-heuristic 0)))) `((psr2 - ((parent-is "program") parent-bol 0) + ((parent-is "program") php-ts-mode--open-statement-group-heuristic 0) ((parent-is "text_interpolation") column-0 0) ((parent-is "function_call_expression") parent-bol php-ts-mode-indent-offset) ,@common) @@ -774,21 +813,32 @@ characters of the current line." "__FUNCTION__" "__LINE__" "__METHOD__" "__NAMESPACE__" "__TRAIT__") "PHP predefined constant.") -(defun php-ts-mode--test-namespace-name-as-prefix-p () - "Return t if namespace_name_as_prefix keyword is a named node, nil otherwise." +(defconst php-ts-mode--class-magic-methods + '("__construct" "__destruct" "__call" "__callStatic" "__get" "__set" + "__isset" "__unset" "__sleep" "__wakeup" "__serialize" "__unserialize" + "__toString" "__invoke" "__set_state" "__clone" "__debugInfo") + "PHP predefined magic methods.") + +(defun php-ts-mode--test-namespace-name-as-prefix-p () + "Return t if namespace_name_as_prefix is a named node, nil otherwise." (ignore-errors (progn (treesit-query-compile 'php "(namespace_name_as_prefix)" t) t))) -(defun php-ts-mode--test-namespace-aliasing-clause-p () - "Return t if namespace_name_as_prefix keyword is named node, nil otherwise." +(defun php-ts-mode--test-namespace-aliasing-clause-p () + "Return t if namespace_aliasing_clause is a named node, nil otherwise." (ignore-errors - (progn (treesit-query-compile 'php "(namespace_name_as_prefix)" t) t))) + (progn (treesit-query-compile 'php "(namespace_aliasing_clause)" t) t))) (defun php-ts-mode--test-namespace-use-group-clause-p () - "Return t if namespace_use_group_clause keyword is named node, nil otherwise." + "Return t if namespace_use_group_clause is a named node, nil otherwise." (ignore-errors (progn (treesit-query-compile 'php "(namespace_use_group_clause)" t) t))) +(defun php-ts-mode--test-visibility-modifier-operation-clause-p () + "Return t if (visibility_modifier (operation)) is defined, nil otherwise." + (ignore-errors + (progn (treesit-query-compile 'php "(visibility_modifier (operation))" t) t))) + (defun php-ts-mode--font-lock-settings () "Tree-sitter font-lock settings." (treesit-font-lock-rules @@ -796,7 +846,10 @@ characters of the current line." :language 'php :feature 'keyword :override t - `([,@php-ts-mode--keywords] @font-lock-keyword-face) + `([,@php-ts-mode--keywords] @font-lock-keyword-face + ,@(when (php-ts-mode--test-visibility-modifier-operation-clause-p) + '((visibility_modifier (operation) @font-lock-builtin-face))) + (var_modifier) @font-lock-builtin-face) :language 'php :feature 'comment @@ -826,7 +879,6 @@ characters of the current line." (named_label_statement (name) @font-lock-constant-face)) :language 'php - ;;:override t :feature 'delimiter `((["," ":" ";" "\\"]) @font-lock-delimiter-face) @@ -850,7 +902,6 @@ characters of the current line." :language 'php :feature 'string - ;;:override t `(("\"") @font-lock-string-face (encapsed_string) @font-lock-string-face (string_content) @font-lock-string-face @@ -892,32 +943,37 @@ characters of the current line." name: (_) @font-lock-type-face) (trait_declaration name: (_) @font-lock-type-face) - (property_declaration - (visibility_modifier) @font-lock-keyword-face) - (property_declaration - (var_modifier) @font-lock-keyword-face) (enum_declaration name: (_) @font-lock-type-face) (function_definition name: (_) @font-lock-function-name-face) (method_declaration name: (_) @font-lock-function-name-face) + (method_declaration + name: (name) @font-lock-builtin-face + (:match ,(rx-to-string + `(: bos (or ,@php-ts-mode--class-magic-methods) eos)) + @font-lock-builtin-face)) ("=>") @font-lock-keyword-face (object_creation_expression (name) @font-lock-type-face) ,@(when (php-ts-mode--test-namespace-name-as-prefix-p) - '((namespace_name_as_prefix "\\" @font-lock-delimiter-face) - (namespace_name_as_prefix - (namespace_name (name)) @font-lock-type-face))) + '((namespace_name_as_prefix "\\" @font-lock-delimiter-face) + (namespace_name_as_prefix + (namespace_name (name)) @font-lock-type-face))) ,@(if (php-ts-mode--test-namespace-aliasing-clause-p) - '((namespace_aliasing_clause (name) @font-lock-type-face)) - '((namespace_use_clause alias: (name) @font-lock-type-face))) + '((namespace_aliasing_clause (name) @font-lock-type-face)) + '((namespace_use_clause alias: (name) @font-lock-type-face))) ,@(when (not (php-ts-mode--test-namespace-use-group-clause-p)) - '((namespace_use_group - (namespace_use_clause (name) @font-lock-type-face)))) + '((namespace_use_group + (namespace_use_clause (name) @font-lock-type-face)))) (namespace_name "\\" @font-lock-delimiter-face) (namespace_name (name) @font-lock-type-face) - (use_declaration (name) @font-lock-property-use-face)) + (use_declaration (name) @font-lock-property-use-face) + (use_instead_of_clause (name) @font-lock-type-face) + (binary_expression + operator: "instanceof" + right: (name) @font-lock-type-face)) :language 'php :feature 'function-scope @@ -932,9 +988,9 @@ characters of the current line." '((function_call_expression function: (name) @font-lock-function-call-face) (scoped_call_expression - name: (_) @font-lock-function-name-face) + name: (_) @font-lock-function-call-face) (member_call_expression - name: (_) @font-lock-function-name-face) + name: (_) @font-lock-function-call-face) (nullsafe_member_call_expression name: (_) @font-lock-constant-face)) From ac4151e0023f4bf17eb128036c006618332f1ac0 Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Sun, 20 Oct 2024 11:35:06 +0200 Subject: [PATCH 02/11] * test/Makefile.in: Do not show emacs-module-tests.log by default. --- test/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Makefile.in b/test/Makefile.in index 3cbdbec4414..7a3178546a1 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -170,7 +170,7 @@ WRITE_LOG = > $@ 2>&1 || { STAT=$$?; cat $@; exit $$STAT; } endif ## On Emba, always show logs for certain problematic tests. ifdef EMACS_EMBA_CI -lisp/filenotify-tests.log lisp/net/tramp-tests.log src/emacs-module-tests.log \ +lisp/filenotify-tests.log lisp/net/tramp-tests.log \ : WRITE_LOG = 2>&1 | tee $@ endif From 681f70ea04a30bb43bb87448a6d71458d773d247 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 20 Oct 2024 22:39:53 +0300 Subject: [PATCH 03/11] * src/lread.c (READ_AND_BUFFER): Reject negative chars (bug#73914). --- src/lread.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lread.c b/src/lread.c index c336c6db6e1..854aaa784ad 100644 --- a/src/lread.c +++ b/src/lread.c @@ -3913,6 +3913,8 @@ read_stack_reset (intmax_t sp) #define READ_AND_BUFFER(c) \ c = READCHAR; \ + if (c < 0) \ + INVALID_SYNTAX_WITH_BUFFER (); \ if (multibyte) \ p += CHAR_STRING (c, (unsigned char *) p); \ else \ From 6be47058cd741e5868f5c2fdef0fd59e296f18b6 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 21 Oct 2024 13:01:53 +0300 Subject: [PATCH 04/11] ; Add indexing for 'use-default-font-for-symbols' * doc/emacs/mule.texi (Modifying Fontsets): * doc/lispref/display.texi (Fontsets): Index 'use-default-font-for-symbols'. --- doc/emacs/mule.texi | 1 + doc/lispref/display.texi | 1 + 2 files changed, 2 insertions(+) diff --git a/doc/emacs/mule.texi b/doc/emacs/mule.texi index 8b16c661a7e..84edc0d086a 100644 --- a/doc/emacs/mule.texi +++ b/doc/emacs/mule.texi @@ -1681,6 +1681,7 @@ used. Some examples are: nil 'append) @end example +@vindex use-default-font-for-symbols When modifying the fontset for the @code{symbol} script, the value of @code{use-default-font-for-symbols} will affect whether the fontset is actually used. diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 1d5ba98f062..3492f4dc29b 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -4025,6 +4025,7 @@ in the range @var{from} and @var{to} (inclusive). @var{characters} may be a charset symbol (@pxref{Character Sets}). In that case, use @var{font-spec} for all the characters in the charset. +@vindex use-default-font-for-symbols @var{characters} may be a script symbol (@pxref{Character Properties, char-script-table}). In that case, use @var{font-spec} for all the characters belonging to the script. See also From 88a1a32fc57817d5e0e1f79b83ff23d7274cbace Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 21 Oct 2024 13:04:18 +0300 Subject: [PATCH 05/11] ; * doc/lispref/display.texi (Fontsets): Fix typo. --- doc/lispref/display.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 3492f4dc29b..ac712c43208 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -4030,7 +4030,7 @@ that case, use @var{font-spec} for all the characters in the charset. char-script-table}). In that case, use @var{font-spec} for all the characters belonging to the script. See also @code{use-default-font-for-symbols}, which affects font selection -when @var{fontset} is @code{symbol}. +when @var{characters} is @code{symbol}. @var{characters} may be @code{nil}, which means to use @var{font-spec} for any character in @var{fontset} for which no font-spec is From c35d6ba9f07b0a8417ef116359049c0dd63e12b5 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 21 Oct 2024 18:32:07 +0300 Subject: [PATCH 06/11] ; * doc/lispref/display.texi (Fontsets): Clarify wording. --- doc/lispref/display.texi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index ac712c43208..afb1272ae41 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -4030,7 +4030,8 @@ that case, use @var{font-spec} for all the characters in the charset. char-script-table}). In that case, use @var{font-spec} for all the characters belonging to the script. See also @code{use-default-font-for-symbols}, which affects font selection -when @var{characters} is @code{symbol}. +when @var{characters} specify or belong to the @code{symbol} script +(which includes symbol and punctuation characters). @var{characters} may be @code{nil}, which means to use @var{font-spec} for any character in @var{fontset} for which no font-spec is From 48024096fea5ccdeb79dab5793a6f7a293b95919 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 21 Oct 2024 20:42:01 +0300 Subject: [PATCH 07/11] Avoid crashes when scrolling images under winner-mode * src/window.c (window_scroll_pixel_based): Fix calculation of a window's vscroll. (Bug#73933) --- src/window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/window.c b/src/window.c index dba2d6a3523..a2b40cb197f 100644 --- a/src/window.c +++ b/src/window.c @@ -6017,7 +6017,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) /* The last line was only partially visible, make it fully visible. */ w->vscroll = (it.last_visible_y - - it.current_y + it.max_ascent + it.max_descent); + - (it.current_y + it.max_ascent + it.max_descent)); adjust_frame_glyphs (it.f); } else From 2289e162268b82d1d757c2354bf3fdf92316e91d Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Tue, 22 Oct 2024 12:35:18 -0400 Subject: [PATCH 08/11] * etc/package-keyring.gpg: Update expiration and add new key --- etc/package-keyring.gpg | Bin 2043 -> 2343 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/etc/package-keyring.gpg b/etc/package-keyring.gpg index 563acbb16b6978eb9b7ccb7a6b8ca7d8a1442efd..f88d60b24576ed74831f42e0cae029973f0f3104 100644 GIT binary patch delta 392 zcmey(zg%duD9d*yW+rK-$vo_mJn7;m7qfB-ojJXXp>eVudwD&lz|YAC%-inOojSIc z;jjFij|=;Xe!kb*{_v06*^1z*F?*rv&yYwFrnlDW+NS0@9*4r7*d@#Fi%IJMarSr~7*^D{ECJNWGk-7J)-bjah7 z@1%0>DA!HXtc?w~arxR@Vtb-GG0tb&WEOVCdXPS#J3-E4W?*PUxU5WpMN*7|K~_wW zg)Q=tZ;Vf?eaJ>#mkpEn8FW2lH?T5+bTV*p3cy5!PBHwikAJ9mC_OwTS>%^f|MpliK6N|u zaz0Z>Muz>|1vgK)Ti%hXG0auBRpFBKofGQ0H-=}!{-4wO?=`nG{4e|cf5%Q?{uNrA fs+KWVneRKC_VNes%PD;O?QeNK@d#wyAj$#&041Ta delta 117 zcmV-*0E+*o68jIc5(O0mu=fI!BLo>4W2>!d0viGa2?=HafB=CB5c!k9H-_GR%99@h zcSe(P0RYL|aK}rVCKZvEKpozBm40D^(n;J)vsf^e#lH>tAPoTjU2iTlAcnnHtdOg> XvU%6w{`iw6@fTPQo!QFZMog{_OQ14I From b7a375f5c49ac86399b9af7a6a74720ed294abd7 Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Tue, 22 Oct 2024 09:43:00 -0700 Subject: [PATCH 09/11] Fix error when splicing Eshell globs and a glob expands to itself This could happen when 'eshell-extended-glob' determines that a "glob" is not really a glob. This mainly happens for remote file names with a "~" in them, like "/ssh:remote:~/file.txt". * lisp/eshell/em-glob.el (eshell-extended-glob): Return a list when 'eshell-glob-splice-results' is non-nil. * test/lisp/eshell/em-glob-tests.el (em-glob-test/expand/splice-results) em-glob-test/expand/no-splice-results): Extend tests. --- lisp/eshell/em-glob.el | 2 +- test/lisp/eshell/em-glob-tests.el | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/lisp/eshell/em-glob.el b/lisp/eshell/em-glob.el index 36e4f90aed2..2aceaf188f3 100644 --- a/lisp/eshell/em-glob.el +++ b/lisp/eshell/em-glob.el @@ -348,7 +348,7 @@ regular expressions, and these cannot support the above constructs." ;; always be sure if the "~" is a home directory reference or ;; part of a glob (e.g. if the argument was assembled from ;; variables). - glob + (if eshell-glob-splice-results (list glob) glob) (unwind-protect (apply #'eshell-glob-entries globs) (if message-shown diff --git a/test/lisp/eshell/em-glob-tests.el b/test/lisp/eshell/em-glob-tests.el index 2efb3a9df69..88e9cc73bbd 100644 --- a/test/lisp/eshell/em-glob-tests.el +++ b/test/lisp/eshell/em-glob-tests.el @@ -74,7 +74,13 @@ component ending in \"symlink\" is treated as a symbolic link." ;; Ensure the default expansion splices the glob. (eshell-command-result-equal "funcall list *.el" '("a.el" "b.el")) (eshell-command-result-equal "funcall list *.txt" '("c.txt")) - (eshell-command-result-equal "funcall list *.no" '("*.no"))))) + ;; When spliting, no-matches cases also return a list containing + ;; the original non-matching glob. + (eshell-command-result-equal "funcall list *.no" '("*.no")) + (when (eshell-tests-remote-accessible-p) + (let ((remote (file-remote-p ert-remote-temporary-file-directory))) + (eshell-command-result-equal (format "funcall list %s~/a.el" remote) + `(,(format "%s~/a.el" remote)))))))) (ert-deftest em-glob-test/expand/no-splice-results () "Test that globs are treated as lists when @@ -85,9 +91,13 @@ component ending in \"symlink\" is treated as a symbolic link." ;; Ensure the default expansion splices the glob. (eshell-command-result-equal "funcall list *.el" '(("a.el" "b.el"))) (eshell-command-result-equal "funcall list *.txt" '(("c.txt"))) - ;; The no-matches case is special here: the glob is just the + ;; The no-matches cases are special here: the glob is just the ;; string, not the list of results. - (eshell-command-result-equal "funcall list *.no" '("*.no"))))) + (eshell-command-result-equal "funcall list *.no" '("*.no")) + (when (eshell-tests-remote-accessible-p) + (let ((remote (file-remote-p ert-remote-temporary-file-directory))) + (eshell-command-result-equal (format "funcall list %s~/a.el" remote) + `(,(format "%s~/a.el" remote)))))))) (ert-deftest em-glob-test/expand/explicitly-splice-results () "Test explicitly splicing globs works the same no matter the From 09e05f7ee4de89f5f1dd95aa9498feccfa9a78d6 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 23 Oct 2024 09:07:06 +0800 Subject: [PATCH 10/11] Document and-let* vs. when-let* usage convention * lisp/subr.el (and-let*): Document and/and-let* vs. when/when-let* usage convention (some discussion in bug#73853). (when-let*): Add cross-reference to and-let*. --- lisp/subr.el | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lisp/subr.el b/lisp/subr.el index 28ba30f584e..d1b2a1efe6e 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -2640,14 +2640,22 @@ This is like `if-let' but doesn't handle a VARLIST of the form (defmacro when-let* (varlist &rest body) "Bind variables according to VARLIST and conditionally evaluate BODY. This is like `when-let' but doesn't handle a VARLIST of the form -\(SYMBOL SOMETHING) specially." +\(SYMBOL SOMETHING) specially. + +See also `and-let*'." (declare (indent 1) (debug if-let*)) (list 'if-let* varlist (macroexp-progn body))) (defmacro and-let* (varlist &rest body) "Bind variables according to VARLIST and conditionally evaluate BODY. Like `when-let*', except if BODY is empty and all the bindings -are non-nil, then the result is the value of the last binding." +are non-nil, then the result is the value of the last binding. + +Some Lisp programmers follow the convention that `and' and `and-let*' +are for forms evaluated for return value, and `when' and `when-let*' are +for forms evaluated for side-effect with returned values ignored." + ;; Document this convention here because it partially explains why we + ;; have both `when-let*' and `and-let*'. (declare (indent 1) (debug if-let*)) (let (res) (if varlist From f5451b6a0668f4dc9992562b62ed37a199f1fdad Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 23 Oct 2024 10:53:02 +0800 Subject: [PATCH 11/11] ; Improve comment from last change --- lisp/subr.el | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lisp/subr.el b/lisp/subr.el index d1b2a1efe6e..0acc24042f8 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -2654,8 +2654,9 @@ are non-nil, then the result is the value of the last binding. Some Lisp programmers follow the convention that `and' and `and-let*' are for forms evaluated for return value, and `when' and `when-let*' are for forms evaluated for side-effect with returned values ignored." - ;; Document this convention here because it partially explains why we - ;; have both `when-let*' and `and-let*'. + ;; ^ Document this convention here because it explains why we have + ;; both `when-let*' and `and-let*' (in addition to the additional + ;; feature of `and-let*' when BODY is empty). (declare (indent 1) (debug if-let*)) (let (res) (if varlist