From 1bdccd3c34a5355183fd0fee4cadb99dd5675151 Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Wed, 6 Jul 2022 21:59:11 -0700 Subject: [PATCH 3/3] Ensure Eshell variable aliases properly handle indexing * lisp/eshell/em-dirs.el (eshell-dirs-initialize): Properly handle indexing for variable aliases. * lisp/eshell/esh-var (eshell-variable-aliases-list): Properly handle indexing for variable aliases, and add SIMPLE-FUNCTION entry for aliases. (eshell-get-variable): Update how variable alias functions are called. * test/lisp/eshell/em-alias-tests.el (em-alias-test/alias-arg-vars-indices) (em-alias-test/alias-arg-vars-split-indices) (em-alias-test/alias-all-args-var-split-indices): * test/lisp/eshell/em-dirs-tests.el (em-dirs-test/pwd-var-indices) (em-dirs-test/oldpwd-var-indices) (em-dirs-test/directory-ring-var-indices): * test/lisp/eshell/esh-var-tests.el (esh-var-test/inside-emacs-var-split-indices) (esh-var-test/last-result-var-split-indices): New tests. (esh-var-test/last-arg-var-split-indices): Expand test to check conversion behavior inside double quotes (bug#56509). --- lisp/eshell/em-dirs.el | 36 ++++++++------- lisp/eshell/esh-var.el | 73 ++++++++++++++++++------------ test/lisp/eshell/em-alias-tests.el | 23 ++++++++++ test/lisp/eshell/em-dirs-tests.el | 28 ++++++++++++ test/lisp/eshell/esh-var-tests.el | 22 ++++++++- 5 files changed, 134 insertions(+), 48 deletions(-) diff --git a/lisp/eshell/em-dirs.el b/lisp/eshell/em-dirs.el index a3cf0b9131..00880b9f28 100644 --- a/lisp/eshell/em-dirs.el +++ b/lisp/eshell/em-dirs.el @@ -175,22 +175,26 @@ eshell-dirs-initialize (setq-local eshell-variable-aliases-list (append eshell-variable-aliases-list - `(("-" ,(lambda (indices) - (if (not indices) - (unless (ring-empty-p eshell-last-dir-ring) - (expand-file-name - (ring-ref eshell-last-dir-ring 0))) - (expand-file-name - (eshell-apply-indices eshell-last-dir-ring indices))))) - ("+" "PWD") - ("PWD" ,(lambda (_indices) - (expand-file-name (eshell/pwd))) - t) - ("OLDPWD" ,(lambda (_indices) - (unless (ring-empty-p eshell-last-dir-ring) - (expand-file-name - (ring-ref eshell-last-dir-ring 0)))) - t)))) + `(("-" ,(lambda (indices quoted) + (if (not indices) + (unless (ring-empty-p eshell-last-dir-ring) + (expand-file-name + (ring-ref eshell-last-dir-ring 0))) + ;; Apply the first index, expand the file name, + ;; and then apply the rest of the indices. + (eshell-apply-indices + (expand-file-name + (eshell-apply-indices eshell-last-dir-ring + (list (car indices)) quoted)) + (cdr indices) quoted)))) + ("+" "PWD") + ("PWD" ,(lambda () (expand-file-name (eshell/pwd))) + t t) + ("OLDPWD" ,(lambda () + (unless (ring-empty-p eshell-last-dir-ring) + (expand-file-name + (ring-ref eshell-last-dir-ring 0)))) + t t)))) (when eshell-cd-on-directory (setq-local eshell-interpreter-alist diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el index e1535c1c5d..cbd7942de4 100644 --- a/lisp/eshell/esh-var.el +++ b/lisp/eshell/esh-var.el @@ -152,59 +152,63 @@ eshell-variable-name-regexp (defcustom eshell-variable-aliases-list `(;; for eshell.el - ("COLUMNS" ,(lambda (_indices) (window-body-width nil 'remap)) t) - ("LINES" ,(lambda (_indices) (window-body-height nil 'remap)) t) + ("COLUMNS" ,(lambda () (window-body-width nil 'remap)) t t) + ("LINES" ,(lambda () (window-body-height nil 'remap)) t t) ("INSIDE_EMACS" eshell-inside-emacs t) ;; for eshell-cmd.el - ("_" ,(lambda (indices) + ("_" ,(lambda (indices quoted) (if (not indices) (car (last eshell-last-arguments)) (eshell-apply-indices eshell-last-arguments - indices)))) + indices quoted)))) ("?" eshell-last-command-status) ("$" eshell-last-command-result) ;; for em-alias.el and em-script.el ("0" eshell-command-name) - ("1" ,(lambda (_indices) (nth 0 eshell-command-arguments))) - ("2" ,(lambda (_indices) (nth 1 eshell-command-arguments))) - ("3" ,(lambda (_indices) (nth 2 eshell-command-arguments))) - ("4" ,(lambda (_indices) (nth 3 eshell-command-arguments))) - ("5" ,(lambda (_indices) (nth 4 eshell-command-arguments))) - ("6" ,(lambda (_indices) (nth 5 eshell-command-arguments))) - ("7" ,(lambda (_indices) (nth 6 eshell-command-arguments))) - ("8" ,(lambda (_indices) (nth 7 eshell-command-arguments))) - ("9" ,(lambda (_indices) (nth 8 eshell-command-arguments))) - ("*" ,(lambda (indices) - (if (not indices) - eshell-command-arguments - (eshell-apply-indices eshell-command-arguments - indices))))) + ("1" ,(lambda () (nth 0 eshell-command-arguments)) nil t) + ("2" ,(lambda () (nth 1 eshell-command-arguments)) nil t) + ("3" ,(lambda () (nth 2 eshell-command-arguments)) nil t) + ("4" ,(lambda () (nth 3 eshell-command-arguments)) nil t) + ("5" ,(lambda () (nth 4 eshell-command-arguments)) nil t) + ("6" ,(lambda () (nth 5 eshell-command-arguments)) nil t) + ("7" ,(lambda () (nth 6 eshell-command-arguments)) nil t) + ("8" ,(lambda () (nth 7 eshell-command-arguments)) nil t) + ("9" ,(lambda () (nth 8 eshell-command-arguments)) nil t) + ("*" eshell-command-arguments)) "This list provides aliasing for variable references. -Each member defines the name of a variable, and a Lisp value used to +Each member is of the following form: + + (NAME VALUE [COPY-TO-ENVIRONMENT] [SIMPLE-FUNCTION]) + +NAME defines the name of the variable, VALUE is a Lisp value used to compute the string value that will be returned when the variable is accessed via the syntax `$NAME'. -If the value is a function, call that function with one argument: the -list of the indices that was used in the reference. For example, if +If VALUE is a function, its behavior depends on the value of +SIMPLE-FUNCTION. If SIMPLE-FUNCTION is nil, call VALUE with two +arguments: the list of the indices that was used in the reference and +whether the variable was used within double quotes. For example, if `NAME' were aliased to a function, a reference of `$NAME[10][20]' -would result in that function being called with the argument -`((\"10\") (\"20\"))'. (For more details, see `eshell-apply-indices'). +would result in that function being called with the arguments +`((\"10\") (\"20\"))' and nil. If SIMPLE-FUNCTION is non-nil, call +the function with no arguments and then pass its result to +`eshell-apply-indices'. -If the value is a string, return the value for the variable with that +If VALUE is a string, return the value for the variable with that name in the current environment. If no variable with that name exists in the environment, but if a symbol with that same name exists and has a value bound to it, return its value instead. You can prioritize symbol values over environment values by setting `eshell-prefer-lisp-variables' to t. -If the value is a symbol, return the value bound to it. +If VALUE is a symbol, return the value bound to it. -If the value has any other type, signal an error. +If VALUE has any other type, signal an error. -Additionally, each member may specify if it should be copied to the -environment of created subprocesses." +Additionally, if COPY-TO-ENVIRONMENT is non-nil, the alias should be +copied to the environment of created subprocesses." :type '(repeat (list string sexp (choice (const :tag "Copy to environment" t) (const :tag "Use only in Eshell" nil)))) @@ -550,10 +554,19 @@ eshell-get-variable INDICES is a list of index-lists (see `eshell-parse-indices'). If QUOTED is non-nil, this was invoked inside double-quotes." (if-let ((alias (assoc name eshell-variable-aliases-list))) - (let ((target (cadr alias))) + (let ((target (nth 1 alias))) (cond ((functionp target) - (funcall target indices)) + (if (nth 3 alias) + (eshell-apply-indices (funcall target) indices quoted) + (condition-case nil + (funcall target indices quoted) + (wrong-number-of-arguments + (display-warning + :warning (concat "Function for `eshell-variable-aliases-list' " + "entry should accept two arguments: INDICES " + "and QUOTED.'")) + (funcall target indices))))) ((symbolp target) (eshell-apply-indices (symbol-value target) indices quoted)) (t diff --git a/test/lisp/eshell/em-alias-tests.el b/test/lisp/eshell/em-alias-tests.el index 762f125a78..497159e346 100644 --- a/test/lisp/eshell/em-alias-tests.el +++ b/test/lisp/eshell/em-alias-tests.el @@ -47,6 +47,23 @@ em-alias-test/alias-arg-vars (eshell-insert-command "alias show-args 'printnl $0 \"$1 $2\"'") (eshell-command-result-p "show-args one two" "show-args\none two\n"))) +(ert-deftest em-alias-test/alias-arg-vars-indices () + "Test alias with $1, $2, ... variables using indices" + (with-temp-eshell + (eshell-insert-command "alias funny-sum '+ $1[0] $2[1]'") + (eshell-command-result-p "funny-sum (list 1 2) (list 3 4)" + "5\n"))) + +(ert-deftest em-alias-test/alias-arg-vars-split-indices () + "Test alias with $0, $1, ... variables using split indices" + (with-temp-eshell + (eshell-insert-command "alias my-prefix 'echo $0[- 0]'") + (eshell-command-result-p "my-prefix" + "my\n") + (eshell-insert-command "alias funny-sum '+ $1[: 0] $2[: 1]'") + (eshell-command-result-p "funny-sum 1:2 3:4" + "5\n"))) + (ert-deftest em-alias-test/alias-all-args-var () "Test alias with the $* variable" (with-temp-eshell @@ -61,4 +78,10 @@ em-alias-test/alias-all-args-var-indices (eshell-insert-command "alias add-pair '+ $*[0] $*[1]'") (eshell-command-result-p "add-pair 1 2" "3\n"))) +(ert-deftest em-alias-test/alias-all-args-var-split-indices () + "Test alias with the $* variable using split indices" + (with-temp-eshell + (eshell-insert-command "alias add-funny-pair '+ $*[0][: 0] $*[1][: 1]'") + (eshell-command-result-p "add-funny-pair 1:2 3:4" "5\n"))) + ;; em-alias-tests.el ends here diff --git a/test/lisp/eshell/em-dirs-tests.el b/test/lisp/eshell/em-dirs-tests.el index 69480051e4..8e96cc0747 100644 --- a/test/lisp/eshell/em-dirs-tests.el +++ b/test/lisp/eshell/em-dirs-tests.el @@ -40,6 +40,14 @@ em-dirs-test/pwd-var (should (equal (eshell-test-command-result "echo $PWD") (expand-file-name default-directory))))) +(ert-deftest em-dirs-test/pwd-var-indices () + "Test using the $PWD variable with indices." + (let ((default-directory "/some/path/here")) + (should (equal (eshell-test-command-result "echo $PWD[/ 1]") + "some")) + (should (equal (eshell-test-command-result "echo $PWD[/ 1 3]") + '("some" "here"))))) + (ert-deftest em-dirs-test/short-pwd-var () "Test using the $+ (current directory) variable." (let ((default-directory "/some/path")) @@ -56,6 +64,16 @@ em-dirs-test/oldpwd-var (eshell-command-result-p "echo $OLDPWD" "/some/path\n")))) +(ert-deftest em-dirs-test/oldpwd-var-indices () + "Test using the $OLDPWD variable with indices." + (let (eshell-last-dir-ring-file-name) + (with-temp-eshell + (ring-insert eshell-last-dir-ring "/some/path/here") + (eshell-command-result-p "echo $OLDPWD[/ 1]" + "some\n") + (eshell-command-result-p "echo $OLDPWD[/ 1 3]" + "(\"some\" \"here\")\n")))) + (ert-deftest em-dirs-test/directory-ring-var () "Test using the $- (directory ring) variable." (let (eshell-last-dir-ring-file-name) @@ -71,4 +89,14 @@ em-dirs-test/directory-ring-var (eshell-command-result-p "echo $-[1]" "/some/path\n")))) +(ert-deftest em-dirs-test/directory-ring-var-indices () + "Test using the $- (directory ring) variable with multiple indices." + (let (eshell-last-dir-ring-file-name) + (with-temp-eshell + (ring-insert eshell-last-dir-ring "/some/path/here") + (eshell-command-result-p "echo $-[0][/ 1]" + "some\n") + (eshell-command-result-p "echo $-[1][/ 1 3]" + "(\"some\" \"here\")\n")))) + ;; em-dirs-tests.el ends here diff --git a/test/lisp/eshell/esh-var-tests.el b/test/lisp/eshell/esh-var-tests.el index 955190aee0..54e701a6aa 100644 --- a/test/lisp/eshell/esh-var-tests.el +++ b/test/lisp/eshell/esh-var-tests.el @@ -494,6 +494,12 @@ esh-var-test/inside-emacs-var (format "INSIDE_EMACS=%s,eshell" emacs-version)))) +(ert-deftest esh-var-test/inside-emacs-var-split-indices () + "Test using \"INSIDE_EMACS\" with split indices" + (with-temp-eshell + (eshell-command-result-p "echo $INSIDE_EMACS[, 1]" + "eshell"))) + (ert-deftest esh-var-test/last-result-var () "Test using the \"last result\" ($$) variable" (with-temp-eshell @@ -506,6 +512,16 @@ esh-var-test/last-result-var2 (eshell-command-result-p "+ 1 2; + $$ $$" "3\n6\n"))) +(ert-deftest esh-var-test/last-result-var-split-indices () + "Test using the \"last result\" ($$) variable with split indices" + (with-temp-eshell + (eshell-command-result-p + "string-join (list \"01\" \"02\") :; + $$[: 1] 3" + "01:02\n5\n") + (eshell-command-result-p + "string-join (list \"01\" \"02\") :; echo \"$$[: 1]\"" + "01:02\n02\n"))) + (ert-deftest esh-var-test/last-arg-var () "Test using the \"last arg\" ($_) variable" (with-temp-eshell @@ -523,7 +539,9 @@ esh-var-test/last-arg-var-indices (ert-deftest esh-var-test/last-arg-var-split-indices () "Test using the \"last arg\" ($_) variable with split indices" (with-temp-eshell - (eshell-command-result-p "concat 01:02 03:04; echo $_[0][: 1]" - "01:0203:04\n2\n"))) + (eshell-command-result-p "concat 01:02 03:04; + $_[0][: 1] 5" + "01:0203:04\n7\n") + (eshell-command-result-p "concat 01:02 03:04; echo \"$_[0][: 1]\"" + "01:0203:04\n02\n"))) ;; esh-var-tests.el ends here -- 2.25.1