1" VHDL indent ('93 syntax) 2" Language: VHDL 3" Maintainer: Gerald Lai <laigera+vim?gmail.com> 4" Version: 1.56 5" Last Change: 2010 Jun 29 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: "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*\%(\<\%(generic\|map\|port\)\>.*\)\@<!\S\+\s*\%(=>\s*\S\+\|:[^=]\@=\s*\%(\%(in\|out\|inout\|buffer\|linkage\)\>\|\w\+\s\+:=\)\)') && (prevs =~? s:NC.'\<\%(generic\|map\|port\)\s*(\%(\s*\w\)\=' || (ps =~? s:NC.'\<\%(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, '(') + &sw 118 else 119 return ind2 + &sw 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 + &sw 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: "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.'\<\%(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 let ind = ind - &sw 211 " find previous opening statement of 212 " keywords: "architecture", "block", "entity", "function", "generate", "procedure", "process" 213 let s2 = s:NC.s:NE.'\<\%(architecture\|block\|entity\|function\|generate\|procedure\|process\)\>' 214 if (curs !~? s2.'.*'.s:NC.'\<begin\>.*'.s:ES && prevs =~? s2) || m == 1 215 let ind = ind + &sw 216 endif 217 return ind 218 endif 219 220 " indent: +sw if previous line is previous opening statement 221 " keywords: "record", "units" 222 " where: anywhere in current line 223 if curs =~? s:NC.s:NE.'\<\%(record\|units\)\>' 224 " find previous opening statement of 225 " keyword: "type" 226 let s3 = s:NC.s:NE.'\<type\>' 227 if curs !~? s3.'.*'.s:NC.'\<\%(record\|units\)\>.*'.s:ES && prevs =~? s3 228 let ind = ind + &sw 229 endif 230 return ind 231 endif 232 233 " **************************************************************************************** 234 " indent: 0 235 " keywords: "architecture", "configuration", "entity", "library", "package" 236 " where: start of current line 237 if curs =~? '^\s*\%(architecture\|configuration\|entity\|library\|package\)\>' 238 return 0 239 endif 240 241 " indent: maintain indent of previous opening statement 242 " keyword: "is" 243 " where: start of current line 244 " find previous opening statement of 245 " keywords: "architecture", "block", "configuration", "entity", "function", "package", "procedure", "process", "type" 246 if curs =~? '^\s*\<is\>' && prevs =~? s:NC.s:NE.'\<\%(architecture\|block\|configuration\|entity\|function\|package\|procedure\|process\|type\)\>' 247 return ind2 248 endif 249 250 " indent: maintain indent of previous opening statement 251 " keyword: "then" 252 " where: start of current line 253 " find previous opening statement of 254 " keywords: "elsif", "if" 255 if curs =~? '^\s*\<then\>' && prevs =~? s:NC.'\%(\<elsif\>\|'.s:NE.'\<if\>\)' 256 return ind2 257 endif 258 259 " indent: maintain indent of previous opening statement 260 " keyword: "generate" 261 " where: start of current line 262 " find previous opening statement of 263 " keywords: "for", "if" 264 if curs =~? '^\s*\<generate\>' && prevs =~? s:NC.s:NE.'\%(\%(\<wait\s\+\)\@<!\<for\|\<if\)\>' 265 return ind2 266 endif 267 268 " indent: +sw 269 " keywords: "block", "process" 270 " removed: "begin", "case", "elsif", "if", "loop", "record", "units", "while" 271 " where: anywhere in previous line 272 if prevs =~? s:NC.s:NE.'\<\%(block\|process\)\>' 273 return ind + &sw 274 endif 275 276 " indent: +sw 277 " keywords: "architecture", "configuration", "entity", "package" 278 " removed: "component", "for", "when", "with" 279 " where: start of previous line 280 if prevs =~? '^\s*\%(architecture\|configuration\|entity\|package\)\>' 281 return ind + &sw 282 endif 283 284 " indent: +sw 285 " keyword: "select" 286 " removed: "generate", "is", "=>" 287 " where: end of previous line 288 if prevs =~? s:NC.'\<select'.s:ES 289 return ind + &sw 290 endif 291 292 " indent: +sw 293 " keyword: "begin", "loop", "record", "units" 294 " where: anywhere in previous line 295 " keyword: "component", "else", "for" 296 " where: start of previous line 297 " keyword: "generate", "is", "then", "=>" 298 " where: end of previous line 299 " _note_: indent allowed to leave this filter 300 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 301 let ind = ind + &sw 302 endif 303 304 " **************************************************************************************** 305 " indent: -sw 306 " keywords: "when", provided previous line does not begin with "when", does not end with "is" 307 " where: start of current line 308 let s4 = '^\s*when\>' 309 if curs =~? s4 310 if prevs =~? s:NC.'\<is'.s:ES 311 return ind 312 elseif prevs !~? s4 313 return ind - &sw 314 else 315 return ind2 316 endif 317 endif 318 319 " indent: -sw 320 " keywords: "else", "elsif", "end" + "block", "for", "function", "generate", "if", "loop", "procedure", "process", "record", "units" 321 " where: start of current line 322 if curs =~? '^\s*\%(else\|elsif\|end\s\+\%(block\|for\|function\|generate\|if\|loop\|procedure\|process\|record\|units\)\)\>' 323 return ind - &sw 324 endif 325 326 " indent: backtrace previous non-comment lines 327 " keyword: "end" + "case", "component" 328 " where: start of current line 329 let m = 0 330 if curs =~? '^\s*end\s\+case\>' 331 let m = 1 332 elseif curs =~? '^\s*end\s\+component\>' 333 let m = 2 334 endif 335 336 if m > 0 337 " find following previous non-comment line 338 let pn = prevn 339 let ps = getline(pn) 340 while pn > 0 341 if ps !~ '^\s*--' 342 "indent: -2sw 343 "keywords: "end" + "case" 344 "where: start of previous non-comment line 345 "indent: -sw 346 "keywords: "when" 347 "where: start of previous non-comment line 348 "indent: follow 349 "keywords: "case" 350 "where: start of previous non-comment line 351 if m == 1 352 if ps =~? '^\s*end\s\+case\>' 353 return indent(pn) - 2 * &sw 354 elseif ps =~? '^\s*when\>' 355 return indent(pn) - &sw 356 elseif ps =~? '^\s*case\>' 357 return indent(pn) 358 endif 359 "indent: follow 360 "keyword: "component" 361 "where: start of previous non-comment line 362 elseif m == 2 363 if ps =~? '^\s*component\>' 364 return indent(pn) 365 endif 366 endif 367 endif 368 let pn = prevnonblank(pn - 1) 369 let ps = getline(pn) 370 endwhile 371 return ind - &sw 372 endif 373 374 " indent: -sw 375 " keyword: ")" 376 " where: start of current line 377 if curs =~ '^\s*)' 378 return ind - &sw 379 endif 380 381 " indent: 0 382 " keywords: "end" + "architecture", "configuration", "entity", "package" 383 " where: start of current line 384 if curs =~? '^\s*end\s\+\%(architecture\|configuration\|entity\|package\)\>' 385 return 0 386 endif 387 388 " indent: -sw 389 " keywords: "end" + identifier, ";" 390 " where: start of current line 391 "if curs =~? '^\s*end\s\+\w\+\>' 392 if curs =~? '^\s*end\%(\s\|;'.s:ES.'\)' 393 return ind - &sw 394 endif 395 396 " **************************************************************************************** 397 " indent: maintain indent of previous opening statement 398 " keywords: without "generic", "map", "port" + ":" but not ":=" + "in", "out", "inout", "buffer", "linkage", variable & ":=" 399 " where: start of current line 400 if curs =~? '^\s*\%(\<\%(generic\|map\|port\)\>.*\)\@<!\S\+\s*:[^=]\@=\s*\%(\%(in\|out\|inout\|buffer\|linkage\)\>\|\w\+\s\+:=\)' 401 return ind2 402 endif 403 404 " return leftover filtered indent 405 return ind 406endfunction 407