Add new Eshell built-in command 'funcall'

* lisp/eshell/esh-cmd.el (eshell/funcall): New function...

* test/lisp/eshell/em-glob-tests.el (em-glob-test/expand/splice-results)
(em-glob-test/expand/no-splice-results)
(em-glob-test/expand/explicitly-splice-results)
(em-glob-test/expand/explicitly-listify-results):
* test/lisp/eshell/esh-var-tests.el
(esh-var-test/quoted-interp-lisp-indices)
(esh-var-test/quoted-interp-cmd-indices)
(esh-var-test/interp-convert-quoted-var-number)
(esh-var-test/quoted-interp-convert-var-number)
(esh-var-test/quoted-interp-convert-quoted-var-number)
(esh-var-test/last-status-var-lisp-command)
(esh-var-test/last-result-var-split-indices)
(esh-var-test/last-arg-var-split-indices): ... use it in tests.

* doc/misc/eshell.texi (List of Built-ins): Describe this command.
This commit is contained in:
Jim Porter 2024-05-16 20:33:18 -07:00
parent 113bd2082c
commit 2f7d011d18
4 changed files with 48 additions and 29 deletions

View file

@ -782,6 +782,14 @@ the buffer is merely buried instead.
Set environment variables using input like Bash's @command{export}, as
in @samp{export @var{var1}=@var{val1} @var{var2}=@var{val2} @dots{}}.
@cmindex funcall
@item funcall @var{function} [@var{arg}]@dots{}
Call @var{function} with the specified arguments (@var{function} may be
a symbol or a string naming a Lisp function). This command is useful
when you want to call an ordinary Lisp function using Eshell's command
form (@pxref{Invocation}), even if there may be an external program of
the same name.
@cmindex grep
@item grep [@var{arg}]@dots{}
@cmindex agrep

View file

