diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index 8fba2bc032..baafd8c00a 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -2892,6 +2892,9 @@ To enable folding of sections: > Note that folding can cause performance issues on some platforms. +The minimum line syntax sync is set to 50. To modify this number: > + let rst_minlines = 100 + REXX *ft-rexx-syntax* diff --git a/runtime/ftplugin/rst.vim b/runtime/ftplugin/rst.vim index c88e8f2580..887f64bb4c 100644 --- a/runtime/ftplugin/rst.vim +++ b/runtime/ftplugin/rst.vim @@ -4,6 +4,7 @@ " Original Maintainer: Nikolai Weibull " Website: https://github.com/marshallward/vim-restructuredtext " Latest Revision: 2020-03-31 +" 2025 Oct 13 by Vim project: update b:undo_ftplugin #18566 if exists("b:did_ftplugin") finish @@ -18,7 +19,7 @@ if !exists('g:rst_fold_enabled') let g:rst_fold_enabled = 0 endif -let b:undo_ftplugin = "setl com< cms< et< fo<" +let b:undo_ftplugin = "setlocal comments< commentstring< expandtab< formatoptions<" setlocal comments=fb:.. commentstring=..\ %s expandtab setlocal formatoptions+=tcroql @@ -32,15 +33,17 @@ setlocal formatoptions+=tcroql if exists("g:rst_style") && g:rst_style != 0 setlocal expandtab shiftwidth=3 softtabstop=3 tabstop=8 + let b:undo_ftplugin .= " | setlocal softtabstop< shiftwidth< tabstop<" endif -if g:rst_fold_enabled != 0 && has('patch-7.3.867') " Introduced the TextChanged event. +if g:rst_fold_enabled != 0 setlocal foldmethod=expr setlocal foldexpr=RstFold#GetRstFold() setlocal foldtext=RstFold#GetRstFoldText() augroup RstFold autocmd TextChanged,InsertLeave unlet! b:RstFoldCache augroup END + let b:undo_ftplugin .= " | setlocal foldexpr< foldmethod< foldtext<" endif let &cpo = s:cpo_save diff --git a/runtime/indent/rst.vim b/runtime/indent/rst.vim index e3c10865a6..e10079213b 100644 --- a/runtime/indent/rst.vim +++ b/runtime/indent/rst.vim @@ -4,13 +4,18 @@ " Maintainer: Marshall Ward " Previous Maintainer: Nikolai Weibull " Latest Revision: 2020-03-31 -" 2023 Aug 28 by Vim Project (undo_indent) +" 2023 Aug 28 by Vim Project (undo_indent) +" 2025 Oct 13 by Vim project: preserve indentation #18566 if exists("b:did_indent") finish endif let b:did_indent = 1 +" Save and modify cpoptions +let s:save_cpo = &cpo +set cpo&vim + setlocal indentexpr=GetRSTIndent() setlocal indentkeys=!^F,o,O setlocal nosmartindent @@ -27,7 +32,8 @@ let s:note_pattern = '^\.\. ' function! s:get_paragraph_start() let paragraph_mark_start = getpos("'{")[1] - return getline(paragraph_mark_start) =~ '\S' ? paragraph_mark_start : paragraph_mark_start + 1 + return getline(paragraph_mark_start) =~ + \ '\S' ? paragraph_mark_start : paragraph_mark_start + 1 endfunction function GetRSTIndent() @@ -42,7 +48,7 @@ function GetRSTIndent() let psnum = s:get_paragraph_start() if psnum != 0 if getline(psnum) =~ s:note_pattern - let ind = 3 + let ind = max([3, ind]) endif endif @@ -75,3 +81,7 @@ function GetRSTIndent() return ind endfunction + +" Restore 'cpoptions' +let &cpo = s:save_cpo +unlet s:save_cpo diff --git a/runtime/syntax/rst.vim b/runtime/syntax/rst.vim index a90c90be21..9584947df5 100644 --- a/runtime/syntax/rst.vim +++ b/runtime/syntax/rst.vim @@ -2,8 +2,9 @@ " Language: reStructuredText documentation format " Maintainer: Marshall Ward " Previous Maintainer: Nikolai Weibull +" Reference: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html " Website: https://github.com/marshallward/vim-restructuredtext -" Latest Revision: 2020-03-31 +" Latest Revision: 2025-10-13 if exists("b:current_syntax") finish @@ -12,13 +13,15 @@ endif let s:cpo_save = &cpo set cpo&vim -syn case ignore +" reStructuredText is case-insensitive +syntax case ignore syn match rstTransition /^[=`:.'"~^_*+#-]\{4,}\s*$/ syn cluster rstCruft contains=rstEmphasis,rstStrongEmphasis, - \ rstInterpretedText,rstInlineLiteral,rstSubstitutionReference, - \ rstInlineInternalTargets,rstFootnoteReference,rstHyperlinkReference + \ rstInterpretedTextOrHyperlinkReference,rstInlineLiteral, + \ rstSubstitutionReference,rstInlineInternalTargets,rstFootnoteReference, + \ rstHyperlinkReference syn region rstLiteralBlock matchgroup=rstDelimiter \ start='\(^\z(\s*\).*\)\@<=::\n\s*\n' skip='^\s*$' end='^\(\z1\s\+\)\@!' @@ -28,8 +31,11 @@ syn region rstQuotedLiteralBlock matchgroup=rstDelimiter \ start="::\_s*\n\ze\z([!\"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]\)" \ end='^\z1\@!' contains=@NoSpell -syn region rstDoctestBlock oneline display matchgroup=rstDelimiter +syn region rstDoctestBlock matchgroup=rstDoctestBlockPrompt \ start='^>>>\s' end='^$' + \ contains=rstDoctestBlockPrompt + +syn match rstDoctestBlockPrompt contained '^>>>\s' syn region rstTable transparent start='^\n\s*+[-=+]\+' end='^$' \ contains=rstTableLines,@rstCruft @@ -48,7 +54,8 @@ syn cluster rstDirectives contains=rstFootnote,rstCitation, \ rstHyperlinkTarget,rstExDirective syn match rstExplicitMarkup '^\s*\.\.\_s' - \ nextgroup=@rstDirectives,rstComment,rstSubstitutionDefinition + \ nextgroup=@rstDirectives,rstSubstitutionDefinition + \ contains=rstComment " "Simple reference names are single words consisting of alphanumerics plus " isolated (no two adjacent) internal hyphens, underscores, periods, colons @@ -57,20 +64,23 @@ let s:ReferenceName = '[[:alnum:]]\%([-_.:+]\?[[:alnum:]]\+\)*' syn keyword rstTodo contained FIXME TODO XXX NOTE -execute 'syn region rstComment contained' . - \ ' start=/.*/' +syn region rstComment + \ start='\v^\z(\s*)\.\.(\_s+[\[|_]|\_s+.*::)@!' skip=+^$+ end=/^\(\z1 \)\@!/ + \ contains=@Spell,rstTodo + +" Note: Order matters for rstCitation and rstFootnote as the regex for +" citations also matches numeric only patterns, e.g. [1], which are footnotes. +" Since we define rstFootnote after rstCitation, it takes precedence, see +" |:syn-define|. +execute 'syn region rstCitation contained matchgroup=rstDirective' . + \ ' start=+\[' . s:ReferenceName . '\]\_s+' . \ ' skip=+^$+' . - \ ' end=/^\s\@!/ contains=rstTodo' + \ ' end=+^\s\@!+ contains=@Spell,@rstCruft' execute 'syn region rstFootnote contained matchgroup=rstDirective' . \ ' start=+\[\%(\d\+\|#\%(' . s:ReferenceName . '\)\=\|\*\)\]\_s+' . \ ' skip=+^$+' . - \ ' end=+^\s\@!+ contains=@rstCruft,@NoSpell' - -execute 'syn region rstCitation contained matchgroup=rstDirective' . - \ ' start=+\[' . s:ReferenceName . '\]\_s+' . - \ ' skip=+^$+' . - \ ' end=+^\s\@!+ contains=@rstCruft,@NoSpell' + \ ' end=+^\s\@!+ contains=@Spell,@rstCruft' syn region rstHyperlinkTarget contained matchgroup=rstDirective \ start='_\%(_\|[^:\\]*\%(\\.[^:\\]*\)*\):\_s' skip=+^$+ end=+^\s\@!+ @@ -84,11 +94,14 @@ syn region rstHyperlinkTarget matchgroup=rstDirective execute 'syn region rstExDirective contained matchgroup=rstDirective' . \ ' start=+' . s:ReferenceName . '::\_s+' . \ ' skip=+^$+' . - \ ' end=+^\s\@!+ contains=@rstCruft,rstLiteralBlock' + \ ' end=+^\s\@!+ contains=@Spell,@rstCruft,rstLiteralBlock,rstExplicitMarkup' execute 'syn match rstSubstitutionDefinition contained' . \ ' /|.*|\_s\+/ nextgroup=@rstDirectives' + +"" Inline Markup "" + function! s:DefineOneInlineMarkup(name, start, middle, end, char_left, char_right) " Only escape the first char of a multichar delimiter (e.g. \* inside **) if a:start[0] == '\' @@ -97,23 +110,33 @@ function! s:DefineOneInlineMarkup(name, start, middle, end, char_left, char_righ let first = a:start[0] endif - execute 'syn match rstEscape'.a:name.' +\\\\\|\\'.first.'+'.' contained' + if a:start != '``' + let rst_contains=' contains=@Spell,rstEscape' . a:name + execute 'syn match rstEscape'.a:name.' +\\\\\|\\'.first.'+'.' contained' + else + let rst_contains=' contains=@Spell' + endif execute 'syn region rst' . a:name . \ ' start=+' . a:char_left . '\zs' . a:start . \ '\ze[^[:space:]' . a:char_right . a:start[strlen(a:start) - 1] . ']+' . \ a:middle . \ ' end=+' . a:end . '\ze\%($\|\s\|[''"’)\]}>/:.,;!?\\-]\)+' . - \ ' contains=rstEscape' . a:name + \ rst_contains - execute 'hi def link rstEscape'.a:name.' Special' + if a:start != '``' + execute 'hi def link rstEscape'.a:name.' Special' + endif endfunction function! s:DefineInlineMarkup(name, start, middle, end) - let middle = a:middle != "" ? - \ (' skip=+\\\\\|\\' . a:middle . '\|\s' . a:middle . '+') : - \ "" + if a:middle == '`' + let middle = ' skip=+\s'.a:middle.'+' + else + let middle = ' skip=+\\\\\|\\' . a:middle . '\|\s' . a:middle . '+' + endif + " Some characters may precede or follow an inline token call s:DefineOneInlineMarkup(a:name, a:start, middle, a:end, "'", "'") call s:DefineOneInlineMarkup(a:name, a:start, middle, a:end, '"', '"') call s:DefineOneInlineMarkup(a:name, a:start, middle, a:end, '(', ')') @@ -121,8 +144,8 @@ function! s:DefineInlineMarkup(name, start, middle, end) call s:DefineOneInlineMarkup(a:name, a:start, middle, a:end, '{', '}') call s:DefineOneInlineMarkup(a:name, a:start, middle, a:end, '<', '>') call s:DefineOneInlineMarkup(a:name, a:start, middle, a:end, '’', '’') - " TODO: Additional Unicode Pd, Po, Pi, Pf, Ps characters + " TODO: Additional whitespace Unicode characters: Pd, Po, Pi, Pf, Ps call s:DefineOneInlineMarkup(a:name, a:start, middle, a:end, '\%(^\|\s\|\%ua0\|[/:]\)', '') execute 'syn match rst' . a:name . @@ -136,7 +159,7 @@ endfunction call s:DefineInlineMarkup('Emphasis', '\*', '\*', '\*') call s:DefineInlineMarkup('StrongEmphasis', '\*\*', '\*', '\*\*') call s:DefineInlineMarkup('InterpretedTextOrHyperlinkReference', '`', '`', '`_\{0,2}') -call s:DefineInlineMarkup('InlineLiteral', '``', "", '``') +call s:DefineInlineMarkup('InlineLiteral', '``', '`', '``') call s:DefineInlineMarkup('SubstitutionReference', '|', '|', '|_\{0,2}') call s:DefineInlineMarkup('InlineInternalTargets', '_`', '`', '`') @@ -172,6 +195,8 @@ execute 'syn match rstHyperlinkReference' . syn match rstStandaloneHyperlink contains=@NoSpell \ "\<\%(\%(\%(https\=\|file\|ftp\|gopher\)://\|\%(mailto\|news\):\)[^[:space:]'\"<>]\+\|www[[:alnum:]_-]*\.[[:alnum:]_-]\+\.[^[:space:]'\"<>]\+\)[[:alnum:]/]" +" `code` is the standard reST directive for source code. +" `code-block` and `sourcecode` are nearly identical directives in Sphinx. syn region rstCodeBlock contained matchgroup=rstDirective \ start=+\%(sourcecode\|code\%(-block\)\=\)::\s*\(\S*\)\?\s*\n\%(\s*:.*:\s*.*\s*\n\)*\n\ze\z(\s\+\)+ \ skip=+^$+ @@ -243,11 +268,11 @@ for s:filetype in keys(g:rst_syntax_code_list) unlet! prior_isk endfor + " Enable top level spell checking syntax spell toplevel -" TODO: Use better syncing. -syn sync minlines=50 linebreaks=2 +exe "syn sync minlines=" . get(g:, 'rst_minlines', 50) . " linebreaks=2" hi def link rstTodo Todo hi def link rstComment Comment @@ -256,6 +281,7 @@ hi def link rstTransition rstSections hi def link rstLiteralBlock String hi def link rstQuotedLiteralBlock String hi def link rstDoctestBlock PreProc +hi def link rstDoctestBlockPrompt rstDelimiter hi def link rstTableLines rstDelimiter hi def link rstSimpleTableLines rstTableLines hi def link rstExplicitMarkup rstDirective