mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-01-23 12:50:04 +08:00
167 lines
5.4 KiB
Python
167 lines
5.4 KiB
Python
|
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("<output>" + complete_output + "</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("<output>" + complete_output + "</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
|