From eafe5a261271650fcd36e6f09f65691e187d4d35 Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Sat, 25 Jun 2022 20:05:57 -0700 Subject: [PATCH] Optionally signal an error if an Eshell predicate fails to match anything * lisp/eshell/em-pred.el (eshell-error-if-no-glob): Declare it. (eshell-apply-modifiers): Add STRING-DESC argument and signal an error if there are no matches and 'eshell-error-if-no-glob' is set. (eshell-parse-arg-modifier): Pass modifier string to 'eshell-apply-modifiers'. * test/lisp/eshell/em-pred-tests.el (eshell-eval-predicate): Simplify. (em-pred-test/no-matches): New test. * doc/misc/eshell.texi (Bugs and ideas): Remove todo entry about this change. --- doc/misc/eshell.texi | 5 ----- lisp/eshell/em-pred.el | 18 +++++++++++++----- test/lisp/eshell/em-pred-tests.el | 26 ++++++++++++++++++++++---- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi index 85e5a4933f..2e3ba4c273 100644 --- a/doc/misc/eshell.texi +++ b/doc/misc/eshell.texi @@ -1902,11 +1902,6 @@ Bugs and ideas At the moment, this is not supported. -@item Error if a glob doesn't expand due to a predicate - -An error should be generated only if @code{eshell-error-if-no-glob} is -non-@code{nil}. - @item @samp{(+ @key{RET} @key{SPC} @key{TAB}} does not cause @code{indent-according-to-mode} to occur @item Create @code{eshell-auto-accumulate-list} diff --git a/lisp/eshell/em-pred.el b/lisp/eshell/em-pred.el index d73976d346..b4ef154f8c 100644 --- a/lisp/eshell/em-pred.el +++ b/lisp/eshell/em-pred.el @@ -233,6 +233,8 @@ eshell-pred-delimiter-pairs are characters representing the opening and closing delimiter, respectively.") +(defvar eshell-error-if-no-glob) ; Defined in em-glob.el. + (defvar-keymap eshell-pred-mode-map "C-c M-q" #'eshell-display-predicate-help "C-c M-m" #'eshell-display-modifier-help) @@ -263,14 +265,19 @@ eshell-pred-initialize #'eshell-parse-arg-modifier t t) (eshell-pred-mode)) -(defun eshell-apply-modifiers (lst predicates modifiers) - "Apply to list LST a series of PREDICATES and MODIFIERS." +(defun eshell-apply-modifiers (lst predicates modifiers string-desc) + "Apply to list LST a series of PREDICATES and MODIFIERS. +STRING-DESC is the original string defining these predicates and +modifiers." (let (stringified) (if (stringp lst) (setq lst (list lst) stringified t)) (when (listp lst) - (setq lst (eshell-winnow-list lst nil predicates)) + (when lst + (setq lst (or (eshell-winnow-list lst nil predicates) + (when eshell-error-if-no-glob + (error "No matches found: (%s)" string-desc))))) (while modifiers (setq lst (funcall (car modifiers) lst) modifiers (cdr modifiers))) @@ -290,7 +297,8 @@ eshell-parse-arg-modifier (when (eshell-arg-delimiter (1+ end)) (save-restriction (narrow-to-region (point) end) - (let* ((modifiers (eshell-parse-modifiers)) + (let* ((modifier-string (buffer-string)) + (modifiers (eshell-parse-modifiers)) (preds (car modifiers)) (mods (cdr modifiers))) (if (or preds mods) @@ -302,7 +310,7 @@ eshell-parse-arg-modifier (list (lambda (lst) (eshell-apply-modifiers - lst preds mods)))))))) + lst preds mods modifier-string)))))))) (goto-char (1+ end)) (eshell-finish-arg)))))) diff --git a/test/lisp/eshell/em-pred-tests.el b/test/lisp/eshell/em-pred-tests.el index 3b50543d69..c8c1a6a931 100644 --- a/test/lisp/eshell/em-pred-tests.el +++ b/test/lisp/eshell/em-pred-tests.el @@ -26,6 +26,7 @@ (require 'ert) (require 'esh-mode) (require 'eshell) +(require 'em-glob) (require 'em-pred) (require 'eshell-tests-helpers @@ -39,10 +40,9 @@ eshell-eval-predicate "Evaluate PREDICATE on INITIAL-VALUE, returning the result. PREDICATE is an Eshell argument predicate/modifier." (let ((eshell-test-value initial-value)) - (with-temp-eshell - (eshell-insert-command - (format "setq eshell-test-value $eshell-test-value(%s)" predicate))) - eshell-test-value)) + (ignore-errors + (eshell-test-command-result + (format "echo $eshell-test-value(%s)" predicate))))) (defun eshell-parse-file-name-attributes (file) "Parse a fake FILE name to determine its attributes. @@ -545,4 +545,22 @@ em-pred-test/predicate-escaping (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":j'\\\"'") "foo\\\"bar\\\"baz"))) +(ert-deftest em-pred-test/no-matches () + "Test behavior when a predicate fails to match any files." + (eshell-with-file-attributes-from-name + (let ((files '("/fake/modes=0666" "/fake/type=d,modes=0777" + "/fake/type=l,modes=0777"))) + (should (equal (eshell-eval-predicate files "*") nil)) + (let ((eshell-error-if-no-glob t)) + ;; Don't signal an error if the original list is empty. + (should (equal (eshell-eval-predicate nil "*") nil)) + ;; Ensure this signals an error. This test case is a bit + ;; clumsy, since `eshell-do-eval' makes it hard to catch + ;; errors otherwise. + (let ((modifiers (with-temp-eshell + (eshell-with-temp-command "*" + (eshell-parse-modifiers))))) + (should-error (eshell-apply-modifiers files (car modifiers) + (cdr modifiers) "*"))))))) + ;; em-pred-tests.el ends here -- 2.25.1