]> git.eshelyaron.com Git - emacs.git/commitdiff
Return a list of numbers if all lines of an Eshell subcommand are numeric
authorJim Porter <jporterbugs@gmail.com>
Mon, 2 May 2022 05:09:17 +0000 (22:09 -0700)
committerLars Ingebrigtsen <larsi@gnus.org>
Tue, 3 May 2022 16:23:00 +0000 (18:23 +0200)
* lisp/eshell/esh-util.el (eshell-convertible-to-number-p)
(eshell-convert-to-number): New functions...
(eshell-convert): ... use them.

* test/lisp/eshell/esh-var-tests.el
(esh-var-test/interp-convert-cmd-string-newline): Add checks for
numeric output.

* doc/misc/eshell.texi (Dollars Expansion): Document the new behavior.

* etc/NEWS: Announce the change (bug#55236).

doc/misc/eshell.texi
etc/NEWS
lisp/eshell/esh-util.el
test/lisp/eshell/esh-var-tests.el

index fff06b527cf68ea598d2f779c890dbf2dd88bfd9..be32b2aced40b602cc862203e148cb51cc92fbba 100644 (file)
@@ -1061,9 +1061,11 @@ when on its own, but the @code{$} allows it to be used inside double
 quotes or as part of a string.
 
 Normally, the output is split line-by-line, returning a list (or the
-first element if there's only one line of output).  However, when this
-expansion is surrounded by double quotes, it returns the output as a
-single string instead.
+first element if there's only one line of output); if
+@code{eshell-convert-numeric-arguments} is non-@code{nil} and every
+line of output looks like a number, convert each line to a number.
+However, when this expansion is surrounded by double quotes, it
+returns the output as a single string instead.
 
 @item $<@var{command}>
 As with @samp{$@{@var{command}@}}, evaluates the Eshell command invocation
index 967fe6cffe23cb40ef4aa362d5fa726b7d0ca5c9..592b4b788868db2cfe2fed42b9035fedb3c5cf7b 100644 (file)
--- 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.
 
++++
+*** Eshell subcommands with multiline numeric output return lists of numbers.
+If every line of the output of an Eshell subcommand like '${COMMAND}'
+is numeric, the result will be a list of numbers (or a single number
+if only one line of output).  Previously, this only converted numbers
+when there was a single line of output.
+
 ---
 *** Built-in Eshell commands now follow POSIX/GNU argument syntax conventions.
 Built-in commands in Eshell now accept command-line options with
index 6c130974e95efa65c1c1db7b650f63594bb5d200..9960912bce8c34d47dd7f051b32281e13a988a67 100644 (file)
@@ -198,6 +198,23 @@ doubling it up."
       (when (= depth 0)
         (if reverse-p (point) (1- (point)))))))
 
+(defun eshell-convertible-to-number-p (string)
+  "Return non-nil if STRING can be converted to a number.
+If `eshell-convert-numeric-aguments', always return nil."
+  (and eshell-convert-numeric-arguments
+       (string-match
+        (concat "\\`\\s-*" eshell-number-regexp "\\s-*\\'")
+        string)))
+
+(defun eshell-convert-to-number (string)
+  "Try to convert STRING to a number.
+If STRING doesn't look like a number (or
+`eshell-convert-numeric-aguments' is nil), just return STRING
+unchanged."
+  (if (eshell-convertible-to-number-p string)
+      (string-to-number string)
+    string))
+
 (defun eshell-convert (string &optional to-string)
   "Convert STRING into a more-native Lisp object.
 If TO-STRING is non-nil, always return a single string with
@@ -207,8 +224,8 @@ trailing newlines removed.  Otherwise, this behaves as follows:
 
 * Split multiline strings by line.
 
-* If `eshell-convert-numeric-aguments' is non-nil, convert
-  numeric strings to numbers."
+* If `eshell-convert-numeric-aguments' is non-nil and every line
+  of output looks like a number, convert them to numbers."
   (cond
    ((not (stringp string))
     (if to-string
@@ -220,15 +237,12 @@ trailing newlines removed.  Otherwise, this behaves as follows:
            string
          (when (eq (aref string (1- len)) ?\n)
            (setq string (substring string 0 (1- len))))
-          (cond
-           ((string-search "\n" string)
-            (split-string string "\n"))
-           ((and eshell-convert-numeric-arguments
-                (string-match
-                  (concat "\\`\\s-*" eshell-number-regexp "\\s-*\\'")
-                  string))
-            (string-to-number string))
-           (t string)))))))
+          (if (string-search "\n" string)
+              (let ((lines (split-string string "\n")))
+                (if (seq-every-p #'eshell-convertible-to-number-p lines)
+                    (mapcar #'string-to-number lines)
+                  lines))
+            (eshell-convert-to-number string)))))))
 
 (defvar-local eshell-path-env (getenv "PATH")
   "Content of $PATH.
index 5363a86e718fabbb96e1d6bba40a50a214c7e44d..2ce6bb4f1bac0f95731e94ba563c0b91c89068a1 100644 (file)
@@ -366,7 +366,13 @@ inside double-quotes"
 (ert-deftest esh-var-test/interp-convert-cmd-multiline ()
   "Interpolate multi-line command result"
   (should (equal (eshell-test-command-result "echo ${echo \"foo\nbar\"}")
-                 '("foo" "bar"))))
+                 '("foo" "bar")))
+  ;; Numeric output should be converted to numbers...
+  (should (equal (eshell-test-command-result "echo ${echo \"01\n02\n03\"}")
+                 '(1 2 3)))
+  ;; ... but only if every line is numeric.
+  (should (equal (eshell-test-command-result "echo ${echo \"01\n02\nhi\"}")
+                 '("01" "02" "hi"))))
 
 (ert-deftest esh-var-test/interp-convert-cmd-number ()
   "Interpolate numeric command result"