vhdl.vim (14778B)
1 " VHDL indent ('93 syntax) 2 " Language: VHDL 3 " Maintainer: Gerald Lai <laigera+vim?gmail.com> 4 " Version: 1.62 5 " Last Change: 2017 Oct 17 6 " 2023 Aug 28 by Vim Project (undo_indent) 7 " URL: http://www.vim.org/scripts/script.php?script_id=1450 8 9 " only load this indent file when no other was loaded 10 if exists("b:did_indent") 11 finish 12 endif 13 let b:did_indent = 1 14 15 " setup indent options for local VHDL buffer 16 setlocal indentexpr=GetVHDLindent() 17 setlocal indentkeys=!^F,o,O,0(,0) 18 setlocal indentkeys+==~begin,=~end\ ,=~end\ ,=~is,=~select,=~when 19 setlocal indentkeys+==~if,=~then,=~elsif,=~else 20 setlocal indentkeys+==~case,=~loop,=~for,=~generate,=~record,=~units,=~process,=~block,=~function,=~component,=~procedure 21 setlocal indentkeys+==~architecture,=~configuration,=~entity,=~package 22 23 let b:undo_indent = "setlocal indentexpr< indentkeys<" 24 25 " constants 26 " not a comment 27 let s:NC = '\%(--.*\)\@<!' 28 " end of string 29 let s:ES = '\s*\%(--.*\)\=$' 30 " no "end" keyword in front 31 let s:NE = '\%(\<end\s\+\)\@<!' 32 33 " option to disable alignment of generic/port mappings 34 if !exists("g:vhdl_indent_genportmap") 35 let g:vhdl_indent_genportmap = 1 36 endif 37 38 " option to disable alignment of right-hand side assignment "<=" statements 39 if !exists("g:vhdl_indent_rhsassign") 40 let g:vhdl_indent_rhsassign = 1 41 endif 42 43 " only define indent function once 44 if exists("*GetVHDLindent") 45 finish 46 endif 47 48 function GetVHDLindent() 49 " store current line & string 50 let curn = v:lnum 51 let curs = getline(curn) 52 53 " find previous line that is not a comment 54 let prevn = prevnonblank(curn - 1) 55 let prevs = getline(prevn) 56 while prevn > 0 && prevs =~ '^\s*--' 57 let prevn = prevnonblank(prevn - 1) 58 let prevs = getline(prevn) 59 endwhile 60 let prevs_noi = substitute(prevs, '^\s*', '', '') 61 62 " default indent starts as previous non-comment line's indent 63 let ind = prevn > 0 ? indent(prevn) : 0 64 " backup default 65 let ind2 = ind 66 67 " indent: special; kill string so it would not affect other filters 68 " keywords: "report" + string 69 " where: anywhere in current or previous line 70 let s0 = s:NC.'\<report\>\s*".*"' 71 if curs =~? s0 72 let curs = "" 73 endif 74 if prevs =~? s0 75 let prevs = "" 76 endif 77 78 " indent: previous line's comment position, otherwise follow next non-comment line if possible 79 " keyword: "--" 80 " where: start of current line 81 if curs =~ '^\s*--' 82 let pn = curn - 1 83 let ps = getline(pn) 84 if curs =~ '^\s*--\s' && ps =~ '--' 85 return indent(pn) + stridx(substitute(ps, '^\s*', '', ''), '--') 86 else 87 " find nextnonblank line that is not a comment 88 let nn = nextnonblank(curn + 1) 89 let ns = getline(nn) 90 while nn > 0 && ns =~ '^\s*--' 91 let nn = nextnonblank(nn + 1) 92 let ns = getline(nn) 93 endwhile 94 let n = indent(nn) 95 return n != -1 ? n : ind 96 endif 97 endif 98 99 " **************************************************************************************** 100 " indent: align generic variables & port names 101 " keywords: "procedure" + name, "generic", "map", "port" + "(", provided current line is part of mapping 102 " where: anywhere in previous 2 lines 103 " find following previous non-comment line 104 let pn = prevnonblank(prevn - 1) 105 let ps = getline(pn) 106 while pn > 0 && ps =~ '^\s*--' 107 let pn = prevnonblank(pn - 1) 108 let ps = getline(pn) 109 endwhile 110 if (curs =~ '^\s*)' || curs =~? '^\s*\%(\<\%(procedure\|generic\|map\|port\)\>.*\)\@<!\w\+\s*\w*\s*\((.*)\)*\s*\%(=>\s*\S\+\|:[^=]\@=\s*\%(\%(in\|out\|inout\|buffer\|linkage\)\>\|\s\+\)\)') && (prevs =~? s:NC.'\<\%(procedure\s\+\S\+\|generic\|map\|port\)\s*(\%(\s*\w\)\=' || (ps =~? s:NC.'\<\%(procedure\|generic\|map\|port\)'.s:ES && prevs =~ '^\s*(')) 111 " align closing ")" with opening "(" 112 if curs =~ '^\s*)' 113 return ind2 + stridx(prevs_noi, '(') 114 endif 115 let m = matchend(prevs_noi, '(\s*\ze\w') 116 if m != -1 117 return ind2 + m 118 else 119 if g:vhdl_indent_genportmap 120 return ind2 + stridx(prevs_noi, '(') + shiftwidth() 121 else 122 return ind2 + shiftwidth() 123 endif 124 endif 125 endif 126 127 " indent: align conditional/select statement 128 " keywords: variable + "<=" without ";" ending 129 " where: start of previous line 130 if prevs =~? '^\s*\S\+\s*<=[^;]*'.s:ES 131 if g:vhdl_indent_rhsassign 132 return ind2 + matchend(prevs_noi, '<=\s*\ze.') 133 else 134 return ind2 + shiftwidth() 135 endif 136 endif 137 138 " indent: backtrace previous non-comment lines for next smaller or equal size indent 139 " keywords: "end" + "record", "units" 140 " where: start of previous line 141 " keyword: ")" 142 " where: start of previous line 143 " keyword: without "<=" + ";" ending 144 " where: anywhere in previous line 145 " keyword: "=>" + ")" ending, provided current line does not begin with ")" 146 " where: anywhere in previous line 147 " _note_: indent allowed to leave this filter 148 let m = 0 149 if prevs =~? '^\s*end\s\+\%(record\|units\)\>' 150 let m = 3 151 elseif prevs =~ '^\s*)' 152 let m = 1 153 elseif prevs =~ s:NC.'\%(<=.*\)\@<!;'.s:ES || (curs !~ '^\s*)' && prevs =~ s:NC.'=>.*'.s:NC.')'.s:ES) 154 let m = 2 155 endif 156 157 if m > 0 158 let pn = prevnonblank(prevn - 1) 159 let ps = getline(pn) 160 while pn > 0 161 let t = indent(pn) 162 if ps !~ '^\s*--' && (t < ind || (t == ind && m == 3)) 163 " make sure one of these is true 164 " keywords: variable + "<=" without ";" ending 165 " where: start of previous non-comment line 166 " keywords: "procedure", "generic", "map", "port" 167 " where: anywhere in previous non-comment line 168 " keyword: "(" 169 " where: start of previous non-comment line 170 if m < 3 && ps !~? '^\s*\S\+\s*<=[^;]*'.s:ES 171 if ps =~? s:NC.'\<\%(procedure\|generic\|map\|port\)\>' || ps =~ '^\s*(' 172 let ind = t 173 endif 174 break 175 endif 176 let ind = t 177 if m > 1 178 " find following previous non-comment line 179 let ppn = prevnonblank(pn - 1) 180 let pps = getline(ppn) 181 while ppn > 0 && pps =~ '^\s*--' 182 let ppn = prevnonblank(ppn - 1) 183 let pps = getline(ppn) 184 endwhile 185 " indent: follow 186 " keyword: "select" 187 " where: end of following previous non-comment line 188 " keyword: "type" 189 " where: start of following previous non-comment line 190 if m == 2 191 let s1 = s:NC.'\<select'.s:ES 192 if ps !~? s1 && pps =~? s1 193 let ind = indent(ppn) 194 endif 195 elseif m == 3 196 let s1 = '^\s*type\>' 197 if ps !~? s1 && pps =~? s1 198 let ind = indent(ppn) 199 endif 200 endif 201 endif 202 break 203 endif 204 let pn = prevnonblank(pn - 1) 205 let ps = getline(pn) 206 endwhile 207 endif 208 209 " indent: follow indent of previous opening statement, otherwise -sw 210 " keyword: "begin" 211 " where: anywhere in current line 212 if curs =~? s:NC.'\<begin\>' 213 " find previous opening statement of 214 " keywords: "architecture", "block", "entity", "function", "generate", "procedure", "process" 215 let s2 = s:NC.s:NE.'\<\%(architecture\|block\|entity\|function\|generate\|procedure\|process\)\>' 216 217 let pn = prevnonblank(curn - 1) 218 let ps = getline(pn) 219 while pn > 0 && (ps =~ '^\s*--' || ps !~? s2) 220 let pn = prevnonblank(pn - 1) 221 let ps = getline(pn) 222 223 if (ps =~? s:NC.'\<begin\>') 224 return indent(pn) - shiftwidth() 225 endif 226 endwhile 227 228 if (pn == 0) 229 return ind - shiftwidth() 230 else 231 return indent(pn) 232 endif 233 endif 234 235 " indent: +sw if previous line is previous opening statement 236 " keywords: "record", "units" 237 " where: anywhere in current line 238 if curs =~? s:NC.s:NE.'\<\%(record\|units\)\>' 239 " find previous opening statement of 240 " keyword: "type" 241 let s3 = s:NC.s:NE.'\<type\>' 242 if curs !~? s3.'.*'.s:NC.'\<\%(record\|units\)\>.*'.s:ES && prevs =~? s3 243 let ind = ind + shiftwidth() 244 endif 245 return ind 246 endif 247 248 " **************************************************************************************** 249 " indent: 0 250 " keywords: "architecture", "configuration", "entity", "library", "package" 251 " where: start of current line 252 if curs =~? '^\s*\%(architecture\|configuration\|entity\|library\|package\)\>' 253 return 0 254 endif 255 256 " indent: maintain indent of previous opening statement 257 " keyword: "is" 258 " where: start of current line 259 " find previous opening statement of 260 " keywords: "architecture", "block", "configuration", "entity", "function", "package", "procedure", "process", "type" 261 if curs =~? '^\s*\<is\>' && prevs =~? s:NC.s:NE.'\<\%(architecture\|block\|configuration\|entity\|function\|package\|procedure\|process\|type\)\>' 262 return ind2 263 endif 264 265 " indent: maintain indent of previous opening statement 266 " keyword: "then" 267 " where: start of current line 268 " find previous opening statement of 269 " keywords: "elsif", "if" 270 if curs =~? '^\s*\<then\>' && prevs =~? s:NC.'\%(\<elsif\>\|'.s:NE.'\<if\>\)' 271 return ind2 272 endif 273 274 " indent: maintain indent of previous opening statement 275 " keyword: "generate" 276 " where: start of current line 277 " find previous opening statement of 278 " keywords: "for", "if" 279 if curs =~? '^\s*\<generate\>' && prevs =~? s:NC.s:NE.'\%(\%(\<wait\s\+\)\@<!\<for\|\<if\)\>' 280 return ind2 281 endif 282 283 " indent: +sw 284 " keywords: "block", "process" 285 " removed: "begin", "case", "elsif", "if", "loop", "record", "units", "while" 286 " where: anywhere in previous line 287 if prevs =~? s:NC.s:NE.'\<\%(block\|process\)\>' 288 return ind + shiftwidth() 289 endif 290 291 " indent: +sw 292 " keywords: "architecture", "configuration", "entity", "package" 293 " removed: "component", "for", "when", "with" 294 " where: start of previous line 295 if prevs =~? '^\s*\%(architecture\|configuration\|entity\|package\)\>' 296 return ind + shiftwidth() 297 endif 298 299 " indent: +sw 300 " keyword: "select" 301 " removed: "generate", "is", "=>" 302 " where: end of previous line 303 if prevs =~? s:NC.'\<select'.s:ES 304 return ind + shiftwidth() 305 endif 306 307 " indent: +sw 308 " keyword: "begin", "loop", "record", "units" 309 " where: anywhere in previous line 310 " keyword: "component", "else", "for" 311 " where: start of previous line 312 " keyword: "generate", "is", "then", "=>" 313 " where: end of previous line 314 " _note_: indent allowed to leave this filter 315 if prevs =~? s:NC.'\%(\<begin\>\|'.s:NE.'\<\%(loop\|record\|units\)\>\)' || prevs =~? '^\s*\%(component\|else\|for\)\>' || prevs =~? s:NC.'\%('.s:NE.'\<generate\|\<\%(is\|then\)\|=>\)'.s:ES 316 let ind = ind + shiftwidth() 317 endif 318 319 " **************************************************************************************** 320 " indent: -sw 321 " keywords: "when", provided previous line does not begin with "when", does not end with "is" 322 " where: start of current line 323 let s4 = '^\s*when\>' 324 if curs =~? s4 325 if prevs =~? s:NC.'\<is'.s:ES 326 return ind 327 elseif prevs !~? s4 328 return ind - shiftwidth() 329 else 330 return ind2 331 endif 332 endif 333 334 " indent: -sw 335 " keywords: "else", "elsif", "end" + "block", "for", "function", "generate", "if", "loop", "procedure", "process", "record", "units" 336 " where: start of current line 337 let s5 = 'block\|for\|function\|generate\|if\|loop\|procedure\|process\|record\|units' 338 if curs =~? '^\s*\%(else\|elsif\|end\s\+\%('.s5.'\)\)\>' 339 if prevs =~? '^\s*\%(elsif\|'.s5.'\)' 340 return ind 341 else 342 return ind - shiftwidth() 343 endif 344 endif 345 346 " indent: backtrace previous non-comment lines 347 " keyword: "end" + "case", "component" 348 " where: start of current line 349 let m = 0 350 if curs =~? '^\s*end\s\+case\>' 351 let m = 1 352 elseif curs =~? '^\s*end\s\+component\>' 353 let m = 2 354 endif 355 356 if m > 0 357 " find following previous non-comment line 358 let pn = prevn 359 let ps = getline(pn) 360 while pn > 0 361 if ps !~ '^\s*--' 362 "indent: -2sw 363 "keywords: "end" + "case" 364 "where: start of previous non-comment line 365 "indent: -sw 366 "keywords: "when" 367 "where: start of previous non-comment line 368 "indent: follow 369 "keywords: "case" 370 "where: start of previous non-comment line 371 if m == 1 372 if ps =~? '^\s*end\s\+case\>' 373 return indent(pn) - 2 * shiftwidth() 374 elseif ps =~? '^\s*when\>' 375 return indent(pn) - shiftwidth() 376 elseif ps =~? '^\s*case\>' 377 return indent(pn) 378 endif 379 "indent: follow 380 "keyword: "component" 381 "where: start of previous non-comment line 382 elseif m == 2 383 if ps =~? '^\s*component\>' 384 return indent(pn) 385 endif 386 endif 387 endif 388 let pn = prevnonblank(pn - 1) 389 let ps = getline(pn) 390 endwhile 391 return ind - shiftwidth() 392 endif 393 394 " indent: -sw 395 " keyword: ")" 396 " where: start of current line 397 if curs =~ '^\s*)' 398 return ind - shiftwidth() 399 endif 400 401 " indent: 0 402 " keywords: "end" + "architecture", "configuration", "entity", "package" 403 " where: start of current line 404 if curs =~? '^\s*end\s\+\%(architecture\|configuration\|entity\|package\)\>' 405 return 0 406 endif 407 408 " indent: -sw 409 " keywords: "end" + identifier, ";" 410 " where: start of current line 411 "if curs =~? '^\s*end\s\+\w\+\>' 412 if curs =~? '^\s*end\%(\s\|;'.s:ES.'\)' 413 return ind - shiftwidth() 414 endif 415 416 " **************************************************************************************** 417 " indent: maintain indent of previous opening statement 418 " keywords: without "procedure", "generic", "map", "port" + ":" but not ":=" + "in", "out", "inout", "buffer", "linkage", variable & ":=" 419 " where: start of current line 420 if curs =~? '^\s*\%(\<\%(procedure\|generic\|map\|port\)\>.*\)\@<!\w\+\s*\w*\s*:[^=]\@=\s*\%(\%(in\|out\|inout\|buffer\|linkage\)\>\|\w\+\s\+:=\)' 421 return ind2 422 endif 423 424 " **************************************************************************************** 425 " indent: maintain indent of previous opening statement, corner case which 426 " does not end in ;, but is part of a mapping 427 " keywords: without "procedure", "generic", "map", "port" + ":" but not ":=", never + ;$ and 428 " prevline without "procedure", "generic", "map", "port" + ":" but not ":=" + eventually ;$ 429 " where: start of current line 430 if curs =~? '^\s*\%(\<\%(procedure\|generic\|map\|port\)\>.*\)\@<!\w\+\s*\w*\s*:[^=].*[^;].*$' 431 if prevs =~? '^\s*\%(\<\%(procedure\|generic\|map\|port\)\>.*\)\@<!\w\+\s*\w*\s*:[^=].*;.*$' 432 return ind2 433 endif 434 endif 435 436 " return leftover filtered indent 437 return ind 438 endfunction