Run command on tab completion in zsh

2

I'm trying to set up a zsh function that will take me back to the top level git directory with an optional argument to move relative to that directory. I've currently got this which works:

alias gitdir='git rev-parse --show-toplevel'
cdgit() { cd $(gitdir)/$1 }

The issue is, tab completion doesn't work properly, it will autocomplete from whatever directory I'm in when I run cdgit, but I want it to complete from $(gitdir). If I type the following line before running cdgit, the completion will work correctly (from $(gitdir)):

compctl -W $(gitdir) -/ cdgit

However, I don't want to type that command every time before I type cdgit just to get tab completion. Is there any way that I can make a completion function for cdgit that will somehow run that command so my completion is correct?

Josh Sherick

Posted 2016-06-10T20:31:16.270

Reputation: 131

Why the downvote? – Josh Sherick – 2016-06-13T14:42:29.807

Why don't you want to stick with the compctl solution? This can go to the rc file where you define the cdgit function, can't it?! – mpy – 2016-06-14T18:58:16.883

1No, because I don't want it to run when my shell starts. That would change the directory that cdgit <path> completes to to whatever $(gitdir) evaluated to at the time that my .zshrc was run. However, I want it to autocomplete to whatever $(gitdir) evaluates to at the time that I type cdgit <path>. So I want to type cdgit and press tab and get completion from where it would cd me to, which might not be the same place as when the shell was started. – Josh Sherick – 2016-06-14T20:00:27.060

It could potentially run on every directory change, I guess. Not the cleanest solution but it's a quick command. – Josh Sherick – 2016-06-14T20:01:26.800

Of course, my bad not realizing that $(gitdir) will be static then. See my answer for a suggestion. – mpy – 2016-06-15T16:46:55.420

Answers

2

I'd suggest to write a completion function for your cdgit function.

Put this file named _cdgit into a directory which is in your $fpath, e.g. /usr/share/zsh/site-functions, then start a new shell instance:

#compdef cdgit

local expl
local ret=1

[[ CURRENT -eq 2 ]] && _wanted directories expl 'git toplevel directory' \
    _path_files -/ -W $(git rev-parse --show-toplevel) && ret=0

return ret

This is borrowed from one of the last lines in the _cd completion function itself, which is of course much more complex.

Demo:

/usr/src/linux-git/Documentation/x86> cd [TAB]
local directory
i386/    x86_64/

/usr/src/linux-git/Documentation/x86> cdgit [TAB]
git toplevel directory
Documentation/  crypto/         include/        lib/            scripts/        usr/                          
arch/           drivers/        init/           mm/             security/       virt/                         
block/          firmware/       ipc/            net/            sound/                                      
certs/          fs/             kernel/         samples/        tools/                                      

mpy

Posted 2016-06-10T20:31:16.270

Reputation: 20 866