1

When I start typing something into an interactive login shell (zsh or bash) and click tab, the shell offers me autocomplete suggestions.

I broadly understand how completion specs are defined. For reference it's outlined here:

What I don't understand is how bash/zsh identify which command to complete on when a user presses tab i.e. if I do ls [tab], how does bash/zsh identify ls. Put differently, how do bash/zsh know to generate completions using the ls completion spec.

Some more examples with more complicated parsing which Bash/Zsh still get right:

  • ls [tab] -> completes on ls
  • echo $( echo $(ls [tab] -> completes on ls
  • echo hi; git a[tab] -> completes on git
  • echo 'cd [tab] -> does NOT complete on cd
  • echo "$(ls [tab] -> completes on ls
  • echo $( echo hi | ls [tab] -> completes on ls
    (I know ls doesn't take stdin but this example still illustrates bash/zsh's parsing abilities)

I am presuming bash/zsh are using some sort of parser. However, it's not a normal parser. It completes without a properly structured command. It is aware that something is in quotes or a shell expansion, even if they are not closed.

What function is bash/zsh running to "identify" the relevant command or determine whether or not there is a command to complete on at all?

6
  • the shells have a parser, and obviously know their own syntax, so it's normal that they are able to determine that they are completing on a certain command context, or that the command ended on a string context. It's easier to confuse them when completing in the middle of a command. Try something like echo $(ls [TAB])
    – Ángel
    Commented Nov 8, 2020 at 0:25
  • Thanks @Ángel - I am sure it's easier to confuse them in the middle of a command. The thing is, it's not confusing them! Considering everything is open source, I would love to find the source code for the parser...
    – falky
    Commented Nov 8, 2020 at 3:36
  • Files in /etc/bash_completion.d and /usr/share/bash-completion/completions are pretty self-explanatory. 1. You define a completion function via: complete -F _function_name application_name i.e. complete -F _ls ls 2. Then you define function _function_name which expands values. Commented Nov 8, 2020 at 11:30
  • Shells keep a cache of all the names of the executables in the directories in $PATH. This is used for completion. See the rehash builtin in man bash.
    – waltinator
    Commented Nov 8, 2020 at 15:00
  • 1
    I would assume that the shell uses a simple left to right parser (I am not hot on the terminology). E.g put cursor after ls in echo $(ls ( ) ) and press tab, it auto completes even when the code to the right is invalid syntax. Commented Nov 16, 2020 at 21:15

1 Answer 1

2
+50

What function is bash/zsh running to "identify" the relevant command or determine whether or not there is a command to complete on at all?

When you press tab, readline executes the complete function.

You can override this in ~/.inputrc:

"\t": complete

complete is defined in lib/readline/funmap.c as:

static const FUNMAP default_funmap[] = {
[..]
{ "complete", rl_complete },

rl_complete can be found in lib/readline/complete.c (browse source):

/* Complete the word at or before point.  You have supplied the function
   that does the initial simple matching selection algorithm (see
   rl_completion_matches ()).  The default is to do filename completion. */
int
rl_complete (int ignore, int invoking_key)
{
..

This is the starting point. It breaks apart the words, checks which completions are registered and then looks for the relevant completions.

zsh will probably have a similar implementation.

There is also a good explanation of the process here.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .