From dd5a423c1d9f2c033e44abe5dae3f5a3a312802b Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Sat, 2 Sep 2023 22:29:22 -0700 Subject: [PATCH 1/2] Mark all backslash-escaped characters in Eshell as 'escaped' * lisp/eshell/esh-arg.el (eshell-parse-backslash): Mark all backslash-escaped characters with the 'escaped' property, even if they're non-special. * test/lisp/eshell/esh-arg-tests.el (esh-arg-test/escape/backslash-nonspecial) (esh-arg-test/escape/backslash-nonspecial-unicode) (esh-arg-test/escape/backslash-special) (esh-arg-test/escape/backslash-newline) (esh-arg-test/escape/backslash-newline-conditional) (esh-arg-test/escape-quoted/backslash-nonspecial) (esh-arg-test/escape-quoted/backslash-special) (esh-arg-test/escape-quoted/backslash-newline): Rename tests, and check string properties. (esh-arg-test/escape-quoted/basic) (esh-arg-test/escape-single-quoted/basic) (esh-arg-test/escape-single-quoted/single-quote): New tests. --- lisp/eshell/esh-arg.el | 7 +- test/lisp/eshell/esh-arg-tests.el | 124 +++++++++++++++++------------- 2 files changed, 74 insertions(+), 57 deletions(-) diff --git a/lisp/eshell/esh-arg.el b/lisp/eshell/esh-arg.el index 78cf28d785a..b62f0893e89 100644 --- a/lisp/eshell/esh-arg.el +++ b/lisp/eshell/esh-arg.el @@ -477,15 +477,14 @@ eshell-parse-backslash ;; multiple lines. ((eq (char-before) ?\n) 'eshell-empty-token) - ((memq (char-before) special-chars) - (list 'eshell-escape-arg (char-to-string (char-before)))) ;; If the char is in a quote, backslash only has special ;; meaning if it is escaping a special char. Otherwise, the ;; result is the literal string "\c". - (eshell-current-quoted + ((and eshell-current-quoted + (not (memq (char-before) special-chars))) (concat "\\" (char-to-string (char-before)))) (t - (char-to-string (char-before))))))) + (list 'eshell-escape-arg (char-to-string (char-before)))))))) (defun eshell-parse-literal-quote () "Parse a literally quoted string. Nothing has special meaning!" diff --git a/test/lisp/eshell/esh-arg-tests.el b/test/lisp/eshell/esh-arg-tests.el index b748c5ab4c0..8c139cee589 100644 --- a/test/lisp/eshell/esh-arg-tests.el +++ b/test/lisp/eshell/esh-arg-tests.el @@ -36,42 +36,40 @@ eshell-test-value ;;; Tests: -(ert-deftest esh-arg-test/escape/nonspecial () - "Test that \"\\c\" and \"c\" are equivalent when \"c\" is not a -special character." - (with-temp-eshell - (eshell-match-command-output "echo he\\llo" - "hello\n"))) - -(ert-deftest esh-arg-test/escape/nonspecial-unicode () - "Test that \"\\c\" and \"c\" are equivalent when \"c\" is a -unicode character (unicode characters are nonspecial by -definition)." - (with-temp-eshell - (eshell-match-command-output "echo Vid\\éos" - "Vidéos\n"))) - -(ert-deftest esh-arg-test/escape/special () - "Test that the backslash is not preserved for escaped special -chars." - (with-temp-eshell - (eshell-match-command-output "echo he\\\\llo" - ;; Backslashes are doubled for regexp. - "he\\\\llo\n"))) - -(ert-deftest esh-arg-test/escape/newline () - "Test that an escaped newline is equivalent to the empty string." - (with-temp-eshell - (eshell-match-command-output "echo hi\\\nthere" - "hithere\n"))) - -(ert-deftest esh-arg-test/escape/trailing-newline () - "Test that an escaped newline is equivalent to the empty string." +(ert-deftest esh-arg-test/escape/backslash-nonspecial () + "Test that \"\\c\" expands to \"c\" when \"c\" is not a special character. +It should mark \"c\" as being escaped, though." + (should (equal-including-properties + (eshell-test-command-result "echo he\\llo") + #("hello" 2 3 (escaped t))))) + +(ert-deftest esh-arg-test/escape/backslash-nonspecial-unicode () + "Test that \"\\c\" expands to \"c\" when \"c\" is a Unicode character. +Unicode characters are nonspecial by definition. As above, this +would mark \"c\" as escaped." + (should (equal-including-properties + (eshell-test-command-result "echo Vid\\éos") + #("Vidéos" 3 4 (escaped t))))) + +(ert-deftest esh-arg-test/escape/backslash-special () + "Test that the backslash is removed for escaped special characters." + (should (equal-including-properties + (eshell-test-command-result "echo he\\\\llo") + #("he\\llo" 2 3 (escaped t))))) + +(ert-deftest esh-arg-test/escape/backslash-newline () + "Test that an escaped newline expands to the empty string." + (should (equal-including-properties + (eshell-test-command-result "echo hi\\\nthere") + "hithere"))) + +(ert-deftest esh-arg-test/escape/trailing-backslash-newline () + "Test that an escaped newline expands to the empty string." (with-temp-eshell (eshell-match-command-output "echo hi\\\n" "hi\n"))) -(ert-deftest esh-arg-test/escape/newline-conditional () +(ert-deftest esh-arg-test/escape/backslash-newline-conditional () "Test invocation of an if/else statement using line continuations." (let ((eshell-test-value t)) (eshell-command-result-equal @@ -82,27 +80,47 @@ esh-arg-test/escape/newline-conditional "if $eshell-test-value \\\n{echo yes} \\\n{echo no}" "no"))) -(ert-deftest esh-arg-test/escape-quoted/nonspecial () - "Test that the backslash is preserved for escaped nonspecial -chars." - (with-temp-eshell - (eshell-match-command-output "echo \"h\\i\"" - ;; Backslashes are doubled for regexp. - "h\\\\i\n"))) - -(ert-deftest esh-arg-test/escape-quoted/special () - "Test that the backslash is not preserved for escaped special -chars." - (with-temp-eshell - (eshell-match-command-output "echo \"\\\"hi\\\\\"" - ;; Backslashes are doubled for regexp. - "\\\"hi\\\\\n"))) - -(ert-deftest esh-arg-test/escape-quoted/newline () - "Test that an escaped newline is equivalent to the empty string." - (with-temp-eshell - (eshell-match-command-output "echo \"hi\\\nthere\"" - "hithere\n"))) +(ert-deftest esh-arg-test/escape-quoted/basic () + "Test that double-quoted text is marked as escaped." + (should (equal-including-properties + (eshell-test-command-result "echo \"hi\"") + #("hi" 0 2 (escaped t)))) + (should (equal-including-properties + (eshell-test-command-result "echo \"hi\"there") + #("hithere" 0 2 (escaped t))))) + +(ert-deftest esh-arg-test/escape-quoted/backslash-nonspecial () + "Test that in double-quotes, \"\\\" is preserved before nonspecial chars." + (should (equal-including-properties + (eshell-test-command-result "echo \"h\\i\"") + #("h\\i" 0 3 (escaped t))))) + +(ert-deftest esh-arg-test/escape-quoted/backslash-special () + "Test that in double-quotes, \"\\\" is not preserved before special chars." + (should (equal-including-properties + (eshell-test-command-result "echo \"\\\"hi\\\\\"") + #("\"hi\\" 0 4 (escaped t))))) + +(ert-deftest esh-arg-test/escape-quoted/backslash-newline () + "Test that in double-quotes, an escaped newline expands to the empty string." + (should (equal-including-properties + (eshell-test-command-result "echo \"hi\\\nthere\"") + #("hithere" 0 7 (escaped t))))) + +(ert-deftest esh-arg-test/escape-single-quoted/basic () + "Test that single-quoted text is marked as escaped." + (should (equal-including-properties + (eshell-test-command-result "echo 'hi'") + #("hi" 0 2 (escaped t)))) + (should (equal-including-properties + (eshell-test-command-result "echo 'hi'there") + #("hithere" 0 2 (escaped t))))) + +(ert-deftest esh-arg-test/escape-single-quoted/single-quote () + "Test that a doubled single-quote inside single-quotes is one single-quote." + (should (equal-including-properties + (eshell-test-command-result "echo 'it''s me'") + #("it's me" 0 7 (escaped t))))) (ert-deftest esh-arg-test/special-reference/default () "Test that \"#\" refers to the buffer \"buf\"." -- 2.25.1