rst.vim 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. " Vim reST syntax file
  2. " Language: reStructuredText documentation format
  3. " Maintainer: Marshall Ward <marshall.ward@gmail.com>
  4. " Previous Maintainer: Nikolai Weibull <now@bitwi.se>
  5. " Website: https://github.com/marshallward/vim-restructuredtext
  6. " Latest Revision: 2020-03-31
  7. if exists("b:current_syntax")
  8. finish
  9. endif
  10. let s:cpo_save = &cpo
  11. set cpo&vim
  12. syn case ignore
  13. syn match rstTransition /^[=`:.'"~^_*+#-]\{4,}\s*$/
  14. syn cluster rstCruft contains=rstEmphasis,rstStrongEmphasis,
  15. \ rstInterpretedText,rstInlineLiteral,rstSubstitutionReference,
  16. \ rstInlineInternalTargets,rstFootnoteReference,rstHyperlinkReference
  17. syn region rstLiteralBlock matchgroup=rstDelimiter
  18. \ start='\(^\z(\s*\).*\)\@<=::\n\s*\n' skip='^\s*$' end='^\(\z1\s\+\)\@!'
  19. \ contains=@NoSpell
  20. syn region rstQuotedLiteralBlock matchgroup=rstDelimiter
  21. \ start="::\_s*\n\ze\z([!\"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]\)"
  22. \ end='^\z1\@!' contains=@NoSpell
  23. syn region rstDoctestBlock oneline display matchgroup=rstDelimiter
  24. \ start='^>>>\s' end='^$'
  25. syn region rstTable transparent start='^\n\s*+[-=+]\+' end='^$'
  26. \ contains=rstTableLines,@rstCruft
  27. syn match rstTableLines contained display '|\|+\%(=\+\|-\+\)\='
  28. syn region rstSimpleTable transparent
  29. \ start='^\n\%(\s*\)\@>\%(\%(=\+\)\@>\%(\s\+\)\@>\)\%(\%(\%(=\+\)\@>\%(\s*\)\@>\)\+\)\@>$'
  30. \ end='^$'
  31. \ contains=rstSimpleTableLines,@rstCruft
  32. syn match rstSimpleTableLines contained display
  33. \ '^\%(\s*\)\@>\%(\%(=\+\)\@>\%(\s\+\)\@>\)\%(\%(\%(=\+\)\@>\%(\s*\)\@>\)\+\)\@>$'
  34. syn match rstSimpleTableLines contained display
  35. \ '^\%(\s*\)\@>\%(\%(-\+\)\@>\%(\s\+\)\@>\)\%(\%(\%(-\+\)\@>\%(\s*\)\@>\)\+\)\@>$'
  36. syn cluster rstDirectives contains=rstFootnote,rstCitation,
  37. \ rstHyperlinkTarget,rstExDirective
  38. syn match rstExplicitMarkup '^\s*\.\.\_s'
  39. \ nextgroup=@rstDirectives,rstComment,rstSubstitutionDefinition
  40. " "Simple reference names are single words consisting of alphanumerics plus
  41. " isolated (no two adjacent) internal hyphens, underscores, periods, colons
  42. " and plus signs."
  43. let s:ReferenceName = '[[:alnum:]]\%([-_.:+]\?[[:alnum:]]\+\)*'
  44. syn keyword rstTodo contained FIXME TODO XXX NOTE
  45. execute 'syn region rstComment contained' .
  46. \ ' start=/.*/'
  47. \ ' skip=+^$+' .
  48. \ ' end=/^\s\@!/ contains=rstTodo'
  49. execute 'syn region rstFootnote contained matchgroup=rstDirective' .
  50. \ ' start=+\[\%(\d\+\|#\%(' . s:ReferenceName . '\)\=\|\*\)\]\_s+' .
  51. \ ' skip=+^$+' .
  52. \ ' end=+^\s\@!+ contains=@rstCruft,@NoSpell'
  53. execute 'syn region rstCitation contained matchgroup=rstDirective' .
  54. \ ' start=+\[' . s:ReferenceName . '\]\_s+' .
  55. \ ' skip=+^$+' .
  56. \ ' end=+^\s\@!+ contains=@rstCruft,@NoSpell'
  57. syn region rstHyperlinkTarget contained matchgroup=rstDirective
  58. \ start='_\%(_\|[^:\\]*\%(\\.[^:\\]*\)*\):\_s' skip=+^$+ end=+^\s\@!+
  59. syn region rstHyperlinkTarget contained matchgroup=rstDirective
  60. \ start='_`[^`\\]*\%(\\.[^`\\]*\)*`:\_s' skip=+^$+ end=+^\s\@!+
  61. syn region rstHyperlinkTarget matchgroup=rstDirective
  62. \ start=+^__\_s+ skip=+^$+ end=+^\s\@!+
  63. execute 'syn region rstExDirective contained matchgroup=rstDirective' .
  64. \ ' start=+' . s:ReferenceName . '::\_s+' .
  65. \ ' skip=+^$+' .
  66. \ ' end=+^\s\@!+ contains=@rstCruft,rstLiteralBlock'
  67. execute 'syn match rstSubstitutionDefinition contained' .
  68. \ ' /|.*|\_s\+/ nextgroup=@rstDirectives'
  69. function! s:DefineOneInlineMarkup(name, start, middle, end, char_left, char_right)
  70. " Only escape the first char of a multichar delimiter (e.g. \* inside **)
  71. if a:start[0] == '\'
  72. let first = a:start[0:1]
  73. else
  74. let first = a:start[0]
  75. endif
  76. execute 'syn match rstEscape'.a:name.' +\\\\\|\\'.first.'+'.' contained'
  77. execute 'syn region rst' . a:name .
  78. \ ' start=+' . a:char_left . '\zs' . a:start .
  79. \ '\ze[^[:space:]' . a:char_right . a:start[strlen(a:start) - 1] . ']+' .
  80. \ a:middle .
  81. \ ' end=+' . a:end . '\ze\%($\|\s\|[''"’)\]}>/:.,;!?\\-]\)+' .
  82. \ ' contains=rstEscape' . a:name
  83. execute 'hi def link rstEscape'.a:name.' Special'
  84. endfunction
  85. function! s:DefineInlineMarkup(name, start, middle, end)
  86. let middle = a:middle != "" ?
  87. \ (' skip=+\\\\\|\\' . a:middle . '\|\s' . a:middle . '+') :
  88. \ ""
  89. call s:DefineOneInlineMarkup(a:name, a:start, middle, a:end, "'", "'")
  90. call s:DefineOneInlineMarkup(a:name, a:start, middle, a:end, '"', '"')
  91. call s:DefineOneInlineMarkup(a:name, a:start, middle, a:end, '(', ')')
  92. call s:DefineOneInlineMarkup(a:name, a:start, middle, a:end, '\[', '\]')
  93. call s:DefineOneInlineMarkup(a:name, a:start, middle, a:end, '{', '}')
  94. call s:DefineOneInlineMarkup(a:name, a:start, middle, a:end, '<', '>')
  95. call s:DefineOneInlineMarkup(a:name, a:start, middle, a:end, '’', '’')
  96. " TODO: Additional Unicode Pd, Po, Pi, Pf, Ps characters
  97. call s:DefineOneInlineMarkup(a:name, a:start, middle, a:end, '\%(^\|\s\|\%ua0\|[/:]\)', '')
  98. execute 'syn match rst' . a:name .
  99. \ ' +\%(^\|\s\|\%ua0\|[''"([{</:]\)\zs' . a:start .
  100. \ '[^[:space:]' . a:start[strlen(a:start) - 1] . ']'
  101. \ a:end . '\ze\%($\|\s\|[''")\]}>/:.,;!?\\-]\)+'
  102. execute 'hi def link rst' . a:name . 'Delimiter' . ' rst' . a:name
  103. endfunction
  104. call s:DefineInlineMarkup('Emphasis', '\*', '\*', '\*')
  105. call s:DefineInlineMarkup('StrongEmphasis', '\*\*', '\*', '\*\*')
  106. call s:DefineInlineMarkup('InterpretedTextOrHyperlinkReference', '`', '`', '`_\{0,2}')
  107. call s:DefineInlineMarkup('InlineLiteral', '``', "", '``')
  108. call s:DefineInlineMarkup('SubstitutionReference', '|', '|', '|_\{0,2}')
  109. call s:DefineInlineMarkup('InlineInternalTargets', '_`', '`', '`')
  110. " Sections are identified through their titles, which are marked up with
  111. " adornment: "underlines" below the title text, or underlines and matching
  112. " "overlines" above the title. An underline/overline is a single repeated
  113. " punctuation character that begins in column 1 and forms a line extending at
  114. " least as far as the right edge of the title text.
  115. "
  116. " It is difficult to count characters in a regex, but we at least special-case
  117. " the case where the title has at least three characters to require the
  118. " adornment to have at least three characters as well, in order to handle
  119. " properly the case of a literal block:
  120. "
  121. " this is the end of a paragraph
  122. " ::
  123. " this is a literal block
  124. syn match rstSections "\v^%(([=`:.'"~^_*+#-])\1+\n)?.{1,2}\n([=`:.'"~^_*+#-])\2+$"
  125. \ contains=@Spell
  126. syn match rstSections "\v^%(([=`:.'"~^_*+#-])\1{2,}\n)?.{3,}\n([=`:.'"~^_*+#-])\2{2,}$"
  127. \ contains=@Spell
  128. " TODO: Can’t remember why these two can’t be defined like the ones above.
  129. execute 'syn match rstFootnoteReference contains=@NoSpell' .
  130. \ ' +\%(\s\|^\)\[\%(\d\+\|#\%(' . s:ReferenceName . '\)\=\|\*\)\]_+'
  131. execute 'syn match rstCitationReference contains=@NoSpell' .
  132. \ ' +\%(\s\|^\)\[' . s:ReferenceName . '\]_\ze\%($\|\s\|[''")\]}>/:.,;!?\\-]\)+'
  133. execute 'syn match rstHyperlinkReference' .
  134. \ ' /\<' . s:ReferenceName . '__\=\ze\%($\|\s\|[''")\]}>/:.,;!?\\-]\)/'
  135. syn match rstStandaloneHyperlink contains=@NoSpell
  136. \ "\<\%(\%(\%(https\=\|file\|ftp\|gopher\)://\|\%(mailto\|news\):\)[^[:space:]'\"<>]\+\|www[[:alnum:]_-]*\.[[:alnum:]_-]\+\.[^[:space:]'\"<>]\+\)[[:alnum:]/]"
  137. syn region rstCodeBlock contained matchgroup=rstDirective
  138. \ start=+\%(sourcecode\|code\%(-block\)\=\)::\s*\(\S*\)\?\s*\n\%(\s*:.*:\s*.*\s*\n\)*\n\ze\z(\s\+\)+
  139. \ skip=+^$+
  140. \ end=+^\z1\@!+
  141. \ contains=@NoSpell
  142. syn cluster rstDirectives add=rstCodeBlock
  143. if !exists('g:rst_syntax_code_list')
  144. " A mapping from a Vim filetype to a list of alias patterns (pattern
  145. " branches to be specific, see ':help /pattern'). E.g. given:
  146. "
  147. " let g:rst_syntax_code_list = {
  148. " \ 'cpp': ['cpp', 'c++'],
  149. " \ }
  150. "
  151. " then the respective contents of the following two rST directives:
  152. "
  153. " .. code:: cpp
  154. "
  155. " auto i = 42;
  156. "
  157. " .. code:: C++
  158. "
  159. " auto i = 42;
  160. "
  161. " will both be highlighted as C++ code. As shown by the latter block
  162. " pattern matching will be case-insensitive.
  163. let g:rst_syntax_code_list = {
  164. \ 'vim': ['vim'],
  165. \ 'java': ['java'],
  166. \ 'cpp': ['cpp', 'c++'],
  167. \ 'lisp': ['lisp'],
  168. \ 'php': ['php'],
  169. \ 'python': ['python'],
  170. \ 'perl': ['perl'],
  171. \ 'sh': ['sh'],
  172. \ }
  173. elseif type(g:rst_syntax_code_list) == type([])
  174. " backward compatibility with former list format
  175. let s:old_spec = g:rst_syntax_code_list
  176. let g:rst_syntax_code_list = {}
  177. for s:elem in s:old_spec
  178. let g:rst_syntax_code_list[s:elem] = [s:elem]
  179. endfor
  180. endif
  181. for s:filetype in keys(g:rst_syntax_code_list)
  182. unlet! b:current_syntax
  183. " guard against setting 'isk' option which might cause problems (issue #108)
  184. let prior_isk = &l:iskeyword
  185. let s:alias_pattern = ''
  186. \.'\%('
  187. \.join(g:rst_syntax_code_list[s:filetype], '\|')
  188. \.'\)'
  189. exe 'syn include @rst'.s:filetype.' syntax/'.s:filetype.'.vim'
  190. exe 'syn region rstDirective'.s:filetype
  191. \.' matchgroup=rstDirective fold'
  192. \.' start="\c\%(sourcecode\|code\%(-block\)\=\)::\s\+'.s:alias_pattern.'\_s*\n\ze\z(\s\+\)"'
  193. \.' skip=#^$#'
  194. \.' end=#^\z1\@!#'
  195. \.' contains=@NoSpell,@rst'.s:filetype
  196. exe 'syn cluster rstDirectives add=rstDirective'.s:filetype
  197. " reset 'isk' setting, if it has been changed
  198. if &l:iskeyword !=# prior_isk
  199. let &l:iskeyword = prior_isk
  200. endif
  201. unlet! prior_isk
  202. endfor
  203. " Enable top level spell checking
  204. syntax spell toplevel
  205. " TODO: Use better syncing.
  206. syn sync minlines=50 linebreaks=2
  207. hi def link rstTodo Todo
  208. hi def link rstComment Comment
  209. hi def link rstSections Title
  210. hi def link rstTransition rstSections
  211. hi def link rstLiteralBlock String
  212. hi def link rstQuotedLiteralBlock String
  213. hi def link rstDoctestBlock PreProc
  214. hi def link rstTableLines rstDelimiter
  215. hi def link rstSimpleTableLines rstTableLines
  216. hi def link rstExplicitMarkup rstDirective
  217. hi def link rstDirective Keyword
  218. hi def link rstFootnote String
  219. hi def link rstCitation String
  220. hi def link rstHyperlinkTarget String
  221. hi def link rstExDirective String
  222. hi def link rstSubstitutionDefinition rstDirective
  223. hi def link rstDelimiter Delimiter
  224. hi def link rstInterpretedTextOrHyperlinkReference Identifier
  225. hi def link rstInlineLiteral String
  226. hi def link rstSubstitutionReference PreProc
  227. hi def link rstInlineInternalTargets Identifier
  228. hi def link rstFootnoteReference Identifier
  229. hi def link rstCitationReference Identifier
  230. hi def link rstHyperLinkReference Identifier
  231. hi def link rstStandaloneHyperlink Identifier
  232. hi def link rstCodeBlock String
  233. if exists('g:rst_use_emphasis_colors')
  234. " TODO: Less arbitrary color selection
  235. hi def rstEmphasis ctermfg=13 term=italic cterm=italic gui=italic
  236. hi def rstStrongEmphasis ctermfg=1 term=bold cterm=bold gui=bold
  237. else
  238. hi def rstEmphasis term=italic cterm=italic gui=italic
  239. hi def rstStrongEmphasis term=bold cterm=bold gui=bold
  240. endif
  241. let b:current_syntax = "rst"
  242. let &cpo = s:cpo_save
  243. unlet s:cpo_save