├── .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 |
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 | 
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 |
--------------------------------------------------------------------------------