Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Menu completion on empty line

On Nov 3,  7:17am, ml@xxxxxxxx wrote:
} If I press the tab key on an empty line and I am in a build directory,
} which can be detected by a presence of, let's say the makefile file,
} it would be useful to get a menu with items: clean build rebuild. I
} could use the tab key to move around these items. If I choose one, it
} would expand to a particular command, like 'make clean'.

As a prelude, there are two problems with this.

(1) Completion is VERY single-word-oriented.  Anything that completes to
something with spaces in it is going to be quoted by default, so you have
to jump through even more hoops than usual to make it work.

I would recommend avoiding this by creating three aliases
    alias clean='make clean'
    alias build='make all'
    alias rebuild='clean;build'
and then use the menu to select those aliases.

(2) By default TAB doesn't do anything on an empty command line except
insert itself.  To fix that, you need:

    zstyle ':completion::*' insert-tab 'pending=1'

With that out of the way ...

There are two approaches here:  Change the widget invoked by the TAB
key, or change the handling for the context of an empty line.  The
former would let you do the hoop-jumping to insert multiple words as
the completion, but the latter is probably what you want to do.

To get started, note that with compinit loaded you can always type
control-x h to get a description of the current context.  If you do
that on a blank line, you get:

tags in context :completion::complete:-command-::
    commands builtins functions aliases suffix-aliases reserved-words jobs parameters  (_command_names _autocd) 
	(_path_commands _command_names _autocd) 
	(_jobs _command_names _autocd) 
	(_parameters _command_names _autocd)

This is telling you that:
* the start of an empty line is the special "-command-" context;
* there are eight tags recognized in this context; 
* there are five completion functions that may supply candidate
  completions for these tags, and which functions use which tags.

The important thing in this case is that you would want to change the
handling of the -command- context.  Here again you have two choices:
Replace the default completion function for -command-, or augment
one of the existing tags.

I'll note at this point that your three aliases show up in the "aliases"
tag automatically, and if that were good enough we just stop here.  But
you want special handling if there's a makefile, so on we go.

There is an example in the documentation of supplementing a context.
It's found under the fake-always style and discusses the context of the
"cd" command.  We need to change it to the context we care about.

    # Create a preferred aliases-make tag for build commands
    zstyle ':completion::*:-command-::' \
	tag-order 'aliases:-make:"build\ commands"' '*'

The "*" there in place of "complete" makes this work for other completers,
though that's not strictly necessary.  The additional '*' in the style
definition means that if there is something on the line and it does not
match one of those three aliases, you'll get normal completion.  Next:

    # Ignore everything but our three aliases for make
    zstyle ':completion::*:-command-:*:aliases-make' \
	ignored-patterns '*~(clean|build|rebuild)'

Now if you press TAB on an empty line, you'll see only your three

To limit it so this happens only when there is a makefile present, we
need to use "zstyle -e":

    # Create a preferred aliases-make tag for build commands
    # but do so only when there is a makefile in this directory
    zstyle -e ':completion::*:-command-::' \
	tag-order '[[ -f makefile || -f Makefile ]] && 
                   reply=("aliases:-make:build\ commands" "*")'

And there you have it.

Barton E. Schaefer

Messages sorted by: Reverse Date, Date, Thread, Author