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 Nov 8 '20 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 Nov 8 '20 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. – Artem S. Tashkinov Nov 8 '20 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 Nov 8 '20 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. – ctrl-alt-delor Nov 16 '20 at 21:15
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.