blob: 8aaf82e21f3ca2dda9dcb8fb7b129057f5345333 [file] [log] [blame]
Bram Moolenaarec7944a2013-06-12 21:29:15 +02001" Vim indent script for HTML
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +02002" Header: "{{{
3" Maintainer: Bram Moolenaar
4" Original Author: Andy Wokula <anwoku@yahoo.de>
Bram Moolenaarca635012015-09-25 20:34:21 +02005" Last Change: 2015 Sep 25
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +02006" Version: 1.0
7" Description: HTML indent script with cached state for faster indenting on a
8" range of lines.
9" Supports template systems through hooks.
10" Supports Closure stylesheets.
Bram Moolenaarec7944a2013-06-12 21:29:15 +020011"
12" Credits:
13" indent/html.vim (2006 Jun 05) from J. Zellner
14" indent/css.vim (2006 Dec 20) from N. Weibull
15"
16" History:
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +020017" 2014 June (v1.0) overhaul (Bram)
Bram Moolenaar52b91d82013-06-15 21:39:51 +020018" 2012 Oct 21 (v0.9) added support for shiftwidth()
19" 2011 Sep 09 (v0.8) added HTML5 tags (thx to J. Zuckerman)
20" 2008 Apr 28 (v0.6) revised customization
21" 2008 Mar 09 (v0.5) fixed 'indk' issue (thx to C.J. Robinson)
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +020022"}}}
Bram Moolenaar071d4272004-06-13 20:20:40 +000023
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +020024" Init Folklore, check user settings (2nd time ++)
25if exists("b:did_indent") "{{{
26 finish
Bram Moolenaar071d4272004-06-13 20:20:40 +000027endif
28let b:did_indent = 1
29
Bram Moolenaarec7944a2013-06-12 21:29:15 +020030setlocal indentexpr=HtmlIndent()
31setlocal indentkeys=o,O,<Return>,<>>,{,},!^F
Bram Moolenaar071d4272004-06-13 20:20:40 +000032
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +020033" "j1" is included to make cindent() work better with Javascript.
34setlocal cino=j1
35" "J1" should be included, but it doen't work properly before 7.4.355.
36if has("patch-7.4.355")
37 setlocal cino+=J1
38endif
39" Before patch 7.4.355 indenting after "(function() {" does not work well, add
40" )2 to limit paren search.
41if !has("patch-7.4.355")
42 setlocal cino+=)2
43endif
44
45" Needed for % to work when finding start/end of a tag.
Bram Moolenaar946e27a2014-06-25 18:50:27 +020046setlocal matchpairs+=<:>
47
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +020048let b:undo_indent = "setlocal inde< indk< cino<"
Bram Moolenaar071d4272004-06-13 20:20:40 +000049
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +020050" b:hi_indent keeps state to speed up indenting consecutive lines.
51let b:hi_indent = {"lnum": -1}
52
53"""""" Code below this is loaded only once. """""
54if exists("*HtmlIndent") && !exists('g:force_reload_html')
55 call HtmlIndent_CheckUserSettings()
56 finish
Bram Moolenaar071d4272004-06-13 20:20:40 +000057endif
58
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +020059" shiftwidth() exists since patch 7.3.694
Bram Moolenaar52b91d82013-06-15 21:39:51 +020060if exists('*shiftwidth')
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +020061 let s:ShiftWidth = function('shiftwidth')
Bram Moolenaar52b91d82013-06-15 21:39:51 +020062else
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +020063 func! s:ShiftWidth()
64 return &shiftwidth
65 endfunc
Bram Moolenaar52b91d82013-06-15 21:39:51 +020066endif
67
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +020068" Allow for line continuation below.
Bram Moolenaar91170f82006-05-05 21:15:17 +000069let s:cpo_save = &cpo
Bram Moolenaar071d4272004-06-13 20:20:40 +000070set cpo-=C
Bram Moolenaarec7944a2013-06-12 21:29:15 +020071"}}}
Bram Moolenaar071d4272004-06-13 20:20:40 +000072
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +020073" Check and process settings from b:html_indent and g:html_indent... variables.
74" Prefer using buffer-local settings over global settings, so that there can
75" be defaults for all HTML files and exceptions for specific types of HTML
76" files.
77func! HtmlIndent_CheckUserSettings()
78 "{{{
79 let inctags = ''
80 if exists("b:html_indent_inctags")
81 let inctags = b:html_indent_inctags
82 elseif exists("g:html_indent_inctags")
83 let inctags = g:html_indent_inctags
84 endif
85 let b:hi_tags = {}
86 if len(inctags) > 0
87 call s:AddITags(b:hi_tags, split(inctags, ","))
88 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000089
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +020090 let autotags = ''
91 if exists("b:html_indent_autotags")
92 let autotags = b:html_indent_autotags
93 elseif exists("g:html_indent_autotags")
94 let autotags = g:html_indent_autotags
95 endif
96 let b:hi_removed_tags = {}
Bram Moolenaar541f92d2015-06-19 13:27:23 +020097 if len(autotags) > 0
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +020098 call s:RemoveITags(b:hi_removed_tags, split(autotags, ","))
99 endif
100
101 " Syntax names indicating being inside a string of an attribute value.
102 let string_names = []
103 if exists("b:html_indent_string_names")
104 let string_names = b:html_indent_string_names
105 elseif exists("g:html_indent_string_names")
106 let string_names = g:html_indent_string_names
107 endif
108 let b:hi_insideStringNames = ['htmlString']
109 if len(string_names) > 0
110 for s in string_names
111 call add(b:hi_insideStringNames, s)
112 endfor
113 endif
114
115 " Syntax names indicating being inside a tag.
116 let tag_names = []
117 if exists("b:html_indent_tag_names")
118 let tag_names = b:html_indent_tag_names
119 elseif exists("g:html_indent_tag_names")
120 let tag_names = g:html_indent_tag_names
121 endif
122 let b:hi_insideTagNames = ['htmlTag', 'htmlScriptTag']
123 if len(tag_names) > 0
124 for s in tag_names
125 call add(b:hi_insideTagNames, s)
126 endfor
127 endif
128
129 let indone = {"zero": 0
130 \,"auto": "indent(prevnonblank(v:lnum-1))"
131 \,"inc": "b:hi_indent.blocktagind + s:ShiftWidth()"}
132
133 let script1 = ''
134 if exists("b:html_indent_script1")
135 let script1 = b:html_indent_script1
136 elseif exists("g:html_indent_script1")
137 let script1 = g:html_indent_script1
138 endif
139 if len(script1) > 0
140 let b:hi_js1indent = get(indone, script1, indone.zero)
141 else
142 let b:hi_js1indent = 0
143 endif
144
145 let style1 = ''
146 if exists("b:html_indent_style1")
147 let style1 = b:html_indent_style1
148 elseif exists("g:html_indent_style1")
149 let style1 = g:html_indent_style1
150 endif
151 if len(style1) > 0
152 let b:hi_css1indent = get(indone, style1, indone.zero)
153 else
154 let b:hi_css1indent = 0
155 endif
156
157 if !exists('b:html_indent_line_limit')
158 if exists('g:html_indent_line_limit')
159 let b:html_indent_line_limit = g:html_indent_line_limit
160 else
161 let b:html_indent_line_limit = 200
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200162 endif
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200163 endif
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200164endfunc "}}}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000165
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200166" Init Script Vars
167"{{{
168let b:hi_lasttick = 0
169let b:hi_newstate = {}
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200170let s:countonly = 0
171 "}}}
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200172
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200173" Fill the s:indent_tags dict with known tags.
174" The key is "tagname" or "/tagname". {{{
175" The value is:
176" 1 opening tag
177" 2 "pre"
178" 3 "script"
179" 4 "style"
180" 5 comment start
Bram Moolenaarca635012015-09-25 20:34:21 +0200181" 6 conditional comment start
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200182" -1 closing tag
183" -2 "/pre"
184" -3 "/script"
185" -4 "/style"
186" -5 comment end
Bram Moolenaarca635012015-09-25 20:34:21 +0200187" -6 conditional comment end
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200188let s:indent_tags = {}
Bram Moolenaarca635012015-09-25 20:34:21 +0200189let s:endtags = [0,0,0,0,0,0,0] " long enough for the highest index
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200190"}}}
191
192" Add a list of tag names for a pair of <tag> </tag> to "tags".
193func! s:AddITags(tags, taglist)
194 "{{{
195 for itag in a:taglist
196 let a:tags[itag] = 1
197 let a:tags['/' . itag] = -1
198 endfor
199endfunc "}}}
200
201" Take a list of tag name pairs that are not to be used as tag pairs.
202func! s:RemoveITags(tags, taglist)
203 "{{{
204 for itag in a:taglist
205 let a:tags[itag] = 1
206 let a:tags['/' . itag] = 1
207 endfor
208endfunc "}}}
209
210" Add a block tag, that is a tag with a different kind of indenting.
211func! s:AddBlockTag(tag, id, ...)
212 "{{{
213 if !(a:id >= 2 && a:id < len(s:endtags))
214 echoerr 'AddBlockTag ' . a:id
215 return
216 endif
217 let s:indent_tags[a:tag] = a:id
218 if a:0 == 0
219 let s:indent_tags['/' . a:tag] = -a:id
220 let s:endtags[a:id] = "</" . a:tag . ">"
221 else
222 let s:indent_tags[a:1] = -a:id
223 let s:endtags[a:id] = a:1
224 endif
225endfunc "}}}
226
227" Add known tag pairs.
228" Self-closing tags and tags that are sometimes {{{
229" self-closing (e.g., <p>) are not here (when encountering </p> we can find
230" the matching <p>, but not the other way around).
231" Old HTML tags:
232call s:AddITags(s:indent_tags, [
233 \ 'a', 'abbr', 'acronym', 'address', 'b', 'bdo', 'big',
234 \ 'blockquote', 'body', 'button', 'caption', 'center', 'cite', 'code',
235 \ 'colgroup', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font',
236 \ 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'html',
237 \ 'i', 'iframe', 'ins', 'kbd', 'label', 'legend', 'li',
238 \ 'map', 'menu', 'noframes', 'noscript', 'object', 'ol',
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200239 \ 'optgroup', 'q', 's', 'samp', 'select', 'small', 'span', 'strong', 'sub',
240 \ 'sup', 'table', 'textarea', 'title', 'tt', 'u', 'ul', 'var', 'th', 'td',
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200241 \ 'tr', 'tbody', 'tfoot', 'thead'])
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200242
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200243" Tags added 2011 Sep 09 (especially HTML5 tags):
244call s:AddITags(s:indent_tags, [
245 \ 'area', 'article', 'aside', 'audio', 'bdi', 'canvas',
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200246 \ 'command', 'datalist', 'details', 'embed', 'figure', 'footer',
247 \ 'header', 'group', 'keygen', 'mark', 'math', 'meter', 'nav', 'output',
248 \ 'progress', 'ruby', 'section', 'svg', 'texture', 'time', 'video',
249 \ 'wbr', 'text'])
Bram Moolenaard8b77f72015-03-05 21:21:19 +0100250
251" Tags added for web components:
252call s:AddITags(s:indent_tags, [
253 \ 'content', 'shadow', 'template'])
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200254"}}}
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200255
256" Add Block Tags: these contain alien content
257"{{{
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200258call s:AddBlockTag('pre', 2)
259call s:AddBlockTag('script', 3)
260call s:AddBlockTag('style', 4)
261call s:AddBlockTag('<!--', 5, '-->')
Bram Moolenaarca635012015-09-25 20:34:21 +0200262call s:AddBlockTag('<!--[', 6, '![endif]-->')
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200263"}}}
264
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200265" Return non-zero when "tagname" is an opening tag, not being a block tag, for
266" which there should be a closing tag. Can be used by scripts that include
267" HTML indenting.
268func! HtmlIndent_IsOpenTag(tagname)
269 "{{{
270 if get(s:indent_tags, a:tagname) == 1
271 return 1
272 endif
273 return get(b:hi_tags, a:tagname) == 1
274endfunc "}}}
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200275
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200276" Get the value for "tagname", taking care of buffer-local tags.
277func! s:get_tag(tagname)
278 "{{{
279 let i = get(s:indent_tags, a:tagname)
280 if (i == 1 || i == -1) && get(b:hi_removed_tags, a:tagname) != 0
281 return 0
282 endif
283 if i == 0
284 let i = get(b:hi_tags, a:tagname)
285 endif
286 return i
287endfunc "}}}
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200288
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200289" Count the number of start and end tags in "text".
290func! s:CountITags(text)
291 "{{{
292 " Store the result in s:curind and s:nextrel.
293 let s:curind = 0 " relative indent steps for current line [unit &sw]:
294 let s:nextrel = 0 " relative indent steps for next line [unit &sw]:
295 let s:block = 0 " assume starting outside of a block
296 let s:countonly = 1 " don't change state
Bram Moolenaarca635012015-09-25 20:34:21 +0200297 call substitute(a:text, '<\zs/\=\w\+\(-\w\+\)*\>\|<!--\[\|\[endif\]-->\|<!--\|-->', '\=s:CheckTag(submatch(0))', 'g')
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200298 let s:countonly = 0
299endfunc "}}}
300
301" Count the number of start and end tags in text.
302func! s:CountTagsAndState(text)
303 "{{{
304 " Store the result in s:curind and s:nextrel. Update b:hi_newstate.block.
305 let s:curind = 0 " relative indent steps for current line [unit &sw]:
306 let s:nextrel = 0 " relative indent steps for next line [unit &sw]:
307
308 let s:block = b:hi_newstate.block
Bram Moolenaarca635012015-09-25 20:34:21 +0200309 let tmp = substitute(a:text, '<\zs/\=\w\+\(-\w\+\)*\>\|<!--\[\|\[endif\]-->\|<!--\|-->', '\=s:CheckTag(submatch(0))', 'g')
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200310 if s:block == 3
311 let b:hi_newstate.scripttype = s:GetScriptType(matchstr(tmp, '\C.*<SCRIPT\>\zs[^>]*'))
312 endif
313 let b:hi_newstate.block = s:block
314endfunc "}}}
315
316" Used by s:CountITags() and s:CountTagsAndState().
317func! s:CheckTag(itag)
318 "{{{
319 " Returns an empty string or "SCRIPT".
320 " a:itag can be "tag" or "/tag" or "<!--" or "-->"
Bram Moolenaard8b77f72015-03-05 21:21:19 +0100321 if (s:CheckCustomTag(a:itag))
322 return ""
323 endif
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200324 let ind = s:get_tag(a:itag)
325 if ind == -1
326 " closing tag
327 if s:block != 0
328 " ignore itag within a block
329 return ""
330 endif
331 if s:nextrel == 0
332 let s:curind -= 1
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200333 else
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200334 let s:nextrel -= 1
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200335 endif
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200336 elseif ind == 1
337 " opening tag
338 if s:block != 0
339 return ""
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200340 endif
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200341 let s:nextrel += 1
342 elseif ind != 0
343 " block-tag (opening or closing)
344 return s:CheckBlockTag(a:itag, ind)
345 " else ind==0 (other tag found): keep indent
346 endif
347 return ""
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200348endfunc "}}}
349
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200350" Used by s:CheckTag(). Returns an empty string or "SCRIPT".
351func! s:CheckBlockTag(blocktag, ind)
352 "{{{
353 if a:ind > 0
354 " a block starts here
355 if s:block != 0
356 " already in a block (nesting) - ignore
357 " especially ignore comments after other blocktags
358 return ""
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200359 endif
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200360 let s:block = a:ind " block type
361 if s:countonly
362 return ""
363 endif
364 let b:hi_newstate.blocklnr = v:lnum
365 " save allover indent for the endtag
366 let b:hi_newstate.blocktagind = b:hi_indent.baseindent + (s:nextrel + s:curind) * s:ShiftWidth()
367 if a:ind == 3
368 return "SCRIPT" " all except this must be lowercase
369 " line is to be checked again for the type attribute
370 endif
371 else
372 let s:block = 0
373 " we get here if starting and closing a block-tag on the same line
374 endif
375 return ""
376endfunc "}}}
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200377
Bram Moolenaard8b77f72015-03-05 21:21:19 +0100378" Used by s:CheckTag().
379func! s:CheckCustomTag(ctag)
380 "{{{
381 " Returns 1 if ctag is the tag for a custom element, 0 otherwise.
382 " a:ctag can be "tag" or "/tag" or "<!--" or "-->"
383 let pattern = '\%\(\w\+-\)\+\w\+'
384 if match(a:ctag, pattern) == -1
385 return 0
386 endif
387 if matchstr(a:ctag, '\/\ze.\+') == "/"
388 " closing tag
389 if s:block != 0
390 " ignore ctag within a block
391 return 1
392 endif
393 if s:nextrel == 0
394 let s:curind -= 1
395 else
396 let s:nextrel -= 1
397 endif
398 else
399 " opening tag
400 if s:block != 0
401 return 1
402 endif
403 let s:nextrel += 1
404 endif
405 return 1
406endfunc "}}}
407
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200408" Return the <script> type: either "javascript" or ""
409func! s:GetScriptType(str)
410 "{{{
411 if a:str == "" || a:str =~ "java"
412 return "javascript"
413 else
414 return ""
415 endif
416endfunc "}}}
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200417
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200418" Look back in the file, starting at a:lnum - 1, to compute a state for the
419" start of line a:lnum. Return the new state.
420func! s:FreshState(lnum)
421 "{{{
422 " A state is to know ALL relevant details about the
423 " lines 1..a:lnum-1, initial calculating (here!) can be slow, but updating is
424 " fast (incremental).
425 " TODO: this should be split up in detecting the block type and computing the
426 " indent for the block type, so that when we do not know the indent we do
427 " not need to clear the whole state and re-detect the block type again.
428 " State:
429 " lnum last indented line == prevnonblank(a:lnum - 1)
430 " block = 0 a:lnum located within special tag: 0:none, 2:<pre>,
Bram Moolenaarca635012015-09-25 20:34:21 +0200431 " 3:<script>, 4:<style>, 5:<!--, 6:<!--[
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200432 " baseindent use this indent for line a:lnum as a start - kind of
433 " autoindent (if block==0)
434 " scripttype = '' type attribute of a script tag (if block==3)
435 " blocktagind indent for current opening (get) and closing (set)
436 " blocktag (if block!=0)
437 " blocklnr lnum of starting blocktag (if block!=0)
438 " inattr line {lnum} starts with attributes of a tag
439 let state = {}
440 let state.lnum = prevnonblank(a:lnum - 1)
441 let state.scripttype = ""
442 let state.blocktagind = -1
443 let state.block = 0
444 let state.baseindent = 0
445 let state.blocklnr = 0
446 let state.inattr = 0
447
448 if state.lnum == 0
449 return state
450 endif
451
452 " Heuristic:
453 " remember startline state.lnum
454 " look back for <pre, </pre, <script, </script, <style, </style tags
455 " remember stopline
456 " if opening tag found,
457 " assume a:lnum within block
458 " else
459 " look back in result range (stopline, startline) for comment
460 " \ delimiters (<!--, -->)
461 " if comment opener found,
462 " assume a:lnum within comment
463 " else
464 " assume usual html for a:lnum
465 " if a:lnum-1 has a closing comment
466 " look back to get indent of comment opener
467 " FI
468
469 " look back for a blocktag
Bram Moolenaarca635012015-09-25 20:34:21 +0200470 let stopline2 = v:lnum + 1
471 if has_key(b:hi_indent, 'block') && b:hi_indent.block > 5
472 let [stopline2, stopcol2] = searchpos('<!--', 'bnW')
473 endif
474 let [stopline, stopcol] = searchpos('\c<\zs\/\=\%(pre\>\|script\>\|style\>\)', "bnW")
475 if stopline > 0 && stopline < stopline2
476 " ugly ... why isn't there searchstr()
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200477 let tagline = tolower(getline(stopline))
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200478 let blocktag = matchstr(tagline, '\/\=\%(pre\>\|script\>\|style\>\)', stopcol - 1)
479 if blocktag[0] != "/"
480 " opening tag found, assume a:lnum within block
481 let state.block = s:indent_tags[blocktag]
482 if state.block == 3
483 let state.scripttype = s:GetScriptType(matchstr(tagline, '\>[^>]*', stopcol))
484 endif
485 let state.blocklnr = stopline
486 " check preceding tags in the line:
487 call s:CountITags(tagline[: stopcol-2])
488 let state.blocktagind = indent(stopline) + (s:curind + s:nextrel) * s:ShiftWidth()
489 return state
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200490 elseif stopline == state.lnum
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200491 " handle special case: previous line (= state.lnum) contains a
492 " closing blocktag which is preceded by line-noise;
493 " blocktag == "/..."
494 let swendtag = match(tagline, '^\s*</') >= 0
495 if !swendtag
Bram Moolenaarca635012015-09-25 20:34:21 +0200496 let [bline, bcol] = searchpos('<'.blocktag[1:].'\>', "bnW")
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200497 call s:CountITags(tolower(getline(bline)[: bcol-2]))
498 let state.baseindent = indent(bline) + (s:curind + s:nextrel) * s:ShiftWidth()
499 return state
500 endif
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200501 endif
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200502 endif
Bram Moolenaarca635012015-09-25 20:34:21 +0200503 if stopline > stopline2
504 let stopline = stopline2
505 let stopcol = stopcol2
506 endif
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200507
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200508 " else look back for comment
Bram Moolenaarca635012015-09-25 20:34:21 +0200509 let [comlnum, comcol, found] = searchpos('\(<!--\[\)\|\(<!--\)\|-->', 'bpnW', stopline)
510 if found == 2 || found == 3
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200511 " comment opener found, assume a:lnum within comment
Bram Moolenaarca635012015-09-25 20:34:21 +0200512 let state.block = (found == 3 ? 5 : 6)
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200513 let state.blocklnr = comlnum
514 " check preceding tags in the line:
515 call s:CountITags(tolower(getline(comlnum)[: comcol-2]))
Bram Moolenaarca635012015-09-25 20:34:21 +0200516 if found == 2
517 let state.baseindent = b:hi_indent.baseindent
518 endif
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200519 let state.blocktagind = indent(comlnum) + (s:curind + s:nextrel) * s:ShiftWidth()
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200520 return state
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200521 endif
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200522
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200523 " else within usual HTML
524 let text = tolower(getline(state.lnum))
525
526 " Check a:lnum-1 for closing comment (we need indent from the opening line).
527 " Not when other tags follow (might be --> inside a string).
528 let comcol = stridx(text, '-->')
529 if comcol >= 0 && match(text, '[<>]', comcol) <= 0
530 call cursor(state.lnum, comcol + 1)
531 let [comlnum, comcol] = searchpos('<!--', 'bW')
532 if comlnum == state.lnum
533 let text = text[: comcol-2]
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200534 else
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200535 let text = tolower(getline(comlnum)[: comcol-2])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000536 endif
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200537 call s:CountITags(text)
538 let state.baseindent = indent(comlnum) + (s:curind + s:nextrel) * s:ShiftWidth()
539 " TODO check tags that follow "-->"
540 return state
541 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000542
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200543 " Check if the previous line starts with end tag.
544 let swendtag = match(text, '^\s*</') >= 0
545
546 " If previous line ended in a closing tag, line up with the opening tag.
547 if !swendtag && text =~ '</\w\+\s*>\s*$'
548 call cursor(state.lnum, 99999)
Bram Moolenaar7b61a542014-08-23 15:31:19 +0200549 normal! F<
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200550 let start_lnum = HtmlIndent_FindStartTag()
551 if start_lnum > 0
552 let state.baseindent = indent(start_lnum)
553 if col('.') > 2
554 " check for tags before the matching opening tag.
555 let text = getline(start_lnum)
556 let swendtag = match(text, '^\s*</') >= 0
557 call s:CountITags(text[: col('.') - 2])
558 let state.baseindent += s:nextrel * s:ShiftWidth()
559 if !swendtag
560 let state.baseindent += s:curind * s:ShiftWidth()
561 endif
562 endif
563 return state
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200564 endif
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200565 endif
566
567 " Else: no comments. Skip backwards to find the tag we're inside.
568 let [state.lnum, found] = HtmlIndent_FindTagStart(state.lnum)
569 " Check if that line starts with end tag.
570 let text = getline(state.lnum)
571 let swendtag = match(text, '^\s*</') >= 0
572 call s:CountITags(tolower(text))
573 let state.baseindent = indent(state.lnum) + s:nextrel * s:ShiftWidth()
574 if !swendtag
575 let state.baseindent += s:curind * s:ShiftWidth()
576 endif
577 return state
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200578endfunc "}}}
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200579
580" Indent inside a <pre> block: Keep indent as-is.
581func! s:Alien2()
582 "{{{
583 return -1
584endfunc "}}}
585
586" Return the indent inside a <script> block for javascript.
587func! s:Alien3()
588 "{{{
589 let lnum = prevnonblank(v:lnum - 1)
590 while lnum > 1 && getline(lnum) =~ '^\s*/[/*]'
591 " Skip over comments to avoid that cindent() aligns with the <script> tag
592 let lnum = prevnonblank(lnum - 1)
593 endwhile
594 if lnum == b:hi_indent.blocklnr
595 " indent for the first line after <script>
596 return eval(b:hi_js1indent)
597 endif
598 if b:hi_indent.scripttype == "javascript"
599 return cindent(v:lnum)
600 else
601 return -1
602 endif
603endfunc "}}}
604
605" Return the indent inside a <style> block.
606func! s:Alien4()
607 "{{{
608 if prevnonblank(v:lnum-1) == b:hi_indent.blocklnr
609 " indent for first content line
610 return eval(b:hi_css1indent)
611 endif
612 return s:CSSIndent()
613endfunc "}}}
614
615" Indending inside a <style> block. Returns the indent.
616func! s:CSSIndent()
617 "{{{
618 " This handles standard CSS and also Closure stylesheets where special lines
619 " start with @.
620 " When the line starts with '*' or the previous line starts with "/*"
621 " and does not end in "*/", use C indenting to format the comment.
622 " Adopted $VIMRUNTIME/indent/css.vim
623 let curtext = getline(v:lnum)
624 if curtext =~ '^\s*[*]'
625 \ || (v:lnum > 1 && getline(v:lnum - 1) =~ '\s*/\*'
626 \ && getline(v:lnum - 1) !~ '\*/\s*$')
627 return cindent(v:lnum)
628 endif
629
630 let min_lnum = b:hi_indent.blocklnr
631 let prev_lnum = s:CssPrevNonComment(v:lnum - 1, min_lnum)
632 let [prev_lnum, found] = HtmlIndent_FindTagStart(prev_lnum)
633 if prev_lnum <= min_lnum
634 " Just below the <style> tag, indent for first content line after comments.
635 return eval(b:hi_css1indent)
636 endif
637
638 " If the current line starts with "}" align with it's match.
639 if curtext =~ '^\s*}'
640 call cursor(v:lnum, 1)
641 try
642 normal! %
643 " Found the matching "{", align with it after skipping unfinished lines.
644 let align_lnum = s:CssFirstUnfinished(line('.'), min_lnum)
645 return indent(align_lnum)
646 catch
647 " can't find it, try something else, but it's most likely going to be
648 " wrong
649 endtry
650 endif
651
652 " add indent after {
653 let brace_counts = HtmlIndent_CountBraces(prev_lnum)
654 let extra = brace_counts.c_open * s:ShiftWidth()
655
656 let prev_text = getline(prev_lnum)
657 let below_end_brace = prev_text =~ '}\s*$'
658
659 " Search back to align with the first line that's unfinished.
660 let align_lnum = s:CssFirstUnfinished(prev_lnum, min_lnum)
661
662 " Handle continuation lines if aligning with previous line and not after a
663 " "}".
664 if extra == 0 && align_lnum == prev_lnum && !below_end_brace
665 let prev_hasfield = prev_text =~ '^\s*[a-zA-Z0-9-]\+:'
666 let prev_special = prev_text =~ '^\s*\(/\*\|@\)'
667 if curtext =~ '^\s*\(/\*\|@\)'
668 " if the current line is not a comment or starts with @ (used by template
669 " systems) reduce indent if previous line is a continuation line
670 if !prev_hasfield && !prev_special
671 let extra = -s:ShiftWidth()
672 endif
673 else
674 let cur_hasfield = curtext =~ '^\s*[a-zA-Z0-9-]\+:'
675 let prev_unfinished = s:CssUnfinished(prev_text)
676 if !cur_hasfield && (prev_hasfield || prev_unfinished)
677 " Continuation line has extra indent if the previous line was not a
678 " continuation line.
679 let extra = s:ShiftWidth()
680 " Align with @if
681 if prev_text =~ '^\s*@if '
682 let extra = 4
683 endif
684 elseif cur_hasfield && !prev_hasfield && !prev_special
685 " less indent below a continuation line
686 let extra = -s:ShiftWidth()
687 endif
688 endif
689 endif
690
691 if below_end_brace
692 " find matching {, if that line starts with @ it's not the start of a rule
693 " but something else from a template system
694 call cursor(prev_lnum, 1)
695 call search('}\s*$')
696 try
697 normal! %
698 " Found the matching "{", align with it.
699 let align_lnum = s:CssFirstUnfinished(line('.'), min_lnum)
700 let special = getline(align_lnum) =~ '^\s*@'
701 catch
702 let special = 0
703 endtry
704 if special
705 " do not reduce indent below @{ ... }
706 if extra < 0
707 let extra += s:ShiftWidth()
708 endif
709 else
710 let extra -= (brace_counts.c_close - (prev_text =~ '^\s*}')) * s:ShiftWidth()
711 endif
712 endif
713
714 " if no extra indent yet...
715 if extra == 0
716 if brace_counts.p_open > brace_counts.p_close
717 " previous line has more ( than ): add a shiftwidth
718 let extra = s:ShiftWidth()
719 elseif brace_counts.p_open < brace_counts.p_close
720 " previous line has more ) than (: subtract a shiftwidth
721 let extra = -s:ShiftWidth()
722 endif
723 endif
724
725 return indent(align_lnum) + extra
726endfunc "}}}
727
728" Inside <style>: Whether a line is unfinished.
729func! s:CssUnfinished(text)
730 "{{{
731 return a:text =~ '\s\(||\|&&\|:\)\s*$'
732endfunc "}}}
733
734" Search back for the first unfinished line above "lnum".
735func! s:CssFirstUnfinished(lnum, min_lnum)
736 "{{{
737 let align_lnum = a:lnum
738 while align_lnum > a:min_lnum && s:CssUnfinished(getline(align_lnum - 1))
739 let align_lnum -= 1
740 endwhile
741 return align_lnum
742endfunc "}}}
743
744" Find the non-empty line at or before "lnum" that is not a comment.
745func! s:CssPrevNonComment(lnum, stopline)
746 "{{{
747 " caller starts from a line a:lnum + 1 that is not a comment
748 let lnum = prevnonblank(a:lnum)
749 while 1
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200750 let ccol = match(getline(lnum), '\*/')
751 if ccol < 0
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200752 " No comment end thus its something else.
753 return lnum
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200754 endif
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200755 call cursor(lnum, ccol + 1)
756 " Search back for the /* that starts the comment
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200757 let lnum = search('/\*', 'bW', a:stopline)
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200758 if indent(".") == virtcol(".") - 1
759 " The found /* is at the start of the line. Now go back to the line
760 " above it and again check if it is a comment.
761 let lnum = prevnonblank(lnum - 1)
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200762 else
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200763 " /* is after something else, thus it's not a comment line.
764 return lnum
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200765 endif
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200766 endwhile
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200767endfunc "}}}
768
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200769" Check the number of {} and () in line "lnum". Return a dict with the counts.
770func! HtmlIndent_CountBraces(lnum)
771 "{{{
772 let brs = substitute(getline(a:lnum), '[''"].\{-}[''"]\|/\*.\{-}\*/\|/\*.*$\|[^{}()]', '', 'g')
773 let c_open = 0
774 let c_close = 0
775 let p_open = 0
776 let p_close = 0
777 for brace in split(brs, '\zs')
778 if brace == "{"
779 let c_open += 1
780 elseif brace == "}"
781 if c_open > 0
782 let c_open -= 1
783 else
784 let c_close += 1
785 endif
786 elseif brace == '('
787 let p_open += 1
788 elseif brace == ')'
789 if p_open > 0
790 let p_open -= 1
791 else
792 let p_close += 1
793 endif
794 endif
795 endfor
796 return {'c_open': c_open,
797 \ 'c_close': c_close,
798 \ 'p_open': p_open,
799 \ 'p_close': p_close}
800endfunc "}}}
801
802" Return the indent for a comment: <!-- -->
803func! s:Alien5()
804 "{{{
805 let curtext = getline(v:lnum)
806 if curtext =~ '^\s*\zs-->'
807 " current line starts with end of comment, line up with comment start.
808 call cursor(v:lnum, 0)
809 let lnum = search('<!--', 'b')
810 if lnum > 0
811 " TODO: what if <!-- is not at the start of the line?
812 return indent(lnum)
813 endif
814
815 " Strange, can't find it.
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200816 return -1
Bram Moolenaar946e27a2014-06-25 18:50:27 +0200817 endif
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200818
819 let prevlnum = prevnonblank(v:lnum - 1)
820 let prevtext = getline(prevlnum)
821 let idx = match(prevtext, '^\s*\zs<!--')
822 if idx >= 0
823 " just below comment start, add a shiftwidth
824 return idx + s:ShiftWidth()
825 endif
826
827 " Some files add 4 spaces just below a TODO line. It's difficult to detect
828 " the end of the TODO, so let's not do that.
829
830 " Align with the previous non-blank line.
831 return indent(prevlnum)
Bram Moolenaar946e27a2014-06-25 18:50:27 +0200832endfunc "}}}
833
Bram Moolenaarca635012015-09-25 20:34:21 +0200834" Return the indent for conditional comment: <!--[ ![endif]-->
835func! s:Alien6()
836 "{{{
837 let curtext = getline(v:lnum)
838 if curtext =~ '\s*\zs<!\[endif\]-->'
839 " current line starts with end of comment, line up with comment start.
840 let lnum = search('<!--', 'bn')
841 if lnum > 0
842 return indent(lnum)
843 endif
844 endif
845 return b:hi_indent.baseindent + s:ShiftWidth()
846endfunc "}}}
847
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200848" When the "lnum" line ends in ">" find the line containing the matching "<".
849func! HtmlIndent_FindTagStart(lnum)
850 "{{{
851 " Avoids using the indent of a continuation line.
852 " Moves the cursor.
853 " Return two values:
854 " - the matching line number or "lnum".
855 " - a flag indicating whether we found the end of a tag.
856 " This method is global so that HTML-like indenters can use it.
857 " To avoid matching " > " or " < " inside a string require that the opening
858 " "<" is followed by a word character and the closing ">" comes after a
859 " non-white character.
860 let idx = match(getline(a:lnum), '\S>\s*$')
861 if idx > 0
862 call cursor(a:lnum, idx)
863 let lnum = searchpair('<\w', '' , '\S>', 'bW', '', max([a:lnum - b:html_indent_line_limit, 0]))
864 if lnum > 0
865 return [lnum, 1]
Bram Moolenaar071d4272004-06-13 20:20:40 +0000866 endif
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200867 endif
868 return [a:lnum, 0]
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200869endfunc "}}}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000870
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200871" Find the unclosed start tag from the current cursor position.
872func! HtmlIndent_FindStartTag()
873 "{{{
874 " The cursor must be on or before a closing tag.
875 " If found, positions the cursor at the match and returns the line number.
876 " Otherwise returns 0.
877 let tagname = matchstr(getline('.')[col('.') - 1:], '</\zs\w\+\ze')
878 let start_lnum = searchpair('<' . tagname . '\>', '', '</' . tagname . '\>', 'bW')
879 if start_lnum > 0
880 return start_lnum
881 endif
882 return 0
883endfunc "}}}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000884
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200885" Moves the cursor from a "<" to the matching ">".
886func! HtmlIndent_FindTagEnd()
887 "{{{
888 " Call this with the cursor on the "<" of a start tag.
889 " This will move the cursor to the ">" of the matching end tag or, when it's
890 " a self-closing tag, to the matching ">".
891 " Limited to look up to b:html_indent_line_limit lines away.
892 let text = getline('.')
893 let tagname = matchstr(text, '\w\+\|!--', col('.'))
894 if tagname == '!--'
895 call search('--\zs>')
896 elseif s:get_tag('/' . tagname) != 0
897 " tag with a closing tag, find matching "</tag>"
898 call searchpair('<' . tagname, '', '</' . tagname . '\zs>', 'W', '', line('.') + b:html_indent_line_limit)
899 else
900 " self-closing tag, find the ">"
901 call search('\S\zs>')
902 endif
903endfunc "}}}
Bram Moolenaarec7944a2013-06-12 21:29:15 +0200904
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200905" Indenting inside a start tag. Return the correct indent or -1 if unknown.
906func! s:InsideTag(foundHtmlString)
907 "{{{
908 if a:foundHtmlString
909 " Inside an attribute string.
910 " Align with the previous line or use an external function.
911 let lnum = v:lnum - 1
912 if lnum > 1
913 if exists('b:html_indent_tag_string_func')
914 return b:html_indent_tag_string_func(lnum)
915 endif
916 return indent(lnum)
917 endif
918 endif
919
920 " Should be another attribute: " attr="val". Align with the previous
921 " attribute start.
922 let lnum = v:lnum
923 while lnum > 1
924 let lnum -= 1
925 let text = getline(lnum)
926 " Find a match with one of these, align with "attr":
927 " attr=
928 " <tag attr=
929 " text<tag attr=
930 " <tag>text</tag>text<tag attr=
931 " For long lines search for the first match, finding the last match
932 " gets very slow.
933 if len(text) < 300
934 let idx = match(text, '.*\s\zs[_a-zA-Z0-9-]\+="')
935 else
936 let idx = match(text, '\s\zs[_a-zA-Z0-9-]\+="')
937 endif
938 if idx > 0
939 " Found the attribute. TODO: assumes spaces, no Tabs.
940 return idx
941 endif
942 endwhile
943 return -1
944endfunc "}}}
945
946" THE MAIN INDENT FUNCTION. Return the amount of indent for v:lnum.
947func! HtmlIndent()
948 "{{{
Bram Moolenaar9da7ff72015-01-14 12:52:36 +0100949 if prevnonblank(v:lnum - 1) < 1
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200950 " First non-blank line has no indent.
951 return 0
952 endif
953
954 let curtext = tolower(getline(v:lnum))
955 let indentunit = s:ShiftWidth()
956
957 let b:hi_newstate = {}
958 let b:hi_newstate.lnum = v:lnum
959
960 " When syntax HL is enabled, detect we are inside a tag. Indenting inside
961 " a tag works very differently. Do not do this when the line starts with
962 " "<", it gets the "htmlTag" ID but we are not inside a tag then.
963 if curtext !~ '^\s*<'
Bram Moolenaar7b61a542014-08-23 15:31:19 +0200964 normal! ^
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +0200965 let stack = synstack(v:lnum, col('.')) " assumes there are no tabs
966 let foundHtmlString = 0
967 for synid in reverse(stack)
968 let name = synIDattr(synid, "name")
969 if index(b:hi_insideStringNames, name) >= 0
970 let foundHtmlString = 1
971 elseif index(b:hi_insideTagNames, name) >= 0
972 " Yes, we are inside a tag.
973 let indent = s:InsideTag(foundHtmlString)
974 if indent >= 0
975 " Do not keep the state. TODO: could keep the block type.
976 let b:hi_indent.lnum = 0
977 return indent
978 endif
979 endif
980 endfor
981 endif
982
983 " does the line start with a closing tag?
984 let swendtag = match(curtext, '^\s*</') >= 0
985
986 if prevnonblank(v:lnum - 1) == b:hi_indent.lnum && b:hi_lasttick == b:changedtick - 1
987 " use state (continue from previous line)
988 else
989 " start over (know nothing)
990 let b:hi_indent = s:FreshState(v:lnum)
991 endif
992
993 if b:hi_indent.block >= 2
994 " within block
995 let endtag = s:endtags[b:hi_indent.block]
996 let blockend = stridx(curtext, endtag)
997 if blockend >= 0
998 " block ends here
999 let b:hi_newstate.block = 0
1000 " calc indent for REST OF LINE (may start more blocks):
1001 call s:CountTagsAndState(strpart(curtext, blockend + strlen(endtag)))
1002 if swendtag && b:hi_indent.block != 5
1003 let indent = b:hi_indent.blocktagind + s:curind * indentunit
1004 let b:hi_newstate.baseindent = indent + s:nextrel * indentunit
1005 else
1006 let indent = s:Alien{b:hi_indent.block}()
1007 let b:hi_newstate.baseindent = b:hi_indent.blocktagind + s:nextrel * indentunit
1008 endif
1009 else
1010 " block continues
1011 " indent this line with alien method
1012 let indent = s:Alien{b:hi_indent.block}()
1013 endif
1014 else
1015 " not within a block - within usual html
1016 let b:hi_newstate.block = b:hi_indent.block
1017 if swendtag
1018 " The current line starts with an end tag, align with its start tag.
1019 call cursor(v:lnum, 1)
1020 let start_lnum = HtmlIndent_FindStartTag()
1021 if start_lnum > 0
1022 " check for the line starting with something inside a tag:
1023 " <sometag <- align here
1024 " attr=val><open> not here
1025 let text = getline(start_lnum)
1026 let angle = matchstr(text, '[<>]')
1027 if angle == '>'
1028 call cursor(start_lnum, 1)
1029 normal! f>%
1030 let start_lnum = line('.')
1031 let text = getline(start_lnum)
1032 endif
1033
1034 let indent = indent(start_lnum)
1035 if col('.') > 2
1036 let swendtag = match(text, '^\s*</') >= 0
1037 call s:CountITags(text[: col('.') - 2])
1038 let indent += s:nextrel * s:ShiftWidth()
1039 if !swendtag
1040 let indent += s:curind * s:ShiftWidth()
1041 endif
1042 endif
1043 else
1044 " not sure what to do
1045 let indent = b:hi_indent.baseindent
1046 endif
1047 let b:hi_newstate.baseindent = indent
1048 else
1049 call s:CountTagsAndState(curtext)
1050 let indent = b:hi_indent.baseindent
1051 let b:hi_newstate.baseindent = indent + (s:curind + s:nextrel) * indentunit
1052 endif
1053 endif
1054
1055 let b:hi_lasttick = b:changedtick
1056 call extend(b:hi_indent, b:hi_newstate, "force")
1057 return indent
1058endfunc "}}}
1059
1060" Check user settings when loading this script the first time.
Bram Moolenaarec7944a2013-06-12 21:29:15 +02001061call HtmlIndent_CheckUserSettings()
Bram Moolenaar071d4272004-06-13 20:20:40 +00001062
Bram Moolenaar91170f82006-05-05 21:15:17 +00001063let &cpo = s:cpo_save
1064unlet s:cpo_save
1065
Bram Moolenaar8bb1c3e2014-07-04 16:43:17 +02001066" vim: fdm=marker ts=8 sw=2 tw=78