emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master a3a7279a4a 3/3: Improve the behavior of concatenating parts of Es


From: Lars Ingebrigtsen
Subject: master a3a7279a4a 3/3: Improve the behavior of concatenating parts of Eshell arguments
Date: Tue, 3 May 2022 12:25:16 -0400 (EDT)

branch: master
commit a3a7279a4ab00be69519f98536ec75dc81217b50
Author: Jim Porter <jporterbugs@gmail.com>
Commit: Lars Ingebrigtsen <larsi@gnus.org>

    Improve the behavior of concatenating parts of Eshell arguments
    
    Previously, concatenating a list to a string would first convert the
    list to a string.  Now, the string is concatenated with the last
    element of the list.
    
    * lisp/eshell/esh-util.el (eshell-to-flat-string): Make obsolete.
    
    * lisp/eshell/esh-arg.el (eshell-concat, eshell-concat-1): New
    functions.
    (eshell-resolve-current-argument): Use 'eshell-concat'.
    
    * test/lisp/eshell/esh-var-tests.el (esh-var-test/interp-concat-cmd):
    Add check for concatenation of multiline output of subcommands.
    (esh-var-test/quoted-interp-concat-cmd): New test.
    
    * test/lisp/eshell/em-extpipe-tests.el (em-extpipe-test-13): Use
    'eshell-concat'.
    
    * doc/misc/eshell.texi (Expansion): Document this behavior.
    
    * etc/NEWS: Announce the change (bug#55236).
---
 doc/misc/eshell.texi                 | 34 +++++++++++++++++---
 etc/NEWS                             |  7 ++++
 lisp/eshell/esh-arg.el               | 62 ++++++++++++++++++++++++++++++------
 lisp/eshell/esh-util.el              |  1 +
 test/lisp/eshell/em-extpipe-tests.el |  2 +-
 test/lisp/eshell/esh-var-tests.el    | 19 +++++++++--
 6 files changed, 109 insertions(+), 16 deletions(-)

diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
index be32b2aced..dfb22bcb51 100644
--- a/doc/misc/eshell.texi
+++ b/doc/misc/eshell.texi
@@ -1017,11 +1017,37 @@ parsers (such as @command{cpp} and @command{m4}), but 
in a command
 shell, they are less often used for constants, and usually for using
 variables and string manipulation.@footnote{Eshell has no
 string-manipulation expansions because the Elisp library already
-provides many functions for this.}  For example, @code{$var} on a line
-expands to the value of the variable @code{var} when the line is
+provides many functions for this.}  For example, @code{$@var{var}} on
+a line expands to the value of the variable @var{var} when the line is
 executed.  Expansions are usually passed as arguments, but may also be
-used as commands.@footnote{E.g., entering just @samp{$var} at the prompt
-is equivalent to entering the value of @code{var} at the prompt.}
+used as commands.@footnote{E.g., entering just @samp{$@var{var}} at
+the prompt is equivalent to entering the value of @var{var} at the
+prompt.}
+
+You can concatenate expansions with regular string arguments or even
+other expansions.  In the simplest case, when the expansion returns a
+string value, this is equivalent to ordinary string concatenation; for
+example, @samp{$@{echo "foo"@}bar} returns @samp{foobar}.  The exact
+behavior depends on the types of each value being concatenated:
+
+@table @asis
+
+@item both strings
+Concatenate both values together.
+
+@item one or both numbers
+Concatenate the string representation of each value, converting back to
+a number if possible.
+
+@item one or both (non-@code{nil}) lists
+Concatenate ``adjacent'' elements of each value (possibly converting
+back to a number as above).  For example, @samp{$list("a" "b")c}
+returns @samp{("a" "bc")}.
+
+@item anything else
+Concatenate the string represenation of each value.
+
+@end table
 
 @menu
 * Dollars Expansion::
diff --git a/etc/NEWS b/etc/NEWS
index 592b4b7888..15c7ce8a90 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1396,6 +1396,13 @@ If an Eshell expansion like '$FOO' is surrounded by 
double quotes, the
 result will always be a single string, no matter the type that would
 otherwise be returned.
 
++++
+*** Concatenating Eshell expansions now works more similarly to other shells.
+When concatenating an Eshell expansion that returns a list, "adjacent"
+elements of each operand are now concatenated together,
+e.g. '$list("a" "b")c' returns '("a" "bc")'.  See the "(eshell)
+Expansion" node in the Eshell manual for more details.
+
 +++
 *** Eshell subcommands with multiline numeric output return lists of numbers.
 If every line of the output of an Eshell subcommand like '${COMMAND}'
diff --git a/lisp/eshell/esh-arg.el b/lisp/eshell/esh-arg.el
index 395aa87ff0..459487f435 100644
--- a/lisp/eshell/esh-arg.el
+++ b/lisp/eshell/esh-arg.el
@@ -180,19 +180,63 @@ treated as a literal character."
       (add-text-properties 0 (length string) '(escaped t) string))
   string)
 
