Subject: bug#54227: 29.0.50; [PATCH] Inconsistencies with Eshell variable interpolation

From: Eli Zaretskii <[email-masked]>
Date: Thu, 03 Mar 2022 20:43:14 +0200

> Cc: [email-masked]
> From: Jim Porter <[email-masked]>
> Date: Thu, 3 Mar 2022 09:56:14 -0800
> 
> >> +(defmacro eshell-with-temp-command (command &rest body)
> >> +  "Narrow the buffer to COMMAND and execute the forms in BODY.
> > 
> > What does it mean to "narrow the buffer to COMMAND"?
> > 
> > Imagine that the user only sees this one line of the doc string --
> > that actually happens in apropos commands.  How can such a user
> > understand what this macro does?
> 
> The macro's job is to take an Eshell command (or some fragment thereof) 
> and narrow the buffer so that it's just looking at that part. This is to 
> make sure that whatever is called in the body knows where to start and 
> stop looking.
> 
> I agree that this isn't very clear, but I had trouble coming up with a 
> concise explanation. It's essentially a workaround for how Eshell 
> expects things; a lot of the Eshell command parsing functions operate on 
> a range of text in the buffer. Normally, if you wanted to use those 
> functions with a temporary string, you'd use `with-temp-buffer' and 
> insert the string there. That doesn't work here though, since Eshell 
> uses lots of buffer-local state. This function tries to abstract that 
> out in a way that's useful for a few different places in Eshell.
> 
> If you have any ideas about how to improve the wording, I'm happy to 
> update it though. I'll try to keep thinking as well.

Something like the below:

  (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.

> diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
> index 5581e5cd9e..47f8902d5a 100644
> --- a/doc/misc/eshell.texi
> +++ b/doc/misc/eshell.texi
> @@ -1043,15 +1043,16 @@ Dollars Expansion
>  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
> -Emacs Lisp Reference Manual}).
> +Lisp Reference Manual}), this will return the value associated with
> +the key @code{"i"}.
>  
> -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})}.
> +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 would add to the last sentence: ", i.e.@: the second element of the
first list member (all indices are zero-based)."

Also, it sounds like you just dropped the ball on the alist use case?

> -(defun eshell-parse-inner-double-quote (bound)
> -  "Parse the inner part of a double quoted string.
> +(defun eshell-unescape-inner-double-quote (bound)
> +  "Unescape the inner part of a double quoted string.

"Unescape escaped characters of a double-quoted string."

Thanks.