From 3d5d59f39d9309e341ad099801afdfa207f0f8e8 Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Fri, 1 Nov 2024 13:11:47 -0700 Subject: [PATCH] Remove 'eshell-escape-arg' Eshell no longer needs this function, since all command parsing is performed first, with special syntax annotated with text properties as needed, as opposed to marking literal text with a property (bug#54486). * lisp/eshell/em-pred.el (eshell-modifier-alist): Make "q" modifier obsolete. (eshell-modifier-help-string): Remove mention of "q". * lisp/eshell/esh-arg.el (eshell-escape-arg): Make obsolete. (eshell-parse-backslash, eshell-parse-literal-quote) (eshell-parse-double-quote): Don't call 'eshell-escape-arg'. * lisp/eshell/esh-var.el (eshell-parse-variable): Don't call 'eshell-escape-arg'. * test/lisp/eshell/em-extpipe-tests.el (em-extpipe-test-2) (em-extpipe-test-9, em-extpipe-test-11): Remove 'eshell-escape-arg'. * test/lisp/eshell/em-pred-tests.el (em-pred-test/modifier-quote): Remove test. * test/lisp/eshell/esh-var-tests.el (esh-var-test/quoted-interp-var-indices) (esh-var-test/quote-interp-var-indices-subcommand): Remove workaround in tests. * doc/misc/eshell.texi (Argument Modifiers): Remove documentation of obsolete "q" modifier. (cherry picked from commit b4655ff99b512f30220f22226514267d78a70605) --- doc/misc/eshell.texi | 5 -- lisp/eshell/em-pred.el | 79 +++++++++++++++++++++++++++- lisp/eshell/esh-arg.el | 72 ++++++++++++------------- lisp/eshell/esh-var.el | 1 - test/lisp/eshell/em-extpipe-tests.el | 8 ++- test/lisp/eshell/em-pred-tests.el | 6 --- test/lisp/eshell/esh-var-tests.el | 19 +++---- 7 files changed, 120 insertions(+), 70 deletions(-) diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi index 146fed6c8f8..5c56bdd2fb1 100644 --- a/doc/misc/eshell.texi +++ b/doc/misc/eshell.texi @@ -2255,11 +2255,6 @@ Treating the value as a file name, gets the file name excluding the final extension. For example, @samp{foo/bar/baz.tar.gz(:r)} expands to @samp{foo/bar/baz.tar}. -@item q -Marks that the value should be interpreted by Eshell literally, so -that any special characters like @samp{$} no longer have any special -meaning. - @item s/@var{pattern}/@var{replace}/ Replaces the first instance of the regular expression @var{pattern} with @var{replace}. Signals an error if no match is found. diff --git a/lisp/eshell/em-pred.el b/lisp/eshell/em-pred.el index 9618df055e2..47ebba5a776 100644 --- a/lisp/eshell/em-pred.el +++ b/lisp/eshell/em-pred.el @@ -121,7 +121,7 @@ The format of each entry is (?r . (lambda (lst) (mapcar #'file-name-sans-extension lst))) (?e . (lambda (lst) (mapcar #'file-name-extension lst))) (?t . (lambda (lst) (mapcar #'file-name-nondirectory lst))) - (?q . (lambda (lst) (mapcar #'eshell-escape-arg lst))) + (?q . #'identity) ; Obsolete as of Emacs 31.1. (?u . (lambda (lst) (seq-uniq lst))) (?o . (lambda (lst) (sort lst #'string-lessp))) (?O . (lambda (lst) (sort lst #'string-greaterp))) @@ -141,6 +141,83 @@ The format of each entry is :type '(repeat (cons character sexp)) :risky t) +(defvar eshell-predicate-help-string + "Eshell predicate quick reference: + + - follow symbolic references for predicates after the `-' + ^ invert sense of predicates after the `^' + +FILE TYPE: + / directories s sockets + . regular files p named pipes + * executable (files only) @ symbolic links + + %x file type == `x' (as by ls -l; so `c' = char device, etc.) + +PERMISSION BITS (for owner/group/world): + r/A/R readable s setuid + w/I/W writable S setgid + x/E/X executable t sticky bit + +OWNERSHIP: + U owned by effective uid + G owned by effective gid + u(UID|\\='user\\=') owned by UID/user + g(GID|\\='group\\=') owned by GID/group + +FILE ATTRIBUTES: + l[+-]N +/-/= N links + a[Mwhms][+-](N|\\='FILE\\=') access time +/-/= N months/weeks/hours/mins/secs + (days if unspecified) if FILE specified, + use as comparison basis; so a+\\='file.c\\=' + shows files accessed before file.c was + last accessed + m[Mwhms][+-](N|\\='FILE\\=') modification time... + c[Mwhms][+-](N|\\='FILE\\=') change time... + L[kmp][+-]N file size +/-/= N Kb/Mb/blocks + +EXAMPLES: + *(^@) all non-dot files which are not symlinks + .#*(^@) all files which are not symbolic links + **/.#*(*) all executable files, searched recursively + ***/*~f*(-/) recursively (though not traversing symlinks), + find all directories (or symlinks referring to + directories) whose names do not begin with f. + e*(*Lk+50) executables 50k or larger beginning with `e'") + +(defvar eshell-modifier-help-string + "Eshell modifier quick reference: + +FOR SINGLE ARGUMENTS, or each argument of a list of strings: + E evaluate again + L lowercase + U uppercase + C capitalize + h dirname + t basename + e file extension + r strip file extension + + S split string at any whitespace character + S/PAT/ split string at each occurrence of PAT + +FOR LISTS OF ARGUMENTS: + o sort alphabetically + O reverse sort alphabetically + u uniq list (typically used after :o or :O) + R reverse list + + j join list members, separated by a space + j/PAT/ join list members, separated by PAT + i/PAT/ exclude all members not matching PAT + x/PAT/ exclude all members matching PAT + + s/pat/match/ substitute PAT with MATCH + gs/pat/match/ substitute PAT with MATCH for all occurrences + +EXAMPLES: + *.c(:o) sorted list of .c files") + (defvar eshell-pred-delimiter-pairs '((?\( . ?\)) (?\[ . ?\]) diff --git a/lisp/eshell/esh-arg.el b/lisp/eshell/esh-arg.el index 7e8d6444a7a..22ae4630993 100644 --- a/lisp/eshell/esh-arg.el +++ b/lisp/eshell/esh-arg.el @@ -209,6 +209,7 @@ Eshell will expand special refs like \"#\" into (defsubst eshell-escape-arg (string) "Return STRING with the `escaped' property on it." + (declare (obsolete nil "31.1")) (if (stringp string) (add-text-properties 0 (length string) '(escaped t) string)) string) @@ -540,53 +541,46 @@ after are both returned." (when (= (1+ (point)) (point-max)) (throw 'eshell-incomplete "\\")) (forward-char 2) ; Move one char past the backslash. - (let ((special-chars (if eshell-current-quoted - eshell-special-chars-inside-quoting - eshell-special-chars-outside-quoting))) - (cond - ;; Escaped newlines are extra-special: they expand to an empty - ;; token to allow for continuing Eshell commands across - ;; 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 - (concat "\\" (char-to-string (char-before)))) - (t - (char-to-string (char-before))))))) + (cond + ;; Escaped newlines are extra-special: they expand to an empty + ;; token to allow for continuing Eshell commands across + ;; multiple lines. + ((eq (char-before) ?\n) + 'eshell-empty-token) + ;; 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". + ((and eshell-current-quoted + (not (memq (char-before) eshell-special-chars-inside-quoting))) + (concat "\\" (char-to-string (char-before)))) + (t + (char-to-string (char-before)))))) (defun eshell-parse-literal-quote () "Parse a literally quoted string. Nothing has special meaning!" - (if (eq (char-after) ?\') - (let ((end (eshell-find-delimiter ?\' ?\'))) - (if (not end) - (throw 'eshell-incomplete "'") - (let ((string (buffer-substring-no-properties (1+ (point)) end))) - (goto-char (1+ end)) - (while (string-match "''" string) - (setq string (replace-match "'" t t string))) - (list 'eshell-escape-arg string)))))) + (when (eq (char-after) ?\') + (let ((end (eshell-find-delimiter ?\' ?\'))) + (unless end + (throw 'eshell-incomplete "'")) + (let ((string (buffer-substring-no-properties (1+ (point)) end))) + (goto-char (1+ end)) + (while (string-match "''" string) + (setq string (replace-match "'" t t string))) + string)))) (defun eshell-parse-double-quote () "Parse a double quoted string, which allows for variable interpolation." (when (eq (char-after) ?\") (let* ((end (eshell-find-delimiter ?\" ?\" nil nil t)) - (eshell-current-quoted t)) - (if (not end) - (throw 'eshell-incomplete "\"") - (prog1 - (save-restriction - (forward-char) - (narrow-to-region (point) end) - (let ((arg (eshell-parse-argument))) - (if (eq arg nil) - "" - (list 'eshell-escape-arg arg)))) - (goto-char (1+ end))))))) + (eshell-current-quoted t)) + (unless end + (throw 'eshell-incomplete "\"")) + (prog1 + (save-restriction + (forward-char) + (narrow-to-region (point) end) + (or (eshell-parse-argument) "")) + (goto-char (1+ end)))))) (defun eshell-unescape-inner-double-quote (bound) "Unescape escaped characters inside a double-quoted string. diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el index eaa73290a83..b8fd3482242 100644 --- a/lisp/eshell/esh-var.el +++ b/lisp/eshell/esh-var.el @@ -496,7 +496,6 @@ process any indices that come after the variable reference." (setq value `(eshell-list-to-string ,value) splice nil) (setq value `(eshell-stringify ,value t)))) - (setq value `(eshell-escape-arg ,value)) (when splice (setq value `(eshell-splice-args ,value))) value)) diff --git a/test/lisp/eshell/em-extpipe-tests.el b/test/lisp/eshell/em-extpipe-tests.el index 4c3adbc2d90..b7573806ad8 100644 --- a/test/lisp/eshell/em-extpipe-tests.el +++ b/test/lisp/eshell/em-extpipe-tests.el @@ -93,7 +93,7 @@ (skip-unless (executable-find "rev")) (should-parse '(eshell-execute-pipeline - '((eshell-named-command "echo" (list (eshell-escape-arg "bar"))) + '((eshell-named-command "echo" (list "bar")) (eshell-named-command "sh" (list "-c" "rev >temp"))))) (with-substitute-for-temp (eshell-match-command-output input "^$") @@ -156,8 +156,7 @@ (em-extpipe-tests--deftest em-extpipe-test-9 "foo \\*| bar" (should-parse '(eshell-execute-pipeline - '((eshell-named-command "foo" - (list (eshell-escape-arg "*"))) + '((eshell-named-command "foo" (list "*")) (eshell-named-command "bar"))))) (em-extpipe-tests--deftest em-extpipe-test-10 "foo \"*|\" *>bar" @@ -165,8 +164,7 @@ '(eshell-named-command "sh" (list "-c" "foo \"*|\" >bar")))) (em-extpipe-tests--deftest em-extpipe-test-11 "foo '*|' bar" - (should-parse '(eshell-named-command - "foo" (list (eshell-escape-arg "*|") "bar")))) + (should-parse '(eshell-named-command "foo" (list "*|" "bar")))) (em-extpipe-tests--deftest em-extpipe-test-12 ">foo bar *| baz" (should-parse diff --git a/test/lisp/eshell/em-pred-tests.el b/test/lisp/eshell/em-pred-tests.el index 3bffc918b66..71d5bf6c62e 100644 --- a/test/lisp/eshell/em-pred-tests.el +++ b/test/lisp/eshell/em-pred-tests.el @@ -417,12 +417,6 @@ PREDICATE is the predicate used to query that attribute." '("/path/to/file.el" "/other/path/") ":r") '("/path/to/file" "/other/path/")))) -(ert-deftest em-pred-test/modifier-quote () - "Test that \":q\" quotes arguments." - (should (equal-including-properties - (eshell-eval-predicate '("foo" "bar") ":q") - (list (eshell-escape-arg "foo") (eshell-escape-arg "bar"))))) - (ert-deftest em-pred-test/modifier-substitute () "Test that \":s/PAT/REP/\" replaces PAT with REP once." (should (equal (eshell-eval-predicate "bar" ":s/a/*/") "b*r")) diff --git a/test/lisp/eshell/esh-var-tests.el b/test/lisp/eshell/esh-var-tests.el index 2f8ac32b0b5..d8ebd02f168 100644 --- a/test/lisp/eshell/esh-var-tests.el +++ b/test/lisp/eshell/esh-var-tests.el @@ -342,15 +342,10 @@ nil, use FUNCTION instead." (let ((eshell-test-value '("zero" "one" "two" "three" "four"))) (eshell-command-result-equal "echo \"$eshell-test-value[0]\"" "zero") - ;; FIXME: These tests would use the 0th index like the other tests - ;; here, but evaluating the command just above adds an `escaped' - ;; property to the string "zero". This results in the output - ;; printing the string properties, which is probably the wrong - ;; behavior. See bug#54486. - (eshell-command-result-equal "echo \"$eshell-test-value[1 2]\"" - "(\"one\" \"two\")") - (eshell-command-result-equal "echo \"$eshell-test-value[1 2 4]\"" - "(\"one\" \"two\" \"four\")"))) + (eshell-command-result-equal "echo \"$eshell-test-value[0 2]\"" + "(\"zero\" \"two\")") + (eshell-command-result-equal "echo \"$eshell-test-value[0 2 4]\"" + "(\"zero\" \"two\" \"four\")"))) (ert-deftest esh-var-test/quote-interp-var-indices-subcommand () "Interpolate list variable with subcommand expansion for indices inside double-quotes." @@ -359,11 +354,9 @@ nil, use FUNCTION instead." (eshell-command-result-equal "echo \"$eshell-test-value[${*echo 0}]\"" "zero") - ;; FIXME: These tests would use the 0th index like the other tests - ;; here, but see above. (eshell-command-result-equal - "echo \"$eshell-test-value[${*echo 1} ${*echo 2}]\"" - "(\"one\" \"two\")"))) + "echo \"$eshell-test-value[${*echo 0} ${*echo 2}]\"" + "(\"zero\" \"two\")"))) (ert-deftest esh-var-test/quoted-interp-var-split-indices () "Interpolate string variable with indices inside double-quotes." -- 2.39.2