systemverilog.vim (10804B)
1 " Vim indent file 2 " Language: SystemVerilog 3 " Maintainer: kocha <kocha.lsifrontend@gmail.com> 4 " Last Change: 05-Feb-2017 by Bilal Wasim 5 " 03-Aug-2022 Improved indent 6 7 " Only load this indent file when no other was loaded. 8 if exists("b:did_indent") 9 finish 10 endif 11 let b:did_indent = 1 12 13 setlocal indentexpr=SystemVerilogIndent() 14 setlocal indentkeys=!^F,o,O,0),0},=begin,=end,=join,=endcase,=join_any,=join_none 15 setlocal indentkeys+==endmodule,=endfunction,=endtask,=endspecify 16 setlocal indentkeys+==endclass,=endpackage,=endsequence,=endclocking 17 setlocal indentkeys+==endinterface,=endgroup,=endprogram,=endproperty,=endchecker 18 setlocal indentkeys+==`else,=`elsif,=`endif 19 20 let b:undo_indent = "setl inde< indk<" 21 22 " Only define the function once. 23 if exists("*SystemVerilogIndent") 24 finish 25 endif 26 27 let s:cpo_save = &cpo 28 set cpo&vim 29 30 let s:multiple_comment = 0 31 let s:open_statement = 0 32 33 function SystemVerilogIndent() 34 35 if exists('b:systemverilog_indent_width') 36 let offset = b:systemverilog_indent_width 37 else 38 let offset = shiftwidth() 39 endif 40 if exists('b:systemverilog_indent_modules') 41 let indent_modules = offset 42 else 43 let indent_modules = 0 44 endif 45 46 if exists('b:systemverilog_indent_ifdef_off') 47 let indent_ifdef = 0 48 else 49 let indent_ifdef = 1 50 endif 51 52 " Find a non-blank line above the current line. 53 let lnum = prevnonblank(v:lnum - 1) 54 55 " At the start of the file use zero indent. 56 if lnum == 0 57 return 0 58 endif 59 60 let lnum2 = prevnonblank(lnum - 1) 61 let curr_line = getline(v:lnum) 62 let last_line = getline(lnum) 63 let last_line2 = getline(lnum2) 64 let ind = indent(lnum) 65 let ind2 = indent(lnum - 1) 66 " Define the condition of an open statement 67 " Exclude the match of //, /* or */ 68 let sv_openstat = '\(\<or\>\|\([*/]\)\@<![*(,{><+-/%^&|!=?:]\([*/]\)\@!\)' 69 " Define the condition when the statement ends with a one-line comment 70 let sv_comment = '\(//.*\|/\*.*\*/\s*\)' 71 if exists('b:systemverilog_indent_verbose') 72 let vverb_str = 'INDENT VERBOSE: '. v:lnum .":" 73 let vverb = 1 74 else 75 let vverb = 0 76 endif 77 78 " Multiple-line comment count 79 if curr_line =~ '^\s*/\*' && curr_line !~ '/\*.\{-}\*/' 80 let s:multiple_comment += 1 81 if vverb | echom vverb_str "Start of multiple-line comment" | endif 82 elseif curr_line =~ '\*/\s*$' && curr_line !~ '/\*.\{-}\*/' 83 let s:multiple_comment -= 1 84 if vverb | echom vverb_str "End of multiple-line comment" | endif 85 return ind 86 endif 87 " Maintain indentation during commenting. 88 if s:multiple_comment > 0 89 return ind 90 endif 91 92 " Indent after if/else/for/case/always/initial/specify/fork blocks 93 if last_line =~ '^\s*\(end\)\=\s*`\@<!\<\(if\|else\)\>' || 94 \ last_line =~ '^\s*\<\(for\|while\|repeat\|case\%[[zx]]\|do\|foreach\|forever\|randcase\)\>' || 95 \ last_line =~ '^\s*\<\(always\|always_comb\|always_ff\|always_latch\)\>' || 96 \ last_line =~ '^\s*\<\(initial\|specify\|fork\|final\)\>' 97 if last_line !~ '\(;\|\<end\>\|\*/\)\s*' . sv_comment . '*$' || 98 \ last_line =~ '\(//\|/\*\).*\(;\|\<end\>\)\s*' . sv_comment . '*$' 99 let ind = ind + offset 100 if vverb | echom vverb_str "Indent after a block statement." | endif 101 endif 102 " Indent after function/task/class/package/sequence/clocking/ 103 " interface/covergroup/property/checkerprogram blocks 104 elseif last_line =~ '^\s*\<\(function\|task\|class\|package\)\>' || 105 \ last_line =~ '^\s*\<\(sequence\|clocking\|interface\)\>' || 106 \ last_line =~ '^\s*\(\w\+\s*:\)\=\s*\<covergroup\>' || 107 \ last_line =~ '^\s*\<\(property\|checker\|program\)\>' || 108 \ ( last_line =~ '^\s*\<virtual\>' && last_line =~ '\<\(function\|task\|class\|interface\)\>' ) || 109 \ ( last_line =~ '^\s*\<pure\>' && last_line =~ '\<virtual\>' && last_line =~ '\<\(function\|task\)\>' ) 110 if last_line !~ '\<end\>\s*' . sv_comment . '*$' || 111 \ last_line =~ '\(//\|/\*\).*\(;\|\<end\>\)\s*' . sv_comment . '*$' 112 let ind = ind + offset 113 if vverb 114 echom vverb_str "Indent after function/task/class block statement." 115 endif 116 endif 117 118 " Indent after module/function/task/specify/fork blocks 119 elseif last_line =~ '^\s*\(\<extern\>\s*\)\=\<module\>' 120 let ind = ind + indent_modules 121 if vverb && indent_modules 122 echom vverb_str "Indent after module statement." 123 endif 124 if last_line =~ '[(,]\s*' . sv_comment . '*$' && 125 \ last_line !~ '\(//\|/\*\).*[(,]\s*' . sv_comment . '*$' 126 let ind = ind + offset 127 if vverb 128 echom vverb_str "Indent after a multiple-line module statement." 129 endif 130 endif 131 132 " Indent after a 'begin' statement 133 elseif last_line =~ '\(\<begin\>\)\(\s*:\s*\w\+\)*' . sv_comment . '*$' && 134 \ last_line !~ '\(//\|/\*\).*\(\<begin\>\)' && 135 \ ( last_line2 !~ sv_openstat . '\s*' . sv_comment . '*$' || 136 \ last_line2 =~ '^\s*[^=!]\+\s*:\s*' . sv_comment . '*$' ) 137 let ind = ind + offset 138 if vverb | echom vverb_str "Indent after begin statement." | endif 139 140 " Indent after a '{' or a '(' 141 elseif last_line =~ '[{(]' . sv_comment . '*$' && 142 \ last_line !~ '\(//\|/\*\).*[{(]' && 143 \ ( last_line2 !~ sv_openstat . '\s*' . sv_comment . '*$' || 144 \ last_line2 =~ '^\s*[^=!]\+\s*:\s*' . sv_comment . '*$' ) 145 let ind = ind + offset 146 if vverb | echom vverb_str "Indent after begin statement." | endif 147 148 " Ignore de-indent for the end of one-line block 149 elseif ( last_line !~ '\<begin\>' || 150 \ last_line =~ '\(//\|/\*\).*\<begin\>' ) && 151 \ last_line2 =~ '\<\(`\@<!if\|`\@<!else\|for\|always\|initial\|do\|foreach\|forever\|final\)\>.*' . 152 \ sv_comment . '*$' && 153 \ last_line2 !~ '\(//\|/\*\).*\<\(`\@<!if\|`\@<!else\|for\|always\|initial\|do\|foreach\|forever\|final\)\>' && 154 \ last_line2 !~ sv_openstat . '\s*' . sv_comment . '*$' && 155 \ ( last_line2 !~ '\<begin\>' || 156 \ last_line2 =~ '\(//\|/\*\).*\<begin\>' ) && 157 \ last_line2 =~ ')*\s*;\s*' . sv_comment . '*$' 158 if vverb 159 echom vverb_str "Ignore de-indent after the end of one-line statement." 160 endif 161 162 " De-indent for the end of one-line block 163 elseif ( last_line !~ '\<begin\>' || 164 \ last_line =~ '\(//\|/\*\).*\<begin\>' ) && 165 \ last_line2 =~ '\<\(`\@<!if\|`\@<!else\|for\|always\|initial\|do\|foreach\|forever\|final\)\>.*' . 166 \ sv_comment . '*$' && 167 \ last_line2 !~ '\(//\|/\*\).*\<\(`\@<!if\|`\@<!else\|for\|always\|initial\|do\|foreach\|forever\|final\)\>' && 168 \ last_line2 !~ sv_openstat . '\s*' . sv_comment . '*$' && 169 \ last_line2 !~ '\(;\|\<end\>\|\*/\)\s*' . sv_comment . '*$' && 170 \ ( last_line2 !~ '\<begin\>' || 171 \ last_line2 =~ '\(//\|/\*\).*\<begin\>' ) 172 let ind = ind - offset 173 if vverb 174 echom vverb_str "De-indent after the end of one-line statement." 175 endif 176 177 " Multiple-line statement (including case statement) 178 " Open statement 179 " Ident the first open line 180 elseif last_line =~ sv_openstat . '\s*' . sv_comment . '*$' && 181 \ last_line !~ '\(//\|/\*\).*' . sv_openstat . '\s*$' && 182 \ last_line2 !~ sv_openstat . '\s*' . sv_comment . '*$' 183 let ind = ind + offset 184 let s:open_statement = 1 185 if vverb | echom vverb_str "Indent after an open statement." | endif 186 187 " `ifdef or `ifndef or `elsif or `else 188 elseif last_line =~ '^\s*`\<\(ifn\?def\|elsif\|else\)\>' && indent_ifdef 189 let ind = ind + offset 190 if vverb 191 echom vverb_str "Indent after a `ifdef or `ifndef or `elsif or `else statement." 192 endif 193 194 endif 195 196 " Re-indent current line 197 198 " De-indent on the end of the block 199 " join/end/endcase/endfunction/endtask/endspecify 200 if curr_line =~ '^\s*\<\(join\|join_any\|join_none\|\|end\|endcase\)\>' || 201 \ curr_line =~ '^\s*\<\(endfunction\|endtask\|endspecify\|endclass\)\>' || 202 \ curr_line =~ '^\s*\<\(endpackage\|endsequence\|endclocking\|endinterface\)\>' || 203 \ curr_line =~ '^\s*\<\(endgroup\|endproperty\|endchecker\|endprogram\)\>' 204 let ind = ind - offset 205 if vverb | echom vverb_str "De-indent the end of a block." | endif 206 if s:open_statement == 1 207 let ind = ind - offset 208 let s:open_statement = 0 209 if vverb | echom vverb_str "De-indent the close statement." | endif 210 endif 211 elseif curr_line =~ '^\s*\<endmodule\>' 212 let ind = ind - indent_modules 213 if vverb && indent_modules 214 echom vverb_str "De-indent the end of a module." 215 endif 216 217 " De-indent on a stand-alone 'begin' 218 elseif curr_line =~ '^\s*\<begin\>' 219 if last_line !~ '^\s*\<\(function\|task\|specify\|module\|class\|package\)\>' || 220 \ last_line !~ '^\s*\<\(sequence\|clocking\|interface\|covergroup\)\>' || 221 \ last_line !~ '^\s*\<\(property\|checker\|program\)\>' && 222 \ last_line !~ '^\s*\()*\s*;\|)\+\)\s*' . sv_comment . '*$' && 223 \ ( last_line =~ 224 \ '\<\(`\@<!if\|`\@<!else\|for\|case\%[[zx]]\|always\|initial\|do\|foreach\|forever\|randcase\|final\)\>' || 225 \ last_line =~ ')\s*' . sv_comment . '*$' || 226 \ last_line =~ sv_openstat . '\s*' . sv_comment . '*$' ) 227 let ind = ind - offset 228 if vverb 229 echom vverb_str "De-indent a stand alone begin statement." 230 endif 231 if s:open_statement == 1 232 let ind = ind - offset 233 let s:open_statement = 0 234 if vverb | echom vverb_str "De-indent the close statement." | endif 235 endif 236 endif 237 238 " " Close statement 239 " " De-indent for an optional close parenthesis and a semicolon, and only 240 " " if there exists precedent non-whitespace char 241 " elseif last_line =~ ')*\s*;\s*' . sv_comment . '*$' && 242 " \ last_line !~ '^\s*)*\s*;\s*' . sv_comment . '*$' && 243 " \ last_line !~ '\(//\|/\*\).*\S)*\s*;\s*' . sv_comment . '*$' && 244 " \ ( last_line2 =~ sv_openstat . '\s*' . sv_comment . '*$' && 245 " \ last_line2 !~ ';\s*//.*$') && 246 " \ last_line2 !~ '^\s*' . sv_comment . '$' 247 " let ind = ind - offset 248 " if vverb | echom vverb_str "De-indent after a close statement." | endif 249 250 " " De-indent after the end of multiple-line statement 251 " elseif curr_line =~ '^\s*)' && 252 " \ ( last_line =~ sv_openstat . '\s*' . sv_comment . '*$' || 253 " \ last_line !~ sv_openstat . '\s*' . sv_comment . '*$' && 254 " \ last_line2 =~ sv_openstat . '\s*' . sv_comment . '*$' ) 255 " let ind = ind - offset 256 " if vverb 257 " echom vverb_str "De-indent the end of a multiple statement." 258 " endif 259 260 " De-indent `elsif or `else or `endif 261 elseif curr_line =~ '^\s*`\<\(elsif\|else\|endif\)\>' && indent_ifdef 262 let ind = ind - offset 263 if vverb | echom vverb_str "De-indent `elsif or `else or `endif statement." | endif 264 if b:systemverilog_open_statement == 1 265 let ind = ind - offset 266 let b:systemverilog_open_statement = 0 267 if vverb | echom vverb_str "De-indent the open statement." | endif 268 endif 269 endif 270 271 " Return the indentation 272 return ind 273 endfunction 274 275 let &cpo = s:cpo_save 276 unlet s:cpo_save 277 278 " vim:sw=2