Subject: bug#50470: 27.1; 'company-mode' 'eshell'

From: Jim Porter <[email-masked]>
Date: Thu, 16 Mar 2023 23:26:44 -0700

I've recently been digging through how Eshell and Pcomplete interact, so 
I think I understand what's happening here.

On 6/7/2022 3:39 PM, Dmitry Gutov wrote:
> pcomplete-completions-at-point somehow has pcomplete-stub pointing to 
> the necessary value (e.g. "/home/dgutov/Do") in the asterisk-less cases 
> (due to some other code path being taken), but not in this specific one.

I believe the problem is that when Eshell parses the command line to 
figure out what to give Pcomplete, it expands the globs itself, so 
things get messed up. So we want to prevent glob-expansion before 
passing to Pcomplete.

The below patch does this, but it's probably not the right way to do it. 
  However, it's a simple change, and before I go through the larger 
effort of a proper patch, I want to be sure I'm actually solving the 
right thing.

For some background/explanation of how I'm thinking we should solve 
this: in Emacs 30, while fixing some other completion issues, I added 
'eshell-complete--eval-argument-form' (Emacs 29 does a similar thing, 
but the code is in 'eshell-complete-parse-arguments'). We probably want 
to enhance this function so that it only evaluates Eshell arguments 
forms that we know are ok. For a fun example of why the current behavior 
is wrong, try pressing TAB at the end of this command: "cd ${sleep 5; 
echo Doc}". Yes, it actually *runs* that subcommand before passing it to 
Pcomplete. :/

--------------------------------------------------

diff --git a/lisp/eshell/em-cmpl.el b/lisp/eshell/em-cmpl.el
index b65652019d4..7168f91d774 100644
--- a/lisp/eshell/em-cmpl.el
+++ b/lisp/eshell/em-cmpl.el
@@ -325,6 +325,10 @@ eshell-complete-parse-arguments
        (if (= begin end)
           (end-of-line))
        (setq end (point-marker)))
+    ;; Don't expand globs when parsing arguments; we want to pass any
+    ;; globs to Pcomplete unaltered.
+    (let ((eshell-parse-argument-hook (remq #'eshell-parse-glob-chars
+                                            eshell-parse-argument-hook)))
        (if (setq delim
                 (catch 'eshell-incomplete
                   (ignore
@@ -341,7 +345,7 @@ eshell-complete-parse-arguments
                  ((member (car delim) '("(" "$("))
                  (throw 'pcompleted (elisp-completion-at-point)))
                 (t
-              (eshell--pcomplete-insert-tab))))
+                (eshell--pcomplete-insert-tab)))))
      (when (get-text-property (1- end) 'comment)
        (eshell--pcomplete-insert-tab))
      (let ((pos (1- end)))