diff options
| author | Jim Porter | 2024-10-19 11:52:42 -0700 |
|---|---|---|
| committer | Jim Porter | 2024-10-19 12:01:10 -0700 |
| commit | 43d5b7a04c4b1a8a7d57f25824df2e8720d2c567 (patch) | |
| tree | 189201134e9e92c6bbf156ebb772f573f65cf71f /test/lisp/eshell | |
| parent | c2a9f519f7e9a5cbb5dbe50ba7b4e4b2757bb3b6 (diff) | |
| download | emacs-43d5b7a04c4b1a8a7d57f25824df2e8720d2c567.tar.gz emacs-43d5b7a04c4b1a8a7d57f25824df2e8720d2c567.zip | |
Lazily convert numeric strings to Lisp numbers in Eshell
This should reduce the number of issues with Eshell converting strings
to numbers too aggressively and losing information (e.g. "001" -> 1)
while still allowing almost all of the beneficial uses, like summing a
list of numeric strings with '+'.
* lisp/eshell/esh-util.el (eshell--do-mark-numeric-string): New
function.
(eshell-convert-to-number): Make obsolete in favor of...
(eshell-mark-numeric-string): ... this. Update callers.
* lisp/eshell/esh-arg.el (eshell--numberlike-p): New function...
(eshell-concat-1): ... use it.
* test/lisp/eshell/esh-util-tests.el: Reimplement type conversion tests
to use 'eshell-convertible-to-number-p' instead.
* test/lisp/eshell/esh-var-tests.el
(esh-var-test/interp-var-splice-concat, esh-var-test/interp-concat-cmd)
(esh-var-test/interp-convert-var-split-indices)
(esh-var-test/interp-convert-quoted-var-split-indices)
(esh-var-test/interp-convert-cmd-multiline)
(esh-var-test/interp-convert-cmd-split-indices): Adjust tests to check
the new behavior.
* doc/misc/eshell.texi (Type Conversion): New section.
(Expansion): Clarify concatenation behavior.
Diffstat (limited to 'test/lisp/eshell')
| -rw-r--r-- | test/lisp/eshell/esh-util-tests.el | 114 | ||||
| -rw-r--r-- | test/lisp/eshell/esh-var-tests.el | 29 |
2 files changed, 83 insertions, 60 deletions
diff --git a/test/lisp/eshell/esh-util-tests.el b/test/lisp/eshell/esh-util-tests.el index 031de558d1f..4a0874bff39 100644 --- a/test/lisp/eshell/esh-util-tests.el +++ b/test/lisp/eshell/esh-util-tests.el | |||
| @@ -66,70 +66,70 @@ | |||
| 66 | "Test that `eshell-stringify' correctly stringifies complex objects." | 66 | "Test that `eshell-stringify' correctly stringifies complex objects." |
| 67 | (should (equal (eshell-stringify (list 'quote 'hello)) "'hello"))) | 67 | (should (equal (eshell-stringify (list 'quote 'hello)) "'hello"))) |
| 68 | 68 | ||
| 69 | (ert-deftest esh-util-test/eshell-convert-to-number/integer () | 69 | (ert-deftest esh-util-test/eshell-convertible-to-number-p/integer () |
| 70 | "Test that `eshell-convert-to-number' correctly converts integers." | 70 | "Test that `eshell-convertible-to-number-p' matches integers." |
| 71 | (should (equal (eshell-convert-to-number "123") 123)) | 71 | (should (eshell-convertible-to-number-p "123")) |
| 72 | (should (equal (eshell-convert-to-number "-123") -123)) | 72 | (should (eshell-convertible-to-number-p "-123")) |
| 73 | ;; These are technially integers, since Emacs Lisp requires at least | 73 | ;; These are technially integers, since Emacs Lisp requires at least |
| 74 | ;; one digit after the "." to be a float: | 74 | ;; one digit after the "." to be a float: |
| 75 | (should (equal (eshell-convert-to-number "123.") 123)) | 75 | (should (eshell-convertible-to-number-p "123.")) |
| 76 | (should (equal (eshell-convert-to-number "-123.") -123))) | 76 | (should (eshell-convertible-to-number-p "-123."))) |
| 77 | 77 | ||
| 78 | (ert-deftest esh-util-test/eshell-convert-to-number/floating-point () | 78 | (ert-deftest esh-util-test/eshell-convertible-to-number-p/float () |
| 79 | "Test that `eshell-convert-to-number' correctly converts floats." | 79 | "Test that `eshell-convertible-to-number-p' matches floats." |
| 80 | (should (equal (eshell-convert-to-number "1.23") 1.23)) | 80 | (should (eshell-convertible-to-number-p "1.23")) |
| 81 | (should (equal (eshell-convert-to-number "-1.23") -1.23)) | 81 | (should (eshell-convertible-to-number-p "-1.23")) |
| 82 | (should (equal (eshell-convert-to-number ".1") 0.1)) | 82 | (should (eshell-convertible-to-number-p ".1")) |
| 83 | (should (equal (eshell-convert-to-number "-.1") -0.1))) | 83 | (should (eshell-convertible-to-number-p "-.1"))) |
| 84 | 84 | ||
| 85 | (ert-deftest esh-util-test/eshell-convert-to-number/floating-point-exponent () | 85 | (ert-deftest esh-util-test/eshell-convertible-to-number-p/float-exponent () |
| 86 | "Test that `eshell-convert-to-number' correctly converts exponent notation." | 86 | "Test that `eshell-convertible-to-number-p' matches exponent notation." |
| 87 | ;; Positive exponent: | 87 | ;; Positive exponent: |
| 88 | (dolist (exp '("e2" "e+2" "E2" "E+2")) | 88 | (dolist (exp '("e2" "e+2" "E2" "E+2")) |
| 89 | (should (equal (eshell-convert-to-number (concat "123" exp)) 12300.0)) | 89 | (should (eshell-convertible-to-number-p (concat "123" exp))) |
| 90 | (should (equal (eshell-convert-to-number (concat "-123" exp)) -12300.0)) | 90 | (should (eshell-convertible-to-number-p (concat "-123" exp))) |
| 91 | (should (equal (eshell-convert-to-number (concat "1.23" exp)) 123.0)) | 91 | (should (eshell-convertible-to-number-p (concat "1.23" exp))) |
| 92 | (should (equal (eshell-convert-to-number (concat "-1.23" exp)) -123.0)) | 92 | (should (eshell-convertible-to-number-p (concat "-1.23" exp))) |
| 93 | (should (equal (eshell-convert-to-number (concat "1." exp)) 100.0)) | 93 | (should (eshell-convertible-to-number-p (concat "1." exp))) |
| 94 | (should (equal (eshell-convert-to-number (concat "-1." exp)) -100.0)) | 94 | (should (eshell-convertible-to-number-p (concat "-1." exp))) |
| 95 | (should (equal (eshell-convert-to-number (concat ".1" exp)) 10.0)) | 95 | (should (eshell-convertible-to-number-p (concat ".1" exp))) |
| 96 | (should (equal (eshell-convert-to-number (concat "-.1" exp)) -10.0))) | 96 | (should (eshell-convertible-to-number-p (concat "-.1" exp)))) |
| 97 | ;; Negative exponent: | 97 | ;; Negative exponent: |
| 98 | (dolist (exp '("e-2" "E-2")) | 98 | (dolist (exp '("e-2" "E-2")) |
| 99 | (should (equal (eshell-convert-to-number (concat "123" exp)) 1.23)) | 99 | (should (eshell-convertible-to-number-p (concat "123" exp))) |
| 100 | (should (equal (eshell-convert-to-number (concat "-123" exp)) -1.23)) | 100 | (should (eshell-convertible-to-number-p (concat "-123" exp))) |
| 101 | (should (equal (eshell-convert-to-number (concat "1.23" exp)) 0.0123)) | 101 | (should (eshell-convertible-to-number-p (concat "1.23" exp))) |
| 102 | (should (equal (eshell-convert-to-number (concat "-1.23" exp)) -0.0123)) | 102 | (should (eshell-convertible-to-number-p (concat "-1.23" exp))) |
| 103 | (should (equal (eshell-convert-to-number (concat "1." exp)) 0.01)) | 103 | (should (eshell-convertible-to-number-p (concat "1." exp))) |
| 104 | (should (equal (eshell-convert-to-number (concat "-1." exp)) -0.01)) | 104 | (should (eshell-convertible-to-number-p (concat "-1." exp))) |
| 105 | (should (equal (eshell-convert-to-number (concat ".1" exp)) 0.001)) | 105 | (should (eshell-convertible-to-number-p (concat ".1" exp))) |
| 106 | (should (equal (eshell-convert-to-number (concat "-.1" exp)) -0.001)))) | 106 | (should (eshell-convertible-to-number-p (concat "-.1" exp))))) |
| 107 | 107 | ||
| 108 | (ert-deftest esh-util-test/eshell-convert-to-number/floating-point/infinite () | 108 | (ert-deftest esh-util-test/eshell-convertible-to-number-p/float/infinite () |
| 109 | "Test that `eshell-convert-to-number' correctly converts infinite floats." | 109 | "Test that `eshell-convertible-to-number-p' matches infinite floats." |
| 110 | (should (equal (eshell-convert-to-number "1.0e+INF") 1.0e+INF)) | 110 | (should (eshell-convertible-to-number-p "1.0e+INF")) |
| 111 | (should (equal (eshell-convert-to-number "2.e+INF") 1.0e+INF)) | 111 | (should (eshell-convertible-to-number-p "2.e+INF")) |
| 112 | (should (equal (eshell-convert-to-number "-1.0e+INF") -1.0e+INF)) | 112 | (should (eshell-convertible-to-number-p "-1.0e+INF")) |
| 113 | (should (equal (eshell-convert-to-number "-2.e+INF") -1.0e+INF))) | 113 | (should (eshell-convertible-to-number-p "-2.e+INF"))) |
| 114 | 114 | ||
| 115 | (ert-deftest esh-util-test/eshell-convert-to-number/floating-point/nan () | 115 | (ert-deftest esh-util-test/eshell-convertible-to-number-p/float/nan () |
| 116 | "Test that `eshell-convert-to-number' correctly converts NaNs." | 116 | "Test that `eshell-convertible-to-number-p' matches NaNs." |
| 117 | (should (equal (eshell-convert-to-number "1.0e+NaN") 1.0e+NaN)) | 117 | (should (eshell-convertible-to-number-p "1.0e+NaN")) |
| 118 | (should (equal (eshell-convert-to-number "2.e+NaN") 2.0e+NaN)) | 118 | (should (eshell-convertible-to-number-p "2.e+NaN")) |
| 119 | (should (equal (eshell-convert-to-number "-1.0e+NaN") -1.0e+NaN)) | 119 | (should (eshell-convertible-to-number-p "-1.0e+NaN")) |
| 120 | (should (equal (eshell-convert-to-number "-2.e+NaN") -2.0e+NaN))) | 120 | (should (eshell-convertible-to-number-p "-2.e+NaN"))) |
| 121 | 121 | ||
| 122 | (ert-deftest esh-util-test/eshell-convert-to-number/non-numeric () | 122 | (ert-deftest esh-util-test/eshell-convertible-to-number-p/non-numeric () |
| 123 | "Test that `eshell-convert-to-number' does nothing to non-numeric values." | 123 | "Test that `eshell-convertible-to-number-p' returns nil for non-numerics." |
| 124 | (should (equal (eshell-convert-to-number "foo") "foo")) | 124 | (should-not (eshell-convertible-to-number-p "foo")) |
| 125 | (should (equal (eshell-convert-to-number "") "")) | 125 | (should-not (eshell-convertible-to-number-p "")) |
| 126 | (should (equal (eshell-convert-to-number "123foo") "123foo"))) | 126 | (should-not (eshell-convertible-to-number-p "123foo"))) |
| 127 | 127 | ||
| 128 | (ert-deftest esh-util-test/eshell-convert-to-number/no-convert () | 128 | (ert-deftest esh-util-test/eshell-convertible-to-number-p/no-convert () |
| 129 | "Test that `eshell-convert-to-number' does nothing when disabled." | 129 | "Test that `eshell-convertible-to-number-p' returns nil when disabled." |
| 130 | (let ((eshell-convert-numeric-arguments nil)) | 130 | (let ((eshell-convert-numeric-arguments nil)) |
| 131 | (should (equal (eshell-convert-to-number "123") "123")) | 131 | (should-not (eshell-convertible-to-number-p "123")) |
| 132 | (should (equal (eshell-convert-to-number "1.23") "1.23")))) | 132 | (should-not (eshell-convertible-to-number-p "1.23")))) |
| 133 | 133 | ||
| 134 | (ert-deftest esh-util-test/eshell-printable-size () | 134 | (ert-deftest esh-util-test/eshell-printable-size () |
| 135 | (should (equal (eshell-printable-size (expt 2 16)) "65536")) | 135 | (should (equal (eshell-printable-size (expt 2 16)) "65536")) |
diff --git a/test/lisp/eshell/esh-var-tests.el b/test/lisp/eshell/esh-var-tests.el index 7ac9807a1a7..70f6e9c7777 100644 --- a/test/lisp/eshell/esh-var-tests.el +++ b/test/lisp/eshell/esh-var-tests.el | |||
| @@ -231,7 +231,7 @@ nil, use FUNCTION instead." | |||
| 231 | ;; into the first value of the non-spliced list. | 231 | ;; into the first value of the non-spliced list. |
| 232 | (eshell-command-result-equal | 232 | (eshell-command-result-equal |
| 233 | "echo it is $@'eshell-test-value'$eshell-test-value" | 233 | "echo it is $@'eshell-test-value'$eshell-test-value" |
| 234 | '("it" "is" 1 2 (31 2 3))))) | 234 | '("it" "is" 1 2 ("31" 2 3))))) |
| 235 | 235 | ||
| 236 | (ert-deftest esh-var-test/interp-lisp () | 236 | (ert-deftest esh-var-test/interp-lisp () |
| 237 | "Interpolate Lisp form evaluation." | 237 | "Interpolate Lisp form evaluation." |
| @@ -280,12 +280,16 @@ nil, use FUNCTION instead." | |||
| 280 | (eshell-command-result-equal "+ ${+ 1 2}3 3" 36) | 280 | (eshell-command-result-equal "+ ${+ 1 2}3 3" 36) |
| 281 | (eshell-command-result-equal "echo ${*echo \"foo\nbar\"}-baz" | 281 | (eshell-command-result-equal "echo ${*echo \"foo\nbar\"}-baz" |
| 282 | '("foo" "bar-baz")) | 282 | '("foo" "bar-baz")) |
| 283 | ;; Concatenating to a number in a list should produce a number... | 283 | ;; Concatenating to a number in a list should produce a numeric value... |
| 284 | (eshell-command-result-equal "echo ${*echo \"1\n2\"}3" | 284 | (eshell-command-result-equal "echo ${*echo \"1\n2\"}3" |
| 285 | '("1" "23")) | ||
| 286 | (eshell-command-result-equal "echo $@{*echo \"1\n2\"}3" | ||
| 285 | '(1 23)) | 287 | '(1 23)) |
| 286 | ;; ... but concatenating to a string that looks like a number in a list | 288 | ;; ... but concatenating to a string that looks like a number in a list |
| 287 | ;; should produce a string. | 289 | ;; should produce a string. |
| 288 | (eshell-command-result-equal "echo ${*echo \"hi\n2\"}3" | 290 | (eshell-command-result-equal "echo ${*echo \"hi\n2\"}3" |
| 291 | '("hi" "23")) | ||
| 292 | (eshell-command-result-equal "echo $@{*echo \"hi\n2\"}3" | ||
| 289 | '("hi" "23"))) | 293 | '("hi" "23"))) |
| 290 | 294 | ||
| 291 | (ert-deftest esh-var-test/interp-concat-cmd2 () | 295 | (ert-deftest esh-var-test/interp-concat-cmd2 () |
| @@ -491,11 +495,16 @@ nil, use FUNCTION instead." | |||
| 491 | 495 | ||
| 492 | (ert-deftest esh-var-test/interp-convert-var-split-indices () | 496 | (ert-deftest esh-var-test/interp-convert-var-split-indices () |
| 493 | "Interpolate and convert string variable with indices." | 497 | "Interpolate and convert string variable with indices." |
| 494 | ;; Check that numeric forms are converted to numbers. | 498 | ;; Check that numeric forms are marked as numeric. |
| 495 | (let ((eshell-test-value "000 010 020 030 040")) | 499 | (let ((eshell-test-value "000 010 020 030 040")) |
| 500 | ;; `eshell/echo' converts numeric strings to Lisp numbers... | ||
| 496 | (eshell-command-result-equal "echo $eshell-test-value[0]" | 501 | (eshell-command-result-equal "echo $eshell-test-value[0]" |
| 497 | 0) | 502 | 0) |
| 503 | ;; ... but not lists of numeric strings... | ||
| 498 | (eshell-command-result-equal "echo $eshell-test-value[0 2]" | 504 | (eshell-command-result-equal "echo $eshell-test-value[0 2]" |
| 505 | '("000" "020")) | ||
| 506 | ;; ... unless each element is a separate argument to `eshell/echo'. | ||
| 507 | (eshell-command-result-equal "echo $@eshell-test-value[0 2]" | ||
| 499 | '(0 20))) | 508 | '(0 20))) |
| 500 | ;; Check that multiline forms are preserved as-is. | 509 | ;; Check that multiline forms are preserved as-is. |
| 501 | (let ((eshell-test-value "foo\nbar:baz\n")) | 510 | (let ((eshell-test-value "foo\nbar:baz\n")) |
| @@ -515,9 +524,14 @@ nil, use FUNCTION instead." | |||
| 515 | (ert-deftest esh-var-test/interp-convert-quoted-var-split-indices () | 524 | (ert-deftest esh-var-test/interp-convert-quoted-var-split-indices () |
| 516 | "Interpolate and convert quoted string variable with indices." | 525 | "Interpolate and convert quoted string variable with indices." |
| 517 | (let ((eshell-test-value "000 010 020 030 040")) | 526 | (let ((eshell-test-value "000 010 020 030 040")) |
| 527 | ;; `eshell/echo' converts numeric strings to Lisp numbers... | ||
| 518 | (eshell-command-result-equal "echo $'eshell-test-value'[0]" | 528 | (eshell-command-result-equal "echo $'eshell-test-value'[0]" |
| 519 | 0) | 529 | 0) |
| 530 | ;; ... but not lists of numeric strings... | ||
| 520 | (eshell-command-result-equal "echo $'eshell-test-value'[0 2]" | 531 | (eshell-command-result-equal "echo $'eshell-test-value'[0 2]" |
| 532 | '("000" "020")) | ||
| 533 | ;; ... unless each element is a separate argument to `eshell/echo'. | ||
| 534 | (eshell-command-result-equal "echo $@'eshell-test-value'[0 2]" | ||
| 521 | '(0 20)))) | 535 | '(0 20)))) |
| 522 | 536 | ||
| 523 | (ert-deftest esh-var-test/interp-convert-cmd-string-newline () | 537 | (ert-deftest esh-var-test/interp-convert-cmd-string-newline () |
| @@ -530,9 +544,13 @@ nil, use FUNCTION instead." | |||
| 530 | '("foo" "bar")) | 544 | '("foo" "bar")) |
| 531 | ;; Numeric output should be converted to numbers... | 545 | ;; Numeric output should be converted to numbers... |
| 532 | (eshell-command-result-equal "echo ${echo \"01\n02\n03\"}" | 546 | (eshell-command-result-equal "echo ${echo \"01\n02\n03\"}" |
| 547 | '("01" "02" "03")) | ||
| 548 | (eshell-command-result-equal "echo $@{echo \"01\n02\n03\"}" | ||
| 533 | '(1 2 3)) | 549 | '(1 2 3)) |
| 534 | ;; ... but only if every line is numeric. | 550 | ;; ... but only if every line is numeric. |
| 535 | (eshell-command-result-equal "echo ${echo \"01\n02\nhi\"}" | 551 | (eshell-command-result-equal "echo ${echo \"01\n02\nhi\"}" |
| 552 | '("01" "02" "hi")) | ||
| 553 | (eshell-command-result-equal "echo $@{echo \"01\n02\nhi\"}" | ||
| 536 | '("01" "02" "hi"))) | 554 | '("01" "02" "hi"))) |
| 537 | 555 | ||
| 538 | (ert-deftest esh-var-test/interp-convert-cmd-number () | 556 | (ert-deftest esh-var-test/interp-convert-cmd-number () |
| @@ -541,9 +559,14 @@ nil, use FUNCTION instead." | |||
| 541 | 559 | ||
| 542 | (ert-deftest esh-var-test/interp-convert-cmd-split-indices () | 560 | (ert-deftest esh-var-test/interp-convert-cmd-split-indices () |
| 543 | "Interpolate command result with indices." | 561 | "Interpolate command result with indices." |
| 562 | ;; `eshell/echo' converts numeric strings to Lisp numbers... | ||
| 544 | (eshell-command-result-equal "echo ${echo \"000 010 020\"}[0]" | 563 | (eshell-command-result-equal "echo ${echo \"000 010 020\"}[0]" |
| 545 | 0) | 564 | 0) |
| 565 | ;; ... but not lists of numeric strings... | ||
| 546 | (eshell-command-result-equal "echo ${echo \"000 010 020\"}[0 2]" | 566 | (eshell-command-result-equal "echo ${echo \"000 010 020\"}[0 2]" |
| 567 | '("000" "020")) | ||
| 568 | ;; ... unless each element is a separate argument to `eshell/echo'. | ||
| 569 | (eshell-command-result-equal "echo $@{echo \"000 010 020\"}[0 2]" | ||
| 547 | '(0 20))) | 570 | '(0 20))) |
| 548 | 571 | ||
| 549 | (ert-deftest esh-var-test/quoted-interp-convert-var-number () | 572 | (ert-deftest esh-var-test/quoted-interp-convert-var-number () |