Open wernight opened 9 years ago
Argcomplete is designed to be dynamic, as demonstrated in the network service-driven example in the readme. That doesn't completely exclude a static generator that you envision, but could you sketch out what the statically generated code would look like?
It'd look for example like:
File _mycommand
for ZSH:
#compdef mycommand
_mycommand()
{
# Those lines are to enable an action of the form '->state'.
local curcontext="$curcontext"
local state
typeset -A opt_args
# The option -C tells _arguments to modify the $curcontext parameter for
# an action of the form '->state'. This is the standard parameter used to
# keep track of the current context.
_arguments -C \
{-h,--help}'[Help.]' \
'--to=[Destination directory.]:Directories:_directories' \
# *- indicates it can appear more than once:
'*'{-u,--user}'=[Searches for clients owned by USER]:Usernames:_users' \
# 1 means the first non-named argument
'1:Client Names:->client' \
'2:Target Countries:(France Germany Italy)'
# '::' means it's optional:
'*::Image:_files -g \*.\(ps\|eps\)'
case $state in
(client)
compadd ‘John Doe’ 'Lorem Ipsum’
compadd $(ls -m1)
;;
esac
}
This is more of a complex example but I guess you get the point. All flags would be in that file. No need to run the Python script to get them, no need even to source the file for ZSH. Also subcommands can become functions which other users can use. Yes I know the hit would be only on the source and initial auto-complete and then cached. Still I do start terminals frequently and ZSH auto-complete fuzzy function means a lot more gets auto-completed.
Here's a 30 min hack I wrote that seems relevant to the conversation/request although it was intended for dynamic use not static use, and there's 3 problems with it : 1 : There's no obvious way to resolve the filename afaik 2 : I'm notsure you could give this a dynamic name (IE #compdef *.py) 3 : It's horribly implemented, (but not a bad concept)
#compdef argparsecompleter
ARGS=`python<<EOF
import subprocess
import re
def parse(l):
parsed_args = []
for i in l:
try:
short_arg = re.search(r'-[a-zA-z+],', i).group().strip(',')
except AttributeError:
short_arg = ''
try:
long_arg = re.search(r'--[a-zA-z+] ', i).group().strip(' ')
except AttributeError:
long_arg = ''
try:
help_text = re.search(r' .+', i).group().lstrip(' ')
except AttributeError:
help_text = ''
parsed_args.append('{}||{}||{}'.format(short_arg,long_arg,help_text))
return parsed_args
def build_associative_array(l):
associative_array = ""
for i in l:
i = i.split('||')
short_arg = i[0]
long_arg = i[1]
help_text = i[2]
if short_arg != '':
associative_array = "{}[{}]\n".format(short_arg, help_text)
associative_array = "{}[{}]\n".format(long_arg, help_text)
return associative_array
filename = '' #TODO: Resolve filename
p = subprocess.Popen(['python', filename, '--help'], stdout=subprocess.PIPE).communicate()[0].decode('utf-8').splitlines()
for n, i in enumerate(p):
if i == 'optional arguments:':
start_position = n
args_list = p[start_position+1:]
args = parse(args_list)
args = build_associative_array(args)
print(args)
EOF`
typeset -A opt_args
local context state line
_arguments -s -S \
$ARGS
It basically calls the script with the --help flag, parses the output, and builds an associative array to hand back to zsh.
If anyone wants to do anything with that, consider this my blessing. I originally started writing this when I couldn't get argcomplete to work for me and wanted a dynamic quick and dirty replacement, after writting what I posted here I decided it'd probably be a better option to just figure out why argcomplete isn't working for me so my hack is not complete (nor is it recommended, mostly just posting it as a concept)
As reference: there is a project which can generate a completion script for bash and zsh using docopt: https://github.com/Infinidat/infi.docopt_completion
Second reference: python-fire is generating a static shell script too.
Not sure if this helps, but maybe it is possible to copy some ideas from these projects.
I found myself wishing often to have a statically generated auto-complete, because:
fpath=(my-app-zsh-completion-dir $fpath)
which is even faster than sourcing a file and cleanerAs a pseudo-woraround I do
$ register-python-argcomplete my-awesome-script.py >auto-complete-my-awesome-script.sh
which is shipped with the software but this doesn't have all the benefits above.The generator could read my current script once and generate a file to source for Bash and a file to add to fpath for ZSH.