diff options
author | liljencrantz <liljencrantz@gmail.com> | 2007-10-29 04:51:43 +1000 |
---|---|---|
committer | liljencrantz <liljencrantz@gmail.com> | 2007-10-29 04:51:43 +1000 |
commit | bdd1b6b4b23836ccfe441e1c40374f00aab442f3 (patch) | |
tree | c0e8fb748dbfb825a5d6dcae519718eae0f321a8 /make_completions.py | |
parent | 6dfdb3ba6edf7e7939657818ed6c27907aef60ba (diff) |
Rewrite automatic completion creator from scratch. The new implementation uses a finite state machine instead of a set of regexes, which inpractice seems to make the parser more robust and the code subjectively more readable
darcs-hash:20071028185143-75c98-92c1a0cd579ff0c41f47e75c975405fe3e002ddb.gz
Diffstat (limited to 'make_completions.py')
-rwxr-xr-x | make_completions.py | 211 |
1 files changed, 130 insertions, 81 deletions
diff --git a/make_completions.py b/make_completions.py index cee4698a..5830bfea 100755 --- a/make_completions.py +++ b/make_completions.py @@ -4,103 +4,152 @@ import sys import commands import re +# Regexes for performing cleanup + +cl = {re.compile(r"[ \n\t\r]+", re.MULTILINE):" ", + re.compile(r"^[ \n\t\r]"):"", + re.compile(r"[ \n\t\r]$"):"", + re.compile(r"-[ \t]*\n[ \t\r]+" ):""} + +def header(cmd): + print '''# +# Command specific completions for the %s command. +# These completions where generated from the commands +# man page by the make_completions.py script, but may +# have been hand edited since. +# +''' % (cmd) + +def up_first(s): + return s[0].upper() + s[1:] + def escape_quotes(s): return re.sub('\'', '\\\'', s) def escape(s): return re.sub('([\'"#%*?])', r"\\\1", s) -def print_completion( cmd, switch_name, arg, desc ): +def clean(s): + res=s + for r, str in cl.items(): + res = r.sub(str, res) + return res - offset=1 - switch_type = "o" +def print_completion( cmd, switch_arr, arg, desc ): - if len(switch_name) == 2: - switch_type = "s" + if len(switch_arr)==0: + return + + res = "complete -c %s" % (cmd) + for sw in switch_arr: + + offset=1 + switch_type = "o" + + if len(sw) == 2: + switch_type = "s" - if switch_name[1] == "-": - switch_type = "l" - offset=2 + if sw[1] == "-": + switch_type = "l" + offset=2 - arg_str = "" - if arg == None: - pass - elif arg == "standard": - arg_str = "-a 'c89 c99 gnu89 gnu99 c++98 gnu++98'" - else: - pass - - print "complete -c %s -%s %s %s --description '%s'" % (cmd, switch_type, escape( switch_name[offset:] ), arg_str, escape_quotes(desc)) - -def clean_whitespace( str ): - clean_whitespace_prog0 = re.compile( r"-[ \t]*\n[ \t\r]+" ) - clean_whitespace_prog1 = re.compile( r"[ \n\t]+" ) - clean_whitespace_prog2 = re.compile( r"^[ \t\r]*", re.MULTILINE ) - str = clean_whitespace_prog0.sub( "", str ) - str = clean_whitespace_prog1.sub( " ", str ) - str = clean_whitespace_prog2.sub( "", str ) - return str + res += " -%s %s" % (switch_type, escape(sw[offset:])) + res += " --description '%s'" % (up_first(escape_quotes(clean(desc)))) + print res cmd = sys.argv[1] -man = commands.getoutput( "man %s | col -b" % cmd ) -remainder = man - -re1 = r"\n( *-[^ ,]* *(|\n))+[^.]+" -prog1 = re.compile(re1, re.MULTILINE) - -re2 = r"^(|=[^ ]*)( |\n)*(?P<switch>-[^ =./\n]+)( *[^-\n ]*\n|)" -prog2 = re.compile(re2, re.MULTILINE) - -re3 = r"^=(?P<arg>[^ ]*)" -prog3 = re.compile(re2, 0) - -while True: - - match = prog1.search( remainder ) - - if match == None: - break -# print "yay match!!!\n" - str = match.string[match.start():match.end()] +header(cmd) -# print str - - rem2 = str - - switch = [] - - while True: - match2 = prog2.search( rem2 ) - - if match2 == None: - break - - sw = match2.expand( r"\g<switch>" ) -# print "yay switch %s!!!\n" %sw - - switch.append( sw ) - - rem2 = rem2[match2.end():] - - match_arg = prog3.search( rem2 ) - arg = None - - if match_arg != None: - arg = match_arg.expand( r"\g<arg>" ) - rem2 = rem2[match_arg.end():] - - desc = clean_whitespace(rem2) - - if len( desc) > 8 and arg != None: - -# print "Yay desc '%s'!!\n" % desc - - for i in switch: - print_completion( cmd, i, arg, desc ) +man = commands.getoutput( "man %s | col -b" % cmd ) +remainder = man - remainder = remainder[match.end():] +MODE_NONE = 0 +MODE_SWITCH = 1 +MODE_BETWEEN = 2 +MODE_BETWEEN_IGNORE = 3 +MODE_DESC = 4 + +mode = MODE_NONE +pos = 0 +sw='' +sw_arr=[] +switch_end="= \t\n[," +switch_between_ignore="[=" +switch_between_continue=" \t\n|" +before_switch=" \t\r" +between_ignore=" \t\n]" +pc=False +desc='' + +can_be_switch =True + +for c in man: + + if mode == MODE_NONE: + if c == '-' and can_be_switch: + mode = MODE_SWITCH + sw = '-' + + elif c == '\n': + can_be_switch = True + elif before_switch.find(c)<0: + can_be_switch = False + + + elif mode == MODE_SWITCH: + if not switch_end.find(c)>=0: + sw+=c + else: + if len(sw) > 1: + sw_arr.append(sw) + + if switch_between_ignore.find(c) >= 0: + mode=MODE_BETWEEN_IGNORE + else: + mode=MODE_BETWEEN + # print "End of switch argumnt", sw, "switch to between mode" + sw='' + + elif mode == MODE_BETWEEN: + if c == '-': + mode = MODE_SWITCH + sw = '-' + elif switch_between_ignore.find(c) >= 0: + mode = MODE_BETWEEN_IGNORE + # print "Found character", c, "switching to ignore mode" + elif not switch_between_continue.find(c) >= 0: + mode = MODE_DESC + desc = c + + elif mode == MODE_BETWEEN_IGNORE: + if between_ignore.find(c)>=0: + mode = MODE_BETWEEN + + elif mode == MODE_DESC: + + stop = False + + if c == '.': + stop = True + + if c == '\n' and pc == '\n': + stop=True + + if stop: + mode=MODE_NONE + + print_completion( cmd, sw_arr, None, desc ) + + sw_arr = [] + + desc = '' + + else: + desc += c + + pc = c |