├── .gittron ├── ftplugin └── solidity.vim ├── ftdetect └── solidity.vim ├── LICENSE ├── README.md ├── indent └── solidity.vim └── syntax └── solidity.vim /.gittron: -------------------------------------------------------------------------------- 1 | 0x0808185476f8f410B6600947a4022E154ca1Baf4 2 | -------------------------------------------------------------------------------- /ftplugin/solidity.vim: -------------------------------------------------------------------------------- 1 | setlocal commentstring=//\ %s 2 | -------------------------------------------------------------------------------- /ftdetect/solidity.vim: -------------------------------------------------------------------------------- 1 | au BufNewFile,BufRead *.sol setf solidity 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Youcai Qian 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vim-solidity 2 | 3 | Syntax files for [Solidity](https://github.com/ethereum/solidity), the 4 | contract-oriented programming language for Ethereum. 5 | 6 | This repo has been forked from [tomlion's repo](https://github.com/tomlion/vim-solidity). It seems that the repository has been abandoned so I figured I would pick it up and improve my regex game :) 7 | 8 | I intend to use this tool daily, so expect updates! PRs are also welcome. 9 | 10 | ## Support this project and get a cool robot! 11 | 12 |
gittronSUPPORT US WITH GITTRON
13 | 14 | ## Improvements over the old repo: 15 | 16 | - assembly syntax highlighting 17 | - natspec syntax 18 | - more extensive color scheme 19 | - scientific number notation (1e18 used much anyone?) 20 | - constructor keyword highlighting 21 | - calldata highlighting 22 | - typecase highlighting 23 | - abi keyword added 24 | - anonymous & indexed event modifiers includes 25 | - reserved words give errors 26 | - overall more extensive and detailed syntax highlighting 27 | - various bug fixes 28 | 29 | ## Before and After Example (new on left old on right) 30 | 31 | ![vim-solidity before & after](https://i.imgur.com/mmfron7.png) 32 | 33 | ## Installation 34 | 35 | **Important:** If you are using the latest version of `vim-polyglot`, this repo's syntax is already included. No further action is required. 36 | 37 | ### Pathogen 38 | 39 | Run the following command: 40 | 41 | ```bash 42 | git clone https://github.com/TovarishFin/vim-solidity.git ~/.vim/bundle/vim-solidity 43 | ``` 44 | 45 | ### Vundle 46 | 47 | Add the following line to your `~/.vimrc`: 48 | 49 | ```vim 50 | Plugin 'TovarishFin/vim-solidity' 51 | ``` 52 | 53 | ### Plug 54 | 55 | Add the following line to your `~/.vimrc`: 56 | 57 | ```vim 58 | Plug 'TovarishFin/vim-solidity' 59 | ``` 60 | 61 | ### No Plugin Manager 62 | 63 | Copy all of the files manually into your `~/.vim`. 64 | -------------------------------------------------------------------------------- /indent/solidity.vim: -------------------------------------------------------------------------------- 1 | " Vim indent file 2 | " Language: Solidity 3 | " Acknowledgement: Based off of vim-javascript 4 | 5 | " 0. Initialization {{{1 6 | " ================= 7 | 8 | " Only load this indent file when no other was loaded. 9 | if exists("b:did_indent") 10 | finish 11 | endif 12 | let b:did_indent = 1 13 | 14 | setlocal nosmartindent 15 | 16 | " Now, set up our indentation expression and keys that trigger it. 17 | setlocal indentexpr=GetSolidityIndent() 18 | setlocal indentkeys=0{,0},0),0],0\,,!^F,o,O,e,0* 19 | 20 | " Only define the function once. 21 | if exists("*GetSolidityIndent") 22 | finish 23 | endif 24 | 25 | let s:cpo_save = &cpo 26 | set cpo&vim 27 | 28 | " 1. Variables {{{1 29 | " ============ 30 | 31 | let s:js_keywords = '^\s*\(break\|case\|catch\|continue\|debugger\|default\|delete\|do\|else\|finally\|for\|function\|if\|in\|instanceof\|new\|return\|switch\|this\|throw\|try\|typeof\|var\|void\|while\|with\)' 32 | 33 | " Regex of syntax group names that are or delimit string or are comments. 34 | let s:syng_strcom = 'string\|regex\|comment\c' 35 | 36 | " Regex of syntax group names that are strings. 37 | let s:syng_string = 'regex\c' 38 | 39 | " Regex of syntax group names that are strings or documentation. 40 | let s:syng_multiline = 'comment\|natspecblock\c' 41 | 42 | " Regex of syntax group names that are line comment. 43 | let s:syng_linecom = 'linecomment\c' 44 | 45 | " Expression used to check whether we should skip a match with searchpair(). 46 | let s:skip_expr = "synIDattr(synID(line('.'),col('.'),1),'name') =~ '".s:syng_strcom."'" 47 | 48 | let s:line_term = '\s*\%(\%(\/\/\).*\)\=$' 49 | 50 | " Regex that defines continuation lines, not including (, {, or [. 51 | let s:continuation_regex = '\%([\\*+/.:]\|\%(<%\)\@[^{;]*' . s:line_term 58 | 59 | " Regex that defines blocks. 60 | let s:block_regex = '\%([{[]\)\s*\%(|\%([*@]\=\h\w*,\=\s*\)\%(,\s*[*@]\=\h\w*\)*|\)\=' . s:line_term 61 | 62 | let s:var_stmt = '^\s*var' 63 | 64 | let s:comma_first = '^\s*,' 65 | let s:comma_last = ',\s*$' 66 | 67 | let s:ternary = '^\s\+[?|:]' 68 | let s:ternary_q = '^\s\+?' 69 | 70 | " 2. Auxiliary Functions {{{1 71 | " ====================== 72 | 73 | " Check if the character at lnum:col is inside a string, comment, or is ascii. 74 | function s:IsInStringOrComment(lnum, col) 75 | return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_strcom 76 | endfunction 77 | 78 | " Check if the character at lnum:col is inside a string. 79 | function s:IsInString(lnum, col) 80 | return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_string 81 | endfunction 82 | 83 | " Check if the character at lnum:col is inside a multi-line comment. 84 | function s:IsInMultilineComment(lnum, col) 85 | return !s:IsLineComment(a:lnum, a:col) && synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_multiline 86 | endfunction 87 | 88 | " Check if the character at lnum:col is a line comment. 89 | function s:IsLineComment(lnum, col) 90 | return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_linecom 91 | endfunction 92 | 93 | " Find line above 'lnum' that isn't empty, in a comment, or in a string. 94 | function s:PrevNonBlankNonString(lnum) 95 | let in_block = 0 96 | let lnum = prevnonblank(a:lnum) 97 | while lnum > 0 98 | " Go in and out of blocks comments as necessary. 99 | " If the line isn't empty (with opt. comment) or in a string, end search. 100 | let line = getline(lnum) 101 | if line =~ '/\*' 102 | if in_block 103 | let in_block = 0 104 | else 105 | break 106 | endif 107 | elseif !in_block && line =~ '\*/' 108 | let in_block = 1 109 | elseif !in_block && line !~ '^\s*\%(//\).*$' && !(s:IsInStringOrComment(lnum, 1) && s:IsInStringOrComment(lnum, strlen(line))) 110 | break 111 | endif 112 | let lnum = prevnonblank(lnum - 1) 113 | endwhile 114 | return lnum 115 | endfunction 116 | 117 | " Find line above 'lnum' that started the continuation 'lnum' may be part of. 118 | function s:GetMSL(lnum, in_one_line_scope) 119 | " Start on the line we're at and use its indent. 120 | let msl = a:lnum 121 | let lnum = s:PrevNonBlankNonString(a:lnum - 1) 122 | while lnum > 0 123 | " If we have a continuation line, or we're in a string, use line as MSL. 124 | " Otherwise, terminate search as we have found our MSL already. 125 | let line = getline(lnum) 126 | let col = match(line, s:msl_regex) + 1 127 | if (col > 0 && !s:IsInStringOrComment(lnum, col)) || s:IsInString(lnum, strlen(line)) 128 | let msl = lnum 129 | else 130 | " Don't use lines that are part of a one line scope as msl unless the 131 | " flag in_one_line_scope is set to 1 132 | " 133 | if a:in_one_line_scope 134 | break 135 | end 136 | let msl_one_line = s:Match(lnum, s:one_line_scope_regex) 137 | if msl_one_line == 0 138 | break 139 | endif 140 | endif 141 | let lnum = s:PrevNonBlankNonString(lnum - 1) 142 | endwhile 143 | return msl 144 | endfunction 145 | 146 | function s:RemoveTrailingComments(content) 147 | let single = '\/\/\(.*\)\s*$' 148 | let multi = '\/\*\(.*\)\*\/\s*$' 149 | return substitute(substitute(a:content, single, '', ''), multi, '', '') 150 | endfunction 151 | 152 | " Find if the string is inside var statement (but not the first string) 153 | function s:InMultiVarStatement(lnum) 154 | let lnum = s:PrevNonBlankNonString(a:lnum - 1) 155 | 156 | " let type = synIDattr(synID(lnum, indent(lnum) + 1, 0), 'name') 157 | 158 | " loop through previous expressions to find a var statement 159 | while lnum > 0 160 | let line = getline(lnum) 161 | 162 | " if the line is a js keyword 163 | if (line =~ s:js_keywords) 164 | " check if the line is a var stmt 165 | " if the line has a comma first or comma last then we can assume that we 166 | " are in a multiple var statement 167 | if (line =~ s:var_stmt) 168 | return lnum 169 | endif 170 | 171 | " other js keywords, not a var 172 | return 0 173 | endif 174 | 175 | let lnum = s:PrevNonBlankNonString(lnum - 1) 176 | endwhile 177 | 178 | " beginning of program, not a var 179 | return 0 180 | endfunction 181 | 182 | " Find line above with beginning of the var statement or returns 0 if it's not 183 | " this statement 184 | function s:GetVarIndent(lnum) 185 | let lvar = s:InMultiVarStatement(a:lnum) 186 | let prev_lnum = s:PrevNonBlankNonString(a:lnum - 1) 187 | 188 | if lvar 189 | let line = s:RemoveTrailingComments(getline(prev_lnum)) 190 | 191 | " if the previous line doesn't end in a comma, return to regular indent 192 | if (line !~ s:comma_last) 193 | return indent(prev_lnum) - &sw 194 | else 195 | return indent(lvar) + &sw 196 | endif 197 | endif 198 | 199 | return -1 200 | endfunction 201 | 202 | 203 | " Check if line 'lnum' has more opening brackets than closing ones. 204 | function s:LineHasOpeningBrackets(lnum) 205 | let open_0 = 0 206 | let open_2 = 0 207 | let open_4 = 0 208 | let line = getline(a:lnum) 209 | let pos = match(line, '[][(){}]', 0) 210 | while pos != -1 211 | if !s:IsInStringOrComment(a:lnum, pos + 1) 212 | let idx = stridx('(){}[]', line[pos]) 213 | if idx % 2 == 0 214 | let open_{idx} = open_{idx} + 1 215 | else 216 | let open_{idx - 1} = open_{idx - 1} - 1 217 | endif 218 | endif 219 | let pos = match(line, '[][(){}]', pos + 1) 220 | endwhile 221 | return (open_0 > 0) . (open_2 > 0) . (open_4 > 0) 222 | endfunction 223 | 224 | function s:Match(lnum, regex) 225 | let col = match(getline(a:lnum), a:regex) + 1 226 | return col > 0 && !s:IsInStringOrComment(a:lnum, col) ? col : 0 227 | endfunction 228 | 229 | function s:IndentWithContinuation(lnum, ind, width) 230 | " Set up variables to use and search for MSL to the previous line. 231 | let p_lnum = a:lnum 232 | let lnum = s:GetMSL(a:lnum, 1) 233 | let line = getline(lnum) 234 | 235 | " If the previous line wasn't a MSL and is continuation return its indent. 236 | " TODO: the || s:IsInString() thing worries me a bit. 237 | if p_lnum != lnum 238 | if s:Match(p_lnum,s:continuation_regex)||s:IsInString(p_lnum,strlen(line)) 239 | return a:ind 240 | endif 241 | endif 242 | 243 | " Set up more variables now that we know we aren't continuation bound. 244 | let msl_ind = indent(lnum) 245 | 246 | " If the previous line ended with [*+/.-=], start a continuation that 247 | " indents an extra level. 248 | if s:Match(lnum, s:continuation_regex) 249 | if lnum == p_lnum 250 | return msl_ind + a:width 251 | else 252 | return msl_ind 253 | endif 254 | endif 255 | 256 | return a:ind 257 | endfunction 258 | 259 | function s:InOneLineScope(lnum) 260 | let msl = s:GetMSL(a:lnum, 1) 261 | if msl > 0 && s:Match(msl, s:one_line_scope_regex) 262 | return msl 263 | endif 264 | return 0 265 | endfunction 266 | 267 | function s:ExitingOneLineScope(lnum) 268 | let msl = s:GetMSL(a:lnum, 1) 269 | if msl > 0 270 | " if the current line is in a one line scope .. 271 | if s:Match(msl, s:one_line_scope_regex) 272 | return 0 273 | else 274 | let prev_msl = s:GetMSL(msl - 1, 1) 275 | if s:Match(prev_msl, s:one_line_scope_regex) 276 | return prev_msl 277 | endif 278 | endif 279 | endif 280 | return 0 281 | endfunction 282 | 283 | " 3. GetSolidityIndent Function {{{1 284 | " ========================= 285 | 286 | function GetSolidityIndent() 287 | " 3.1. Setup {{{2 288 | " ---------- 289 | 290 | " Set up variables for restoring position in file. Could use v:lnum here. 291 | let vcol = col('.') 292 | 293 | " 3.2. Work on the current line {{{2 294 | " ----------------------------- 295 | 296 | let ind = -1 297 | " Get the current line. 298 | let line = getline(v:lnum) 299 | " previous nonblank line number 300 | let prevline = prevnonblank(v:lnum - 1) 301 | 302 | " If we got a closing bracket on an empty line, find its match and indent 303 | " according to it. For parentheses we indent to its column - 1, for the 304 | " others we indent to the containing line's MSL's level. Return -1 if fail. 305 | let col = matchend(line, '^\s*[],})]') 306 | if col > 0 && !s:IsInStringOrComment(v:lnum, col) 307 | call cursor(v:lnum, col) 308 | 309 | let lvar = s:InMultiVarStatement(v:lnum) 310 | if lvar 311 | let prevline_contents = s:RemoveTrailingComments(getline(prevline)) 312 | 313 | " check for comma first 314 | if (line[col - 1] =~ ',') 315 | " if the previous line ends in comma or semicolon don't indent 316 | if (prevline_contents =~ '[;,]\s*$') 317 | return indent(s:GetMSL(line('.'), 0)) 318 | " get previous line indent, if it's comma first return prevline indent 319 | elseif (prevline_contents =~ s:comma_first) 320 | return indent(prevline) 321 | " otherwise we indent 1 level 322 | else 323 | return indent(lvar) + &sw 324 | endif 325 | endif 326 | endif 327 | 328 | 329 | let bs = strpart('(){}[]', stridx(')}]', line[col - 1]) * 2, 2) 330 | if searchpair(escape(bs[0], '\['), '', bs[1], 'bW', s:skip_expr) > 0 331 | if line[col-1]==')' && col('.') != col('$') - 1 332 | let ind = virtcol('.')-1 333 | else 334 | let ind = indent(s:GetMSL(line('.'), 0)) 335 | endif 336 | endif 337 | return ind 338 | endif 339 | 340 | " If the line is comma first, dedent 1 level 341 | if (getline(prevline) =~ s:comma_first) 342 | return indent(prevline) - &sw 343 | endif 344 | 345 | if (line =~ s:ternary) 346 | if (getline(prevline) =~ s:ternary_q) 347 | return indent(prevline) 348 | else 349 | return indent(prevline) + &sw 350 | endif 351 | endif 352 | 353 | " If we are in a multi-line comment, cindent does the right thing. 354 | if s:IsInMultilineComment(v:lnum, 1) && !s:IsLineComment(v:lnum, 1) 355 | return cindent(v:lnum) 356 | endif 357 | 358 | " Check for multiple var assignments 359 | " let var_indent = s:GetVarIndent(v:lnum) 360 | " if var_indent >= 0 361 | " return var_indent 362 | " endif 363 | 364 | " 3.3. Work on the previous line. {{{2 365 | " ------------------------------- 366 | 367 | " If the line is empty and the previous nonblank line was a multi-line 368 | " comment, use that comment's indent. Deduct one char to account for the 369 | " space in ' */'. 370 | if line =~ '^\s*$' && s:IsInMultilineComment(prevline, 1) 371 | return indent(prevline) - 1 372 | endif 373 | 374 | " Find a non-blank, non-multi-line string line above the current line. 375 | let lnum = s:PrevNonBlankNonString(v:lnum - 1) 376 | 377 | " If the line is empty and inside a string, use the previous line. 378 | if line =~ '^\s*$' && lnum != prevline 379 | return indent(prevnonblank(v:lnum)) 380 | endif 381 | 382 | " At the start of the file use zero indent. 383 | if lnum == 0 384 | return 0 385 | endif 386 | 387 | " Set up variables for current line. 388 | let line = getline(lnum) 389 | let ind = indent(lnum) 390 | 391 | " If the previous line ended with a block opening, add a level of indent. 392 | if s:Match(lnum, s:block_regex) 393 | return indent(s:GetMSL(lnum, 0)) + &sw 394 | endif 395 | 396 | " If the previous line contained an opening bracket, and we are still in it, 397 | " add indent depending on the bracket type. 398 | if line =~ '[[({]' 399 | let counts = s:LineHasOpeningBrackets(lnum) 400 | if counts[0] == '1' && searchpair('(', '', ')', 'bW', s:skip_expr) > 0 401 | if col('.') + 1 == col('$') 402 | return ind + &sw 403 | else 404 | return virtcol('.') 405 | endif 406 | elseif counts[1] == '1' || counts[2] == '1' 407 | return ind + &sw 408 | else 409 | call cursor(v:lnum, vcol) 410 | end 411 | endif 412 | 413 | " 3.4. Work on the MSL line. {{{2 414 | " -------------------------- 415 | 416 | let ind_con = ind 417 | let ind = s:IndentWithContinuation(lnum, ind_con, &sw) 418 | 419 | " }}}2 420 | " 421 | " 422 | let ols = s:InOneLineScope(lnum) 423 | if ols > 0 424 | let ind = ind + &sw 425 | else 426 | let ols = s:ExitingOneLineScope(lnum) 427 | while ols > 0 && ind > 0 428 | let ind = ind - &sw 429 | let ols = s:InOneLineScope(ols - 1) 430 | endwhile 431 | endif 432 | 433 | return ind 434 | endfunction 435 | 436 | " }}}1 437 | 438 | let &cpo = s:cpo_save 439 | unlet s:cpo_save 440 | -------------------------------------------------------------------------------- /syntax/solidity.vim: -------------------------------------------------------------------------------- 1 | " Vim syntax file 2 | " Language: Solidity 3 | " Maintainer: TovarishFin (tovarishFin@gmail.com) 4 | " URL: https://github.com/TovarishFin/vim-solidity 5 | 6 | if exists("b:current_syntax") 7 | finish 8 | endif 9 | 10 | syn sync minlines=50 11 | 12 | " Common Groups 13 | syn match solComma ',' 14 | syn keyword solStorageType contained skipempty skipwhite nextgroup=solStorageType,solStorageConst,solStorageImmutable 15 | \ public private internal 16 | syn keyword solStorageConst contained skipempty skipwhite nextgroup=solStorageType 17 | \ constant 18 | syn keyword solStorageImmutable contained skipempty skipwhite nextgroup=solStorageType 19 | \ immutable 20 | syn keyword solFuncStorageType contained 21 | \ storage calldata memory 22 | syn keyword solPayableType contained 23 | \ payable 24 | 25 | hi def link solStorageType Keyword 26 | hi def link solFuncStorageType Keyword 27 | hi def link solStorageConst Keyword 28 | hi def link solStorageImmutable Keyword 29 | hi def link solPayableType Keyword 30 | 31 | " Common Groups Highlighting 32 | hi def link solParens Normal 33 | hi def link solComma Normal 34 | 35 | " Complex Types 36 | syn keyword solMapping skipempty skipwhite nextgroup=solMappingParens 37 | \ mapping 38 | syn region solMappingParens start='(' end=')' contained contains=solValueType,solMapping nextgroup=solStorageType skipempty skipwhite 39 | syn keyword solEnum nextgroup=solEnumBody skipwhite skipempty 40 | \ enum 41 | syn region solEnumBody start='(' end=')' contained contains=solComma,solValueType 42 | syn keyword solStruct nextgroup=solStructBody skipempty skipwhite 43 | \ struct 44 | syn region solStructBody start='{' end='}' contained contains=solComma,solValueType,solStruct,solEnum,solMapping 45 | syn match solCustomType skipempty skipwhite nextgroup=solStorageType,solStorageConst,solStorageImmutable 46 | \ '\v[a-zA-Z_][a-zA-Z0-9_]*\s*' 47 | 48 | hi def link solMapping Define 49 | hi def link solEnum Define 50 | hi def link solStruct Define 51 | 52 | " Numbers 53 | syntax match solNumber '\v0x\x+>' 54 | syntax match solNumber '\v\c<%(\d+%(e[+-]=\d+)=|0b[01]+|0o\o+|0x\x+)>' 55 | syntax match solNumber '\v\c<%(\d+.\d+|\d+.|.\d+)%(e[+-]=\d+)=>' 56 | 57 | " Strings 58 | syntax region solString start=/\v"/ skip=/\v\\./ end=/\v"/ contains=@Spell 59 | syntax region solString start="\v'" skip="\v\\." end="\v'" contains=@Spell 60 | 61 | hi def link solNumber Number 62 | hi def link solString String 63 | 64 | " Operators 65 | syn match solOperator '\v\!' 66 | syn match solOperator '\v\|' 67 | syn match solOperator '\v\&' 68 | syn match solOperator '\v\%' 69 | syn match solOperator '\v\~' 70 | syn match solOperator '\v\^' 71 | syn match solOperator '\v\*' 72 | syn match solOperator '\v/' 73 | syn match solOperator '\v\+' 74 | syn match solOperator '\v-' 75 | syn match solOperator '\v\?' 76 | syn match solOperator '\v\:' 77 | syn match solOperator '\v\;' 78 | syn match solOperator '\v\>' 79 | syn match solOperator '\v\<' 80 | syn match solOperator '\v\>\=' 81 | syn match solOperator '\v\<\=' 82 | syn match solOperator '\v\=' 83 | syn match solOperator '\v\*\=' 84 | syn match solOperator '\v/\=' 85 | syn match solOperator '\v\+\=' 86 | syn match solOperator '\v-\=' 87 | 88 | hi def link solOperator Operator 89 | 90 | " Functions 91 | syn keyword solConstructor nextgroup=solFuncParam skipwhite skipempty 92 | \ constructor 93 | syn keyword solFunction nextgroup=solFuncName,solFuncParam skipwhite skipempty 94 | \ function 95 | syn keyword solFallback nextgroup=solFuncParam skipwhite skipempty 96 | \ fallback 97 | syn keyword solReceive nextgroup=solFuncParam skipwhite skipempty 98 | \ receive 99 | syn match solFuncName contained nextgroup=solFuncParam skipwhite skipempty 100 | \ '\v<[a-zA-Z_][0-9a-zA-Z_]*' 101 | syn region solFuncParam 102 | \ contained 103 | \ contains=solComma,solValueType,solFuncStorageType 104 | \ nextgroup=solFuncModCustom,solFuncModifier,solFuncReturn,solFuncBody 105 | \ skipempty 106 | \ skipwhite 107 | \ start='(' 108 | \ end=')' 109 | 110 | syn keyword solFuncModifier contained nextgroup=solFuncModifier,solFuncModCustom,solFuncReturn,solFuncBody skipwhite skipempty 111 | \ external internal payable public pure view private constant override virtual 112 | syn match solFuncModCustom contained nextgroup=solFuncModifier,solFuncModCustom,solFuncReturn,solFuncBody,solFuncModParens skipempty skipwhite 113 | \ '\v<[a-zA-Z_][0-9a-zA-Z_]*' 114 | syn region solFuncModParens contained contains=solString,solFuncCall,solConstant,solNumber,solTypeCast,solComma nextgroup=solFuncReturn,solFuncModifier,solFuncModCustom,solFuncBody skipempty skipwhite transparent 115 | \ start='(' 116 | \ end=')' 117 | syn keyword solFuncReturn contained nextgroup=solFuncRetParens skipwhite skipempty returns 118 | syn region solFuncRetParens contains=solValueType,solFuncStorageType nextgroup=solFuncBody skipempty skipwhite 119 | \ start='(' 120 | \ end=')' 121 | syn region solFuncBody contained contains=solDestructure,solComment,solAssemblyBlock,solEmitEvent,solTypeCast,solMethod,solValueType,solConstant,solKeyword,solRepeat,solLabel,solException,solStructure,solFuncStorageType,solOperator,solNumber,solString,solFuncCall,solIf,solElse,solLoop skipempty skipwhite 122 | \ start='{' 123 | \ end='}' 124 | syn match solFuncCall contained skipempty skipwhite nextgroup=solCallOptions,solFuncCallParens 125 | \ '\v%(%(|||||
||)\s*)@/ containedin=solModifierBody 151 | 152 | hi def link solModifier Define 153 | hi def link solModifierName Function 154 | hi def link solModifierInsert Function 155 | 156 | " Contracts, Libraries, Interfaces 157 | syn match solAbstract /\/ nextgroup=SolContract skipwhite 158 | syn match solContract /\<\%(contract\|library\|interface\)\>/ nextgroup=solContractName skipwhite 159 | syn match solContractName /\<[a-zA-Z_][0-9a-zA-Z_]*/ contained nextgroup=solContractParent skipwhite 160 | syn region solContractParent start=/\/ end='{' contained contains=solContractName,solComma,solInheritor 161 | syn match solInheritor /\/ contained 162 | syn region solLibUsing start=/\/ end=/\/ contains=solLibName 163 | syn match solLibName /[a-zA-Z_][0-9a-zA-Z_]*\s*\zefor/ contained 164 | 165 | hi def link solAbstract Special 166 | hi def link solContract Define 167 | hi def link solContractName Function 168 | hi def link solInheritor Keyword 169 | hi def link solLibUsing Special 170 | hi def link solLibName Type 171 | 172 | " Events 173 | syn match solEvent /\/ nextgroup=solEventName,solEventParams skipwhite 174 | syn match solEventName /\<[a-zA-Z_][0-9a-zA-Z_]*/ nextgroup=solEventParam contained skipwhite 175 | syn region solEventParam start='(' end=')' contains=solComma,solValueType,solEventParamMod,other contained skipwhite skipempty 176 | syn match solEventParamMod /\(\\|\\)/ contained 177 | syn keyword solEmitEvent emit 178 | 179 | hi def link solEvent Define 180 | hi def link solEventName Function 181 | hi def link solEventParamMod Keyword 182 | hi def link solEmitEvent Special 183 | 184 | " Errors 185 | syn match solError /\/ nextgroup=solErrorName,solFuncParams skipwhite 186 | syn match solErrorName /\<[a-zA-Z_][0-9a-zA-Z_]*/ nextgroup=solFuncParam contained skipwhite 187 | syn region solErrorParam start='(' end=')' contains=solComma,solValueType,other contained skipwhite skipempty 188 | 189 | hi def link solError Define 190 | hi def link solErrorName Function 191 | 192 | " Constants 193 | syn keyword solConstant true false wei szabo finney ether seconds minutes hours days weeks years now super 194 | syn keyword solConstant block msg now tx this abi 195 | 196 | hi def link solConstant Constant 197 | 198 | " TODO: add syntax for 'override' and 'abstract' 'try' 'immutable' 199 | " Reserved keywords https://solidity.readthedocs.io/en/v0.5.7/miscellaneous.html#reserved-keywords 200 | syn keyword solReserved after alias apply auto case catch copyof default 201 | syn keyword solReserved define final implements in inline let macro match 202 | syn keyword solReserved mutable null of partial promise reference relocatable 203 | syn keyword solReserved sealed sizeof static supports switch typedef typeof unchecked 204 | 205 | hi def link solReserved Error 206 | 207 | " Pragma 208 | syn keyword solPragma pragma 209 | syn match solPragmaVersion /\(pragma\s*\)\@<=\/ 210 | syn match solPragmaExp /\(pragma\s*\)\@<=\/ 211 | syn match solPragmaABICoder /\(pragma\s*\)\@<=\/ 212 | 213 | hi def link solPragma PreProc 214 | hi def link solPragmaVersion PreProc 215 | hi def link solPragmaExp PreProc 216 | hi def link solPragmaABICoder PreProc 217 | 218 | " Assembly 219 | syn keyword solAssemblyName assembly contained 220 | syn region solAssemblyBlock start=/\/ contained 230 | syn keyword solAssemblyConst pc msize gas address caller callvalue calldatasize codesize contained 231 | syn keyword solAssemblyConst returndatasize origin gasprice coinbase timestamp number difficulty gaslimit contained 232 | syn keyword solAssemblyCond if else contained 233 | syn region solAssmNestedBlock start=/\(assembly\s*\)\@/ nextgroup=solStorageType,solStorageConst,solStorageImmutable skipwhite skipempty 263 | syn match solValueType /\/ nextgroup=solStorageType,solStorageConst,solStorageImmutable skipwhite skipempty 264 | syn match solValueType /\/ nextgroup=solStorageType,solStorageConst,solStorageImmutable skipwhite skipempty 265 | syn match solValueType /\/ nextgroup=solStorageType,solStorageConst,solStorageImmutable skipwhite skipempty 266 | syn match solValueType /\/ nextgroup=solStorageType,solStorageConst,solStorageImmutable skipwhite skipempty 267 | syn match solValueType /\/ nextgroup=solPayableType,solStorageType,solStorageConst,solStorageImmutable skipwhite skipempty 268 | syn match solValueType /\/ nextgroup=solStorageType,solStorageConst,solStorageImmutable skipwhite skipempty 269 | syn match solValueType /\/ nextgroup=solStorageType,solStorageConst,solStorageImmutable skipwhite skipempty 270 | 271 | syn match solValueType /\/ contained skipwhite skipempty nextgroup=solIfParens 294 | syn match solElse /\/ contained skipwhite skipempty nextgroup=solIf,solIfBlock 295 | syn region solIfParens start=/(/ end=/)/ contained nextgroup=solIfBlock skipwhite skipempty transparent 296 | syn region solIfBlock start=/{/ end=/}/ contained nextgroup=solElse skipwhite skipempty transparent 297 | 298 | hi def link solIf Keyword 299 | hi def link solElse Keyword 300 | 301 | " Loops 302 | syn match solLoop /\(\\|\\)/ contained skipwhite skipempty nextgroup=solLoopParens 303 | syn region solLoopParens start=/(/ end=/)/ contained nextgroup=solLoopBlock skipwhite skipempty transparent 304 | syn region solLoopBlock start=/{/ end=/}/ contained skipwhite skipempty transparent 305 | 306 | hi def link solLoop Keyword 307 | 308 | 309 | " Comments 310 | syn keyword solTodo TODO FIXME XXX TBD contained 311 | syn region solComment start=/\/\// end=/$/ contains=solTodo,@Spell 312 | syn region solComment start=/\/\*/ end=/\*\// contains=solTodo,@Spell 313 | 314 | hi def link solTodo Todo 315 | hi def link solComment Comment 316 | 317 | " Natspec 318 | syn match solNatspecTag /@dev\>/ contained 319 | syn match solNatspecTag /@title\>/ contained 320 | syn match solNatspecTag /@author\>/ contained 321 | syn match solNatspecTag /@notice\>/ contained 322 | syn match solNatspecTag /@param\>/ contained 323 | syn match solNatspecTag /@return\>/ contained 324 | syn match solNatspecTag /@inheritdoc\>/ contained 325 | syn match solNatspecTag /@custom:[a-z][a-z-]*/ contained 326 | syn match solNatspecParam /\(@param\s*\)\@<=\<[a-zA-Z_][0-9a-zA-Z_]*/ 327 | syn region solNatspecBlock start=/\/\/\// end=/$/ contains=solTodo,solNatspecTag,solNatspecParam,@Spell 328 | syn region solNatspecBlock start=/\/\*\{2}/ end=/\*\// contains=solTodo,solNatspecTag,solNatspecParam,@Spell 329 | 330 | hi def link solNatspecTag SpecialComment 331 | hi def link solNatspecBlock Comment 332 | hi def link solNatspecParam Define 333 | --------------------------------------------------------------------------------