1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Parse getopt-style help texts for options
# and generate zsh(1) completion function.
# http://github.com/RobSis/zsh-completion-generator
# Usage: program --help | ./help2comp.py program_name
# Changelog:
# 9th September, 2014:
# - Copied from http://github.com/RobSis/zsh-completion-generator.
# - Print argument list instead of completion function.
import os
import sys
import re
import argparse
from string import Template
URL = 'http://github.com/RobSis/zsh-completion-generator'
STRIP_CHARS = " \t\n,="
COMPLETE_FUNCTION_TEMPLATE = """
#compdef $program_name
# zsh completions for '$program_name'
# automatically generated with $url
local arguments
arguments=(
$argument_list
'*:filename:_files'
)
_arguments -s $arguments
"""
ARGUMENT_TEMPLATE = """ {$opts}'[$description]$style'"""
SINGLE_ARGUMENT_TEMPLATE = """ '$opt[$description]$style'"""
def cut_option(line):
"""
Cuts out the first option (short or long) and its argument.
"""
# TODO: dare to make it regex-free?
newline = line.strip(STRIP_CHARS)
opt = re.findall(r'^(-[a-zA-Z0-9\-]+(?:[\[\ =][^\-\ ][a-zA-Z\<\>\[\|\:\]\-\_\?#]*\]?)?)', line)
if len(opt) > 0:
newline = line.replace(opt[0], "", 1).strip(STRIP_CHARS)
# return without parameter
return newline, re.split('[\ \[=]', opt[0])[0]
else:
return newline, None
def parse_options(help_text):
"""
Parses the options line by line.
When description is missing and options are missing on
consecutive line, link them together.
"""
all_options = []
previous_description_missing = False
for line in help_text:
line = line.strip(STRIP_CHARS)
if re.match(r'^--?[a-zA-Z0-9]+', line) != None: # starts with option
previous_description_missing = False
options = []
while True:
line, opt = cut_option(line)
if opt == None:
break
options.append(opt)
if (len(line) == 0):
previous_description_missing = True
options.append(line)
all_options.append(options)
elif previous_description_missing:
all_options[-1][-1] = line
previous_description_missing = False
return all_options
def _escape(line):
"""
Escape the syntax-breaking characters.
"""
line = line.replace('[','\[').replace(']','\]')
line = re.sub('\'', '', line) # ' is unescapable afaik
return line
def generate_argument_list(options):
"""
Generate list of arguments from the template.
"""
argument_list = []
for opts in options:
model = {}
# remove unescapable chars.
model['description'] = _escape(opts[-1])
model['style'] = ""
if (len(opts) > 2):
model['opts'] = ",".join(opts[:-1])
argument_list.append(Template(ARGUMENT_TEMPLATE).safe_substitute(model))
elif (len(opts) == 2):
model['opt'] = opts[0]
argument_list.append(Template(SINGLE_ARGUMENT_TEMPLATE).safe_substitute(model))
else:
pass
return "\n".join(argument_list)
def generate_completion_function(options, program_name):
"""
Generate completion function from the template.
"""
model = {}
model['program_name'] = program_name
model['argument_list'] = generate_argument_list(options)
model['url'] = URL
return Template(COMPLETE_FUNCTION_TEMPLATE).safe_substitute(model).strip()
if __name__ == "__main__":
if len(sys.argv) > 1:
options = parse_options(sys.stdin.readlines())
if (len(options) == 0):
sys.exit(2)
#print generate_completion_function(options, sys.argv[1])
print generate_argument_list(options)
else:
print "Please specify program name."
|