From: Jim Porter Date: Thu, 3 Mar 2022 17:37:25 +0000 (-0800) Subject: Improve wording of Eshell variable interpolation code/documentation X-Git-Tag: emacs-29.0.90~1954 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=58568033f4b648e0dc8d9d893ef2197aded0a69e;p=emacs.git Improve wording of Eshell variable interpolation code/documentation * lisp/eshell/esh-arg.el (eshell-unescape-inner-double-quote): Rename from 'eshell-parse-inner-double-quote'. * lisp/eshell/esh-cmd.el (eshell-with-temp-command): Improve docstring. * lisp/eshell/esh-var.el (eshell-parse-variable-ref): Use 'eshell-unescape-inner-double-quote' and improve robustness of quoted variable name matching. (eshell-parse-indices): Use 'eshell-unescape-inner-double-quote'. * doc/misc/eshell.texi (Dollars Expansion): Improve wording of subscript notation. --- diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi index 5581e5cd9ee..372e4c3ffbd 100644 --- a/doc/misc/eshell.texi +++ b/doc/misc/eshell.texi @@ -1040,18 +1040,37 @@ returns the file name. Expands to the @var{i}th element of the result of @var{expr}, an expression in one of the above forms listed here. If multiple indices are supplied, this will return a list containing the elements for each -index. If @var{expr}'s value is a string, it will first be split at -whitespace to make it a list. If @var{expr}'s value is an alist -(@pxref{Association List Type, Association Lists, , elisp, The Emacs -Lisp Reference Manual}), this will call @code{assoc} on the result of -@var{expr}, returning the @code{cdr} of the element of the result -whose car is equal to @code{"i"}. Raises an error if the value is not -a sequence (@pxref{Sequences Arrays Vectors, Sequences, , elisp, The +index. The exact behavior depends on the type of @var{expr}'s value: + +@table @asis + +@item a sequence +Expands to the element at the (zero-based) index @var{i} of the +sequence (@pxref{Sequences Arrays Vectors, Sequences, , elisp, The Emacs Lisp Reference Manual}). -Multiple sets of indices can also be specified. For example, if -@var{var} is a list of lists, @samp{$@var{var}[0][0]} is equivalent to -@samp{(caar @var{var})}. +@item a string +Split the string at whitespace, and then expand to the @var{i}th +element of the resulting sequence. + +@item an alist +If @var{i} is a non-numeric value, expand to the value associated with +the key @code{"@var{i}"} in the alist. For example, if @var{var} is +@samp{(("dog" . "fido") ("cat" . "felix"))}, then +@samp{$@var{var}[dog]} expands to @code{"fido"}. Otherwise, this +behaves as with sequences; e.g., @samp{$@var{var}[0]} expands to +@code{("dog" . "fido")}. @xref{Association List Type, Association +Lists, , elisp, The Emacs Lisp Reference Manual}. + +@item anything else +Signals an error. + +@end table + +Multiple sets of indices can also be specified. For example, if +@var{var} is @samp{((1 2) (3 4))}, then @samp{$@var{var}[0][1]} will +expand to @code{2}, i.e.@: the second element of the first list member +(all indices are zero-based). @item $@var{expr}[@var{regexp} @var{i...}] As above (when @var{expr} expands to a string), but use @var{regexp} @@ -1063,8 +1082,8 @@ element of a colon-delimited string. Expands to the length of the result of @var{expr}, an expression in one of the above forms. For example, @samp{$#@var{var}} returns the length of the variable @var{var} and @samp{$#@var{var}[0]} returns the -length of the first element of @var{var}. Again, raises an error if -the result of @var{expr} is not a sequence. +length of the first element of @var{var}. Again, signals an error if +the result of @var{expr} is not a string or a sequence. @end table diff --git a/lisp/eshell/esh-arg.el b/lisp/eshell/esh-arg.el index e19481c4ba9..ee3f907f85c 100644 --- a/lisp/eshell/esh-arg.el +++ b/lisp/eshell/esh-arg.el @@ -354,8 +354,8 @@ after are both returned." (list 'eshell-escape-arg arg)))) (goto-char (1+ end))))))) -(defun eshell-parse-inner-double-quote (bound) - "Parse the inner part of a double quoted string. +(defun eshell-unescape-inner-double-quote (bound) + "Unescape escaped characters inside a double-quoted string. The string to parse starts at point and ends at BOUND. If Eshell is currently parsing a quoted string and there are any diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el index 04b54d9d791..8be1136e311 100644 --- a/lisp/eshell/esh-cmd.el +++ b/lisp/eshell/esh-cmd.el @@ -350,24 +350,27 @@ This only returns external (non-Lisp) processes." (defvar eshell--sep-terms) -(defmacro eshell-with-temp-command (command &rest body) - "Narrow the buffer to COMMAND and execute the forms in BODY. -COMMAND can either be a string, or a cons cell demarcating a -buffer region. If COMMAND is a string, temporarily insert it -into the buffer before narrowing. Point will be set to the -beginning of the narrowed region. +(defmacro eshell-with-temp-command (region &rest body) + "Narrow the buffer to REGION and execute the forms in BODY. + +REGION is a cons cell (START . END) that specifies the region to +which to narrow the buffer. REGION can also be a string, in +which case the macro temporarily inserts it into the buffer at +point, and narrows the buffer to the inserted string. Before +executing BODY, point is set to the beginning of the narrowed +REGION. The value returned is the last form in BODY." (declare (indent 1)) - `(let ((cmd ,command)) - (if (stringp cmd) + `(let ((reg ,region)) + (if (stringp reg) ;; Since parsing relies partly on buffer-local state ;; (e.g. that of `eshell-parse-argument-hook'), we need to ;; perform the parsing in the Eshell buffer. (let ((begin (point)) end (inhibit-point-motion-hooks t)) (with-silent-modifications - (insert cmd) + (insert reg) (setq end (point)) (unwind-protect (save-restriction @@ -376,8 +379,8 @@ The value returned is the last form in BODY." ,@body) (delete-region begin end)))) (save-restriction - (narrow-to-region (car cmd) (cdr cmd)) - (goto-char (car cmd)) + (narrow-to-region (car reg) (cdr reg)) + (goto-char (car reg)) ,@body)))) (defun eshell-parse-command (command &optional args toplevel) diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el index af89e35f553..8746f2bb931 100644 --- a/lisp/eshell/esh-var.el +++ b/lisp/eshell/esh-var.el @@ -437,7 +437,7 @@ Possible options are: `(eshell-convert (eshell-command-to-value (eshell-as-subcommand - ,(let ((subcmd (or (eshell-parse-inner-double-quote end) + ,(let ((subcmd (or (eshell-unescape-inner-double-quote end) (cons (point) end))) (eshell-current-quoted nil)) (eshell-parse-command subcmd))))) @@ -470,13 +470,15 @@ Possible options are: (condition-case nil `(eshell-command-to-value (eshell-lisp-command - ',(read (or (eshell-parse-inner-double-quote (point-max)) + ',(read (or (eshell-unescape-inner-double-quote (point-max)) (current-buffer))))) (end-of-file (throw 'eshell-incomplete ?\()))) - ((looking-at (rx (or "'" "\"" "\\\""))) - (eshell-with-temp-command (or (eshell-parse-inner-double-quote (point-max)) - (cons (point) (point-max))) + ((looking-at (rx-to-string + `(or "'" ,(if eshell-current-quoted "\\\"" "\"")))) + (eshell-with-temp-command + (or (eshell-unescape-inner-double-quote (point-max)) + (cons (point) (point-max))) (let ((name (if (eq (char-after) ?\') (eshell-parse-literal-quote) (eshell-parse-double-quote)))) @@ -506,7 +508,7 @@ For example, \"[0 1][2]\" becomes: (if (not end) (throw 'eshell-incomplete ?\[) (forward-char) - (eshell-with-temp-command (or (eshell-parse-inner-double-quote end) + (eshell-with-temp-command (or (eshell-unescape-inner-double-quote end) (cons (point) end)) (let (eshell-glob-function (eshell-current-quoted nil)) (setq indices (cons (eshell-parse-arguments