From d675817d056100bfa909d7ea88cb89f952474992 Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Sun, 1 May 2022 22:09:17 -0700 Subject: [PATCH 2/3] Return a list of numbers if all lines of an Eshell subcommand are numeric * 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 | 8 ++++--- etc/NEWS | 7 ++++++ lisp/eshell/esh-util.el | 36 +++++++++++++++++++++---------- test/lisp/eshell/esh-var-tests.el | 8 ++++++- 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi index 164a71f309..53f7fdd9ea 100644 --- a/doc/misc/eshell.texi +++ b/doc/misc/eshell.texi @@ -1061,9 +1061,11 @@ Dollars Expansion 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-agument} 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 diff --git a/etc/NEWS b/etc/NEWS index ae815bb785..0c77b0bf58 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1376,6 +1376,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 diff --git a/lisp/eshell/esh-util.el b/lisp/eshell/esh-util.el index 6c130974e9..9960912bce 100644 --- a/lisp/eshell/esh-util.el +++ b/lisp/eshell/esh-util.el @@ -198,6 +198,23 @@ eshell-find-delimiter (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 @@ eshell-convert * 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 @@ eshell-convert 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. diff --git a/test/lisp/eshell/esh-var-tests.el b/test/lisp/eshell/esh-var-tests.el index 5363a86e71..2ce6bb4f1b 100644 --- a/test/lisp/eshell/esh-var-tests.el +++ b/test/lisp/eshell/esh-var-tests.el @@ -366,7 +366,13 @@ esh-var-test/interp-convert-cmd-string-newline (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" -- 2.25.1