Subject: bug#36733: 27.0.50; Eshell taking long time to enter directory after TAB completion

From: Ivan Kozlov <[email-masked]>
Date: Sat, 29 Feb 2020 06:51:12 +0300

I think I am starting to understand what’s going on.

The profiler shows that eshell-complete-commands-list is being called. This function completes a command name.

But weren’t we completing a file name? What does this function have to do with it?

completion-in-region-mode installs a hook function completion-in-region--postch to post-command-hook, which is supposed to exit the mode when necessary. I don’t quite understand its logic. It tests for a bunch of conditions; here is the crucial block:

      (and completion-in-region--data
           (and (eq (marker-buffer (nth 0 completion-in-region--data))
                    (current-buffer))
                (>= (point) (nth 0 completion-in-region--data))
                (<= (point)
                    (save-excursion
                      (goto-char (nth 1 completion-in-region--data))
                      (line-end-position)))
                (funcall completion-in-region-mode--predicate)))

The initial conditions somehow turn out to be true when the argument, or the whole line, is deleted, or a new line is entered. Then it calls completion-in-region-mode--predicate, which is in this case apparently provided by completion-at-point, which is what TAB is bound to in eshell. I don’t quite understand the logic. It calls a function which ultimately comes from the completion-at-point-functions list. In eshell it is pcomplete-completions-at-point.

Because C-c C-u has erased the line (apparently post-command-hook is run before redisplay?), or, in the original bug, a line feed has been entered, pcomplete-completions-at-point operates from an empty line.

The result is exactly the same as hitting TAB at an empty prompt. It creates a list of all possible commands including *all executables from $PATH*.

Hence the bug.

I believe fixing it properly requires altering completion-in-region--postch. Altering it requires understanding why it is the way it is (like why doesn’t it already exit the mode when the region is gone), which I don’t have.