1" Vim syntax file 2" Language: Rust 3" Maintainer: Patrick Walton <[email protected]> 4" Maintainer: Ben Blum <[email protected]> 5" Maintainer: Chris Morgan <[email protected]> 6" Last Change: Feb 24, 2016 7" For bugs, patches and license go to https://github.com/rust-lang/rust.vim 8 9if version < 600 10 syntax clear 11elseif exists("b:current_syntax") 12 finish 13endif 14 15" Syntax definitions {{{1 16" Basic keywords {{{2 17syn keyword rustConditional match if else 18syn keyword rustRepeat for loop while 19syn keyword rustTypedef type nextgroup=rustIdentifier skipwhite skipempty 20syn keyword rustStructure struct enum nextgroup=rustIdentifier skipwhite skipempty 21syn keyword rustUnion union nextgroup=rustIdentifier skipwhite skipempty contained 22syn match rustUnionContextual /\<union\_s\+\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*/ transparent contains=rustUnion 23syn keyword rustOperator as 24 25syn match rustAssert "\<assert\(\w\)*!" contained 26syn match rustPanic "\<panic\(\w\)*!" contained 27syn keyword rustKeyword break 28syn keyword rustKeyword box nextgroup=rustBoxPlacement skipwhite skipempty 29syn keyword rustKeyword continue 30syn keyword rustKeyword extern nextgroup=rustExternCrate,rustObsoleteExternMod skipwhite skipempty 31syn keyword rustKeyword fn nextgroup=rustFuncName skipwhite skipempty 32syn keyword rustKeyword in impl let 33syn keyword rustKeyword pub nextgroup=rustPubScope skipwhite skipempty 34syn keyword rustKeyword return 35syn keyword rustSuper super 36syn keyword rustKeyword unsafe where 37syn keyword rustKeyword use nextgroup=rustModPath skipwhite skipempty 38" FIXME: Scoped impl's name is also fallen in this category 39syn keyword rustKeyword mod trait nextgroup=rustIdentifier skipwhite skipempty 40syn keyword rustStorage move mut ref static const 41syn match rustDefault /\<default\ze\_s\+\(impl\|fn\|type\|const\)\>/ 42 43syn keyword rustInvalidBareKeyword crate 44 45syn keyword rustPubScopeCrate crate contained 46syn match rustPubScopeDelim /[()]/ contained 47syn match rustPubScope /([^()]*)/ contained contains=rustPubScopeDelim,rustPubScopeCrate,rustSuper,rustModPath,rustModPathSep,rustSelf transparent 48 49syn keyword rustExternCrate crate contained nextgroup=rustIdentifier,rustExternCrateString skipwhite skipempty 50" This is to get the `bar` part of `extern crate "foo" as bar;` highlighting. 51syn match rustExternCrateString /".*"\_s*as/ contained nextgroup=rustIdentifier skipwhite transparent skipempty contains=rustString,rustOperator 52syn keyword rustObsoleteExternMod mod contained nextgroup=rustIdentifier skipwhite skipempty 53 54syn match rustIdentifier contains=rustIdentifierPrime "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained 55syn match rustFuncName "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained 56 57syn region rustBoxPlacement matchgroup=rustBoxPlacementParens start="(" end=")" contains=TOP contained 58" Ideally we'd have syntax rules set up to match arbitrary expressions. Since 59" we don't, we'll just define temporary contained rules to handle balancing 60" delimiters. 61syn region rustBoxPlacementBalance start="(" end=")" containedin=rustBoxPlacement transparent 62syn region rustBoxPlacementBalance start="\[" end="\]" containedin=rustBoxPlacement transparent 63" {} are handled by rustFoldBraces 64 65syn region rustMacroRepeat matchgroup=rustMacroRepeatDelimiters start="$(" end=")" contains=TOP nextgroup=rustMacroRepeatCount 66syn match rustMacroRepeatCount ".\?[*+]" contained 67syn match rustMacroVariable "$\w\+" 68 69" Reserved (but not yet used) keywords {{{2 70syn keyword rustReservedKeyword alignof become do offsetof priv pure sizeof typeof unsized yield abstract virtual final override macro 71 72" Built-in types {{{2 73syn keyword rustType isize usize char bool u8 u16 u32 u64 u128 f32 74syn keyword rustType f64 i8 i16 i32 i64 i128 str Self 75 76" Things from the libstd v1 prelude (src/libstd/prelude/v1.rs) {{{2 77" This section is just straight transformation of the contents of the prelude, 78" to make it easy to update. 79 80" Reexported core operators {{{3 81syn keyword rustTrait Copy Send Sized Sync 82syn keyword rustTrait Drop Fn FnMut FnOnce 83 84" Reexported functions {{{3 85" There’s no point in highlighting these; when one writes drop( or drop::< it 86" gets the same highlighting anyway, and if someone writes `let drop = …;` we 87" don’t really want *that* drop to be highlighted. 88"syn keyword rustFunction drop 89 90" Reexported types and traits {{{3 91syn keyword rustTrait Box 92syn keyword rustTrait ToOwned 93syn keyword rustTrait Clone 94syn keyword rustTrait PartialEq PartialOrd Eq Ord 95syn keyword rustTrait AsRef AsMut Into From 96syn keyword rustTrait Default 97syn keyword rustTrait Iterator Extend IntoIterator 98syn keyword rustTrait DoubleEndedIterator ExactSizeIterator 99syn keyword rustEnum Option 100syn keyword rustEnumVariant Some None 101syn keyword rustEnum Result 102syn keyword rustEnumVariant Ok Err 103syn keyword rustTrait SliceConcatExt 104syn keyword rustTrait String ToString 105syn keyword rustTrait Vec 106 107" Other syntax {{{2 108syn keyword rustSelf self 109syn keyword rustBoolean true false 110 111" If foo::bar changes to foo.bar, change this ("::" to "\."). 112" If foo::bar changes to Foo::bar, change this (first "\w" to "\u"). 113syn match rustModPath "\w\(\w\)*::[^<]"he=e-3,me=e-3 114syn match rustModPathSep "::" 115 116syn match rustFuncCall "\w\(\w\)*("he=e-1,me=e-1 117syn match rustFuncCall "\w\(\w\)*::<"he=e-3,me=e-3 " foo::<T>(); 118 119" This is merely a convention; note also the use of [A-Z], restricting it to 120" latin identifiers rather than the full Unicode uppercase. I have not used 121" [:upper:] as it depends upon 'noignorecase' 122"syn match rustCapsIdent display "[A-Z]\w\(\w\)*" 123 124syn match rustOperator display "\%(+\|-\|/\|*\|=\|\^\|&\||\|!\|>\|<\|%\)=\?" 125" This one isn't *quite* right, as we could have binary-& with a reference 126syn match rustSigil display /&\s\+[&~@*][^)= \t\r\n]/he=e-1,me=e-1 127syn match rustSigil display /[&~@*][^)= \t\r\n]/he=e-1,me=e-1 128" This isn't actually correct; a closure with no arguments can be `|| { }`. 129" Last, because the & in && isn't a sigil 130syn match rustOperator display "&&\|||" 131" This is rustArrowCharacter rather than rustArrow for the sake of matchparen, 132" so it skips the ->; see http://stackoverflow.com/a/30309949 for details. 133syn match rustArrowCharacter display "->" 134syn match rustQuestionMark display "?\([a-zA-Z]\+\)\@!" 135 136syn match rustMacro '\w\(\w\)*!' contains=rustAssert,rustPanic 137syn match rustMacro '#\w\(\w\)*' contains=rustAssert,rustPanic 138 139syn match rustEscapeError display contained /\\./ 140syn match rustEscape display contained /\\\([nrt0\\'"]\|x\x\{2}\)/ 141syn match rustEscapeUnicode display contained /\\u{\x\{1,6}}/ 142syn match rustStringContinuation display contained /\\\n\s*/ 143syn region rustString start=+b"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeError,rustStringContinuation 144syn region rustString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustStringContinuation,@Spell 145syn region rustString start='b\?r\z(#*\)"' end='"\z1' contains=@Spell 146 147syn region rustAttribute start="#!\?\[" end="\]" contains=rustString,rustDerive,rustCommentLine,rustCommentBlock,rustCommentLineDocError,rustCommentBlockDocError 148syn region rustDerive start="derive(" end=")" contained contains=rustDeriveTrait 149" This list comes from src/libsyntax/ext/deriving/mod.rs 150" Some are deprecated (Encodable, Decodable) or to be removed after a new snapshot (Show). 151syn keyword rustDeriveTrait contained Clone Hash RustcEncodable RustcDecodable Encodable Decodable PartialEq Eq PartialOrd Ord Rand Show Debug Default FromPrimitive Send Sync Copy 152 153" Number literals 154syn match rustDecNumber display "\<[0-9][0-9_]*\%([iu]\%(size\|8\|16\|32\|64\|128\)\)\=" 155syn match rustHexNumber display "\<0x[a-fA-F0-9_]\+\%([iu]\%(size\|8\|16\|32\|64\|128\)\)\=" 156syn match rustOctNumber display "\<0o[0-7_]\+\%([iu]\%(size\|8\|16\|32\|64\|128\)\)\=" 157syn match rustBinNumber display "\<0b[01_]\+\%([iu]\%(size\|8\|16\|32\|64\|128\)\)\=" 158 159" Special case for numbers of the form "1." which are float literals, unless followed by 160" an identifier, which makes them integer literals with a method call or field access, 161" or by another ".", which makes them integer literals followed by the ".." token. 162" (This must go first so the others take precedence.) 163syn match rustFloat display "\<[0-9][0-9_]*\.\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\|\.\)\@!" 164" To mark a number as a normal float, it must have at least one of the three things integral values don't have: 165" a decimal point and more numbers; an exponent; and a type suffix. 166syn match rustFloat display "\<[0-9][0-9_]*\%(\.[0-9][0-9_]*\)\%([eE][+-]\=[0-9_]\+\)\=\(f32\|f64\)\=" 167syn match rustFloat display "\<[0-9][0-9_]*\%(\.[0-9][0-9_]*\)\=\%([eE][+-]\=[0-9_]\+\)\(f32\|f64\)\=" 168syn match rustFloat display "\<[0-9][0-9_]*\%(\.[0-9][0-9_]*\)\=\%([eE][+-]\=[0-9_]\+\)\=\(f32\|f64\)" 169 170" For the benefit of delimitMate 171syn region rustLifetimeCandidate display start=/&'\%(\([^'\\]\|\\\(['nrt0\\\"]\|x\x\{2}\|u{\x\{1,6}}\)\)'\)\@!/ end=/[[:cntrl:][:space:][:punct:]]\@=\|$/ contains=rustSigil,rustLifetime 172syn region rustGenericRegion display start=/<\%('\|[^[cntrl:][:space:][:punct:]]\)\@=')\S\@=/ end=/>/ contains=rustGenericLifetimeCandidate 173syn region rustGenericLifetimeCandidate display start=/\%(<\|,\s*\)\@<='/ end=/[[:cntrl:][:space:][:punct:]]\@=\|$/ contains=rustSigil,rustLifetime 174 175"rustLifetime must appear before rustCharacter, or chars will get the lifetime highlighting 176syn match rustLifetime display "\'\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" 177syn match rustLabel display "\'\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*:" 178syn match rustCharacterInvalid display contained /b\?'\zs[\n\r\t']\ze'/ 179" The groups negated here add up to 0-255 but nothing else (they do not seem to go beyond ASCII). 180syn match rustCharacterInvalidUnicode display contained /b'\zs[^[:cntrl:][:graph:][:alnum:][:space:]]\ze'/ 181syn match rustCharacter /b'\([^\\]\|\\\(.\|x\x\{2}\)\)'/ contains=rustEscape,rustEscapeError,rustCharacterInvalid,rustCharacterInvalidUnicode 182syn match rustCharacter /'\([^\\]\|\\\(.\|x\x\{2}\|u{\x\{1,6}}\)\)'/ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustCharacterInvalid 183 184syn match rustShebang /\%^#![^[].*/ 185syn region rustCommentLine start="//" end="$" contains=rustTodo,@Spell 186syn region rustCommentLineDoc start="//\%(//\@!\|!\)" end="$" contains=rustTodo,@Spell 187syn region rustCommentLineDocError start="//\%(//\@!\|!\)" end="$" contains=rustTodo,@Spell contained 188syn region rustCommentBlock matchgroup=rustCommentBlock start="/\*\%(!\|\*[*/]\@!\)\@!" end="\*/" contains=rustTodo,rustCommentBlockNest,@Spell 189syn region rustCommentBlockDoc matchgroup=rustCommentBlockDoc start="/\*\%(!\|\*[*/]\@!\)" end="\*/" contains=rustTodo,rustCommentBlockDocNest,@Spell 190syn region rustCommentBlockDocError matchgroup=rustCommentBlockDocError start="/\*\%(!\|\*[*/]\@!\)" end="\*/" contains=rustTodo,rustCommentBlockDocNestError,@Spell contained 191syn region rustCommentBlockNest matchgroup=rustCommentBlock start="/\*" end="\*/" contains=rustTodo,rustCommentBlockNest,@Spell contained transparent 192syn region rustCommentBlockDocNest matchgroup=rustCommentBlockDoc start="/\*" end="\*/" contains=rustTodo,rustCommentBlockDocNest,@Spell contained transparent 193syn region rustCommentBlockDocNestError matchgroup=rustCommentBlockDocError start="/\*" end="\*/" contains=rustTodo,rustCommentBlockDocNestError,@Spell contained transparent 194" FIXME: this is a really ugly and not fully correct implementation. Most 195" importantly, a case like ``/* */*`` should have the final ``*`` not being in 196" a comment, but in practice at present it leaves comments open two levels 197" deep. But as long as you stay away from that particular case, I *believe* 198" the highlighting is correct. Due to the way Vim's syntax engine works 199" (greedy for start matches, unlike Rust's tokeniser which is searching for 200" the earliest-starting match, start or end), I believe this cannot be solved. 201" Oh you who would fix it, don't bother with things like duplicating the Block 202" rules and putting ``\*\@<!`` at the start of them; it makes it worse, as 203" then you must deal with cases like ``/*/**/*/``. And don't try making it 204" worse with ``\%(/\@<!\*\)\@<!``, either... 205 206syn keyword rustTodo contained TODO FIXME XXX NB NOTE 207 208" Folding rules {{{2 209" Trivial folding rules to begin with. 210" FIXME: use the AST to make really good folding 211syn region rustFoldBraces start="{" end="}" transparent fold 212 213" Default highlighting {{{1 214hi def link rustDecNumber rustNumber 215hi def link rustHexNumber rustNumber 216hi def link rustOctNumber rustNumber 217hi def link rustBinNumber rustNumber 218hi def link rustIdentifierPrime rustIdentifier 219hi def link rustTrait rustType 220hi def link rustDeriveTrait rustTrait 221 222hi def link rustMacroRepeatCount rustMacroRepeatDelimiters 223hi def link rustMacroRepeatDelimiters Macro 224hi def link rustMacroVariable Define 225hi def link rustSigil StorageClass 226hi def link rustEscape Special 227hi def link rustEscapeUnicode rustEscape 228hi def link rustEscapeError Error 229hi def link rustStringContinuation Special 230hi def link rustString String 231hi def link rustCharacterInvalid Error 232hi def link rustCharacterInvalidUnicode rustCharacterInvalid 233hi def link rustCharacter Character 234hi def link rustNumber Number 235hi def link rustBoolean Boolean 236hi def link rustEnum rustType 237hi def link rustEnumVariant rustConstant 238hi def link rustConstant Constant 239hi def link rustSelf Constant 240hi def link rustFloat Float 241hi def link rustArrowCharacter rustOperator 242hi def link rustOperator Operator 243hi def link rustKeyword Keyword 244hi def link rustTypedef Keyword " More precise is Typedef, but it doesn't feel right for Rust 245hi def link rustStructure Keyword " More precise is Structure 246hi def link rustUnion rustStructure 247hi def link rustPubScopeDelim Delimiter 248hi def link rustPubScopeCrate rustKeyword 249hi def link rustSuper rustKeyword 250hi def link rustReservedKeyword Error 251hi def link rustRepeat Conditional 252hi def link rustConditional Conditional 253hi def link rustIdentifier Identifier 254hi def link rustCapsIdent rustIdentifier 255hi def link rustModPath Include 256hi def link rustModPathSep Delimiter 257hi def link rustFunction Function 258hi def link rustFuncName Function 259hi def link rustFuncCall Function 260hi def link rustShebang Comment 261hi def link rustCommentLine Comment 262hi def link rustCommentLineDoc SpecialComment 263hi def link rustCommentLineDocError Error 264hi def link rustCommentBlock rustCommentLine 265hi def link rustCommentBlockDoc rustCommentLineDoc 266hi def link rustCommentBlockDocError Error 267hi def link rustAssert PreCondit 268hi def link rustPanic PreCondit 269hi def link rustMacro Macro 270hi def link rustType Type 271hi def link rustTodo Todo 272hi def link rustAttribute PreProc 273hi def link rustDerive PreProc 274hi def link rustDefault StorageClass 275hi def link rustStorage StorageClass 276hi def link rustObsoleteStorage Error 277hi def link rustLifetime Special 278hi def link rustLabel Label 279hi def link rustInvalidBareKeyword Error 280hi def link rustExternCrate rustKeyword 281hi def link rustObsoleteExternMod Error 282hi def link rustBoxPlacementParens Delimiter 283hi def link rustQuestionMark Special 284 285" Other Suggestions: 286" hi rustAttribute ctermfg=cyan 287" hi rustDerive ctermfg=cyan 288" hi rustAssert ctermfg=yellow 289" hi rustPanic ctermfg=red 290" hi rustMacro ctermfg=magenta 291 292syn sync minlines=200 293syn sync maxlines=500 294 295let b:current_syntax = "rust" 296