# -*- 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\d+)" "List" br $0 `!p snip.rv = make_items(match.groupdict()['num']) ` endsnippet # usage: ol 3 snippet "ol(st)? (?P\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^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: