mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 05:13:10 +00:00
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
This commit is contained in:
parent
6dfdb3ba6e
commit
bdd1b6b4b2
1 changed files with 117 additions and 68 deletions
|
@ -4,103 +4,152 @@ import sys
|
||||||
import commands
|
import commands
|
||||||
import re
|
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):
|
def escape_quotes(s):
|
||||||
return re.sub('\'', '\\\'', s)
|
return re.sub('\'', '\\\'', s)
|
||||||
|
|
||||||
def escape(s):
|
def escape(s):
|
||||||
return re.sub('([\'"#%*?])', r"\\\1", 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
|
||||||
|
|
||||||
|
def print_completion( cmd, switch_arr, arg, desc ):
|
||||||
|
|
||||||
|
if len(switch_arr)==0:
|
||||||
|
return
|
||||||
|
|
||||||
|
res = "complete -c %s" % (cmd)
|
||||||
|
for sw in switch_arr:
|
||||||
|
|
||||||
offset=1
|
offset=1
|
||||||
switch_type = "o"
|
switch_type = "o"
|
||||||
|
|
||||||
if len(switch_name) == 2:
|
if len(sw) == 2:
|
||||||
switch_type = "s"
|
switch_type = "s"
|
||||||
|
|
||||||
if switch_name[1] == "-":
|
if sw[1] == "-":
|
||||||
switch_type = "l"
|
switch_type = "l"
|
||||||
offset=2
|
offset=2
|
||||||
|
|
||||||
arg_str = ""
|
res += " -%s %s" % (switch_type, escape(sw[offset:]))
|
||||||
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 += " --description '%s'" % (up_first(escape_quotes(clean(desc))))
|
||||||
|
|
||||||
|
print res
|
||||||
|
|
||||||
cmd = sys.argv[1]
|
cmd = sys.argv[1]
|
||||||
|
|
||||||
|
header(cmd)
|
||||||
|
|
||||||
man = commands.getoutput( "man %s | col -b" % cmd )
|
man = commands.getoutput( "man %s | col -b" % cmd )
|
||||||
|
|
||||||
remainder = man
|
remainder = man
|
||||||
|
|
||||||
re1 = r"\n( *-[^ ,]* *(|\n))+[^.]+"
|
MODE_NONE = 0
|
||||||
prog1 = re.compile(re1, re.MULTILINE)
|
MODE_SWITCH = 1
|
||||||
|
MODE_BETWEEN = 2
|
||||||
|
MODE_BETWEEN_IGNORE = 3
|
||||||
|
MODE_DESC = 4
|
||||||
|
|
||||||
re2 = r"^(|=[^ ]*)( |\n)*(?P<switch>-[^ =./\n]+)( *[^-\n ]*\n|)"
|
mode = MODE_NONE
|
||||||
prog2 = re.compile(re2, re.MULTILINE)
|
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=''
|
||||||
|
|
||||||
re3 = r"^=(?P<arg>[^ ]*)"
|
can_be_switch =True
|
||||||
prog3 = re.compile(re2, 0)
|
|
||||||
|
|
||||||
while True:
|
for c in man:
|
||||||
|
|
||||||
match = prog1.search( remainder )
|
if mode == MODE_NONE:
|
||||||
|
if c == '-' and can_be_switch:
|
||||||
|
mode = MODE_SWITCH
|
||||||
|
sw = '-'
|
||||||
|
|
||||||
if match == None:
|
elif c == '\n':
|
||||||
break
|
can_be_switch = True
|
||||||
|
elif before_switch.find(c)<0:
|
||||||
# print "yay match!!!\n"
|
can_be_switch = False
|
||||||
str = match.string[match.start():match.end()]
|
|
||||||
|
|
||||||
# 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 )
|
|
||||||
|
|
||||||
|
|
||||||
remainder = remainder[match.end():]
|
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
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue