| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | " Vim indent script for HTML | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Header: "{{{ | 
					
						
							|  |  |  | " Maintainer:	Bram Moolenaar | 
					
						
							|  |  |  | " Original Author: Andy Wokula <anwoku@yahoo.de> | 
					
						
							| 
									
										
										
										
											2019-03-24 15:09:13 +01:00
										 |  |  | " Last Change:	2019 Mar 20 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Version:	1.0 | 
					
						
							|  |  |  | " Description:	HTML indent script with cached state for faster indenting on a | 
					
						
							|  |  |  | "		range of lines. | 
					
						
							|  |  |  | "		Supports template systems through hooks. | 
					
						
							|  |  |  | "		Supports Closure stylesheets. | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | " | 
					
						
							|  |  |  | " Credits: | 
					
						
							|  |  |  | "	indent/html.vim (2006 Jun 05) from J. Zellner | 
					
						
							|  |  |  | "	indent/css.vim (2006 Dec 20) from N. Weibull | 
					
						
							|  |  |  | " | 
					
						
							|  |  |  | " History: | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " 2014 June	(v1.0) overhaul (Bram) | 
					
						
							| 
									
										
										
										
											2013-06-15 21:39:51 +02:00
										 |  |  | " 2012 Oct 21	(v0.9) added support for shiftwidth() | 
					
						
							|  |  |  | " 2011 Sep 09	(v0.8) added HTML5 tags (thx to J. Zuckerman) | 
					
						
							|  |  |  | " 2008 Apr 28	(v0.6) revised customization | 
					
						
							|  |  |  | " 2008 Mar 09	(v0.5) fixed 'indk' issue (thx to C.J. Robinson) | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | "}}} | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Init Folklore, check user settings (2nd time ++) | 
					
						
							|  |  |  | if exists("b:did_indent") "{{{ | 
					
						
							|  |  |  |   finish | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | endif | 
					
						
							| 
									
										
										
										
											2017-01-28 18:34:47 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | " Load the Javascript indent script first, it defines GetJavascriptIndent(). | 
					
						
							|  |  |  | " Undo the rest. | 
					
						
							|  |  |  | " Load base python indent. | 
					
						
							|  |  |  | if !exists('*GetJavascriptIndent') | 
					
						
							|  |  |  |   runtime! indent/javascript.vim | 
					
						
							|  |  |  | endif | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | let b:did_indent = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | setlocal indentexpr=HtmlIndent() | 
					
						
							|  |  |  | setlocal indentkeys=o,O,<Return>,<>>,{,},!^F | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Needed for % to work when finding start/end of a tag. | 
					
						
							| 
									
										
										
										
											2014-06-25 18:50:27 +02:00
										 |  |  | setlocal matchpairs+=<:> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-28 18:34:47 +01:00
										 |  |  | let b:undo_indent = "setlocal inde< indk<" | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | " b:hi_indent keeps state to speed up indenting consecutive lines. | 
					
						
							|  |  |  | let b:hi_indent = {"lnum": -1} | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | """""" Code below this is loaded only once. """"" | 
					
						
							|  |  |  | if exists("*HtmlIndent") && !exists('g:force_reload_html') | 
					
						
							|  |  |  |   call HtmlIndent_CheckUserSettings() | 
					
						
							|  |  |  |   finish | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | endif | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Allow for line continuation below. | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | let s:cpo_save = &cpo | 
					
						
							|  |  |  | set cpo-=C | 
					
						
							|  |  |  | "}}} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-09 22:22:21 +01:00
										 |  |  | " Pattern to match the name of a tag, including custom elements. | 
					
						
							|  |  |  | let s:tagname = '\w\+\(-\w\+\)*' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Check and process settings from b:html_indent and g:html_indent... variables. | 
					
						
							|  |  |  | " Prefer using buffer-local settings over global settings, so that there can | 
					
						
							|  |  |  | " be defaults for all HTML files and exceptions for specific types of HTML | 
					
						
							|  |  |  | " files. | 
					
						
							|  |  |  | func! HtmlIndent_CheckUserSettings() | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   let inctags = '' | 
					
						
							|  |  |  |   if exists("b:html_indent_inctags") | 
					
						
							|  |  |  |     let inctags = b:html_indent_inctags | 
					
						
							|  |  |  |   elseif exists("g:html_indent_inctags") | 
					
						
							|  |  |  |     let inctags = g:html_indent_inctags | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   let b:hi_tags = {} | 
					
						
							|  |  |  |   if len(inctags) > 0 | 
					
						
							|  |  |  |     call s:AddITags(b:hi_tags, split(inctags, ",")) | 
					
						
							|  |  |  |   endif | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   let autotags = '' | 
					
						
							|  |  |  |   if exists("b:html_indent_autotags") | 
					
						
							|  |  |  |     let autotags = b:html_indent_autotags | 
					
						
							|  |  |  |   elseif exists("g:html_indent_autotags") | 
					
						
							|  |  |  |     let autotags = g:html_indent_autotags | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   let b:hi_removed_tags = {} | 
					
						
							| 
									
										
										
										
											2015-06-19 13:27:23 +02:00
										 |  |  |   if len(autotags) > 0 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     call s:RemoveITags(b:hi_removed_tags, split(autotags, ",")) | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " Syntax names indicating being inside a string of an attribute value. | 
					
						
							|  |  |  |   let string_names = [] | 
					
						
							|  |  |  |   if exists("b:html_indent_string_names") | 
					
						
							|  |  |  |     let string_names = b:html_indent_string_names | 
					
						
							|  |  |  |   elseif exists("g:html_indent_string_names") | 
					
						
							|  |  |  |     let string_names = g:html_indent_string_names | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   let b:hi_insideStringNames = ['htmlString'] | 
					
						
							|  |  |  |   if len(string_names) > 0 | 
					
						
							|  |  |  |     for s in string_names | 
					
						
							|  |  |  |       call add(b:hi_insideStringNames, s) | 
					
						
							|  |  |  |     endfor | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " Syntax names indicating being inside a tag. | 
					
						
							|  |  |  |   let tag_names = [] | 
					
						
							|  |  |  |   if exists("b:html_indent_tag_names") | 
					
						
							|  |  |  |     let tag_names = b:html_indent_tag_names | 
					
						
							|  |  |  |   elseif exists("g:html_indent_tag_names") | 
					
						
							|  |  |  |     let tag_names = g:html_indent_tag_names | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   let b:hi_insideTagNames = ['htmlTag', 'htmlScriptTag'] | 
					
						
							|  |  |  |   if len(tag_names) > 0 | 
					
						
							|  |  |  |     for s in tag_names | 
					
						
							|  |  |  |       call add(b:hi_insideTagNames, s) | 
					
						
							|  |  |  |     endfor | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   let indone = {"zero": 0 | 
					
						
							|  |  |  |               \,"auto": "indent(prevnonblank(v:lnum-1))" | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |               \,"inc": "b:hi_indent.blocktagind + shiftwidth()"} | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   let script1 = '' | 
					
						
							|  |  |  |   if exists("b:html_indent_script1") | 
					
						
							|  |  |  |     let script1 = b:html_indent_script1 | 
					
						
							|  |  |  |   elseif exists("g:html_indent_script1") | 
					
						
							|  |  |  |     let script1 = g:html_indent_script1 | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   if len(script1) > 0 | 
					
						
							|  |  |  |     let b:hi_js1indent = get(indone, script1, indone.zero) | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     let b:hi_js1indent = 0 | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   let style1 = '' | 
					
						
							|  |  |  |   if exists("b:html_indent_style1") | 
					
						
							|  |  |  |     let style1 = b:html_indent_style1 | 
					
						
							|  |  |  |   elseif exists("g:html_indent_style1") | 
					
						
							|  |  |  |     let style1 = g:html_indent_style1 | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   if len(style1) > 0 | 
					
						
							|  |  |  |     let b:hi_css1indent = get(indone, style1, indone.zero) | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     let b:hi_css1indent = 0 | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if !exists('b:html_indent_line_limit') | 
					
						
							|  |  |  |     if exists('g:html_indent_line_limit') | 
					
						
							|  |  |  |       let b:html_indent_line_limit = g:html_indent_line_limit | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       let b:html_indent_line_limit = 200 | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     endif | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   endif | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | endfunc "}}} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Init Script Vars | 
					
						
							|  |  |  | "{{{ | 
					
						
							|  |  |  | let b:hi_lasttick = 0 | 
					
						
							|  |  |  | let b:hi_newstate = {} | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | let s:countonly = 0 | 
					
						
							|  |  |  |  "}}} | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | " Fill the s:indent_tags dict with known tags. | 
					
						
							|  |  |  | " The key is "tagname" or "/tagname".  {{{ | 
					
						
							|  |  |  | " The value is: | 
					
						
							|  |  |  | " 1   opening tag | 
					
						
							|  |  |  | " 2   "pre" | 
					
						
							|  |  |  | " 3   "script" | 
					
						
							|  |  |  | " 4   "style" | 
					
						
							|  |  |  | " 5   comment start | 
					
						
							| 
									
										
										
										
											2015-09-25 20:34:21 +02:00
										 |  |  | " 6   conditional comment start | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " -1  closing tag | 
					
						
							|  |  |  | " -2  "/pre" | 
					
						
							|  |  |  | " -3  "/script" | 
					
						
							|  |  |  | " -4  "/style" | 
					
						
							|  |  |  | " -5  comment end | 
					
						
							| 
									
										
										
										
											2015-09-25 20:34:21 +02:00
										 |  |  | " -6  conditional comment end | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | let s:indent_tags = {} | 
					
						
							| 
									
										
										
										
											2015-09-25 20:34:21 +02:00
										 |  |  | let s:endtags = [0,0,0,0,0,0,0]   " long enough for the highest index | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | "}}} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | " Add a list of tag names for a pair of <tag> </tag> to "tags". | 
					
						
							|  |  |  | func! s:AddITags(tags, taglist) | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   for itag in a:taglist | 
					
						
							|  |  |  |     let a:tags[itag] = 1 | 
					
						
							|  |  |  |     let a:tags['/' . itag] = -1 | 
					
						
							|  |  |  |   endfor | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | endfunc "}}} | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | " Take a list of tag name pairs that are not to be used as tag pairs. | 
					
						
							|  |  |  | func! s:RemoveITags(tags, taglist) | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   for itag in a:taglist | 
					
						
							|  |  |  |     let a:tags[itag] = 1 | 
					
						
							|  |  |  |     let a:tags['/' . itag] = 1 | 
					
						
							|  |  |  |   endfor | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | endfunc "}}} | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | " Add a block tag, that is a tag with a different kind of indenting. | 
					
						
							|  |  |  | func! s:AddBlockTag(tag, id, ...) | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   if !(a:id >= 2 && a:id < len(s:endtags)) | 
					
						
							|  |  |  |     echoerr 'AddBlockTag ' . a:id | 
					
						
							|  |  |  |     return | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   let s:indent_tags[a:tag] = a:id | 
					
						
							|  |  |  |   if a:0 == 0 | 
					
						
							|  |  |  |     let s:indent_tags['/' . a:tag] = -a:id | 
					
						
							|  |  |  |     let s:endtags[a:id] = "</" . a:tag . ">" | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     let s:indent_tags[a:1] = -a:id | 
					
						
							|  |  |  |     let s:endtags[a:id] = a:1 | 
					
						
							|  |  |  |   endif | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | endfunc "}}} | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Add known tag pairs. | 
					
						
							|  |  |  | " Self-closing tags and tags that are sometimes {{{ | 
					
						
							|  |  |  | " self-closing (e.g., <p>) are not here (when encountering </p> we can find | 
					
						
							| 
									
										
										
										
											2018-12-09 20:43:55 +01:00
										 |  |  | " the matching <p>, but not the other way around). | 
					
						
							|  |  |  | " Known self-closing tags: " 'p', 'img', 'source', 'area', 'keygen', 'track', | 
					
						
							|  |  |  | " 'wbr'. | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Old HTML tags: | 
					
						
							|  |  |  | call s:AddITags(s:indent_tags, [ | 
					
						
							|  |  |  |     \ 'a', 'abbr', 'acronym', 'address', 'b', 'bdo', 'big', | 
					
						
							|  |  |  |     \ 'blockquote', 'body', 'button', 'caption', 'center', 'cite', 'code', | 
					
						
							|  |  |  |     \ 'colgroup', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', | 
					
						
							|  |  |  |     \ 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'html', | 
					
						
							|  |  |  |     \ 'i', 'iframe', 'ins', 'kbd', 'label', 'legend', 'li', | 
					
						
							|  |  |  |     \ 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     \ 'optgroup', 'q', 's', 'samp', 'select', 'small', 'span', 'strong', 'sub', | 
					
						
							|  |  |  |     \ 'sup', 'table', 'textarea', 'title', 'tt', 'u', 'ul', 'var', 'th', 'td', | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     \ 'tr', 'tbody', 'tfoot', 'thead']) | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-10 01:31:25 +02:00
										 |  |  | " New HTML5 elements: | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | call s:AddITags(s:indent_tags, [ | 
					
						
							| 
									
										
										
										
											2018-12-09 20:43:55 +01:00
										 |  |  |     \ 'article', 'aside', 'audio', 'bdi', 'canvas', 'command', 'data', | 
					
						
							|  |  |  |     \ 'datalist', 'details', 'dialog', 'embed', 'figcaption', 'figure', | 
					
						
							|  |  |  |     \ 'footer', 'header', 'hgroup', 'main', 'mark', 'meter', 'nav', 'output', | 
					
						
							|  |  |  |     \ 'picture', 'progress', 'rp', 'rt', 'ruby', 'section', 'summary', | 
					
						
							|  |  |  |     \ 'svg', 'time', 'video']) | 
					
						
							| 
									
										
										
										
											2015-03-05 21:21:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | " Tags added for web components: | 
					
						
							|  |  |  | call s:AddITags(s:indent_tags, [ | 
					
						
							|  |  |  |     \ 'content', 'shadow', 'template']) | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | "}}} | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | " Add Block Tags: these contain alien content | 
					
						
							|  |  |  | "{{{ | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | call s:AddBlockTag('pre', 2) | 
					
						
							|  |  |  | call s:AddBlockTag('script', 3) | 
					
						
							|  |  |  | call s:AddBlockTag('style', 4) | 
					
						
							|  |  |  | call s:AddBlockTag('<!--', 5, '-->') | 
					
						
							| 
									
										
										
										
											2015-09-25 20:34:21 +02:00
										 |  |  | call s:AddBlockTag('<!--[', 6, '![endif]-->') | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | "}}} | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Return non-zero when "tagname" is an opening tag, not being a block tag, for | 
					
						
							|  |  |  | " which there should be a closing tag.  Can be used by scripts that include | 
					
						
							|  |  |  | " HTML indenting. | 
					
						
							|  |  |  | func! HtmlIndent_IsOpenTag(tagname) | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   if get(s:indent_tags, a:tagname) == 1 | 
					
						
							|  |  |  |     return 1 | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   return get(b:hi_tags, a:tagname) == 1 | 
					
						
							|  |  |  | endfunc "}}} | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Get the value for "tagname", taking care of buffer-local tags. | 
					
						
							|  |  |  | func! s:get_tag(tagname) | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   let i = get(s:indent_tags, a:tagname) | 
					
						
							|  |  |  |   if (i == 1 || i == -1) && get(b:hi_removed_tags, a:tagname) != 0 | 
					
						
							|  |  |  |     return 0 | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   if i == 0 | 
					
						
							|  |  |  |     let i = get(b:hi_tags, a:tagname) | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   return i | 
					
						
							|  |  |  | endfunc "}}} | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Count the number of start and end tags in "text". | 
					
						
							|  |  |  | func! s:CountITags(text) | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   " Store the result in s:curind and s:nextrel. | 
					
						
							|  |  |  |   let s:curind = 0  " relative indent steps for current line [unit &sw]: | 
					
						
							|  |  |  |   let s:nextrel = 0  " relative indent steps for next line [unit &sw]: | 
					
						
							|  |  |  |   let s:block = 0		" assume starting outside of a block | 
					
						
							|  |  |  |   let s:countonly = 1	" don't change state | 
					
						
							| 
									
										
										
										
											2018-03-09 22:22:21 +01:00
										 |  |  |   call substitute(a:text, '<\zs/\=' . s:tagname . '\>\|<!--\[\|\[endif\]-->\|<!--\|-->', '\=s:CheckTag(submatch(0))', 'g') | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   let s:countonly = 0 | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | endfunc "}}} | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | " Count the number of start and end tags in text. | 
					
						
							|  |  |  | func! s:CountTagsAndState(text) | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   " Store the result in s:curind and s:nextrel.  Update b:hi_newstate.block. | 
					
						
							|  |  |  |   let s:curind = 0  " relative indent steps for current line [unit &sw]: | 
					
						
							|  |  |  |   let s:nextrel = 0  " relative indent steps for next line [unit &sw]: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   let s:block = b:hi_newstate.block | 
					
						
							| 
									
										
										
										
											2018-03-09 22:22:21 +01:00
										 |  |  |   let tmp = substitute(a:text, '<\zs/\=' . s:tagname . '\>\|<!--\[\|\[endif\]-->\|<!--\|-->', '\=s:CheckTag(submatch(0))', 'g') | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   if s:block == 3 | 
					
						
							|  |  |  |     let b:hi_newstate.scripttype = s:GetScriptType(matchstr(tmp, '\C.*<SCRIPT\>\zs[^>]*')) | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   let b:hi_newstate.block = s:block | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | endfunc "}}} | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | " Used by s:CountITags() and s:CountTagsAndState(). | 
					
						
							|  |  |  | func! s:CheckTag(itag) | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   " Returns an empty string or "SCRIPT". | 
					
						
							|  |  |  |   " a:itag can be "tag" or "/tag" or "<!--" or "-->" | 
					
						
							| 
									
										
										
										
											2015-03-05 21:21:19 +01:00
										 |  |  |   if (s:CheckCustomTag(a:itag)) | 
					
						
							|  |  |  |     return "" | 
					
						
							|  |  |  |   endif | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   let ind = s:get_tag(a:itag) | 
					
						
							|  |  |  |   if ind == -1 | 
					
						
							|  |  |  |     " closing tag | 
					
						
							|  |  |  |     if s:block != 0 | 
					
						
							|  |  |  |       " ignore itag within a block | 
					
						
							|  |  |  |       return "" | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     endif | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     if s:nextrel == 0 | 
					
						
							|  |  |  |       let s:curind -= 1 | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |       let s:nextrel -= 1 | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |   elseif ind == 1 | 
					
						
							|  |  |  |     " opening tag | 
					
						
							|  |  |  |     if s:block != 0 | 
					
						
							|  |  |  |       return "" | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     endif | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     let s:nextrel += 1 | 
					
						
							|  |  |  |   elseif ind != 0 | 
					
						
							|  |  |  |     " block-tag (opening or closing) | 
					
						
							|  |  |  |     return s:CheckBlockTag(a:itag, ind) | 
					
						
							|  |  |  |   " else ind==0 (other tag found): keep indent | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   return "" | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | endfunc "}}} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Used by s:CheckTag(). Returns an empty string or "SCRIPT". | 
					
						
							|  |  |  | func! s:CheckBlockTag(blocktag, ind) | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   if a:ind > 0 | 
					
						
							|  |  |  |     " a block starts here | 
					
						
							|  |  |  |     if s:block != 0 | 
					
						
							|  |  |  |       " already in a block (nesting) - ignore | 
					
						
							|  |  |  |       " especially ignore comments after other blocktags | 
					
						
							|  |  |  |       return "" | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |     let s:block = a:ind		" block type | 
					
						
							|  |  |  |     if s:countonly | 
					
						
							|  |  |  |       return "" | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |     let b:hi_newstate.blocklnr = v:lnum | 
					
						
							|  |  |  |     " save allover indent for the endtag | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |     let b:hi_newstate.blocktagind = b:hi_indent.baseindent + (s:nextrel + s:curind) * shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     if a:ind == 3 | 
					
						
							|  |  |  |       return "SCRIPT"    " all except this must be lowercase | 
					
						
							|  |  |  |       " line is to be checked again for the type attribute | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  |     endif | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   else | 
					
						
							|  |  |  |     let s:block = 0 | 
					
						
							|  |  |  |     " we get here if starting and closing a block-tag on the same line | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   return "" | 
					
						
							|  |  |  | endfunc "}}} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-05 21:21:19 +01:00
										 |  |  | " Used by s:CheckTag(). | 
					
						
							|  |  |  | func! s:CheckCustomTag(ctag) | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   " Returns 1 if ctag is the tag for a custom element, 0 otherwise. | 
					
						
							|  |  |  |   " a:ctag can be "tag" or "/tag" or "<!--" or "-->" | 
					
						
							|  |  |  |   let pattern = '\%\(\w\+-\)\+\w\+' | 
					
						
							|  |  |  |   if match(a:ctag, pattern) == -1 | 
					
						
							|  |  |  |     return 0 | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   if matchstr(a:ctag, '\/\ze.\+') == "/" | 
					
						
							|  |  |  |     " closing tag | 
					
						
							|  |  |  |     if s:block != 0 | 
					
						
							|  |  |  |       " ignore ctag within a block | 
					
						
							|  |  |  |       return 1 | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |     if s:nextrel == 0 | 
					
						
							|  |  |  |       let s:curind -= 1 | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       let s:nextrel -= 1 | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     " opening tag | 
					
						
							|  |  |  |     if s:block != 0 | 
					
						
							|  |  |  |       return 1 | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |     let s:nextrel += 1 | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   return 1 | 
					
						
							|  |  |  | endfunc "}}} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Return the <script> type: either "javascript" or "" | 
					
						
							|  |  |  | func! s:GetScriptType(str) | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   if a:str == "" || a:str =~ "java" | 
					
						
							|  |  |  |     return "javascript" | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     return "" | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | endfunc "}}} | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Look back in the file, starting at a:lnum - 1, to compute a state for the | 
					
						
							|  |  |  | " start of line a:lnum.  Return the new state. | 
					
						
							|  |  |  | func! s:FreshState(lnum) | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   " A state is to know ALL relevant details about the | 
					
						
							|  |  |  |   " lines 1..a:lnum-1, initial calculating (here!) can be slow, but updating is | 
					
						
							|  |  |  |   " fast (incremental). | 
					
						
							|  |  |  |   " TODO: this should be split up in detecting the block type and computing the | 
					
						
							|  |  |  |   " indent for the block type, so that when we do not know the indent we do | 
					
						
							|  |  |  |   " not need to clear the whole state and re-detect the block type again. | 
					
						
							|  |  |  |   " State: | 
					
						
							|  |  |  |   "	lnum		last indented line == prevnonblank(a:lnum - 1) | 
					
						
							|  |  |  |   "	block = 0	a:lnum located within special tag: 0:none, 2:<pre>, | 
					
						
							| 
									
										
										
										
											2015-09-25 20:34:21 +02:00
										 |  |  |   "			3:<script>, 4:<style>, 5:<!--, 6:<!--[ | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   "	baseindent	use this indent for line a:lnum as a start - kind of | 
					
						
							|  |  |  |   "			autoindent (if block==0) | 
					
						
							|  |  |  |   "	scripttype = ''	type attribute of a script tag (if block==3) | 
					
						
							|  |  |  |   "	blocktagind	indent for current opening (get) and closing (set) | 
					
						
							|  |  |  |   "			blocktag (if block!=0) | 
					
						
							|  |  |  |   "	blocklnr	lnum of starting blocktag (if block!=0) | 
					
						
							|  |  |  |   "	inattr		line {lnum} starts with attributes of a tag | 
					
						
							|  |  |  |   let state = {} | 
					
						
							|  |  |  |   let state.lnum = prevnonblank(a:lnum - 1) | 
					
						
							|  |  |  |   let state.scripttype = "" | 
					
						
							|  |  |  |   let state.blocktagind = -1 | 
					
						
							|  |  |  |   let state.block = 0 | 
					
						
							|  |  |  |   let state.baseindent = 0 | 
					
						
							|  |  |  |   let state.blocklnr = 0 | 
					
						
							|  |  |  |   let state.inattr = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if state.lnum == 0 | 
					
						
							|  |  |  |     return state | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " Heuristic: | 
					
						
							|  |  |  |   " remember startline state.lnum | 
					
						
							|  |  |  |   " look back for <pre, </pre, <script, </script, <style, </style tags | 
					
						
							|  |  |  |   " remember stopline | 
					
						
							|  |  |  |   " if opening tag found, | 
					
						
							|  |  |  |   "	assume a:lnum within block | 
					
						
							|  |  |  |   " else | 
					
						
							|  |  |  |   "	look back in result range (stopline, startline) for comment | 
					
						
							|  |  |  |   "	    \ delimiters (<!--, -->) | 
					
						
							|  |  |  |   "	if comment opener found, | 
					
						
							|  |  |  |   "	    assume a:lnum within comment | 
					
						
							|  |  |  |   "	else | 
					
						
							|  |  |  |   "	    assume usual html for a:lnum | 
					
						
							|  |  |  |   "	    if a:lnum-1 has a closing comment | 
					
						
							|  |  |  |   "		look back to get indent of comment opener | 
					
						
							|  |  |  |   " FI | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " look back for a blocktag | 
					
						
							| 
									
										
										
										
											2015-09-25 20:34:21 +02:00
										 |  |  |   let stopline2 = v:lnum + 1 | 
					
						
							|  |  |  |   if has_key(b:hi_indent, 'block') && b:hi_indent.block > 5 | 
					
						
							|  |  |  |     let [stopline2, stopcol2] = searchpos('<!--', 'bnW') | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   let [stopline, stopcol] = searchpos('\c<\zs\/\=\%(pre\>\|script\>\|style\>\)', "bnW") | 
					
						
							|  |  |  |   if stopline > 0 && stopline < stopline2 | 
					
						
							|  |  |  |     " ugly ... why isn't there searchstr() | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     let tagline = tolower(getline(stopline)) | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     let blocktag = matchstr(tagline, '\/\=\%(pre\>\|script\>\|style\>\)', stopcol - 1) | 
					
						
							|  |  |  |     if blocktag[0] != "/" | 
					
						
							|  |  |  |       " opening tag found, assume a:lnum within block | 
					
						
							|  |  |  |       let state.block = s:indent_tags[blocktag] | 
					
						
							|  |  |  |       if state.block == 3 | 
					
						
							|  |  |  |         let state.scripttype = s:GetScriptType(matchstr(tagline, '\>[^>]*', stopcol)) | 
					
						
							|  |  |  |       endif | 
					
						
							|  |  |  |       let state.blocklnr = stopline | 
					
						
							|  |  |  |       " check preceding tags in the line: | 
					
						
							|  |  |  |       call s:CountITags(tagline[: stopcol-2]) | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |       let state.blocktagind = indent(stopline) + (s:curind + s:nextrel) * shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |       return state | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     elseif stopline == state.lnum | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |       " handle special case: previous line (= state.lnum) contains a | 
					
						
							|  |  |  |       " closing blocktag which is preceded by line-noise; | 
					
						
							|  |  |  |       " blocktag == "/..." | 
					
						
							|  |  |  |       let swendtag = match(tagline, '^\s*</') >= 0 | 
					
						
							|  |  |  |       if !swendtag | 
					
						
							| 
									
										
										
										
											2015-09-25 20:34:21 +02:00
										 |  |  |         let [bline, bcol] = searchpos('<'.blocktag[1:].'\>', "bnW") | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |         call s:CountITags(tolower(getline(bline)[: bcol-2])) | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |         let state.baseindent = indent(bline) + (s:curind + s:nextrel) * shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |         return state | 
					
						
							|  |  |  |       endif | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  |     endif | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   endif | 
					
						
							| 
									
										
										
										
											2015-09-25 20:34:21 +02:00
										 |  |  |   if stopline > stopline2 | 
					
						
							|  |  |  |     let stopline = stopline2 | 
					
						
							|  |  |  |     let stopcol = stopcol2 | 
					
						
							|  |  |  |   endif | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   " else look back for comment | 
					
						
							| 
									
										
										
										
											2015-09-25 20:34:21 +02:00
										 |  |  |   let [comlnum, comcol, found] = searchpos('\(<!--\[\)\|\(<!--\)\|-->', 'bpnW', stopline) | 
					
						
							|  |  |  |   if found == 2 || found == 3 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     " comment opener found, assume a:lnum within comment | 
					
						
							| 
									
										
										
										
											2015-09-25 20:34:21 +02:00
										 |  |  |     let state.block = (found == 3 ? 5 : 6) | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     let state.blocklnr = comlnum | 
					
						
							|  |  |  |     " check preceding tags in the line: | 
					
						
							|  |  |  |     call s:CountITags(tolower(getline(comlnum)[: comcol-2])) | 
					
						
							| 
									
										
										
										
											2015-09-25 20:34:21 +02:00
										 |  |  |     if found == 2 | 
					
						
							|  |  |  |       let state.baseindent = b:hi_indent.baseindent | 
					
						
							|  |  |  |     endif | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |     let state.blocktagind = indent(comlnum) + (s:curind + s:nextrel) * shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     return state | 
					
						
							|  |  |  |   endif | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   " else within usual HTML | 
					
						
							|  |  |  |   let text = tolower(getline(state.lnum)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " Check a:lnum-1 for closing comment (we need indent from the opening line). | 
					
						
							|  |  |  |   " Not when other tags follow (might be --> inside a string). | 
					
						
							|  |  |  |   let comcol = stridx(text, '-->') | 
					
						
							|  |  |  |   if comcol >= 0 && match(text, '[<>]', comcol) <= 0 | 
					
						
							|  |  |  |     call cursor(state.lnum, comcol + 1) | 
					
						
							|  |  |  |     let [comlnum, comcol] = searchpos('<!--', 'bW') | 
					
						
							|  |  |  |     if comlnum == state.lnum | 
					
						
							|  |  |  |       let text = text[: comcol-2] | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       let text = tolower(getline(comlnum)[: comcol-2]) | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     endif | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     call s:CountITags(text) | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |     let state.baseindent = indent(comlnum) + (s:curind + s:nextrel) * shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     " TODO check tags that follow "-->" | 
					
						
							|  |  |  |     return state | 
					
						
							|  |  |  |   endif | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   " Check if the previous line starts with end tag. | 
					
						
							|  |  |  |   let swendtag = match(text, '^\s*</') >= 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " If previous line ended in a closing tag, line up with the opening tag. | 
					
						
							| 
									
										
										
										
											2018-03-09 22:22:21 +01:00
										 |  |  |   if !swendtag && text =~ '</' . s:tagname . '\s*>\s*$' | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     call cursor(state.lnum, 99999) | 
					
						
							| 
									
										
										
										
											2014-08-23 15:31:19 +02:00
										 |  |  |     normal! F< | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     let start_lnum = HtmlIndent_FindStartTag() | 
					
						
							|  |  |  |     if start_lnum > 0 | 
					
						
							|  |  |  |       let state.baseindent = indent(start_lnum) | 
					
						
							|  |  |  |       if col('.') > 2 | 
					
						
							|  |  |  |         " check for tags before the matching opening tag. | 
					
						
							|  |  |  |         let text = getline(start_lnum) | 
					
						
							|  |  |  |         let swendtag = match(text, '^\s*</') >= 0 | 
					
						
							|  |  |  |         call s:CountITags(text[: col('.') - 2]) | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |         let state.baseindent += s:nextrel * shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |         if !swendtag | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |           let state.baseindent += s:curind * shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-06-25 18:50:27 +02:00
										 |  |  |         endif | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |       endif | 
					
						
							|  |  |  |       return state | 
					
						
							| 
									
										
										
										
											2014-06-25 18:50:27 +02:00
										 |  |  |     endif | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   endif | 
					
						
							| 
									
										
										
										
											2014-06-25 18:50:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   " Else: no comments. Skip backwards to find the tag we're inside. | 
					
						
							|  |  |  |   let [state.lnum, found] = HtmlIndent_FindTagStart(state.lnum) | 
					
						
							|  |  |  |   " Check if that line starts with end tag. | 
					
						
							|  |  |  |   let text = getline(state.lnum) | 
					
						
							|  |  |  |   let swendtag = match(text, '^\s*</') >= 0 | 
					
						
							|  |  |  |   call s:CountITags(tolower(text)) | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |   let state.baseindent = indent(state.lnum) + s:nextrel * shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   if !swendtag | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |     let state.baseindent += s:curind * shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   endif | 
					
						
							|  |  |  |   return state | 
					
						
							|  |  |  | endfunc "}}} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | " Indent inside a <pre> block: Keep indent as-is. | 
					
						
							|  |  |  | func! s:Alien2() | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   return -1 | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | endfunc "}}} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Return the indent inside a <script> block for javascript. | 
					
						
							|  |  |  | func! s:Alien3() | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   let lnum = prevnonblank(v:lnum - 1) | 
					
						
							|  |  |  |   while lnum > 1 && getline(lnum) =~ '^\s*/[/*]' | 
					
						
							|  |  |  |     " Skip over comments to avoid that cindent() aligns with the <script> tag | 
					
						
							|  |  |  |     let lnum = prevnonblank(lnum - 1) | 
					
						
							|  |  |  |   endwhile | 
					
						
							|  |  |  |   if lnum == b:hi_indent.blocklnr | 
					
						
							|  |  |  |     " indent for the first line after <script> | 
					
						
							|  |  |  |     return eval(b:hi_js1indent) | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   if b:hi_indent.scripttype == "javascript" | 
					
						
							| 
									
										
										
										
											2017-01-28 18:34:47 +01:00
										 |  |  |     return GetJavascriptIndent() | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   else | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     return -1 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   endif | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | endfunc "}}} | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | " Return the indent inside a <style> block. | 
					
						
							|  |  |  | func! s:Alien4() | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   if prevnonblank(v:lnum-1) == b:hi_indent.blocklnr | 
					
						
							|  |  |  |     " indent for first content line | 
					
						
							|  |  |  |     return eval(b:hi_css1indent) | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   return s:CSSIndent() | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | endfunc "}}} | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Indending inside a <style> block.  Returns the indent. | 
					
						
							|  |  |  | func! s:CSSIndent() | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   " This handles standard CSS and also Closure stylesheets where special lines | 
					
						
							|  |  |  |   " start with @. | 
					
						
							|  |  |  |   " When the line starts with '*' or the previous line starts with "/*" | 
					
						
							|  |  |  |   " and does not end in "*/", use C indenting to format the comment. | 
					
						
							|  |  |  |   " Adopted $VIMRUNTIME/indent/css.vim | 
					
						
							|  |  |  |   let curtext = getline(v:lnum) | 
					
						
							|  |  |  |   if curtext =~ '^\s*[*]' | 
					
						
							|  |  |  |         \ || (v:lnum > 1 && getline(v:lnum - 1) =~ '\s*/\*' | 
					
						
							|  |  |  |         \     && getline(v:lnum - 1) !~ '\*/\s*$') | 
					
						
							|  |  |  |     return cindent(v:lnum) | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   let min_lnum = b:hi_indent.blocklnr | 
					
						
							|  |  |  |   let prev_lnum = s:CssPrevNonComment(v:lnum - 1, min_lnum) | 
					
						
							|  |  |  |   let [prev_lnum, found] = HtmlIndent_FindTagStart(prev_lnum) | 
					
						
							|  |  |  |   if prev_lnum <= min_lnum | 
					
						
							|  |  |  |     " Just below the <style> tag, indent for first content line after comments. | 
					
						
							|  |  |  |     return eval(b:hi_css1indent) | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-04 14:45:49 +01:00
										 |  |  |   " If the current line starts with "}" align with its match. | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   if curtext =~ '^\s*}' | 
					
						
							|  |  |  |     call cursor(v:lnum, 1) | 
					
						
							|  |  |  |     try | 
					
						
							|  |  |  |       normal! % | 
					
						
							|  |  |  |       " Found the matching "{", align with it after skipping unfinished lines. | 
					
						
							|  |  |  |       let align_lnum = s:CssFirstUnfinished(line('.'), min_lnum) | 
					
						
							|  |  |  |       return indent(align_lnum) | 
					
						
							|  |  |  |     catch | 
					
						
							|  |  |  |       " can't find it, try something else, but it's most likely going to be | 
					
						
							|  |  |  |       " wrong | 
					
						
							|  |  |  |     endtry | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " add indent after { | 
					
						
							|  |  |  |   let brace_counts = HtmlIndent_CountBraces(prev_lnum) | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |   let extra = brace_counts.c_open * shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   let prev_text = getline(prev_lnum) | 
					
						
							|  |  |  |   let below_end_brace = prev_text =~ '}\s*$' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " Search back to align with the first line that's unfinished. | 
					
						
							|  |  |  |   let align_lnum = s:CssFirstUnfinished(prev_lnum, min_lnum) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " Handle continuation lines if aligning with previous line and not after a | 
					
						
							|  |  |  |   " "}". | 
					
						
							|  |  |  |   if extra == 0 && align_lnum == prev_lnum && !below_end_brace | 
					
						
							|  |  |  |     let prev_hasfield = prev_text =~ '^\s*[a-zA-Z0-9-]\+:' | 
					
						
							|  |  |  |     let prev_special = prev_text =~ '^\s*\(/\*\|@\)' | 
					
						
							|  |  |  |     if curtext =~ '^\s*\(/\*\|@\)' | 
					
						
							|  |  |  |       " if the current line is not a comment or starts with @ (used by template | 
					
						
							|  |  |  |       " systems) reduce indent if previous line is a continuation line | 
					
						
							|  |  |  |       if !prev_hasfield && !prev_special | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |         let extra = -shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |       endif | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       let cur_hasfield = curtext =~ '^\s*[a-zA-Z0-9-]\+:' | 
					
						
							|  |  |  |       let prev_unfinished = s:CssUnfinished(prev_text) | 
					
						
							| 
									
										
										
										
											2018-08-28 22:58:02 +02:00
										 |  |  |       if prev_unfinished | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |         " Continuation line has extra indent if the previous line was not a | 
					
						
							|  |  |  |         " continuation line. | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |         let extra = shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |         " Align with @if | 
					
						
							|  |  |  |         if prev_text =~ '^\s*@if ' | 
					
						
							|  |  |  |           let extra = 4 | 
					
						
							|  |  |  |         endif | 
					
						
							|  |  |  |       elseif cur_hasfield && !prev_hasfield && !prev_special | 
					
						
							|  |  |  |         " less indent below a continuation line | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |         let extra = -shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |       endif | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     endif | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if below_end_brace | 
					
						
							|  |  |  |     " find matching {, if that line starts with @ it's not the start of a rule | 
					
						
							|  |  |  |     " but something else from a template system | 
					
						
							|  |  |  |     call cursor(prev_lnum, 1) | 
					
						
							|  |  |  |     call search('}\s*$') | 
					
						
							|  |  |  |     try | 
					
						
							|  |  |  |       normal! % | 
					
						
							|  |  |  |       " Found the matching "{", align with it. | 
					
						
							|  |  |  |       let align_lnum = s:CssFirstUnfinished(line('.'), min_lnum) | 
					
						
							|  |  |  |       let special = getline(align_lnum) =~ '^\s*@' | 
					
						
							|  |  |  |     catch | 
					
						
							|  |  |  |       let special = 0 | 
					
						
							|  |  |  |     endtry | 
					
						
							|  |  |  |     if special | 
					
						
							|  |  |  |       " do not reduce indent below @{ ... } | 
					
						
							|  |  |  |       if extra < 0 | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |         let extra += shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |       endif | 
					
						
							|  |  |  |     else | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |       let extra -= (brace_counts.c_close - (prev_text =~ '^\s*}')) * shiftwidth() | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     endif | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " if no extra indent yet... | 
					
						
							|  |  |  |   if extra == 0 | 
					
						
							|  |  |  |     if brace_counts.p_open > brace_counts.p_close | 
					
						
							|  |  |  |       " previous line has more ( than ): add a shiftwidth | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |       let extra = shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     elseif brace_counts.p_open < brace_counts.p_close | 
					
						
							|  |  |  |       " previous line has more ) than (: subtract a shiftwidth | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |       let extra = -shiftwidth() | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     endif | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return indent(align_lnum) + extra | 
					
						
							|  |  |  | endfunc "}}} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | " Inside <style>: Whether a line is unfinished. | 
					
						
							| 
									
										
										
										
											2018-08-28 22:58:02 +02:00
										 |  |  | " 	tag: | 
					
						
							|  |  |  | " 	tag: blah | 
					
						
							|  |  |  | " 	tag: blah && | 
					
						
							|  |  |  | " 	tag: blah || | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | func! s:CssUnfinished(text) | 
					
						
							|  |  |  |   "{{{ | 
					
						
							| 
									
										
										
										
											2018-08-28 22:58:02 +02:00
										 |  |  |   return a:text =~ '\(||\|&&\|:\|\k\)\s*$' | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | endfunc "}}} | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | " Search back for the first unfinished line above "lnum". | 
					
						
							|  |  |  | func! s:CssFirstUnfinished(lnum, min_lnum) | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   let align_lnum = a:lnum | 
					
						
							|  |  |  |   while align_lnum > a:min_lnum && s:CssUnfinished(getline(align_lnum - 1)) | 
					
						
							|  |  |  |     let align_lnum -= 1 | 
					
						
							|  |  |  |   endwhile | 
					
						
							|  |  |  |   return align_lnum | 
					
						
							|  |  |  | endfunc "}}} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | " Find the non-empty line at or before "lnum" that is not a comment. | 
					
						
							|  |  |  | func! s:CssPrevNonComment(lnum, stopline) | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   " caller starts from a line a:lnum + 1 that is not a comment | 
					
						
							|  |  |  |   let lnum = prevnonblank(a:lnum) | 
					
						
							|  |  |  |   while 1 | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     let ccol = match(getline(lnum), '\*/') | 
					
						
							|  |  |  |     if ccol < 0 | 
					
						
							| 
									
										
										
										
											2016-09-25 22:11:48 +02:00
										 |  |  |       " No comment end thus it's something else. | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |       return lnum | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     endif | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     call cursor(lnum, ccol + 1) | 
					
						
							|  |  |  |     " Search back for the /* that starts the comment | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     let lnum = search('/\*', 'bW', a:stopline) | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     if indent(".") == virtcol(".") - 1 | 
					
						
							|  |  |  |       " The  found /* is at the start of the line. Now go back to the line | 
					
						
							|  |  |  |       " above it and again check if it is a comment. | 
					
						
							|  |  |  |       let lnum = prevnonblank(lnum - 1) | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |       " /* is after something else, thus it's not a comment line. | 
					
						
							|  |  |  |       return lnum | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     endif | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   endwhile | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | endfunc "}}} | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | " Check the number of {} and () in line "lnum". Return a dict with the counts. | 
					
						
							|  |  |  | func! HtmlIndent_CountBraces(lnum) | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   let brs = substitute(getline(a:lnum), '[''"].\{-}[''"]\|/\*.\{-}\*/\|/\*.*$\|[^{}()]', '', 'g') | 
					
						
							|  |  |  |   let c_open = 0 | 
					
						
							|  |  |  |   let c_close = 0 | 
					
						
							|  |  |  |   let p_open = 0 | 
					
						
							|  |  |  |   let p_close = 0 | 
					
						
							|  |  |  |   for brace in split(brs, '\zs') | 
					
						
							|  |  |  |     if brace == "{" | 
					
						
							|  |  |  |       let c_open += 1 | 
					
						
							|  |  |  |     elseif brace == "}" | 
					
						
							|  |  |  |       if c_open > 0 | 
					
						
							|  |  |  |         let c_open -= 1 | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         let c_close += 1 | 
					
						
							|  |  |  |       endif | 
					
						
							|  |  |  |     elseif brace == '(' | 
					
						
							|  |  |  |       let p_open += 1 | 
					
						
							|  |  |  |     elseif brace == ')' | 
					
						
							|  |  |  |       if p_open > 0 | 
					
						
							|  |  |  |         let p_open -= 1 | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         let p_close += 1 | 
					
						
							|  |  |  |       endif | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |   endfor | 
					
						
							|  |  |  |   return {'c_open': c_open, | 
					
						
							|  |  |  |         \ 'c_close': c_close, | 
					
						
							|  |  |  |         \ 'p_open': p_open, | 
					
						
							|  |  |  |         \ 'p_close': p_close} | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | endfunc "}}} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Return the indent for a comment: <!-- --> | 
					
						
							|  |  |  | func! s:Alien5() | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   let curtext = getline(v:lnum) | 
					
						
							|  |  |  |   if curtext =~ '^\s*\zs-->' | 
					
						
							|  |  |  |     " current line starts with end of comment, line up with comment start. | 
					
						
							|  |  |  |     call cursor(v:lnum, 0) | 
					
						
							|  |  |  |     let lnum = search('<!--', 'b') | 
					
						
							|  |  |  |     if lnum > 0 | 
					
						
							|  |  |  |       " TODO: what if <!-- is not at the start of the line? | 
					
						
							|  |  |  |       return indent(lnum) | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     " Strange, can't find it. | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     return -1 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   let prevlnum = prevnonblank(v:lnum - 1) | 
					
						
							|  |  |  |   let prevtext = getline(prevlnum) | 
					
						
							|  |  |  |   let idx = match(prevtext, '^\s*\zs<!--') | 
					
						
							|  |  |  |   if idx >= 0 | 
					
						
							|  |  |  |     " just below comment start, add a shiftwidth | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |     return idx + shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " Some files add 4 spaces just below a TODO line.  It's difficult to detect | 
					
						
							|  |  |  |   " the end of the TODO, so let's not do that. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " Align with the previous non-blank line. | 
					
						
							|  |  |  |   return indent(prevlnum) | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | endfunc "}}} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-25 20:34:21 +02:00
										 |  |  | " Return the indent for conditional comment: <!--[ ![endif]--> | 
					
						
							|  |  |  | func! s:Alien6() | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   let curtext = getline(v:lnum) | 
					
						
							|  |  |  |   if curtext =~ '\s*\zs<!\[endif\]-->' | 
					
						
							|  |  |  |     " current line starts with end of comment, line up with comment start. | 
					
						
							|  |  |  |     let lnum = search('<!--', 'bn') | 
					
						
							|  |  |  |     if lnum > 0 | 
					
						
							|  |  |  |       return indent(lnum) | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |   endif | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |   return b:hi_indent.baseindent + shiftwidth() | 
					
						
							| 
									
										
										
										
											2015-09-25 20:34:21 +02:00
										 |  |  | endfunc "}}} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " When the "lnum" line ends in ">" find the line containing the matching "<". | 
					
						
							|  |  |  | func! HtmlIndent_FindTagStart(lnum) | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   " Avoids using the indent of a continuation line. | 
					
						
							|  |  |  |   " Moves the cursor. | 
					
						
							|  |  |  |   " Return two values: | 
					
						
							|  |  |  |   " - the matching line number or "lnum". | 
					
						
							|  |  |  |   " - a flag indicating whether we found the end of a tag. | 
					
						
							|  |  |  |   " This method is global so that HTML-like indenters can use it. | 
					
						
							|  |  |  |   " To avoid matching " > " or " < " inside a string require that the opening | 
					
						
							|  |  |  |   " "<" is followed by a word character and the closing ">" comes after a | 
					
						
							|  |  |  |   " non-white character. | 
					
						
							|  |  |  |   let idx = match(getline(a:lnum), '\S>\s*$') | 
					
						
							|  |  |  |   if idx > 0 | 
					
						
							|  |  |  |     call cursor(a:lnum, idx) | 
					
						
							|  |  |  |     let lnum = searchpair('<\w', '' , '\S>', 'bW', '', max([a:lnum - b:html_indent_line_limit, 0])) | 
					
						
							|  |  |  |     if lnum > 0 | 
					
						
							|  |  |  |       return [lnum, 1] | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   return [a:lnum, 0] | 
					
						
							| 
									
										
										
										
											2014-06-25 18:50:27 +02:00
										 |  |  | endfunc "}}} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Find the unclosed start tag from the current cursor position. | 
					
						
							|  |  |  | func! HtmlIndent_FindStartTag() | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   " The cursor must be on or before a closing tag. | 
					
						
							|  |  |  |   " If found, positions the cursor at the match and returns the line number. | 
					
						
							|  |  |  |   " Otherwise returns 0. | 
					
						
							| 
									
										
										
										
											2018-03-09 22:22:21 +01:00
										 |  |  |   let tagname = matchstr(getline('.')[col('.') - 1:], '</\zs' . s:tagname . '\ze') | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   let start_lnum = searchpair('<' . tagname . '\>', '', '</' . tagname . '\>', 'bW') | 
					
						
							|  |  |  |   if start_lnum > 0 | 
					
						
							|  |  |  |     return start_lnum | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  |   return 0 | 
					
						
							|  |  |  | endfunc "}}} | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Moves the cursor from a "<" to the matching ">". | 
					
						
							|  |  |  | func! HtmlIndent_FindTagEnd() | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   " Call this with the cursor on the "<" of a start tag. | 
					
						
							|  |  |  |   " This will move the cursor to the ">" of the matching end tag or, when it's | 
					
						
							|  |  |  |   " a self-closing tag, to the matching ">". | 
					
						
							|  |  |  |   " Limited to look up to b:html_indent_line_limit lines away. | 
					
						
							|  |  |  |   let text = getline('.') | 
					
						
							| 
									
										
										
										
											2018-03-09 22:22:21 +01:00
										 |  |  |   let tagname = matchstr(text, s:tagname . '\|!--', col('.')) | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   if tagname == '!--' | 
					
						
							|  |  |  |     call search('--\zs>') | 
					
						
							|  |  |  |   elseif s:get_tag('/' . tagname) != 0 | 
					
						
							|  |  |  |     " tag with a closing tag, find matching "</tag>" | 
					
						
							|  |  |  |     call searchpair('<' . tagname, '', '</' . tagname . '\zs>', 'W', '', line('.') + b:html_indent_line_limit) | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     " self-closing tag, find the ">" | 
					
						
							|  |  |  |     call search('\S\zs>') | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | endfunc "}}} | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Indenting inside a start tag. Return the correct indent or -1 if unknown. | 
					
						
							|  |  |  | func! s:InsideTag(foundHtmlString) | 
					
						
							|  |  |  |   "{{{ | 
					
						
							|  |  |  |   if a:foundHtmlString | 
					
						
							|  |  |  |     " Inside an attribute string. | 
					
						
							| 
									
										
										
										
											2019-03-24 15:09:13 +01:00
										 |  |  |     " Align with the opening quote or use an external function. | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     let lnum = v:lnum - 1 | 
					
						
							|  |  |  |     if lnum > 1 | 
					
						
							|  |  |  |       if exists('b:html_indent_tag_string_func') | 
					
						
							|  |  |  |         return b:html_indent_tag_string_func(lnum) | 
					
						
							|  |  |  |       endif | 
					
						
							| 
									
										
										
										
											2019-03-24 15:09:13 +01:00
										 |  |  |       " If there is a double quote in the previous line, indent with the | 
					
						
							|  |  |  |       " character after it. | 
					
						
							|  |  |  |       if getline(lnum) =~ '"' | 
					
						
							|  |  |  | 	call cursor(lnum, 0) | 
					
						
							|  |  |  | 	normal f" | 
					
						
							|  |  |  | 	return virtcol('.') | 
					
						
							|  |  |  |       endif | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |       return indent(lnum) | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |   endif | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   " Should be another attribute: " attr="val".  Align with the previous | 
					
						
							|  |  |  |   " attribute start. | 
					
						
							|  |  |  |   let lnum = v:lnum | 
					
						
							|  |  |  |   while lnum > 1 | 
					
						
							|  |  |  |     let lnum -= 1 | 
					
						
							|  |  |  |     let text = getline(lnum) | 
					
						
							|  |  |  |     " Find a match with one of these, align with "attr": | 
					
						
							|  |  |  |     "       attr= | 
					
						
							|  |  |  |     "  <tag attr= | 
					
						
							|  |  |  |     "  text<tag attr= | 
					
						
							|  |  |  |     "  <tag>text</tag>text<tag attr= | 
					
						
							|  |  |  |     " For long lines search for the first match, finding the last match | 
					
						
							|  |  |  |     " gets very slow. | 
					
						
							|  |  |  |     if len(text) < 300 | 
					
						
							|  |  |  |       let idx = match(text, '.*\s\zs[_a-zA-Z0-9-]\+="') | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |       let idx = match(text, '\s\zs[_a-zA-Z0-9-]\+="') | 
					
						
							|  |  |  |     endif | 
					
						
							| 
									
										
										
										
											2018-03-09 22:22:21 +01:00
										 |  |  |     if idx == -1 | 
					
						
							|  |  |  |       " try <tag attr | 
					
						
							|  |  |  |       let idx = match(text, '<' . s:tagname . '\s\+\zs\w') | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |     if idx == -1 | 
					
						
							| 
									
										
										
										
											2018-12-09 20:43:55 +01:00
										 |  |  |       " after just "<tag" indent one level more | 
					
						
							| 
									
										
										
										
											2018-03-09 22:22:21 +01:00
										 |  |  |       let idx = match(text, '<' . s:tagname . '$') | 
					
						
							|  |  |  |       if idx >= 0 | 
					
						
							|  |  |  | 	call cursor(lnum, idx) | 
					
						
							|  |  |  | 	return virtcol('.') + shiftwidth() | 
					
						
							|  |  |  |       endif | 
					
						
							|  |  |  |     endif | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     if idx > 0 | 
					
						
							| 
									
										
										
										
											2018-03-09 22:22:21 +01:00
										 |  |  |       " Found the attribute to align with. | 
					
						
							|  |  |  |       call cursor(lnum, idx) | 
					
						
							|  |  |  |       return virtcol('.') | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  |     endif | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   endwhile | 
					
						
							|  |  |  |   return -1 | 
					
						
							|  |  |  | endfunc "}}} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | " THE MAIN INDENT FUNCTION. Return the amount of indent for v:lnum. | 
					
						
							|  |  |  | func! HtmlIndent() | 
					
						
							|  |  |  |   "{{{ | 
					
						
							| 
									
										
										
										
											2015-01-14 12:52:36 +01:00
										 |  |  |   if prevnonblank(v:lnum - 1) < 1 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     " First non-blank line has no indent. | 
					
						
							|  |  |  |     return 0 | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   let curtext = tolower(getline(v:lnum)) | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |   let indentunit = shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   let b:hi_newstate = {} | 
					
						
							|  |  |  |   let b:hi_newstate.lnum = v:lnum | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " When syntax HL is enabled, detect we are inside a tag.  Indenting inside | 
					
						
							|  |  |  |   " a tag works very differently. Do not do this when the line starts with | 
					
						
							|  |  |  |   " "<", it gets the "htmlTag" ID but we are not inside a tag then. | 
					
						
							|  |  |  |   if curtext !~ '^\s*<' | 
					
						
							| 
									
										
										
										
											2014-08-23 15:31:19 +02:00
										 |  |  |     normal! ^ | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |     let stack = synstack(v:lnum, col('.'))  " assumes there are no tabs | 
					
						
							|  |  |  |     let foundHtmlString = 0 | 
					
						
							|  |  |  |     for synid in reverse(stack) | 
					
						
							|  |  |  |       let name = synIDattr(synid, "name") | 
					
						
							|  |  |  |       if index(b:hi_insideStringNames, name) >= 0 | 
					
						
							|  |  |  |         let foundHtmlString = 1 | 
					
						
							|  |  |  |       elseif index(b:hi_insideTagNames, name) >= 0 | 
					
						
							|  |  |  |         " Yes, we are inside a tag. | 
					
						
							|  |  |  |         let indent = s:InsideTag(foundHtmlString) | 
					
						
							|  |  |  |         if indent >= 0 | 
					
						
							|  |  |  |           " Do not keep the state. TODO: could keep the block type. | 
					
						
							|  |  |  |           let b:hi_indent.lnum = 0 | 
					
						
							|  |  |  |           return indent | 
					
						
							|  |  |  |         endif | 
					
						
							|  |  |  |       endif | 
					
						
							|  |  |  |     endfor | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " does the line start with a closing tag? | 
					
						
							|  |  |  |   let swendtag = match(curtext, '^\s*</') >= 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if prevnonblank(v:lnum - 1) == b:hi_indent.lnum && b:hi_lasttick == b:changedtick - 1 | 
					
						
							|  |  |  |     " use state (continue from previous line) | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     " start over (know nothing) | 
					
						
							|  |  |  |     let b:hi_indent = s:FreshState(v:lnum) | 
					
						
							|  |  |  |   endif | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   if b:hi_indent.block >= 2 | 
					
						
							|  |  |  |     " within block | 
					
						
							|  |  |  |     let endtag = s:endtags[b:hi_indent.block] | 
					
						
							|  |  |  |     let blockend = stridx(curtext, endtag) | 
					
						
							|  |  |  |     if blockend >= 0 | 
					
						
							|  |  |  |       " block ends here | 
					
						
							|  |  |  |       let b:hi_newstate.block = 0 | 
					
						
							|  |  |  |       " calc indent for REST OF LINE (may start more blocks): | 
					
						
							|  |  |  |       call s:CountTagsAndState(strpart(curtext, blockend + strlen(endtag))) | 
					
						
							|  |  |  |       if swendtag && b:hi_indent.block != 5 | 
					
						
							|  |  |  |         let indent = b:hi_indent.blocktagind + s:curind * indentunit | 
					
						
							|  |  |  |         let b:hi_newstate.baseindent = indent + s:nextrel * indentunit | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         let indent = s:Alien{b:hi_indent.block}() | 
					
						
							|  |  |  |         let b:hi_newstate.baseindent = b:hi_indent.blocktagind + s:nextrel * indentunit | 
					
						
							|  |  |  |       endif | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |       " block continues | 
					
						
							|  |  |  |       " indent this line with alien method | 
					
						
							|  |  |  |       let indent = s:Alien{b:hi_indent.block}() | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  |     endif | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   else | 
					
						
							|  |  |  |     " not within a block - within usual html | 
					
						
							|  |  |  |     let b:hi_newstate.block = b:hi_indent.block | 
					
						
							|  |  |  |     if swendtag | 
					
						
							|  |  |  |       " The current line starts with an end tag, align with its start tag. | 
					
						
							|  |  |  |       call cursor(v:lnum, 1) | 
					
						
							|  |  |  |       let start_lnum = HtmlIndent_FindStartTag() | 
					
						
							|  |  |  |       if start_lnum > 0 | 
					
						
							|  |  |  |         " check for the line starting with something inside a tag: | 
					
						
							|  |  |  |         " <sometag               <- align here | 
					
						
							|  |  |  |         "    attr=val><open>     not here | 
					
						
							|  |  |  |         let text = getline(start_lnum) | 
					
						
							|  |  |  |         let angle = matchstr(text, '[<>]') | 
					
						
							|  |  |  |         if angle == '>' | 
					
						
							|  |  |  |           call cursor(start_lnum, 1) | 
					
						
							|  |  |  |           normal! f>% | 
					
						
							|  |  |  |           let start_lnum = line('.') | 
					
						
							|  |  |  |           let text = getline(start_lnum) | 
					
						
							|  |  |  |         endif | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |         let indent = indent(start_lnum) | 
					
						
							|  |  |  |         if col('.') > 2 | 
					
						
							|  |  |  |           let swendtag = match(text, '^\s*</') >= 0 | 
					
						
							|  |  |  |           call s:CountITags(text[: col('.') - 2]) | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |           let indent += s:nextrel * shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |           if !swendtag | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |             let indent += s:curind * shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |           endif | 
					
						
							|  |  |  |         endif | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         " not sure what to do | 
					
						
							|  |  |  |         let indent = b:hi_indent.baseindent | 
					
						
							|  |  |  |       endif | 
					
						
							|  |  |  |       let b:hi_newstate.baseindent = indent | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       call s:CountTagsAndState(curtext) | 
					
						
							|  |  |  |       let indent = b:hi_indent.baseindent | 
					
						
							|  |  |  |       let b:hi_newstate.baseindent = indent + (s:curind + s:nextrel) * indentunit | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |   endif | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  |   let b:hi_lasttick = b:changedtick | 
					
						
							|  |  |  |   call extend(b:hi_indent, b:hi_newstate, "force") | 
					
						
							|  |  |  |   return indent | 
					
						
							|  |  |  | endfunc "}}} | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " Check user settings when loading this script the first time. | 
					
						
							| 
									
										
										
										
											2013-06-12 21:29:15 +02:00
										 |  |  | call HtmlIndent_CheckUserSettings() | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-05-05 21:15:17 +00:00
										 |  |  | let &cpo = s:cpo_save | 
					
						
							|  |  |  | unlet s:cpo_save | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 16:43:17 +02:00
										 |  |  | " vim: fdm=marker ts=8 sw=2 tw=78 |