@ -1480,6 +1480,14 @@ Print the result using `eshell-printn'; if an error occurs, print it
via `eshell-errorn'."
(eshell-eval* #'eshell-printn #'eshell-errorn form))
(defun eshell/funcall (func &rest args)
"Eshell built-in command for `funcall' (which see).
This simply calls FUNC with the specified ARGS. FUNC may be a symbol or
a string naming a Lisp function."
(when (stringp func)
(setq func (intern func)))
(apply func args))
(defvar eshell-last-output-end) ;Defined in esh-mode.el.
(defun eshell-lisp-command (object &optional args)

View file

@ -72,9 +72,9 @@ component ending in \"symlink\" is treated as a symbolic link."
(eshell-glob-splice-results t))
(with-fake-files '("a.el" "b.el" "c.txt")
;; Ensure the default expansion splices the glob.
(eshell-command-result-equal "list *.el" '("a.el" "b.el"))
(eshell-command-result-equal "list *.txt" '("c.txt"))
(eshell-command-result-equal "list *.no" '("*.no")))))
(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")))))
(ert-deftest em-glob-test/expand/no-splice-results ()
"Test that globs are treated as lists when
@ -83,11 +83,11 @@ component ending in \"symlink\" is treated as a symbolic link."
(eshell-glob-splice-results nil))
(with-fake-files '("a.el" "b.el" "c.txt")
;; Ensure the default expansion splices the glob.
(eshell-command-result-equal "list *.el" '(("a.el" "b.el")))
(eshell-command-result-equal "list *.txt" '(("c.txt")))
(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
;; string, not the list of results.
(eshell-command-result-equal "list *.no" '("*.no")))))
(eshell-command-result-equal "funcall list *.no" '("*.no")))))
(ert-deftest em-glob-test/expand/explicitly-splice-results ()
"Test explicitly splicing globs works the same no matter the
@ -97,11 +97,11 @@ value of `eshell-glob-splice-results'."
(ert-info ((format "eshell-glob-splice-results: %s"
eshell-glob-splice-results))
(with-fake-files '("a.el" "b.el" "c.txt")
(eshell-command-result-equal "list $@{listify *.el}"
(eshell-command-result-equal "funcall list $@{listify *.el}"
'("a.el" "b.el"))
(eshell-command-result-equal "list $@{listify *.txt}"
(eshell-command-result-equal "funcall list $@{listify *.txt}"
'("c.txt"))
(eshell-command-result-equal "list $@{listify *.no}"
(eshell-command-result-equal "funcall list $@{listify *.no}"
'("*.no")))))))
(ert-deftest em-glob-test/expand/explicitly-listify-results ()
@ -112,11 +112,11 @@ value of `eshell-glob-splice-results'."
(ert-info ((format "eshell-glob-splice-results: %s"
eshell-glob-splice-results))
(with-fake-files '("a.el" "b.el" "c.txt")
(eshell-command-result-equal "list ${listify *.el}"
(eshell-command-result-equal "funcall list ${listify *.el}"
'(("a.el" "b.el")))
(eshell-command-result-equal "list ${listify *.txt}"
(eshell-command-result-equal "funcall list ${listify *.txt}"
'(("c.txt")))
(eshell-command-result-equal "list ${listify *.no}"
(eshell-command-result-equal "funcall list ${listify *.no}"
'(("*.no"))))))))

View file

@ -436,7 +436,7 @@ nil, use FUNCTION instead."
(ert-deftest esh-var-test/quoted-interp-lisp-indices ()
"Interpolate Lisp form evaluation with index."
(eshell-command-result-equal "concat \"$(list 1 2)[1]\" cool"
(eshell-command-result-equal "funcall concat \"$(list 1 2)[1]\" cool"
"2cool"))
(ert-deftest esh-var-test/quoted-interp-cmd ()
@ -446,7 +446,7 @@ nil, use FUNCTION instead."
(ert-deftest esh-var-test/quoted-interp-cmd-indices ()
"Interpolate command result with index inside double-quotes."
(eshell-command-result-equal "concat \"${listify 1 2}[1]\" cool"
(eshell-command-result-equal "funcall concat \"${listify 1 2}[1]\" cool"
"2cool"))
(ert-deftest esh-var-test/quoted-interp-temp-cmd ()
@ -504,9 +504,9 @@ nil, use FUNCTION instead."
(ert-deftest esh-var-test/interp-convert-quoted-var-number ()
"Interpolate numeric quoted numeric variable."
(let ((eshell-test-value 123))
(eshell-command-result-equal "type-of $'eshell-test-value'"
(eshell-command-result-equal "funcall type-of $'eshell-test-value'"
'integer)
(eshell-command-result-equal "type-of $\"eshell-test-value\""
(eshell-command-result-equal "funcall type-of $\"eshell-test-value\""
'integer)))
(ert-deftest esh-var-test/interp-convert-quoted-var-split-indices ()
@ -546,7 +546,7 @@ nil, use FUNCTION instead."
(ert-deftest esh-var-test/quoted-interp-convert-var-number ()
"Interpolate numeric variable inside double-quotes."
(let ((eshell-test-value 123))
(eshell-command-result-equal "type-of \"$eshell-test-value\""
(eshell-command-result-equal "funcall type-of \"$eshell-test-value\""
'string)))
(ert-deftest esh-var-test/quoted-interp-convert-var-split-indices ()
@ -560,10 +560,11 @@ nil, use FUNCTION instead."
(ert-deftest esh-var-test/quoted-interp-convert-quoted-var-number ()
"Interpolate numeric quoted variable inside double-quotes."
(let ((eshell-test-value 123))
(eshell-command-result-equal "type-of \"$'eshell-test-value'\""
(eshell-command-result-equal "funcall type-of \"$'eshell-test-value'\""
'string)
(eshell-command-result-equal "type-of \"$\\\"eshell-test-value\\\"\""
'string)))
(eshell-command-result-equal
"funcall type-of \"$\\\"eshell-test-value\\\"\""
'string)))
(ert-deftest esh-var-test/quoted-interp-convert-quoted-var-split-indices ()
"Interpolate quoted string variable with indices inside double-quotes."
@ -905,11 +906,11 @@ the value of the $PAGER env var."
(ert-deftest esh-var-test/last-status-var-lisp-command ()
"Test using the \"last exit status\" ($?) variable with a Lisp command."
(with-temp-eshell
(eshell-match-command-output "zerop 0; echo $?"
(eshell-match-command-output "funcall zerop 0; echo $?"
"t\n0\n")
(eshell-match-command-output "zerop 1; echo $?"
(eshell-match-command-output "funcall zerop 1; echo $?"
"0\n")
(eshell-match-command-output "zerop foo; echo $?"
(eshell-match-command-output "funcall zerop foo; echo $?"
"1\n" nil t)))
(ert-deftest esh-var-test/last-status-var-lisp-form ()
@ -972,10 +973,10 @@ This tests when `eshell-lisp-form-nil-is-failure' is nil."
"Test using the \"last result\" ($$) variable with split indices."
(with-temp-eshell
(eshell-match-command-output
"string-join (list \"01\" \"02\") :; + $$[: 1] 3"
"funcall string-join (list \"01\" \"02\") :; + $$[: 1] 3"
"01:02\n5\n")
(eshell-match-command-output
"string-join (list \"01\" \"02\") :; echo \"$$[: 1]\""
"funcall string-join (list \"01\" \"02\") :; echo \"$$[: 1]\""
"01:02\n02\n")))
(ert-deftest esh-var-test/last-arg-var ()
@ -995,9 +996,11 @@ This tests when `eshell-lisp-form-nil-is-failure' is nil."
(ert-deftest esh-var-test/last-arg-var-split-indices ()
"Test using the \"last arg\" ($_) variable with split indices."
(with-temp-eshell
(eshell-match-command-output "concat 01:02 03:04; + $_[0][: 1] 5"
"01:0203:04\n7\n")
(eshell-match-command-output "concat 01:02 03:04; echo \"$_[0][: 1]\""
"01:0203:04\n02\n")))
(eshell-match-command-output
"funcall concat 01:02 03:04; + $_[1][: 1] 5"
"01:0203:04\n7\n")
(eshell-match-command-output
"funcall concat 01:02 03:04; echo \"$_[1][: 1]\""
"01:0203:04\n02\n")))
;; esh-var-tests.el ends here