120 lines
4 KiB
Python
120 lines
4 KiB
Python
|
# vim:set et fileencoding=utf8 sts=0 sw=4 ts=4:
|
||
|
|
||
|
"""Helper methods used in UltiSnips snippets."""
|
||
|
|
||
|
import string, vim, re
|
||
|
|
||
|
def complete(tab, opts):
|
||
|
"""
|
||
|
get options that match with tab
|
||
|
|
||
|
:param tab: query string
|
||
|
:param opts: list that needs to be completed
|
||
|
|
||
|
:return: a string that match with tab
|
||
|
"""
|
||
|
el = [x for x in tab]
|
||
|
pat = "".join(list(map(lambda x: x + "\w*" if re.match("\w", x) else x,
|
||
|
el)))
|
||
|
try:
|
||
|
opts = [x for x in opts if re.search(pat, x, re.IGNORECASE)]
|
||
|
except:
|
||
|
opts = [x for x in opts if x.startswith(tab)]
|
||
|
if not len(opts) or str.lower(tab) in list(map(str.lower, opts)):
|
||
|
return ""
|
||
|
cads = "|".join(opts[:5])
|
||
|
if len(opts) > 5: cads += "|..."
|
||
|
return "({0})".format(cads)
|
||
|
|
||
|
def _parse_comments(s):
|
||
|
""" Parses vim's comments option to extract comment format """
|
||
|
i = iter(s.split(","))
|
||
|
|
||
|
rv = []
|
||
|
try:
|
||
|
while True:
|
||
|
# get the flags and text of a comment part
|
||
|
flags, text = next(i).split(':', 1)
|
||
|
|
||
|
if len(flags) == 0:
|
||
|
rv.append(('OTHER', text, text, text, ""))
|
||
|
# parse 3-part comment, but ignore those with O flag
|
||
|
elif 's' in flags and 'O' not in flags:
|
||
|
ctriple = ["TRIPLE"]
|
||
|
indent = ""
|
||
|
|
||
|
if flags[-1] in string.digits:
|
||
|
indent = " " * int(flags[-1])
|
||
|
ctriple.append(text)
|
||
|
|
||
|
flags, text = next(i).split(':', 1)
|
||
|
assert flags[0] == 'm'
|
||
|
ctriple.append(text)
|
||
|
|
||
|
flags, text = next(i).split(':', 1)
|
||
|
assert flags[0] == 'e'
|
||
|
ctriple.append(text)
|
||
|
ctriple.append(indent)
|
||
|
|
||
|
rv.append(ctriple)
|
||
|
elif 'b' in flags:
|
||
|
if len(text) == 1:
|
||
|
rv.insert(0, ("SINGLE_CHAR", text, text, text, ""))
|
||
|
except StopIteration:
|
||
|
return rv
|
||
|
|
||
|
def get_comment_format():
|
||
|
""" Returns a 4-element tuple (first_line, middle_lines, end_line, indent)
|
||
|
representing the comment format for the current file.
|
||
|
|
||
|
It first looks at the 'commentstring', if that ends with %s, it uses that.
|
||
|
Otherwise it parses '&comments' and prefers single character comment
|
||
|
markers if there are any.
|
||
|
"""
|
||
|
commentstring = vim.eval("&commentstring")
|
||
|
if commentstring.endswith("%s"):
|
||
|
c = commentstring[:-2]
|
||
|
return (c.rstrip(), c.rstrip(), c.rstrip(), "")
|
||
|
comments = _parse_comments(vim.eval("&comments"))
|
||
|
for c in comments:
|
||
|
if c[0] == "SINGLE_CHAR":
|
||
|
return c[1:]
|
||
|
return comments[0][1:]
|
||
|
|
||
|
|
||
|
def make_box(twidth, bwidth=None):
|
||
|
b, m, e, i = (s.strip() for s in get_comment_format())
|
||
|
m0 = m[0] if m else ''
|
||
|
bwidth_inner = bwidth - 3 - max(len(b), len(i + e)) if bwidth else twidth + 2
|
||
|
sline = b + m + bwidth_inner * m0 + 2 * m0
|
||
|
nspaces = (bwidth_inner - twidth) // 2
|
||
|
mlines = i + m + " " + " " * nspaces
|
||
|
mlinee = " " + " "*(bwidth_inner - twidth - nspaces) + m
|
||
|
eline = i + m + bwidth_inner * m0 + 2 * m0 + e
|
||
|
return sline, mlines, mlinee, eline
|
||
|
|
||
|
def foldmarker():
|
||
|
"Return a tuple of (open fold marker, close fold marker)"
|
||
|
return vim.eval("&foldmarker").split(",")
|
||
|
|
||
|
|
||
|
def display_width(str):
|
||
|
"""Return the required over-/underline length for str."""
|
||
|
try:
|
||
|
# Respect &ambiwidth and &tabstop, but old vim may not support this
|
||
|
return vim.strdisplaywidth(str)
|
||
|
except AttributeError:
|
||
|
# Fallback
|
||
|
from unicodedata import east_asian_width
|
||
|
result = 0
|
||
|
for c in str:
|
||
|
result += 2 if east_asian_width(c) in ('W', 'F') else 1
|
||
|
return result
|
||
|
|
||
|
# http://stackoverflow.com/questions/2718196/find-all-chinese-text-in-a-string-using-python-and-regex
|
||
|
def has_cjk(s):
|
||
|
"""Detect if s contains CJK characters."""
|
||
|
cjk_re = re.compile(u'[⺀-⺙⺛-⻳⼀-⿕々〇〡-〩〸-〺〻㐀-䶵一-鿃豈-鶴侮-頻並-龎]', re.UNICODE)
|
||
|
|
||
|
return cjk_re.search(s) is not None
|