blob: f6114dc1fdb48912ea0cbc8fcd2bf13ce6b559ff [file] [log] [blame]
Bram Moolenaar92dff182014-02-11 19:15:50 +01001" Vim indent file
2" Language: SystemVerilog
3" Maintainer: kocha <kocha.lsifrontend@gmail.com>
Bram Moolenaar5be4cee2019-09-27 19:34:08 +02004" Last Change: 05-Feb-2017 by Bilal Wasim
Bram Moolenaarcbaff5e2022-04-08 17:45:08 +01005" 2022 April: b:undo_indent added by Doug Kearns
Bram Moolenaar92dff182014-02-11 19:15:50 +01006
7" Only load this indent file when no other was loaded.
8if exists("b:did_indent")
9 finish
10endif
11let b:did_indent = 1
12
13setlocal indentexpr=SystemVerilogIndent()
14setlocal indentkeys=!^F,o,O,0),0},=begin,=end,=join,=endcase,=join_any,=join_none
15setlocal indentkeys+==endmodule,=endfunction,=endtask,=endspecify
16setlocal indentkeys+==endclass,=endpackage,=endsequence,=endclocking
17setlocal indentkeys+==endinterface,=endgroup,=endprogram,=endproperty,=endchecker
18setlocal indentkeys+==`else,=`endif
19
Bram Moolenaarcbaff5e2022-04-08 17:45:08 +010020let b:undo_indent = "setl inde< indk<"
21
Bram Moolenaar92dff182014-02-11 19:15:50 +010022" Only define the function once.
23if exists("*SystemVerilogIndent")
24 finish
25endif
26
27let s:cpo_save = &cpo
28set cpo&vim
29
30function SystemVerilogIndent()
31
32 if exists('b:systemverilog_indent_width')
33 let offset = b:systemverilog_indent_width
34 else
Bram Moolenaar3ec574f2017-06-13 18:12:01 +020035 let offset = shiftwidth()
Bram Moolenaar92dff182014-02-11 19:15:50 +010036 endif
37 if exists('b:systemverilog_indent_modules')
38 let indent_modules = offset
39 else
40 let indent_modules = 0
41 endif
42
43 " Find a non-blank line above the current line.
44 let lnum = prevnonblank(v:lnum - 1)
45
46 " At the start of the file use zero indent.
47 if lnum == 0
48 return 0
49 endif
50
51 let lnum2 = prevnonblank(lnum - 1)
52 let curr_line = getline(v:lnum)
53 let last_line = getline(lnum)
54 let last_line2 = getline(lnum2)
55 let ind = indent(lnum)
56 let ind2 = indent(lnum - 1)
57 let offset_comment1 = 1
58 " Define the condition of an open statement
59 " Exclude the match of //, /* or */
60 let sv_openstat = '\(\<or\>\|\([*/]\)\@<![*(,{><+-/%^&|!=?:]\([*/]\)\@!\)'
61 " Define the condition when the statement ends with a one-line comment
62 let sv_comment = '\(//.*\|/\*.*\*/\s*\)'
63 if exists('b:verilog_indent_verbose')
64 let vverb_str = 'INDENT VERBOSE:'
65 let vverb = 1
66 else
67 let vverb = 0
68 endif
69
Bram Moolenaar6c391a72021-09-09 21:55:11 +020070 " Indent according to last line
Bram Moolenaar92dff182014-02-11 19:15:50 +010071 " End of multiple-line comment
72 if last_line =~ '\*/\s*$' && last_line !~ '/\*.\{-}\*/'
73 let ind = ind - offset_comment1
74 if vverb
75 echo vverb_str "De-indent after a multiple-line comment."
76 endif
77
78 " Indent after if/else/for/case/always/initial/specify/fork blocks
79 elseif last_line =~ '`\@<!\<\(if\|else\)\>' ||
Bram Moolenaar5be4cee2019-09-27 19:34:08 +020080 \ last_line =~ '^\s*\<\(for\|case\%[[zx]]\|do\|foreach\|forever\|randcase\)\>' ||
Bram Moolenaar92dff182014-02-11 19:15:50 +010081 \ last_line =~ '^\s*\<\(always\|always_comb\|always_ff\|always_latch\)\>' ||
82 \ last_line =~ '^\s*\<\(initial\|specify\|fork\|final\)\>'
83 if last_line !~ '\(;\|\<end\>\)\s*' . sv_comment . '*$' ||
84 \ last_line =~ '\(//\|/\*\).*\(;\|\<end\>\)\s*' . sv_comment . '*$'
85 let ind = ind + offset
86 if vverb | echo vverb_str "Indent after a block statement." | endif
87 endif
88 " Indent after function/task/class/package/sequence/clocking/
89 " interface/covergroup/property/checkerprogram blocks
90 elseif last_line =~ '^\s*\<\(function\|task\|class\|package\)\>' ||
91 \ last_line =~ '^\s*\<\(sequence\|clocking\|interface\)\>' ||
92 \ last_line =~ '^\s*\(\w\+\s*:\)\=\s*\<covergroup\>' ||
93 \ last_line =~ '^\s*\<\(property\|checker\|program\)\>'
94 if last_line !~ '\<end\>\s*' . sv_comment . '*$' ||
95 \ last_line =~ '\(//\|/\*\).*\(;\|\<end\>\)\s*' . sv_comment . '*$'
96 let ind = ind + offset
97 if vverb
98 echo vverb_str "Indent after function/task/class block statement."
99 endif
100 endif
101
102 " Indent after module/function/task/specify/fork blocks
103 elseif last_line =~ '^\s*\(\<extern\>\s*\)\=\<module\>'
104 let ind = ind + indent_modules
105 if vverb && indent_modules
106 echo vverb_str "Indent after module statement."
107 endif
108 if last_line =~ '[(,]\s*' . sv_comment . '*$' &&
109 \ last_line !~ '\(//\|/\*\).*[(,]\s*' . sv_comment . '*$'
110 let ind = ind + offset
111 if vverb
112 echo vverb_str "Indent after a multiple-line module statement."
113 endif
114 endif
115
116 " Indent after a 'begin' statement
117 elseif last_line =~ '\(\<begin\>\)\(\s*:\s*\w\+\)*' . sv_comment . '*$' &&
118 \ last_line !~ '\(//\|/\*\).*\(\<begin\>\)' &&
119 \ ( last_line2 !~ sv_openstat . '\s*' . sv_comment . '*$' ||
120 \ last_line2 =~ '^\s*[^=!]\+\s*:\s*' . sv_comment . '*$' )
121 let ind = ind + offset
122 if vverb | echo vverb_str "Indent after begin statement." | endif
123
124 " Indent after a '{' or a '('
125 elseif last_line =~ '[{(]' . sv_comment . '*$' &&
126 \ last_line !~ '\(//\|/\*\).*[{(]' &&
127 \ ( last_line2 !~ sv_openstat . '\s*' . sv_comment . '*$' ||
128 \ last_line2 =~ '^\s*[^=!]\+\s*:\s*' . sv_comment . '*$' )
129 let ind = ind + offset
130 if vverb | echo vverb_str "Indent after begin statement." | endif
131
132 " De-indent for the end of one-line block
133 elseif ( last_line !~ '\<begin\>' ||
134 \ last_line =~ '\(//\|/\*\).*\<begin\>' ) &&
Bram Moolenaar5be4cee2019-09-27 19:34:08 +0200135 \ last_line2 =~ '\<\(`\@<!if\|`\@<!else\|for\|always\|initial\|do\|foreach\|forever\|final\)\>.*' .
Bram Moolenaar92dff182014-02-11 19:15:50 +0100136 \ sv_comment . '*$' &&
Bram Moolenaar5be4cee2019-09-27 19:34:08 +0200137 \ last_line2 !~ '\(//\|/\*\).*\<\(`\@<!if\|`\@<!else\|for\|always\|initial\|do\|foreach\|forever\|final\)\>' &&
Bram Moolenaar92dff182014-02-11 19:15:50 +0100138 \ last_line2 !~ sv_openstat . '\s*' . sv_comment . '*$' &&
139 \ ( last_line2 !~ '\<begin\>' ||
140 \ last_line2 =~ '\(//\|/\*\).*\<begin\>' )
141 let ind = ind - offset
142 if vverb
143 echo vverb_str "De-indent after the end of one-line statement."
144 endif
145
146 " Multiple-line statement (including case statement)
147 " Open statement
148 " Ident the first open line
149 elseif last_line =~ sv_openstat . '\s*' . sv_comment . '*$' &&
150 \ last_line !~ '\(//\|/\*\).*' . sv_openstat . '\s*$' &&
151 \ last_line2 !~ sv_openstat . '\s*' . sv_comment . '*$'
152 let ind = ind + offset
153 if vverb | echo vverb_str "Indent after an open statement." | endif
154
155 " Close statement
156 " De-indent for an optional close parenthesis and a semicolon, and only
157 " if there exists precedent non-whitespace char
158 elseif last_line =~ ')*\s*;\s*' . sv_comment . '*$' &&
159 \ last_line !~ '^\s*)*\s*;\s*' . sv_comment . '*$' &&
160 \ last_line !~ '\(//\|/\*\).*\S)*\s*;\s*' . sv_comment . '*$' &&
161 \ ( last_line2 =~ sv_openstat . '\s*' . sv_comment . '*$' &&
162 \ last_line2 !~ ';\s*//.*$') &&
163 \ last_line2 !~ '^\s*' . sv_comment . '$'
164 let ind = ind - offset
165 if vverb | echo vverb_str "De-indent after a close statement." | endif
166
167 " `ifdef and `else
168 elseif last_line =~ '^\s*`\<\(ifdef\|else\)\>'
169 let ind = ind + offset
170 if vverb
171 echo vverb_str "Indent after a `ifdef or `else statement."
172 endif
173
174 endif
175
176 " Re-indent current line
177
178 " De-indent on the end of the block
179 " join/end/endcase/endfunction/endtask/endspecify
180 if curr_line =~ '^\s*\<\(join\|join_any\|join_none\|\|end\|endcase\|while\)\>' ||
181 \ curr_line =~ '^\s*\<\(endfunction\|endtask\|endspecify\|endclass\)\>' ||
182 \ curr_line =~ '^\s*\<\(endpackage\|endsequence\|endclocking\|endinterface\)\>' ||
183 \ curr_line =~ '^\s*\<\(endgroup\|endproperty\|endchecker\|endprogram\)\>' ||
184 \ curr_line =~ '^\s*}'
185 let ind = ind - offset
186 if vverb | echo vverb_str "De-indent the end of a block." | endif
187 elseif curr_line =~ '^\s*\<endmodule\>'
188 let ind = ind - indent_modules
189 if vverb && indent_modules
190 echo vverb_str "De-indent the end of a module."
191 endif
192
193 " De-indent on a stand-alone 'begin'
194 elseif curr_line =~ '^\s*\<begin\>'
195 if last_line !~ '^\s*\<\(function\|task\|specify\|module\|class\|package\)\>' ||
196 \ last_line !~ '^\s*\<\(sequence\|clocking\|interface\|covergroup\)\>' ||
197 \ last_line !~ '^\s*\<\(property\|checker\|program\)\>' &&
198 \ last_line !~ '^\s*\()*\s*;\|)\+\)\s*' . sv_comment . '*$' &&
199 \ ( last_line =~
Bram Moolenaar5be4cee2019-09-27 19:34:08 +0200200 \ '\<\(`\@<!if\|`\@<!else\|for\|case\%[[zx]]\|always\|initial\|do\|foreach\|forever\|randcase\|final\)\>' ||
Bram Moolenaar92dff182014-02-11 19:15:50 +0100201 \ last_line =~ ')\s*' . sv_comment . '*$' ||
202 \ last_line =~ sv_openstat . '\s*' . sv_comment . '*$' )
203 let ind = ind - offset
204 if vverb
205 echo vverb_str "De-indent a stand alone begin statement."
206 endif
207 endif
208
209 " De-indent after the end of multiple-line statement
210 elseif curr_line =~ '^\s*)' &&
211 \ ( last_line =~ sv_openstat . '\s*' . sv_comment . '*$' ||
212 \ last_line !~ sv_openstat . '\s*' . sv_comment . '*$' &&
213 \ last_line2 =~ sv_openstat . '\s*' . sv_comment . '*$' )
214 let ind = ind - offset
215 if vverb
216 echo vverb_str "De-indent the end of a multiple statement."
217 endif
218
219 " De-indent `else and `endif
220 elseif curr_line =~ '^\s*`\<\(else\|endif\)\>'
221 let ind = ind - offset
222 if vverb | echo vverb_str "De-indent `else and `endif statement." | endif
223
224 endif
225
Bram Moolenaar6c391a72021-09-09 21:55:11 +0200226 " Return the indentation
Bram Moolenaar92dff182014-02-11 19:15:50 +0100227 return ind
228endfunction
229
230let &cpo = s:cpo_save
231unlet s:cpo_save
232
Bram Moolenaar82be4842021-01-11 19:40:15 +0100233" vim:sw=2