import vim, re import string try: import HTMLParser except: from html.parser import HTMLParser import xml.etree.ElementTree as ET import json # This is the python portion of the completion script. Call it with the *name* # of the input vimscript variable, "complete_output_var". This should contain # the output from the --display compiler directive. base_var is an optional # partial word to use for filtering completions. # The output is given in "output_var", which is likewise the name of the # vimscript variable to write. This variable contains a dictionary formatted # appropriately for an omnifunc. "base_var" contains an optional partial word # to filter for def complete(complete_output_var, output_var, base_var , alter_var, collapse_var): complete_output = vim.eval(complete_output_var) base = vim.eval(base_var) alter_sig = vim.eval(alter_var) != '0' collapse_overload = vim.eval(collapse_var) != '0' if complete_output is None: complete_output = '' completes = [] # get rid of non-printable characters that would be # in the embedded doc (e.g. ANSI escape characters) # thus preventing ET.XML to work complete_output = re.sub(f'[^{re.escape(string.printable)}]', '', complete_output ) # wrap in a tag to prevent parsing errors root = ET.XML("" + complete_output + "") fields = root.findall("list/i") types = root.findall("type") completes = [] if len(fields) > 0: # field completion def fieldxml2completion(x): word = x.attrib["n"] menu = x.find("t").text info = x.find("d").text menu = '' if menu is None else menu if info is None: info = [''] else: # get rid of leading/trailing ws/nl info = info.strip() # strip html info = remove_html_markup(info) # split and collapse extra whitespace info = [re.sub(r'\s+',' ',s.strip()) for s in info.split('\n')] abbr = word kind = 'v' if menu == '': kind = 'm' elif re.search("\->", menu): kind = 'f' # if it has a -> if alter_sig: menu = alter_signature(menu) word += "(" return { 'word': word, 'info': info, 'kind': kind ,'menu': menu, 'abbr': abbr, 'dup':1 } completes = [fieldxml2completion(f) for f in fields] elif len(types) > 0: # function type completion otype = types[0].text.strip() h = HTMLParser.HTMLParser() word = ' ' info = [h.unescape(otype)] abbr = info[0] if otype == "Dynamic": completes = [{'word': word,'info':info , 'abbr': "Dynamic (Will likely cause compiler error.)" , 'dup':1} ] elif alter_sig: abbr = alter_signature(abbr) completes= [{'word': word,'info':info, 'abbr':abbr, 'dup':1}] if base != '' and base is not None: completes = [c for c in completes if re.search("^" + base, c['word'])] if collapse_overload: dict_complete = dict() def complete_exists(c): if c in dict_complete: dict_complete[c] += 1 return True else: dict_complete[c] = 1 return False completes = [c for c in completes if not complete_exists(c['abbr'])] for c in completes: if dict_complete[c['abbr']] > 1: c['menu'] = "@:overload " + c['menu'] vim.command("let " + output_var + " = " + json.dumps(completes)) # simple script to grab lists of locations from display-mode completions def locations(complete_output_var, output_var): complete_output = vim.eval(complete_output_var) # wrap in a tag to prevent parsing errors root = ET.XML("" + complete_output + "") pos = root.findall("pos") completes = [] if len(pos) > 0: completes = [p.text for p in pos] else: completes = [] vim.command("let " + output_var + " = " + json.dumps(completes)) def alter_signature(sig): paren = 0 last_string = '' final_expr = '' for i in range(len(sig)): c = sig[i] if c == "(": paren += 1 final_expr += re.sub('->',",", last_string) last_string = c elif c == ")": last_string += c paren -=1 if paren == 0: final_expr += last_string last_string = '' else: last_string += c final_expr = final_expr + re.sub('\s*->\s*', ",", last_string) parts = final_expr.split(',') ret_val = parts.pop() if ret_val == "Void": ret_val = '' else: ret_val = " : " + ret_val if len(parts) ==1 and parts[0] == "Void": parts[0] = '' final_expr = '(' + ", ".join(parts) + ')' + ret_val return final_expr # simple script to strip html markup def remove_html_markup(s): tag = False quote = False out = "" for c in s: if c == '<' and not quote: tag = True elif c == '>' and not quote: tag = False elif (c == '"' or c == "'") and tag: quote = not quote elif not tag: out = out + c return out