278 lines
6.8 KiB
Plaintext
278 lines
6.8 KiB
Plaintext
# -*- coding: utf-8 -*-
|
|
|
|
###########################################################################
|
|
# General Stuff #
|
|
###########################################################################
|
|
global !p
|
|
from os import path as ospath
|
|
from string import Template
|
|
import re
|
|
from collections import Counter
|
|
|
|
#http://docutils.sourceforge.net/docs/ref/rst/roles.html
|
|
TEXT_ROLES = ['emphasis','literal','code','math',
|
|
'pep-reference','rfc-reference',
|
|
'strong','subscript','superscript',
|
|
'title-reference','raw']
|
|
TEXT_ROLES_REGEX = r'\.\.\srole::?\s(w+)'
|
|
|
|
#http://docutils.sourceforge.net/docs/ref/rst/directives.html#specific-admonitions
|
|
SPECIFIC_ADMONITIONS = ["attention", "caution", "danger",
|
|
"error", "hint", "important", "note",
|
|
"tip", "warning"]
|
|
#http://docutils.sourceforge.net/docs/ref/rst/directives.html
|
|
DIRECTIVES = ['topic','sidebar','math','epigraph',
|
|
'parsed-literal','code','highlights',
|
|
'pull-quote','compound','container',
|
|
'list-table','class','sectnum',
|
|
'role','default-role','unicode',
|
|
'raw']
|
|
|
|
NONE_CONTENT_DIRECTIVES = ['rubric', 'contents', 'header',
|
|
'footer', 'date', 'include', 'title'
|
|
]
|
|
INCLUDABLE_DIRECTIVES_INDEX = {'img':'image',
|
|
'fig':'figure',
|
|
'inc':'include'}
|
|
|
|
def real_filename(filename):
|
|
# peal extension name off if possible
|
|
# i.e. "foo.bar.png will return "foo.bar"
|
|
names=filename.split('.')
|
|
return ".".join(names[:-1]) if len(names) > 1 else filename
|
|
|
|
def check_file_exist(rst_path, relative_path):
|
|
"""
|
|
For RST file, it can just include files as relative path.
|
|
|
|
:param rst_path: absolute path to rst file
|
|
:param relative_path: path related to rst file
|
|
:return: relative file's absolute path if file exist
|
|
"""
|
|
abs_path = ospath.join(ospath.dirname(rst_path), relative_path)
|
|
if ospath.isfile(abs_path):
|
|
return abs_path
|
|
|
|
#TODO: File preview
|
|
#TODO: File list complete
|
|
|
|
def rst_char_len(char):
|
|
"""
|
|
return len of string which fit in rst
|
|
For instance:chinese "我" decode as only one character,
|
|
However, the rst interpreter needs 2 "=" instead of 1.
|
|
|
|
:param: char needs to be count
|
|
"""
|
|
return len(re.findall(r'[^\u4e00-\u9fff\s]', char))+len(char)
|
|
|
|
def make_items(times, leading='+'):
|
|
"""
|
|
make lines with leading char multitimes
|
|
|
|
:param: times, how many times you need
|
|
:param: leading, leading character
|
|
"""
|
|
times = int(times)
|
|
if leading == 1:
|
|
msg = ""
|
|
for x in xrange(1, times+1):
|
|
msg += "%s. Item\n" % x
|
|
return msg
|
|
else:
|
|
return ("%s Item\n" % leading) * times
|
|
|
|
|
|
def look_up_directives(regex, fpath):
|
|
"""
|
|
find all directive args in given file
|
|
:param: regex, the regex that needs to match
|
|
:param: path, to path to rst file
|
|
|
|
:return: list, empty list if nothing match
|
|
"""
|
|
with open(fpath) as source:
|
|
match = re.findall(regex, source.read())
|
|
return match
|
|
|
|
|
|
def get_popular_code_type(path):
|
|
# find most popular code type in the given rst
|
|
types = look_up_directives(r'[:|\.\.\s]code::?\s(\w+)', path)
|
|
try:
|
|
popular_type = Counter(types).most_common()[0][0]
|
|
except IndexError:
|
|
popular_type = "lua" # Don't break default
|
|
|
|
return popular_type
|
|
|
|
|
|
def complete(t, opts):
|
|
msg = "({0})"
|
|
if t:
|
|
opts = [ m[len(t):] for m in opts if m.startswith(t) ]
|
|
if len(opts) == 1:
|
|
return opts[0]
|
|
|
|
if not len(opts):
|
|
msg = "{0}"
|
|
return msg.format("|".join(opts))
|
|
|
|
endglobal
|
|
|
|
snippet part "Part" b
|
|
`!p snip.rv = rst_char_len(t[1])*'#'`
|
|
${1:Part name}
|
|
`!p snip.rv = rst_char_len(t[1])*'#'`
|
|
|
|
$0
|
|
endsnippet
|
|
|
|
snippet sec "Section" b
|
|
${1:Section name}
|
|
`!p snip.rv = rst_char_len(t[1])*'='`
|
|
|
|
$0
|
|
endsnippet
|
|
|
|
snippet ssec "Subsection" b
|
|
${1:Section name}
|
|
`!p snip.rv = rst_char_len(t[1])*'-'`
|
|
|
|
$0
|
|
endsnippet
|
|
|
|
snippet sssec "Subsubsection" b
|
|
${1:Section name}
|
|
`!p snip.rv = rst_char_len(t[1])*'^'`
|
|
|
|
$0
|
|
endsnippet
|
|
|
|
snippet chap "Chapter" b
|
|
`!p snip.rv = rst_char_len(t[1])*'*'`
|
|
${1:Chapter name}
|
|
`!p snip.rv = rst_char_len(t[1])*'*'`
|
|
|
|
$0
|
|
endsnippet
|
|
|
|
snippet para "Paragraph" b
|
|
${1:Paragraph name}
|
|
`!p snip.rv = rst_char_len(t[1])*'"'`
|
|
|
|
$0
|
|
endsnippet
|
|
|
|
snippet em "Emphasize string" i
|
|
*${1:${VISUAL:Em}}* $0
|
|
endsnippet
|
|
|
|
# the CJK characters doesn't had space to sperate them, like "我强调"
|
|
# should be "我\ *强调*\ "
|
|
# Therefor we need special snippet
|
|
snippet ec "Emphasize string (CJK)" w
|
|
\ *${1:${VISUAL:Em}}*\ $0
|
|
endsnippet
|
|
|
|
snippet st "Strong string" i
|
|
**${1:${VISUAL:Strong}}** $0
|
|
endsnippet
|
|
|
|
snippet sc "Strong string (CJK)" w
|
|
\ **${1:${VISUAL:Strong}}**\ $0
|
|
endsnippet
|
|
|
|
snippet "li(st)? (?P<num>\d+)" "List" br
|
|
$0
|
|
`!p
|
|
snip.rv = make_items(match.groupdict()['num'])
|
|
`
|
|
endsnippet
|
|
|
|
# usage: ol 3<tab>
|
|
snippet "ol(st)? (?P<num>\d+)" "Order List" br
|
|
$0
|
|
`!p
|
|
snip.rv = make_items(match.groupdict()['num'], 1)
|
|
`
|
|
endsnippet
|
|
###########################################################################
|
|
# More Specialized Stuff. #
|
|
###########################################################################
|
|
snippet cb "Code Block" b
|
|
.. code-block:: ${1:`!p snip.rv = get_popular_code_type(path)`}
|
|
|
|
${2:code}
|
|
|
|
$0
|
|
endsnippet
|
|
|
|
# match snippets :
|
|
# img, inc, fig
|
|
snippet "(?P<shortcut>^img|inc|fig)" "Includable Block" !br
|
|
`!p
|
|
#TODO: Import img.template in rst relative path?
|
|
real_name=real_filename(ospath.basename(t[1]))
|
|
di=INCLUDABLE_DIRECTIVES_INDEX.get(match.groupdict()['shortcut'], 'include')
|
|
link=""
|
|
content=""
|
|
|
|
if di in ['image']:
|
|
link = "|{0}| ".format(real_name)
|
|
|
|
if di == 'figure':
|
|
content="""
|
|
:alt: {0}
|
|
{0}""".format(real_name)
|
|
|
|
snip.rv = ".. {link}{di}:: ".format(di=di,link=link)
|
|
`${1:file}`!p if content:
|
|
snip.rv +=" "+content`
|
|
`!p
|
|
# Tip of whether file is exist in comment type
|
|
if not check_file_exist(path, t[1]):
|
|
snip.rv='.. FILE {0} does not exist'.format(t[1])
|
|
else:
|
|
snip.rv=""
|
|
`$0
|
|
endsnippet
|
|
|
|
snippet di "Directives" b
|
|
.. $1`!p snip.rv=complete(t[1], DIRECTIVES)`:: $2
|
|
|
|
${3:Content}
|
|
$0
|
|
endsnippet
|
|
|
|
snippet nd "None Content Directives" b
|
|
.. $1`!p snip.rv=complete(t[1], NONE_CONTENT_DIRECTIVES)`:: $2
|
|
$0
|
|
endsnippet
|
|
|
|
snippet sa "Specific Admonitions" b
|
|
.. $1`!p snip.rv =complete(t[1], SPECIFIC_ADMONITIONS)`::
|
|
|
|
${2:Content}
|
|
|
|
$0
|
|
endsnippet
|
|
|
|
#it will be trigger at start of line or after a word
|
|
snippet ro "Text Roles" b
|
|
\ :$1`!p snip.rv=complete(t[1],
|
|
TEXT_ROLES+look_up_directives(TEXT_ROLES_REGEX,
|
|
path))`:\`$2\`\
|
|
endsnippet
|
|
|
|
############
|
|
# Sphinx #
|
|
############
|
|
|
|
snippet sid "SideBar" b
|
|
.. sidebar:: ${1:SideBar Title}
|
|
|
|
${2:SideBar Content}
|
|
endsnippet
|
|
# vim:ft=snippets:
|