diff --git a/doc/UltiSnips.txt b/doc/UltiSnips.txt index d05a888..fed76e8 100644 --- a/doc/UltiSnips.txt +++ b/doc/UltiSnips.txt @@ -1392,6 +1392,7 @@ individuals have contributed to UltiSnips (in chronological order): Christian - Oberon00 Andrew Ruder - aeruder Mathias Fußenegger - mfussenegger + Kevin Ballard - kballard Thank you for your support. diff --git a/ftplugin/snippets.vim b/ftplugin/snippets.vim index 134fe01..69e1abf 100644 --- a/ftplugin/snippets.vim +++ b/ftplugin/snippets.vim @@ -7,6 +7,7 @@ setlocal foldlevel=99 setlocal commentstring=#%s setlocal noexpandtab +setlocal autoindent nosmartindent nocindent " Define match words for use with matchit plugin " http://www.vim.org/scripts/script.php?script_id=39 diff --git a/pythonx/UltiSnips/snippet/parsing/_lexer.py b/pythonx/UltiSnips/snippet/parsing/_lexer.py index 5233e31..1c5794f 100644 --- a/pythonx/UltiSnips/snippet/parsing/_lexer.py +++ b/pythonx/UltiSnips/snippet/parsing/_lexer.py @@ -253,7 +253,7 @@ class EscapeCharToken(Token): ) class ShellCodeToken(Token): - """`! echo "hi"`""" + """`echo "hi"`""" @classmethod def starts_here(cls, stream): """Returns true if this token starts at the current position in diff --git a/syntax/snippets.vim b/syntax/snippets.vim index 085b408..19a9da1 100644 --- a/syntax/snippets.vim +++ b/syntax/snippets.vim @@ -5,68 +5,200 @@ if exists("b:current_syntax") finish endif +if expand("%:p:h:t") == "snippets" && search("^endsnippet", "nw") == 0 + \ && !exists("b:ultisnips_override_snipmate") + " this appears to be a snipmate file + " It's in a directory called snippets/ and there's no endsnippet keyword + " anywhere in the file. + source :h/snippets_snipmate.vim + finish +endif + +" Embedded Syntaxes {{{1 + syntax include @Python syntax/python.vim +unlet b:current_syntax syntax include @Viml syntax/vim.vim +unlet b:current_syntax +syntax include @Shell syntax/sh.vim +unlet b:current_syntax -" global matches -syn match snipComment "^#.*" contains=snipTODO -syn keyword snipTODO FIXME NOTE NOTES TODO XXX contained +" Syntax definitions {{{1 -syn match snipDocString '"[^"]*"$' -syn match snipString '"[^"]*"' -syn match snipTabsOnly "^\t\+$" -syn match snipLeadingSpaces "^\t* \+" +" Comments {{{2 -syn match snipKeyword "\(\<\(end\)\?\(snippet\|global\)\>\)\|extends\|clearsnippets\|priority" contained +syn match snipComment "^#.*" contains=snipTODO display +syn keyword snipTODO contained display FIXME NOTE NOTES TODO XXX -" extends definitions -syn match snipExtends "^extends.*" contains=snipKeyword +" Errors {{{2 -" snippet definitions -syn match snipStart "^snippet.*" contained contains=snipKeyword,snipDocString -syn match snipEnd "^endsnippet" contained contains=snipKeyword -syn region snipCommand contained keepend start="`" end="`" contains=snipPythonCommand,snipVimLCommand -syn region snipPythonCommand contained keepend start="`!p" end="`" contained contains=@Python -syn region snipVimLCommand contained keepend start="`!v" end="`" contained contains=@Viml -syn match snipVar "\$\d*" contained -syn region snipVisual matchgroup=Define start="\${VISUAL" end="}" contained -syn region snipVarExpansion matchgroup=Define start="\${\d*" end="}" contained contains=snipVar,snipVarExpansion,snipCommand -syn region snippet fold keepend start="^snippet" end="^endsnippet" contains=snipStart,snipEnd,snipTabsOnly,snipLeadingSpaces,snipCommand,snipVarExpansion,snipVar,snipVisual +syn match snipLeadingSpaces "^\t* \+" contained -" global definitions -syn match snipGlobalStart "^global.*" contained contains=snipKeyword,snipString -syn match snipGlobalEnd "^endglobal" contained contains=snipKeyword -syn region snipGlobal fold keepend start="^global" end="^endglobal" contains=snipGlobalStart,snipGlobalEnd,snipLeadingSpaces,snipTabsOnly,snipCommand,snipVarExpansion,snipVar,@Python +" Extends {{{2 -" snippet clearing -syn match snipClear "^clearsnippets" -syn match snipPriority "^priority" +syn match snipExtends "^extends\%(\s.*\|$\)" contains=snipExtendsKeyword display +syn match snipExtendsKeyword "^extends" contained display -" highlighting rules +" Definitions {{{2 -hi link snipComment Comment -hi link snipLeadingSpaces Error -hi link snipString String -hi link snipDocString String -hi link snipTabsOnly Error +" snippet {{{3 -hi link snipKeyword Keyword +syn region snipSnippet start="^snippet\_s" end="^\zeendsnippet\s*$" contains=snipSnippetHeader nextgroup=snipSnippetFooter fold keepend +syn match snipSnippetHeader "^.*$" nextgroup=snipSnippetBody,snipSnippetFooter skipnl contained contains=snipSnippetHeaderKeyword +syn match snipSnippetHeaderKeyword "^snippet" contained nextgroup=snipSnippetTrigger skipwhite +syn region snipSnippetBody start="\_." end="^\zeendsnippet\s*$" contained contains=snipLeadingSpaces,@snipTokens +syn match snipSnippetFooter "^endsnippet.*" contained contains=snipSnippetFooterKeyword +syn match snipSnippetFooterKeyword "^endsnippet" contained -hi link snipExtends Statement +" The current parser is a bit lax about parsing. For example, given this: +" snippet foo"bar" +" it treats `foo"bar"` as the trigger. But with this: +" snippet foo"bar baz" +" it treats `foo` as the trigger and "bar baz" as the description. +" I think this is an accident. Instead, we'll assume the description must +" be surrounded by spaces. That means we'll treat +" snippet foo"bar" +" as a trigger `foo"bar"` and +" snippet foo"bar baz" +" as an attempted multiword snippet `foo"bar baz"` that is invalid. +" NB: UltiSnips parses right-to-left, which Vim doesn't support, so that makes +" the following patterns very complicated. +syn match snipSnippetTrigger "\S\+" contained nextgroup=snipSnippetDocString,snipSnippetTriggerInvalid skipwhite +" We want to match a trailing " as the start of a doc comment, but we also +" want to allow for using " as the delimiter in a multiword/pattern snippet. +" So we have to define this twice, once in the general case that matches a +" trailing " as the doc comment, and once for the case of the multiword +" delimiter using " that has more constraints +syn match snipSnippetTrigger ,\([^"[:space:]]\).\{-}\1\%(\s*$\)\@!\ze\%(\s\+"[^"]*\%("\s\+[^"[:space:]]\+\|"\)\=\)\=\s*$, contained nextgroup=snipSnippetDocString skipwhite +syn match snipSnippetTrigger ,".\{-}"\ze\%(\s\+"\%(\s*\S\)\@=[^"]*\%("\s\+[^"[:space:]]\+\|"\)\=\)\=\s*$, contained nextgroup=snipSnippetDocString skipwhite +syn match snipSnippetTriggerInvalid ,\S\@=.\{-}\S\ze\%(\s\+"[^"]*\%("\s\+[^"[:space:]]\+\s*\|"\s*\)\=\|\s*\)$, contained nextgroup=snipSnippetDocString skipwhite +syn match snipSnippetDocString ,"[^"]*\%("\ze\s*\%(\s[^"[:space:]]\+\s*\)\=\)\=$, contained nextgroup=snipSnippetOptions skipwhite +syn match snipSnippetOptions ,\S\+, contained contains=snipSnippetOptionFlag +syn match snipSnippetOptionFlag ,[biwrts], contained -hi link snipStart Statement -hi link snipEnd Statement -hi link snipCommand Special -hi link snipVar StorageClass -hi link snipVarExpansion Normal -hi link snipVisual Normal -hi link snippet Normal +" Command substitution {{{4 -hi link snipGlobalStart Statement -hi link snipGlobalEnd Statement -hi link snipGlobal Normal +syn region snipCommand keepend matchgroup=snipCommandDelim start="`" skip="\\[{}\\$`]" end="`" contained contains=snipPythonCommand,snipVimLCommand,snipShellCommand,snipCommandSyntaxOverride +syn region snipShellCommand start="\ze\_." skip="\\[{}\\$`]" end="\ze`" contained contains=@Shell +syn region snipPythonCommand matchgroup=snipPythonCommandP start="`\@<=!p\_s" skip="\\[{}\\$`]" end="\ze`" contained contains=@Python +syn region snipVimLCommand matchgroup=snipVimLCommandV start="`\@<=!v\_s" skip="\\[{}\\$`]" end="\ze`" contained contains=@Viml +syn cluster snipTokens add=snipCommand +syn cluster snipTabStopTokens add=snipCommand -hi link snipClear Statement -hi link snipPriority Statement +" unfortunately due to the balanced braces parsing of commands, if a { occurs +" in the command, we need to prevent the embedded syntax highlighting. +" Otherwise, we can't track the balanced braces properly. -let b:current_syntax = "snippet" +syn region snipCommandSyntaxOverride start="\%(\\[{}\\$`]\|\_[^`"{]\)*\ze{" skip="\\[{}\\$`]" end="\ze`" contained contains=snipBalancedBraces transparent + +" Tab Stops {{{4 + +syn match snipEscape "\\[{}\\$`]" contained +syn cluster snipTokens add=snipEscape +syn cluster snipTabStopTokens add=snipEscape + +syn match snipMirror "\$\d\+" contained +syn cluster snipTokens add=snipMirror +syn cluster snipTabStopTokens add=snipMirror + +syn region snipTabStop matchgroup=snipTabStop start="\${\d\+[:}]\@=" end="}" contained contains=snipTabStopDefault +syn region snipTabStopDefault matchgroup=snipTabStop start=":" skip="\\[{}]" end="\ze}" contained contains=snipTabStopEscape,snipBalancedBraces,@snipTabStopTokens keepend +syn match snipTabStopEscape "\\[{}]" contained +syn region snipBalancedBraces start="{" end="}" contained transparent extend +syn cluster snipTokens add=snipTabStop +syn cluster snipTabStopTokens add=snipTabStop + +syn region snipVisual matchgroup=snipVisual start="\${VISUAL[:}/]\@=" end="}" contained contains=snipVisualDefault,snipTransformationPattern +syn region snipVisualDefault matchgroup=snipVisual start=":" end="\ze[}/]" contained contains=snipTabStopEscape nextgroup=snipTransformationPattern +syn cluster snipTokens add=snipVisual +syn cluster snipTabStopTokens add=snipVisual + +syn region snipTransformation matchgroup=snipTransformation start="\${\d\/\@=" end="}" contained contains=snipTransformationPattern +syn region snipTransformationPattern matchgroup=snipTransformationPatternDelim start="/" end="\ze/" contained contains=snipTransformationEscape nextgroup=snipTransformationReplace skipnl +syn region snipTransformationReplace matchgroup=snipTransformationPatternDelim start="/" end="/" contained contains=snipTransformationEscape nextgroup=snipTransformationOptions skipnl +syn region snipTransformationOptions start="\ze[^}]" end="\ze}" contained contains=snipTabStopEscape +syn match snipTransformationEscape "\\/" contained +syn cluster snipTokens add=snipTransformation +syn cluster snipTabStopTokens add=snipTransformation + +" global {{{3 + +" Generic (non-Python) {{{4 + +syn region snipGlobal start="^global\_s" end="^\zeendglobal\s*$" contains=snipGlobalHeader nextgroup=snipGlobalFooter fold keepend +syn match snipGlobalHeader "^.*$" nextgroup=snipGlobalBody,snipGlobalFooter skipnl contained contains=snipGlobalHeaderKeyword +syn region snipGlobalBody start="\_." end="^\zeendglobal\s*$" contained contains=snipLeadingSpaces + +" Python (!p) {{{4 + +syn region snipGlobal start=,^global\s\+!p\%(\s\+"[^"]*\%("\s\+[^"[:space:]]\+\|"\)\=\)\=\s*$, end=,^\zeendglobal\s*$, contains=snipGlobalPHeader nextgroup=snipGlobalFooter fold keepend +syn match snipGlobalPHeader "^.*$" nextgroup=snipGlobalPBody,snipGlobalFooter skipnl contained contains=snipGlobalHeaderKeyword +syn match snipGlobalHeaderKeyword "^global" contained nextgroup=snipSnippetTrigger skipwhite +syn region snipGlobalPBody start="\_." end="^\zeendglobal\s*$" contained contains=@Python + +" Common {{{4 + +syn match snipGlobalFooter "^endglobal.*" contained contains=snipGlobalFooterKeyword +syn match snipGlobalFooterKeyword "^endglobal" contained + +" priority {{{3 + +syn match snipPriority "^priority\%(\s.*\|$\)" contains=snipPriorityKeyword display +syn match snipPriorityKeyword "^priority" contained nextgroup=snipPriorityValue skipwhite display +syn match snipPriorityValue "-\?\d\+" contained display + +" Snippt Clearing {{{2 + +syn match snipClear "^clearsnippets\%(\s.*\|$\)" contains=snipClearKeyword display +syn match snipClearKeyword "^clearsnippets" contained display + +" Highlight groups {{{1 + +hi def link snipComment Comment +hi def link snipTODO Todo +hi def snipLeadingSpaces term=reverse ctermfg=15 ctermbg=4 gui=reverse guifg=#dc322f + +hi def link snipKeyword Keyword + +hi def link snipExtendsKeyword snipKeyword + +hi def link snipSnippetHeaderKeyword snipKeyword +hi def link snipSnippetFooterKeyword snipKeyword + +hi def link snipSnippetTrigger Identifier +hi def link snipSnippetTriggerInvalid Error +hi def link snipSnippetDocString String +hi def link snipSnippetOptionFlag Special + +hi def link snipGlobalHeaderKeyword snipKeyword +hi def link snipGlobalFooterKeyword snipKeyword + +hi def link snipCommand Special +hi def link snipCommandDelim snipCommand +hi def link snipShellCommand snipCommand +hi def link snipVimLCommand snipCommand +hi def link snipPythonCommandP PreProc +hi def link snipVimLCommandV PreProc + +hi def link snipEscape Special +hi def link snipMirror StorageClass +hi def link snipTabStop Define +hi def link snipTabStopDefault String +hi def link snipTabStopEscape Special +hi def link snipVisual snipTabStop +hi def link snipVisualDefault snipTabStopDefault +hi def link snipTransformation snipTabStop +hi def link snipTransformationPattern String +hi def link snipTransformationPatternDelim Operator +hi def link snipTransformationReplace String +hi def link snipTransformationEscape snipEscape +hi def link snipTransformationOptions Operator + +hi def link snipPriorityKeyword Keyword +hi def link snipPriorityValue Number + +hi def link snipClearKeyword Keyword + +" }}}1 + +let b:current_syntax = "snippets" diff --git a/syntax/snippets_snipmate.vim b/syntax/snippets_snipmate.vim new file mode 100644 index 0000000..aa55c1f --- /dev/null +++ b/syntax/snippets_snipmate.vim @@ -0,0 +1,47 @@ +" Syntax highlighting variant used for snipmate snippets files +" The snippets.vim file sources this if it wants snipmate mode + +if exists("b:current_syntax") + finish +endif + +" Embedded syntaxes {{{1 + +" Re-include the original file so we can share some of its definitions +let b:ultisnips_override_snipmate = 1 +syn include :h/snippets.vim +unlet b:current_syntax +unlet b:ultisnips_override_snipmate + +syn cluster snipTokens contains=snipEscape,snipVisual,snipTabStop,snipMirror,snipmateCommand +syn cluster snipTabStopTokens contains=snipVisual,snipMirror,snipEscape,snipmateCommand + +" Syntax definitions {{{1 + +syn match snipmateComment "^#.*" + +syn match snipmateExtends "^extends\%(\s.*\|$\)" contains=snipExtendsKeyword display + +syn region snipmateSnippet start="^snippet\ze\%(\s\|$\)" end="^\ze[^[:tab:]]" contains=snipmateSnippetHeader keepend +syn match snipmateSnippetHeader "^.*" contained contains=snipmateKeyword nextgroup=snipmateSnippetBody skipnl skipempty +syn match snipmateKeyword "^snippet\ze\%(\s\|$\)" contained nextgroup=snipmateTrigger skipwhite +syn match snipmateTrigger "\S\+" contained nextgroup=snipmateDescription skipwhite +syn match snipmateDescription "\S.*" contained +syn region snipmateSnippetBody start="^\t" end="^\ze[^[:tab:]]" contained contains=@snipTokens + +syn region snipmateCommand keepend matchgroup=snipCommandDelim start="`" skip="\\[{}\\$`]" end="`" contained contains=snipCommandSyntaxOverride,@Viml + +" Highlight groups {{{1 + +hi def link snipmateComment snipComment + +hi def link snipmateSnippet snipSnippet +hi def link snipmateKeyword snipKeyword +hi def link snipmateTrigger snipSnippetTrigger +hi def link snipmateDescription snipSnippetDocString + +hi def link snipmateCommand snipCommand + +" }}}1 + +let b:current_syntax = "snippets"