diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi index 8cb73d4077b..57ee3bf3e9f 100644 --- a/doc/misc/eshell.texi +++ b/doc/misc/eshell.texi @@ -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 diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el index b489822f188..dae1a77552f 100644 --- a/lisp/eshell/esh-cmd.el +++ b/lisp/eshell/esh-cmd.el @@ -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) diff --git a/test/lisp/eshell/em-glob-tests.el b/test/lisp/eshell/em-glob-tests.el index d7d8f59eda0..2efb3a9df69 100644 --- a/test/lisp/eshell/em-glob-tests.el +++ b/test/lisp/eshell/em-glob-tests.el @@ -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")))))))) diff --git a/test/lisp/eshell/esh-var-tests.el b/test/lisp/eshell/esh-var-tests.el index b94e8a276d7..1b46b214e77 100644 --- a/test/lisp/eshell/esh-var-tests.el +++ b/test/lisp/eshell/esh-var-tests.el @@ -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