1" Language:     Verilog HDL
2" Maintainer:	Chih-Tsun Huang <cthuang@larc.ee.nthu.edu.tw>
3" Last Change:	Wed Oct 31 16:13:11 CST 2001
4" URL:		http://larc.ee.nthu.edu.tw/~cthuang/vim/indent/verilog.vim
5"
6" Credits:
7"   Suggestions for improvement, bug reports by
8"     Leo Butlero <lbutler@brocade.com>
9"
10" Buffer Variables:
11"     b:verilog_indent_modules : indenting after the declaration
12"				 of module blocks
13"     b:verilog_indent_width   : indenting width
14"     b:verilog_indent_verbose : verbose to each indenting
15"
16
17" Only load this indent file when no other was loaded.
18if exists("b:did_indent")
19  finish
20endif
21let b:did_indent = 1
22
23setlocal indentexpr=GetVerilogIndent()
24setlocal indentkeys=!^F,o,O,0),=begin,=end,=join,=endcase
25setlocal indentkeys+==endmodule,=endfunction,=endtask,=endspecify
26setlocal indentkeys+==`else,=`endif
27
28" Only define the function once.
29if exists("*GetVerilogIndent")
30  finish
31endif
32
33set cpo-=C
34
35function GetVerilogIndent()
36
37  if exists('b:verilog_indent_width')
38    let offset = b:verilog_indent_width
39  else
40    let offset = &sw
41  endif
42  if exists('b:verilog_indent_modules')
43    let indent_modules = offset
44  else
45    let indent_modules = 0
46  endif
47
48  " Find a non-blank line above the current line.
49  let lnum = prevnonblank(v:lnum - 1)
50
51  " At the start of the file use zero indent.
52  if lnum == 0
53    return 0
54  endif
55
56  let lnum2 = prevnonblank(lnum - 1)
57  let curr_line  = getline(v:lnum)
58  let last_line  = getline(lnum)
59  let last_line2 = getline(lnum2)
60  let ind  = indent(lnum)
61  let ind2 = indent(lnum - 1)
62  let offset_comment1 = 1
63  " Define the condition of an open statement
64  "   Exclude the match of //, /* or */
65  let vlog_openstat = '\(\<or\>\|\([*/]\)\@<![*(,{><+-/%^&|!=?:]\([*/]\)\@!\)'
66  " Define the condition when the statement ends with a one-line comment
67  let vlog_comment = '\(//.*\|/\*.*\*/\s*\)'
68  if exists('b:verilog_indent_verbose')
69    let vverb_str = 'INDENT VERBOSE:'
70    let vverb = 1
71  else
72    let vverb = 0
73  endif
74
75  " Indent accoding to last line
76  " End of multiple-line comment
77  if last_line =~ '\*/\s*$' && last_line !~ '/\*.\{-}\*/'
78    let ind = ind - offset_comment1
79    if vverb
80      echo vverb_str "De-indent after a multiple-line comment."
81    endif
82
83  " Indent after if/else/for/case/always/initial/specify/fork blocks
84  elseif last_line =~ '`\@<!\<\(if\|else\)\>' ||
85    \ last_line =~ '^\s*\<\(for\|case\%[[zx]]\)\>' ||
86    \ last_line =~ '^\s*\<\(always\|initial\)\>' ||
87    \ last_line =~ '^\s*\<\(specify\|fork\)\>'
88    if last_line !~ '\(;\|\<end\>\)\s*' . vlog_comment . '*$' ||
89      \ last_line =~ '\(//\|/\*\).*\(;\|\<end\>\)\s*' . vlog_comment . '*$'
90      let ind = ind + offset
91      if vverb | echo vverb_str "Indent after a block statement." | endif
92    endif
93  " Indent after function/task blocks
94  elseif last_line =~ '^\s*\<\(function\|task\)\>'
95    if last_line !~ '\<end\>\s*' . vlog_comment . '*$' ||
96      \ last_line =~ '\(//\|/\*\).*\(;\|\<end\>\)\s*' . vlog_comment . '*$'
97      let ind = ind + offset
98      if vverb
99	echo vverb_str "Indent after function/task block statement."
100      endif
101    endif
102
103  " Indent after module/function/task/specify/fork blocks
104  elseif last_line =~ '^\s*\<module\>'
105    let ind = ind + indent_modules
106    if vverb && indent_modules
107      echo vverb_str "Indent after module statement."
108    endif
109    if last_line =~ '[(,]\s*' . vlog_comment . '*$' &&
110      \ last_line !~ '\(//\|/\*\).*[(,]\s*' . vlog_comment . '*$'
111      let ind = ind + offset
112      if vverb
113	echo vverb_str "Indent after a multiple-line module statement."
114      endif
115    endif
116
117  " Indent after a 'begin' statement
118  elseif last_line =~ '\(\<begin\>\)\(\s*:\s*\w\+\)*' . vlog_comment . '*$' &&
119    \ last_line !~ '\(//\|/\*\).*\(\<begin\>\)' &&
120    \ ( last_line2 !~ vlog_openstat . '\s*' . vlog_comment . '*$' ||
121    \ last_line2 =~ '^\s*[^=!]\+\s*:\s*' . vlog_comment . '*$' )
122    let ind = ind + offset
123    if vverb | echo vverb_str "Indent after begin statement." | endif
124
125  " De-indent for the end of one-line block
126  elseif ( last_line !~ '\<begin\>' ||
127    \ last_line =~ '\(//\|/\*\).*\<begin\>' ) &&
128    \ last_line2 =~ '\<\(`\@<!if\|`\@<!else\|for\|always\|initial\)\>.*' .
129      \ vlog_comment . '*$' &&
130    \ last_line2 !~
131      \ '\(//\|/\*\).*\<\(`\@<!if\|`\@<!else\|for\|always\|initial\)\>' &&
132    \ last_line2 !~ vlog_openstat . '\s*' . vlog_comment . '*$' &&
133    \ ( last_line2 !~ '\<begin\>' ||
134    \ last_line2 =~ '\(//\|/\*\).*\<begin\>' )
135    let ind = ind - offset
136    if vverb
137      echo vverb_str "De-indent after the end of one-line statement."
138    endif
139
140    " Multiple-line statement (including case statement)
141    " Open statement
142    "   Ident the first open line
143    elseif  last_line =~ vlog_openstat . '\s*' . vlog_comment . '*$' &&
144      \ last_line !~ '\(//\|/\*\).*' . vlog_openstat . '\s*$' &&
145      \ last_line2 !~ vlog_openstat . '\s*' . vlog_comment . '*$'
146      let ind = ind + offset
147      if vverb | echo vverb_str "Indent after an open statement." | endif
148
149    " Close statement
150    "   De-indent for an optional close parenthesis and a semicolon, and only
151    "   if there exists precedent non-whitespace char
152    elseif last_line =~ ')*\s*;\s*' . vlog_comment . '*$' &&
153      \ last_line !~ '^\s*)*\s*;\s*' . vlog_comment . '*$' &&
154      \ last_line !~ '\(//\|/\*\).*\S)*\s*;\s*' . vlog_comment . '*$' &&
155      \ ( last_line2 =~ vlog_openstat . '\s*' . vlog_comment . '*$' &&
156      \ last_line2 !~ ';\s*//.*$') &&
157      \ last_line2 !~ '^\s*' . vlog_comment . '$'
158      let ind = ind - offset
159      if vverb | echo vverb_str "De-indent after a close statement." | endif
160
161  " `ifdef and `else
162  elseif last_line =~ '^\s*`\<\(ifdef\|else\)\>'
163    let ind = ind + offset
164    if vverb
165      echo vverb_str "Indent after a `ifdef or `else statement."
166    endif
167
168  endif
169
170  " Re-indent current line
171
172  " De-indent on the end of the block
173  " join/end/endcase/endfunction/endtask/endspecify
174  if curr_line =~ '^\s*\<\(join\|end\|endcase\)\>' ||
175    \ curr_line =~ '^\s*\<\(endfunction\|endtask\|endspecify\)\>'
176    let ind = ind - offset
177    if vverb | echo vverb_str "De-indent the end of a block." | endif
178  elseif curr_line =~ '^\s*\<endmodule\>'
179    let ind = ind - indent_modules
180    if vverb && indent_modules
181      echo vverb_str "De-indent the end of a module."
182    endif
183
184  " De-indent on a stand-alone 'begin'
185  elseif curr_line =~ '^\s*\<begin\>'
186    if last_line !~ '^\s*\<\(function\|task\|specify\|module\)\>' &&
187      \ last_line !~ '^\s*\()*\s*;\|)\+\)\s*' . vlog_comment . '*$' &&
188      \ ( last_line =~
189	\ '\<\(`\@<!if\|`\@<!else\|for\|case\%[[zx]]\|always\|initial\)\>' ||
190      \ last_line =~ ')\s*' . vlog_comment . '*$' ||
191      \ last_line =~ vlog_openstat . '\s*' . vlog_comment . '*$' )
192      let ind = ind - offset
193      if vverb
194	echo vverb_str "De-indent a stand alone begin statement."
195      endif
196    endif
197
198  " De-indent after the end of multiple-line statement
199  elseif curr_line =~ '^\s*)' &&
200    \ ( last_line =~ vlog_openstat . '\s*' . vlog_comment . '*$' ||
201    \ last_line !~ vlog_openstat . '\s*' . vlog_comment . '*$' &&
202    \ last_line2 =~ vlog_openstat . '\s*' . vlog_comment . '*$' )
203    let ind = ind - offset
204    if vverb
205      echo vverb_str "De-indent the end of a multiple statement."
206    endif
207
208  " De-indent `else and `endif
209  elseif curr_line =~ '^\s*`\<\(else\|endif\)\>'
210    let ind = ind - offset
211    if vverb | echo vverb_str "De-indent `else and `endif statement." | endif
212
213  endif
214
215  " Return the indention
216  return ind
217endfunction
218
219" vim:sw=2
220