ADDED vim/ftdetect/crystal.vim Index: vim/ftdetect/crystal.vim ================================================================== --- vim/ftdetect/crystal.vim +++ vim/ftdetect/crystal.vim @@ -0,0 +1,3 @@ +" vint: -ProhibitAutocmdWithNoGroup +autocmd BufNewFile,BufReadPost *.cr setlocal filetype=crystal +autocmd BufNewFile,BufReadPost Projectfile setlocal filetype=crystal ADDED vim/indent/crystal.vim Index: vim/indent/crystal.vim ================================================================== --- vim/indent/crystal.vim +++ vim/indent/crystal.vim @@ -0,0 +1,120 @@ +" Initialization {{{1 +" ============== + +" Only load this indent file when no other was loaded. +if exists('b:did_indent') + finish +endif + +let b:did_indent = 1 + +if !exists('g:crystal_indent_assignment_style') + " Possible values: 'variable', 'hanging' + let g:crystal_indent_assignment_style = 'hanging' +endif + +if !exists('g:crystal_indent_block_style') + " Possible values: 'expression', 'do' + let g:crystal_indent_block_style = 'expression' +endif + +setlocal nosmartindent + +" Now, set up our indentation expression and keys that trigger it. +setlocal indentexpr=GetCrystalIndent(v:lnum) +setlocal indentkeys=0{,0},0),0],!^F,o,O,e,. +setlocal indentkeys+==end,=else,=elsif,=when,=in,=ensure,=rescue + +" Only define the function once. +if exists('*GetCrystalIndent') + finish +endif + +" Return the value of a single shift-width +if exists('*shiftwidth') + let s:sw = function('shiftwidth') +else + function! s:sw() + return &shiftwidth + endfunction +endif + +" GetCrystalIndent Function {{{1 +" ========================= + +function! GetCrystalIndent(...) abort + " Setup {{{2 + " ----- + + let indent_info = {} + + " The value of a single shift-width + let indent_info.sw = s:sw() + + " For the current line, use the first argument if given, else v:lnum + let indent_info.clnum = a:0 ? a:1 : v:lnum + let indent_info.cline = getline(indent_info.clnum) + + " Set up variables for restoring position in file. + let indent_info.col = col('.') + + " Work on the current line {{{2 + " ------------------------ + + for callback_name in g:crystal#indent#curr_line_callbacks + let indent = call(function(callback_name), [indent_info]) + + if indent >= 0 + return indent + endif + endfor + + " Work on the previous line. {{{2 + " -------------------------- + + " Special case: we don't need the real PrevNonBlank for an empty line + " inside a string. And that call can be quite expensive in that + " particular situation. + let indent = crystal#indent#EmptyInsideString(indent_info) + + if indent >= 0 + return indent + endif + + " Previous line number + let indent_info.plnum = crystal#indent#PrevNonBlank(indent_info.clnum - 1) + let indent_info.pline = getline(indent_info.plnum) + + for callback_name in g:crystal#indent#prev_line_callbacks + let indent = call(function(callback_name), [indent_info]) + + if indent >= 0 + return indent + endif + endfor + + " Work on the MSL. {{{2 + " ---------------- + + " Most Significant line based on the previous one -- in case it's a + " contination of something above + let indent_info.plnum_msl = crystal#indent#GetMSL(indent_info.plnum) + let indent_info.pline_msl = getline(indent_info.plnum_msl) + + for callback_name in g:crystal#indent#msl_callbacks + let indent = call(function(callback_name), [indent_info]) + + if indent >= 0 + return indent + endif + endfor + + " }}}2 + + " By default, just return the previous line's indent + return indent(indent_info.plnum) +endfunction + +" }}}1 + +" vim:sw=2 sts=2 ts=8 fdm=marker et: ADDED vim/syntax/crystal.vim Index: vim/syntax/crystal.vim ================================================================== --- vim/syntax/crystal.vim +++ vim/syntax/crystal.vim @@ -0,0 +1,485 @@ +" Language: Crystal +" Maintainer: +" rhysd +" Jeffrey Crochet +" +" Based on Ruby syntax highlight +" which was made by Mirko Nasato and Doug Kearns +" ---------------------------------------------- + +" Prelude +if exists('b:current_syntax') + finish +endif + +" Adding `@-@` should fix a wide variety of false positives related to +" instance/class variables with keywords in their name, like @def and +" @class +syn iskeyword @,48-57,_,192-255,@-@ + +" eCrystal Config +if exists('g:main_syntax') && g:main_syntax ==# 'ecrystal' + let b:crystal_no_expensive = 1 +end + +" Folding Config +if has('folding') && exists('g:crystal_fold') + setlocal foldmethod=syntax +endif + +let s:foldable_groups = split( + \ get( + \ b:, + \ 'crystal_foldable_groups', + \ get(g:, 'crystal_foldable_groups', 'ALL') + \ ) + \ ) + +function! s:foldable(...) abort + if index(s:foldable_groups, 'NONE') > -1 + return 0 + endif + + if index(s:foldable_groups, 'ALL') > -1 + return 1 + endif + + for l:i in a:000 + if index(s:foldable_groups, l:i) > -1 + return 1 + endif + endfor + + return 0 +endfunction + +function! s:run_syntax_fold(args) abort + let [_0, _1, groups, cmd; _] = matchlist(a:args, '\(["'']\)\(.\{-}\)\1\s\+\(.*\)') + if call('s:foldable', split(groups)) + let cmd .= ' fold' + endif + exe cmd +endfunction + +com! -nargs=* SynFold call s:run_syntax_fold() + +" Top and Not-Top Clusters +syn cluster crystalTop contains=TOP +syn cluster crystalNotTop contains=CONTAINED + +" Whitespace Errors +if exists('g:crystal_space_errors') + if !exists('g:crystal_no_trail_space_error') + syn match crystalSpaceError display excludenl "\s\+$" + endif + if !exists('g:crystal_no_tab_space_error') + syn match crystalSpaceError display " \+\t"me=e-1 + endif +endif + +" Operators +if exists('g:crystal_operators') + syn match crystalOperator "[~!^&|*/%+-]\|<=>\|<=\|\%(<\|\<\%(class\|struct\)\s\+\u\w*\s*\)\@>\|>=\|=\@1\|\*\*\|\.\.\.\|\.\.\|::" + syn match crystalOperator "->\|-=\|/=\|\*\*=\|\*=\|&&=\|&=\|&&\|||=\||=\|||\|%=\|+=\|!\~\|!=\|//" + syn region crystalBracketOperator matchgroup=crystalOperator start="\%(\w[?!]\=\|[]})]\)\@2<=\[" end="]" contains=TOP +endif + +" Expression Substitution and Backslash Notation +syn match crystalStringEscape "\\\\\|\\[abefnrstv]\|\\\o\{1,3}\|\\x\x\{1,2}" contained display +syn match crystalStringEscape "\%(\\M-\\C-\|\\C-\\M-\|\\M-\\c\|\\c\\M-\|\\c\|\\C-\|\\M-\)\%(\\\o\{1,3}\|\\x\x\{1,2}\|\\\=\S\)" contained display + +syn region crystalInterpolation matchgroup=crystalInterpolationDelim start="#{" end="}" contained contains=TOP +syn region crystalNoInterpolation start="\\#{" end="}" contained +syn match crystalNoInterpolation "\\#{" display contained + +syn match crystalDelimEscape "\\[(<{\[)>}\]]" transparent display contained contains=NONE + +syn region crystalNestedParentheses matchgroup=crystalString start="(" skip="\\\\\|\\)" end=")" transparent contained +syn region crystalNestedCurlyBraces matchgroup=crystalString start="{" skip="\\\\\|\\}" end="}" transparent contained +syn region crystalNestedAngleBrackets matchgroup=crystalString start="<" skip="\\\\\|\\>" end=">" transparent contained +syn region crystalNestedSquareBrackets matchgroup=crystalString start="\[" skip="\\\\\|\\\]" end="\]" transparent contained + +" These are mostly Oniguruma ready +syn region crystalRegexpComment matchgroup=crystalRegexpSpecial start="(?#" skip="\\)" end=")" contained +syn region crystalRegexpParens matchgroup=crystalRegexpSpecial start="(\(?:\|?<\=[=!]\|?>\|?<[a-z_]\w*>\|?[imx]*-[imx]*:\=\|\%(?#\)\@!\)" skip="\\)" end=")" contained transparent contains=@crystalRegexpSpecial +syn region crystalRegexpBrackets matchgroup=crystalRegexpCharClass start="\[\^\=" skip="\\\]" end="\]" contained transparent contains=crystalStringEscape,crystalRegexpEscape,crystalRegexpCharClass oneline +syn match crystalRegexpCharClass "\\[DdHhSsWw]" contained display +syn match crystalRegexpCharClass "\[:\^\=\%(alnum\|alpha\|ascii\|blank\|cntrl\|digit\|graph\|lower\|print\|punct\|space\|upper\|xdigit\):\]" contained +syn match crystalRegexpEscape "\\[].*?+^$|\\/(){}[]" contained +syn match crystalRegexpQuantifier "[*?+][?+]\=" contained display +syn match crystalRegexpQuantifier "{\d\+\%(,\d*\)\=}?\=" contained display +syn match crystalRegexpAnchor "[$^]\|\\[ABbGZz]" contained display +syn match crystalRegexpDot "\." contained display +syn match crystalRegexpSpecial "|" contained display +syn match crystalRegexpSpecial "\\[1-9]\d\=\d\@!" contained display +syn match crystalRegexpSpecial "\\k<\%([a-z_]\w*\|-\=\d\+\)\%([+-]\d\+\)\=>" contained display +syn match crystalRegexpSpecial "\\k'\%([a-z_]\w*\|-\=\d\+\)\%([+-]\d\+\)\='" contained display +syn match crystalRegexpSpecial "\\g<\%([a-z_]\w*\|-\=\d\+\)>" contained display +syn match crystalRegexpSpecial "\\g'\%([a-z_]\w*\|-\=\d\+\)'" contained display + +syn cluster crystalStringSpecial contains=crystalInterpolation,crystalNoInterpolation,crystalStringEscape +syn cluster crystalExtendedStringSpecial contains=@crystalStringSpecial,crystalNestedParentheses,crystalNestedCurlyBraces,crystalNestedAngleBrackets,crystalNestedSquareBrackets,crystalNestedRawParentheses,crystalNestedRawCurlyBraces,crystalNestedRawAngleBrackets,crystalNestedRawSquareBrackets +syn cluster crystalRegexpSpecial contains=crystalInterpolation,crystalNoInterpolation,crystalStringEscape,crystalRegexpSpecial,crystalRegexpEscape,crystalRegexpBrackets,crystalRegexpCharClass,crystalRegexpDot,crystalRegexpQuantifier,crystalRegexpAnchor,crystalRegexpParens,crystalRegexpComment + +" Numbers and ASCII Codes +syn match crystalASCIICode "\%(\w\|[]})\"'/]\)\@1" display +syn match crystalInteger "\<0o[0-7_]\+\%([ui]\%(8\|16\|32\|64\|128\)\)\=\>" display +syn match crystalInteger "\<0b[01_]\+\%([ui]\%(8\|16\|32\|64\|128\)\)\=\>" display +syn match crystalInteger "\<\d[[:digit:]_]*\%([ui]\%(8\|16\|32\|64\|128\)\|f\%(32\|64\)\)\=\>" contains=crystalInvalidInteger display +syn match crystalFloat "\<\d[[:digit:]_]*\.\d[[:digit:]_]*\%(f\%(32\|64\)\)\=\>" contains=crystalInvalidInteger display +syn match crystalFloat "\<\d[[:digit:]_]*\%(\.\d[[:digit:]_]*\)\=\%([eE][-+]\=[[:digit:]_]\+\)\%(f\%(32\|64\)\)\=\>" contains=crystalInvalidInteger display +" Note: 042 is invalid but 0, 0_, 0_u8 and 0_1 are valid (#73) +syn match crystalInvalidInteger "\%(\.\|[eE][+-]\)\@2" contained containedin=crystalFloat,crystalInteger display + +" Identifiers +syn match crystalLocalVariableOrMethod "\<[_[:lower:]][_[:alnum:]]*[?!=]\=" contains=NONE display +syn match crystalBlockArgument "&[_[:lower:]][_[:alnum:]]" contains=NONE display transparent + +syn match crystalTypeName "\%(\%([.@$]\@1\|::\)\@=" contained +syn match crystalClassName "\%(\%([.@$]\@1\|::\)\@=" contained +syn match crystalModuleName "\%(\%([.@$]\@1\|::\)\@=" contained +syn match crystalStructName "\%(\%([.@$]\@1\|::\)\@=" contained +syn match crystalLibName "\%(\%([.@$]\@1\|::\)\@=" contained +syn match crystalEnumName "\%(\%([.@$]\@1\|::\)\@=" contained +syn match crystalAnnotationName "\%(\%([.@$]\@1\|::\)\@=" contained +syn match crystalConstant "\%(\%([.@$]\@1\|::\)\@=" +syn match crystalClassVariable "@@\%(\h\|%\|[^\x00-\x7F]\)\%(\w\|%\|[^\x00-\x7F]\)*" display +syn match crystalInstanceVariable "@\%(\h\|%\|[^\x00-\x7F]\)\%(\w\|%\|[^\x00-\x7F]\)*" display +syn match crystalFreshVariable "\%(\h\|[^\x00-\x7F]\)\@1\|<=\|<\|===\|[=!]=\|[=!]\~\|!\|>>\|>=\|>\||\|-@\|-\|/\|\[][=?]\|\[]\|\*\*\|\*\|&\|%\|+@\|+\|`\)" +syn match crystalSymbol "[]})\"':]\@1_,;:!?/.'"@$*\&+0]\)" +syn match crystalSymbol "[]})\"':]\@1\@!\)\=" +syn match crystalSymbol "\%([{(,]\_s*\)\@<=\l\w*[!?]\=::\@!"he=e-1 +syn match crystalSymbol "[]})\"':]\@1\|{\)\s*\)\@<=|" end="|" oneline display contains=crystalBlockParameter + +" In Crystal, almost all special variables were removed and global variables +" are not supported https://github.com/crystal-lang/crystal/commit/e872c716d0e936557b34c614efc5a4c24d845f79 +" NOTE: Only $~ and $? are supported since they are actually not global. +syn match crystalPredefinedVariable "$[~?]" +syn match crystalPredefinedConstant "\%(\%(\.\@1\%(\s*(\)\@!" + +" Normal Regular Expression +SynFold '/' syn region crystalRegexp matchgroup=crystalRegexpDelimiter start="\%(\%(^\|\<\%(and\|or\|while\|until\|unless\|if\|elsif\|ifdef\|when\|in\|not\|then\|else\)\|[;\~=!|&(,[<>?:*+-]\)\s*\)\@<=/" end="/[imx]*" skip="\\\\\|\\/" contains=@crystalRegexpSpecial +SynFold '/' syn region crystalRegexp matchgroup=crystalRegexpDelimiter start="\%(\h\k*\s\+\)\@<=/[ \t=/]\@!" end="/[imx]*" skip="\\\\\|\\/" contains=@crystalRegexpSpecial + +" Generalized Regular Expression +SynFold '%' syn region crystalRegexp matchgroup=crystalRegexpDelimiter start="%r{" end="}[imx]*" skip="\\\\\|\\}" contains=@crystalRegexpSpecial,crystalNestedRawCurlyBraces +SynFold '%' syn region crystalRegexp matchgroup=crystalRegexpDelimiter start="%r<" end=">[imx]*" skip="\\\\\|\\>" contains=@crystalRegexpSpecial,crystalNestedRawAngleBrackets +SynFold '%' syn region crystalRegexp matchgroup=crystalRegexpDelimiter start="%r\[" end="\][imx]*" skip="\\\\\|\\\]" contains=@crystalRegexpSpecial +SynFold '%' syn region crystalRegexp matchgroup=crystalRegexpDelimiter start="%r(" end=")[imx]*" skip="\\\\\|\\)" contains=@crystalRegexpSpecial +SynFold '%' syn region crystalRegexp matchgroup=crystalRegexpDelimiter start="%r|" end="|[imx]*" skip="\\\\\|\\|" contains=@crystalRegexpSpecial + +" Normal String +let s:spell_cluster = exists('crystal_spellcheck_strings') ? ',@Spell' : '' +let s:fold_arg = s:foldable('string') ? ' fold' : '' +exe 'syn region crystalString matchgroup=crystalStringDelimiter start="\"" end="\"" skip="\\\\\|\\\"" contains=@crystalStringSpecial' . s:spell_cluster . s:fold_arg +unlet s:spell_cluster s:fold_arg + +" Shell Command Output +SynFold 'string' syn region crystalString matchgroup=crystalStringDelimiter start="`" end="`" skip="\\\\\|\\`" contains=@crystalStringSpecial + +" Character +syn match crystalCharLiteral "'\%([^\\]\|\\[abefnrstv'\\]\|\\\o\{1,3}\|\\x\x\{1,2}\|\\u\x\{4}\)'" contains=crystalStringEscape display + +" Generalized Single Quoted String, Symbol and Array of Strings +syn region crystalNestedRawParentheses matchgroup=crystalString start="(" end=")" transparent contained +syn region crystalNestedRawCurlyBraces matchgroup=crystalString start="{" end="}" transparent contained +syn region crystalNestedRawAngleBrackets matchgroup=crystalString start="<" end=">" transparent contained +syn region crystalNestedRawSquareBrackets matchgroup=crystalString start="\[" end="\]" transparent contained + +SynFold '%' syn region crystalString matchgroup=crystalStringDelimiter start="%q(" end=")" contains=crystalNestedRawParentheses +SynFold '%' syn region crystalString matchgroup=crystalStringDelimiter start="%q{" end="}" contains=crystalNestedRawCurlyBraces +SynFold '%' syn region crystalString matchgroup=crystalStringDelimiter start="%q<" end=">" contains=crystalNestedRawAngleBrackets +SynFold '%' syn region crystalString matchgroup=crystalStringDelimiter start="%q\[" end="\]" contains=crystalNestedRawSquareBrackets +SynFold '%' syn region crystalString matchgroup=crystalStringDelimiter start="%q|" end="|" + +SynFold '%' syn region crystalString matchgroup=crystalStringDelimiter start="%[wi](" end=")" skip="\\\\\|\\)" contains=crystalNestedParentheses,crystalDelimEscape +SynFold '%' syn region crystalString matchgroup=crystalStringDelimiter start="%[wi]{" end="}" skip="\\\\\|\\}" contains=crystalNestedCurlyBraces,crystalDelimEscape +SynFold '%' syn region crystalString matchgroup=crystalStringDelimiter start="%[wi]<" end=">" skip="\\\\\|\\>" contains=crystalNestedAngleBrackets,crystalDelimEscape +SynFold '%' syn region crystalString matchgroup=crystalStringDelimiter start="%[wi]\[" end="\]" skip="\\\\\|\\\]" contains=crystalNestedSquareBrackets,crystalDelimEscape +SynFold '%' syn region crystalString matchgroup=crystalStringDelimiter start="%[wi]|" end="|" skip="\\\\\|\\|" contains=crystalDelimEscape + +" Generalized Double Quoted String and Array of Strings and Shell Command Output +" Note: %= is not matched here as the beginning of a double quoted string +SynFold '%' syn region crystalString matchgroup=crystalStringDelimiter start="%[Qx]\=(" end=")" skip="\\\\\|\\)" contains=@crystalStringSpecial,crystalNestedParentheses,crystalDelimEscape +SynFold '%' syn region crystalString matchgroup=crystalStringDelimiter start="%[Qx]\={" end="}" skip="\\\\\|\\}" contains=@crystalStringSpecial,crystalNestedCurlyBraces,crystalDelimEscape +SynFold '%' syn region crystalString matchgroup=crystalStringDelimiter start="%[Qx]\=<" end=">" skip="\\\\\|\\>" contains=@crystalStringSpecial,crystalNestedAngleBrackets,crystalDelimEscape +SynFold '%' syn region crystalString matchgroup=crystalStringDelimiter start="%[Qx]\=\[" end="\]" skip="\\\\\|\\\]" contains=@crystalStringSpecial,crystalNestedSquareBrackets,crystalDelimEscape +SynFold '%' syn region crystalString matchgroup=crystalStringDelimiter start="%[Qx]\=|" end="|" skip="\\\\\|\\|" contains=@crystalStringSpecial,crystalDelimEscape + +" Here Document +syn region crystalHeredocStart matchgroup=crystalStringDelimiter start=+\%(\%(class\s*\|\%([]})"'.]\|::\)\)\_s*\|\w\)\@>\|[<>]=\=\|<=>\|===\|[=!]=\|[=!]\~\|!\|`\)\%([[:space:];#(]\|$\)\@=" contained containedin=crystalAliasDeclaration,crystalAliasDeclaration2,crystalMethodDeclaration,crystalFunctionDeclaration + +syn cluster crystalDeclaration contains=crystalAliasDeclaration,crystalAliasDeclaration2,crystalMethodDeclaration,crystalFunctionDeclaration,crystalModuleDeclaration,crystalClassDeclaration,crystalStructDeclaration,crystalLibDeclaration,crystalMacroDeclaration,crystalFunction,crystalBlockParameter,crystalTypeDeclaration,crystalEnumDeclaration,crystalAnnotationDeclaration + +" Keywords +" Note: the following keywords have already been defined: +" begin case class def do end for if module unless until while +syn match crystalControl "\<\%(break\|next\|rescue\|return\)\>[?!]\@!" +syn match crystalKeyword "\<\%(super\|previous_def\|yield\|of\|with\|uninitialized\|union\|out\)\>[?!]\@!" +syn match crystalBoolean "\<\%(true\|false\)\>[?!]\@!" +syn match crystalPseudoVariable "\<\%(nil\|__DIR__\|__FILE__\|__LINE__\|__END_LINE__\)\>[?!]\@!" " TODO: reorganise +syn match crystalPseudoVariable "\[?!]\@!" + +" Expensive Mode - match 'end' with the appropriate opening keyword for syntax +" based folding and special highlighting of module/class/method definitions +if !exists('b:crystal_no_expensive') && !exists('g:crystal_no_expensive') + syn match crystalDefine "\" nextgroup=crystalAliasDeclaration skipwhite skipnl + syn match crystalDefine "\" nextgroup=crystalMethodDeclaration skipwhite skipnl + syn match crystalDefine "\" nextgroup=crystalFunctionDeclaration skipwhite skipnl + syn match crystalDefine "\<\%(type\|alias\)\>\%(\s*\h\w*\s*=\)\@=" nextgroup=crystalTypeDeclaration skipwhite skipnl + syn match crystalClass "\" nextgroup=crystalClassDeclaration skipwhite skipnl + syn match crystalModule "\" nextgroup=crystalModuleDeclaration skipwhite skipnl + syn match crystalStruct "\" nextgroup=crystalStructDeclaration skipwhite skipnl + syn match crystalLib "\" nextgroup=crystalLibDeclaration skipwhite skipnl + syn match crystalMacro "\" nextgroup=crystalMacroDeclaration skipwhite skipnl + syn match crystalEnum "\" nextgroup=crystalEnumDeclaration skipwhite skipnl + syn match crystalAnnotation "\" nextgroup=crystalAnnotationDeclaration skipwhite skipnl + + SynFold 'def' syn region crystalMethodBlock start="\" matchgroup=crystalDefine end="\%(\" contains=TOP,crystalForallKeyword + SynFold 'macro' syn region crystalMethodBlock start="\" matchgroup=crystalDefine end="\%(\" contains=TOP + SynFold 'class' syn region crystalBlock start="\" matchgroup=crystalClass end="\" contains=TOP + SynFold 'module' syn region crystalBlock start="\" matchgroup=crystalModule end="\" contains=TOP + SynFold 'struct' syn region crystalBlock start="\" matchgroup=crystalStruct end="\" contains=TOP + SynFold 'lib' syn region crystalBlock start="\" matchgroup=crystalLib end="\" contains=TOP + SynFold 'enum' syn region crystalBlock start="\" matchgroup=crystalEnum end="\" contains=TOP + SynFold 'annotation' syn region crystalBlock start="\" matchgroup=crystalAnnotation end="\" contains=TOP + + " keywords in method declaration + syn match crystalForallKeyword "\[?!]\@!" contained containedin=crystalMethodBlock + + " modifiers + syn match crystalConditionalModifier "\<\%(if\|unless\|ifdef\)\>" display + + SynFold 'do' syn region crystalDoBlock matchgroup=crystalControl start="\" end="\" contains=TOP + + " curly bracket block or hash literal + SynFold '{' syn region crystalCurlyBlock matchgroup=crystalCurlyBlockDelimiter start="{" end="}" contains=TOP + SynFold '[' syn region crystalArrayLiteral matchgroup=crystalArrayDelimiter start="\%(\w\|[\]})]\)\@1" end="\" contains=TOP + SynFold 'while' syn region crystalRepeatExpression matchgroup=crystalRepeat start="\<\%(while\|until\)\>" end="\" contains=TOP + SynFold 'case' syn region crystalCaseExpression matchgroup=crystalConditional start="\" end="\" contains=TOP + SynFold 'select' syn region crystalSelectExpression matchgroup=crystalConditional start="\" end="\" contains=TOP + SynFold 'if' syn region crystalConditionalExpression matchgroup=crystalConditional start="\%(\%(^\|\.\.\.\=\|[{:,;([<>~\*/%&^|+=-]\|\%(\<[_[:lower:]][_[:alnum:]]*\)\@" end="\%(\%(\%(\.\@1" contains=TOP + + syn match crystalConditional "\<\%(then\|else\|when\|in\)\>[?!]\@!" contained containedin=crystalCaseExpression + syn match crystalConditional "\<\%(when\|else\)\>[?!]\@!" contained containedin=crystalSelectExpression + syn match crystalConditional "\<\%(then\|else\|elsif\)\>[?!]\@!" contained containedin=crystalConditionalExpression + + syn match crystalExceptional "\<\%(\%(\%(;\|^\)\s*\)\@<=rescue\|else\|ensure\)\>[?!]\@!" contained containedin=crystalBlockExpression + syn match crystalMethodExceptional "\<\%(\%(\%(;\|^\)\s*\)\@<=rescue\|else\|ensure\)\>[?!]\@!" contained containedin=crystalMethodBlock + + SynFold 'macro' syn region crystalMacroBlock matchgroup=crystalMacroRegion start="\z(\\\=\){%\s*\%(\%(if\|for\|begin\)\>.*\|.*\\)\s*%}" end="\z1{%\s*end\s*%}" transparent contains=TOP + + if !exists('g:crystal_minlines') + let g:crystal_minlines = 500 + endif + exec 'syn sync minlines=' . g:crystal_minlines +else + " Non-expensive mode + syn match crystalControl "\[?!]\@!" nextgroup=crystalMethodDeclaration skipwhite skipnl + syn match crystalControl "\[?!]\@!" nextgroup=crystalFunctionDeclaration skipwhite skipnl + syn match crystalControl "\[?!]\@!" nextgroup=crystalClassDeclaration skipwhite skipnl + syn match crystalControl "\[?!]\@!" nextgroup=crystalModuleDeclaration skipwhite skipnl + syn match crystalControl "\[?!]\@!" nextgroup=crystalStructDeclaration skipwhite skipnl + syn match crystalControl "\[?!]\@!" nextgroup=crystalLibDeclaration skipwhite skipnl + syn match crystalControl "\[?!]\@!" nextgroup=crystalMacroDeclaration skipwhite skipnl + syn match crystalControl "\[?!]\@!" nextgroup=crystalEnumDeclaration skipwhite skipnl + syn match crystalControl "\[?!]\@!" nextgroup=crystalAnnotationDeclaration skipwhite skipnl + syn match crystalControl "\<\%(case\|begin\|do\|if\|ifdef\|unless\|while\|select\|until\|else\|elsif\|ensure\|then\|when\|in\|end\)\>[?!]\@!" + syn match crystalKeyword "\[?!]\@!" + syn match crystalForallKeyword "\[?!]\@!" +endif + +" Link attribute +syn region crystalLinkAttr matchgroup=crystalLinkAttrDelim start="@\[" end="]" contains=TOP display oneline + +" Special Methods +if !exists('g:crystal_no_special_methods') + syn keyword crystalAccess protected private + " attr is a common variable name + syn keyword crystalAttribute abstract + syn match crystalAttribute "\<\%(\%(class_\)\=\%(getter\|setter\|property\)[!?]\=\|def_\%(clone\|equals\|equals_and_hash\|hash\)\|delegate\|forward_missing_to\)\s" display + syn match crystalControl "\<\%(abort\|at_exit\|exit\|fork\|loop\)\>[?!]\@!" display + syn keyword crystalException raise + " false positive with 'include?' + syn match crystalInclude "\[?!]\@!" display + syn keyword crystalInclude extend require + syn keyword crystalKeyword caller typeof pointerof sizeof instance_sizeof offsetof + syn match crystalRecord "\\)" contains=crystalSharpBang,crystalSpaceError,crystalTodo,@Spell +else + syn match crystalComment "#.*" contains=crystalSharpBang,crystalSpaceError,crystalTodo,@Spell +endif + +SynFold '#' syn region crystalMultilineComment start="\%(\%(^\s*#.*\n\)\@" transparent contains=NONE +syn match crystalKeywordAsMethod "\%(\%(\.\@1" transparent contains=NONE +syn match crystalKeywordAsMethod "\%(\%(\.\@1" transparent contains=NONE +syn match crystalKeywordAsMethod "\%(\%(\.\@1" transparent contains=NONE + +syn match crystalKeywordAsMethod "\<\%(alias\|begin\|case\|class\|def\|do\|end\)[?!]" transparent contains=NONE +syn match crystalKeywordAsMethod "\<\%(if\|ifdef\|module\|unless\|until\|while\)[?!]" transparent contains=NONE + +syn match crystalKeywordAsMethod "\%(\%(\.\@1" transparent contains=NONE +syn match crystalKeywordAsMethod "\%(\%(\.\@1" transparent contains=NONE +syn match crystalKeywordAsMethod "\%(\%(\.\@1" transparent contains=NONE +syn match crystalKeywordAsMethod "\%(\%(\.\@1" transparent contains=NONE +syn match crystalKeywordAsMethod "\%(\%(\.\@1" transparent contains=NONE + +hi def link crystalClass crystalDefine +hi def link crystalModule crystalDefine +hi def link crystalStruct crystalDefine +hi def link crystalLib crystalDefine +hi def link crystalEnum crystalDefine +hi def link crystalAnnotation crystalDefine +hi def link crystalMethodExceptional crystalDefine +hi def link crystalDefine Define +hi def link crystalFunction Function +hi def link crystalConditional Conditional +hi def link crystalConditionalModifier crystalConditional +hi def link crystalExceptional crystalConditional +hi def link crystalRepeat Repeat +hi def link crystalControl Statement +hi def link crystalInclude Include +hi def link crystalRecord Statement +hi def link crystalInteger Number +hi def link crystalASCIICode Character +hi def link crystalFloat Float +hi def link crystalBoolean Boolean +hi def link crystalException Exception +if !exists('g:crystal_no_identifiers') + hi def link crystalIdentifier Identifier +else + hi def link crystalIdentifier NONE +endif +hi def link crystalClassVariable crystalIdentifier +hi def link crystalConstant Type +hi def link crystalTypeName crystalConstant +hi def link crystalClassName crystalConstant +hi def link crystalModuleName crystalConstant +hi def link crystalStructName crystalConstant +hi def link crystalLibName crystalConstant +hi def link crystalEnumName crystalConstant +hi def link crystalAnnotationName crystalConstant +hi def link crystalBlockParameter crystalIdentifier +hi def link crystalInstanceVariable crystalIdentifier +hi def link crystalFreshVariable crystalIdentifier +hi def link crystalPredefinedIdentifier crystalIdentifier +hi def link crystalPredefinedConstant crystalPredefinedIdentifier +hi def link crystalPredefinedVariable crystalPredefinedIdentifier +hi def link crystalSymbol Constant +hi def link crystalKeyword Keyword +hi def link crystalOperator Operator +hi def link crystalAccess Statement +hi def link crystalAttribute Statement +hi def link crystalPseudoVariable Constant +hi def link crystalCharLiteral Character +hi def link crystalComment Comment +hi def link crystalTodo Todo +hi def link crystalStringEscape Special +hi def link crystalInterpolationDelim Delimiter +hi def link crystalNoInterpolation crystalString +hi def link crystalSharpBang PreProc +hi def link crystalRegexpDelimiter crystalStringDelimiter +hi def link crystalSymbolDelimiter crystalStringDelimiter +hi def link crystalStringDelimiter Delimiter +hi def link crystalString String +hi def link crystalHeredoc crystalString +hi def link crystalRegexpEscape crystalRegexpSpecial +hi def link crystalRegexpQuantifier crystalRegexpSpecial +hi def link crystalRegexpAnchor crystalRegexpSpecial +hi def link crystalRegexpDot crystalRegexpCharClass +hi def link crystalRegexpCharClass crystalRegexpSpecial +hi def link crystalRegexpSpecial Special +hi def link crystalRegexpComment Comment +hi def link crystalRegexp crystalString +hi def link crystalMacro PreProc +hi def link crystalMacroDelim crystalMacro +hi def link crystalMacroKeyword crystalKeyword +hi def link crystalForallKeyword crystalDefine +hi def link crystalLinkAttrDelim crystalMacroDelim +hi def link crystalError Error +hi def link crystalSpaceError crystalError +hi def link crystalInvalidInteger crystalError + +let b:current_syntax = 'crystal' + +delc SynFold + +" vim: sw=2 sts=2 et: