vhdl.vim 14 KB

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