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