Subject: Re: bug#19626: 25.0.50; eshell: extended directory syntax ("...") does not complete

From: "Michalis V." <[email-masked]>
Date: Fri, 27 Aug 2021 18:28:16 +0300

Lars Ingebrigtsen <[email-masked]> writes:

> "Michalis V." <[email-masked]> writes:
>
>> i cannot reproduce this in 28.0.50. Basically what i did was
>>
>> mkdir ...
>>
>> then repeat the steps above. Eshell autocompletes .../ fine, even adding
>> another similar directory will bring up the dialog:
>
> I think eshell has an "extended directory" concept where "..." is
> supposed to expand to (I think) all parent directories?  So there isn't
> supposed to be any directory literally called "...".
>
> I think.  But I'm not overly familiar with eshell.  Let's see...  Yup:
>
> (defun eshell-expand-multiple-dots (filename)
>   "Convert `...' to `../..', `....' to `../../..', etc..

oops, i wasn't even aware of this eshell feature, sorry about that!

I did some debugging into how completion works and it looks like
eshell-complete-parse-arguments in em-cmpl.el is responsible for
parsing the arguments before passing them to the generic(?) completion
code. Attached is a patch that adds an additional check at the end of
said defun that will substitute any .../ dots into the proper expanded
form before returning. There are some other defuns that are called by
eshell-complete-parse-arguments, namely eshell-parse-argument(s) but i
*think* this substitution is better suited (read: safer) to be placed to
their caller.
Note that this works for "cd .../", completion for other operations like
cp do not work currently (most probably because cd has its own
implementation in eshell/cd?)

i'm not sure whether this is the correct solution to this problem so if
there are any concerns please let me know and i'll continue the digging

thanks,
Michalis

diff --git a/lisp/eshell/em-cmpl.el b/lisp/eshell/em-cmpl.el
index cbfe0b8154..2352dac7e7 100644
--- a/lisp/eshell/em-cmpl.el
+++ b/lisp/eshell/em-cmpl.el
@@ -377,8 +377,12 @@ eshell-complete-parse-arguments
                           (cl-assert (eq (car result) 'quote))
                           (cadr result))
                       arg)))
-               (if (numberp val)
-                   (setq val (number-to-string val)))
+               (cond ((numberp val)
+                      (setq val (number-to-string val)))
+                     ;; expand .../ etc that only eshell understands to
+                     ;; standard ../../
+                     ((string-match "\\.\\.\\.+/" val)
+                      (setq val (eshell-expand-multiple-dots val))))
                (or val "")))
 	   args)
 	  posns)))