+(defun eshell-concat (quoted &rest rest)
+  "Concatenate all the arguments in REST and return the result.
+If QUOTED is nil, the resulting value(s) may be converted to
+numbers (see `eshell-concat-1').
+
+If each argument in REST is a non-list value, the result will be
+a single value, as if (mapconcat #'eshell-stringify REST) had been
+called, possibly converted to a number.
+
+If there is at least one (non-nil) list argument, the result will
+be a list, with \"adjacent\" elements of consecutive arguments
+concatenated as strings (again, possibly converted to numbers).
+For example, concatenating \"a\", (\"b\"), and (\"c\" \"d\")
+would produce (\"abc\" \"d\")."
+  (let (result)
+    (dolist (i rest result)
+      (when i
+        (cond
+         ((null result)
+          (setq result i))
+         ((listp result)
+          (let (curr-head curr-tail)
+            (if (listp i)
+                (setq curr-head (car i)
+                      curr-tail (cdr i))
+              (setq curr-head i
+                    curr-tail nil))
+            (setq result
+                  (append
+                   (butlast result 1)
+                   (list (eshell-concat-1 quoted (car (last result))
+                                          curr-head))
+                   curr-tail))))
+         ((listp i)
+          (setq result
+                (cons (eshell-concat-1 quoted result (car i))
+                      (cdr i))))
+         (t
+          (setq result (eshell-concat-1 quoted result i))))))))
+
+(defun eshell-concat-1 (quoted first second)
+  "Concatenate FIRST and SECOND.
+If QUOTED is nil and either FIRST or SECOND are numbers, try to
+convert the result to a number as well."
+  (let ((result (concat (eshell-stringify first) (eshell-stringify second))))
+    (if (and (not quoted)
+             (or (numberp first) (numberp second)))
+        (eshell-convert-to-number result)
+      result)))
+
 (defun eshell-resolve-current-argument ()
   "If there are pending modifications to be made, make them now."
   (when eshell-current-argument
     (when eshell-arg-listified
-      (let ((parts eshell-current-argument))
-       (while parts
-         (unless (stringp (car parts))
-           (setcar parts
-                   (list 'eshell-to-flat-string (car parts))))
-         (setq parts (cdr parts)))
-       (setq eshell-current-argument
-             (list 'eshell-convert
-                   (append (list 'concat) eshell-current-argument))))
+      (setq eshell-current-argument
+            (append (list 'eshell-concat eshell-current-quoted)
+                    eshell-current-argument))
       (setq eshell-arg-listified nil))
     (while eshell-current-modifiers
       (setq eshell-current-argument
diff --git a/lisp/eshell/esh-util.el b/lisp/eshell/esh-util.el
index 9960912bce..b5a423f023 100644
--- a/lisp/eshell/esh-util.el
+++ b/lisp/eshell/esh-util.el
@@ -293,6 +293,7 @@ Prepend remote identification of `default-directory', if 
any."
 
 (defun eshell-to-flat-string (value)
   "Make value a string.  If separated by newlines change them to spaces."
+  (declare (obsolete nil "29.1"))
   (let ((text (eshell-stringify value)))
     (if (string-match "\n+\\'" text)
        (setq text (replace-match "" t t text)))
diff --git a/test/lisp/eshell/em-extpipe-tests.el 
b/test/lisp/eshell/em-extpipe-tests.el
index 91c2fba479..3b84d763ac 100644
--- a/test/lisp/eshell/em-extpipe-tests.el
+++ b/test/lisp/eshell/em-extpipe-tests.el
@@ -170,7 +170,7 @@
 
 (em-extpipe-tests--deftest em-extpipe-test-13 "foo*|bar"
   (should-parse '(eshell-execute-pipeline
-                  '((eshell-named-command (concat "foo" "*"))
+                  '((eshell-named-command (eshell-concat nil "foo" "*"))
                     (eshell-named-command "bar")))))
 
 (em-extpipe-tests--deftest em-extpipe-test-14 "tac *<temp"
diff --git a/test/lisp/eshell/esh-var-tests.el 
b/test/lisp/eshell/esh-var-tests.el
index 2ce6bb4f1b..3f3b591c5a 100644
--- a/test/lisp/eshell/esh-var-tests.el
+++ b/test/lisp/eshell/esh-var-tests.el
@@ -176,8 +176,17 @@
   (should (equal (eshell-test-command-result "+ $(+ 1 2)$(+ 1 2) 3") 36)))
 
 (ert-deftest esh-var-test/interp-concat-cmd ()
-  "Interpolate and concat command"
-  (should (equal (eshell-test-command-result "+ ${+ 1 2}3 3") 36)))
+  "Interpolate and concat command with literal"
+  (should (equal (eshell-test-command-result "+ ${+ 1 2}3 3") 36))
+  (should (equal (eshell-test-command-result "echo ${*echo \"foo\nbar\"}-baz")
+                 '("foo" "bar-baz")))
+  ;; Concatenating to a number in a list should produce a number...
+  (should (equal (eshell-test-command-result "echo ${*echo \"1\n2\"}3")
+                 '(1 23)))
+  ;; ... but concatenating to a string that looks like a number in a list
+  ;; should produce a string.
+  (should (equal (eshell-test-command-result "echo ${*echo \"hi\n2\"}3")
+                 '("hi" "23"))))
 
 (ert-deftest esh-var-test/interp-concat-cmd2 ()
   "Interpolate and concat two commands"
@@ -326,6 +335,12 @@ inside double-quotes"
   "Interpolate command result redirected to temp file inside double-quotes"
   (should (equal (eshell-test-command-result "cat \"$<echo hi>\"") "hi")))
 
+(ert-deftest esh-var-test/quoted-interp-concat-cmd ()
+  "Interpolate and concat command with literal"
+  (should (equal (eshell-test-command-result
+                  "echo \"${echo \\\"foo\nbar\\\"} baz\"")
+                 "foo\nbar baz")))
+
 
 ;; Interpolated variable conversion
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]