1ec7944aaSBram Moolenaar" Vim indent script for HTML 28bb1c3e5SBram Moolenaar" Maintainer: Bram Moolenaar 38bb1c3e5SBram Moolenaar" Original Author: Andy Wokula <[email protected]> 4*2346a637SBram Moolenaar" Last Change: 2021 Jun 13 57ff78465SBram Moolenaar" Version: 1.0 "{{{ 68bb1c3e5SBram Moolenaar" Description: HTML indent script with cached state for faster indenting on a 7ec7944aaSBram Moolenaar" range of lines. 88bb1c3e5SBram Moolenaar" Supports template systems through hooks. 98bb1c3e5SBram Moolenaar" Supports Closure stylesheets. 10ec7944aaSBram Moolenaar" 11ec7944aaSBram Moolenaar" Credits: 12ec7944aaSBram Moolenaar" indent/html.vim (2006 Jun 05) from J. Zellner 13ec7944aaSBram Moolenaar" indent/css.vim (2006 Dec 20) from N. Weibull 14ec7944aaSBram Moolenaar" 15ec7944aaSBram Moolenaar" History: 168bb1c3e5SBram Moolenaar" 2014 June (v1.0) overhaul (Bram) 1752b91d80SBram Moolenaar" 2012 Oct 21 (v0.9) added support for shiftwidth() 1852b91d80SBram Moolenaar" 2011 Sep 09 (v0.8) added HTML5 tags (thx to J. Zuckerman) 1952b91d80SBram Moolenaar" 2008 Apr 28 (v0.6) revised customization 2052b91d80SBram Moolenaar" 2008 Mar 09 (v0.5) fixed 'indk' issue (thx to C.J. Robinson) 21ec7944aaSBram Moolenaar"}}} 22071d4279SBram Moolenaar 238bb1c3e5SBram Moolenaar" Init Folklore, check user settings (2nd time ++) 248bb1c3e5SBram Moolenaarif exists("b:did_indent") "{{{ 25071d4279SBram Moolenaar finish 26071d4279SBram Moolenaarendif 27690afe1fSBram Moolenaar 28690afe1fSBram Moolenaar" Load the Javascript indent script first, it defines GetJavascriptIndent(). 29690afe1fSBram Moolenaar" Undo the rest. 30690afe1fSBram Moolenaar" Load base python indent. 31690afe1fSBram Moolenaarif !exists('*GetJavascriptIndent') 32690afe1fSBram Moolenaar runtime! indent/javascript.vim 33690afe1fSBram Moolenaarendif 34071d4279SBram Moolenaarlet b:did_indent = 1 35071d4279SBram Moolenaar 36ec7944aaSBram Moolenaarsetlocal indentexpr=HtmlIndent() 37ec7944aaSBram Moolenaarsetlocal indentkeys=o,O,<Return>,<>>,{,},!^F 38071d4279SBram Moolenaar 398bb1c3e5SBram Moolenaar" Needed for % to work when finding start/end of a tag. 40946e27abSBram Moolenaarsetlocal matchpairs+=<:> 41946e27abSBram Moolenaar 42690afe1fSBram Moolenaarlet b:undo_indent = "setlocal inde< indk<" 43071d4279SBram Moolenaar 448bb1c3e5SBram Moolenaar" b:hi_indent keeps state to speed up indenting consecutive lines. 458bb1c3e5SBram Moolenaarlet b:hi_indent = {"lnum": -1} 468bb1c3e5SBram Moolenaar 478bb1c3e5SBram Moolenaar"""""" Code below this is loaded only once. """"" 488bb1c3e5SBram Moolenaarif exists("*HtmlIndent") && !exists('g:force_reload_html') 49ec7944aaSBram Moolenaar call HtmlIndent_CheckUserSettings() 50ec7944aaSBram Moolenaar finish 51071d4279SBram Moolenaarendif 52071d4279SBram Moolenaar 538bb1c3e5SBram Moolenaar" Allow for line continuation below. 5491170f8aSBram Moolenaarlet s:cpo_save = &cpo 55071d4279SBram Moolenaarset cpo-=C 56ec7944aaSBram Moolenaar"}}} 57071d4279SBram Moolenaar 58b5b75624SBram Moolenaar" Pattern to match the name of a tag, including custom elements. 59b5b75624SBram Moolenaarlet s:tagname = '\w\+\(-\w\+\)*' 60b5b75624SBram Moolenaar 618bb1c3e5SBram Moolenaar" Check and process settings from b:html_indent and g:html_indent... variables. 628bb1c3e5SBram Moolenaar" Prefer using buffer-local settings over global settings, so that there can 638bb1c3e5SBram Moolenaar" be defaults for all HTML files and exceptions for specific types of HTML 648bb1c3e5SBram Moolenaar" files. 65*2346a637SBram Moolenaarfunc HtmlIndent_CheckUserSettings() 668bb1c3e5SBram Moolenaar "{{{ 678bb1c3e5SBram Moolenaar let inctags = '' 688bb1c3e5SBram Moolenaar if exists("b:html_indent_inctags") 698bb1c3e5SBram Moolenaar let inctags = b:html_indent_inctags 708bb1c3e5SBram Moolenaar elseif exists("g:html_indent_inctags") 718bb1c3e5SBram Moolenaar let inctags = g:html_indent_inctags 72071d4279SBram Moolenaar endif 738bb1c3e5SBram Moolenaar let b:hi_tags = {} 748bb1c3e5SBram Moolenaar if len(inctags) > 0 758bb1c3e5SBram Moolenaar call s:AddITags(b:hi_tags, split(inctags, ",")) 768bb1c3e5SBram Moolenaar endif 778bb1c3e5SBram Moolenaar 788bb1c3e5SBram Moolenaar let autotags = '' 798bb1c3e5SBram Moolenaar if exists("b:html_indent_autotags") 808bb1c3e5SBram Moolenaar let autotags = b:html_indent_autotags 818bb1c3e5SBram Moolenaar elseif exists("g:html_indent_autotags") 828bb1c3e5SBram Moolenaar let autotags = g:html_indent_autotags 838bb1c3e5SBram Moolenaar endif 848bb1c3e5SBram Moolenaar let b:hi_removed_tags = {} 85541f92d6SBram Moolenaar if len(autotags) > 0 868bb1c3e5SBram Moolenaar call s:RemoveITags(b:hi_removed_tags, split(autotags, ",")) 878bb1c3e5SBram Moolenaar endif 888bb1c3e5SBram Moolenaar 898bb1c3e5SBram Moolenaar " Syntax names indicating being inside a string of an attribute value. 908bb1c3e5SBram Moolenaar let string_names = [] 918bb1c3e5SBram Moolenaar if exists("b:html_indent_string_names") 928bb1c3e5SBram Moolenaar let string_names = b:html_indent_string_names 938bb1c3e5SBram Moolenaar elseif exists("g:html_indent_string_names") 948bb1c3e5SBram Moolenaar let string_names = g:html_indent_string_names 958bb1c3e5SBram Moolenaar endif 968bb1c3e5SBram Moolenaar let b:hi_insideStringNames = ['htmlString'] 978bb1c3e5SBram Moolenaar if len(string_names) > 0 988bb1c3e5SBram Moolenaar for s in string_names 998bb1c3e5SBram Moolenaar call add(b:hi_insideStringNames, s) 1008bb1c3e5SBram Moolenaar endfor 1018bb1c3e5SBram Moolenaar endif 1028bb1c3e5SBram Moolenaar 1038bb1c3e5SBram Moolenaar " Syntax names indicating being inside a tag. 1048bb1c3e5SBram Moolenaar let tag_names = [] 1058bb1c3e5SBram Moolenaar if exists("b:html_indent_tag_names") 1068bb1c3e5SBram Moolenaar let tag_names = b:html_indent_tag_names 1078bb1c3e5SBram Moolenaar elseif exists("g:html_indent_tag_names") 1088bb1c3e5SBram Moolenaar let tag_names = g:html_indent_tag_names 1098bb1c3e5SBram Moolenaar endif 1108bb1c3e5SBram Moolenaar let b:hi_insideTagNames = ['htmlTag', 'htmlScriptTag'] 1118bb1c3e5SBram Moolenaar if len(tag_names) > 0 1128bb1c3e5SBram Moolenaar for s in tag_names 1138bb1c3e5SBram Moolenaar call add(b:hi_insideTagNames, s) 1148bb1c3e5SBram Moolenaar endfor 115071d4279SBram Moolenaar endif 116071d4279SBram Moolenaar 117ec7944aaSBram Moolenaar let indone = {"zero": 0 118ec7944aaSBram Moolenaar \,"auto": "indent(prevnonblank(v:lnum-1))" 1193ec574f2SBram Moolenaar \,"inc": "b:hi_indent.blocktagind + shiftwidth()"} 1208bb1c3e5SBram Moolenaar 1218bb1c3e5SBram Moolenaar let script1 = '' 1228bb1c3e5SBram Moolenaar if exists("b:html_indent_script1") 1238bb1c3e5SBram Moolenaar let script1 = b:html_indent_script1 1248bb1c3e5SBram Moolenaar elseif exists("g:html_indent_script1") 1258bb1c3e5SBram Moolenaar let script1 = g:html_indent_script1 12691170f8aSBram Moolenaar endif 1278bb1c3e5SBram Moolenaar if len(script1) > 0 1288bb1c3e5SBram Moolenaar let b:hi_js1indent = get(indone, script1, indone.zero) 1298bb1c3e5SBram Moolenaar else 1308bb1c3e5SBram Moolenaar let b:hi_js1indent = 0 1318bb1c3e5SBram Moolenaar endif 1328bb1c3e5SBram Moolenaar 1338bb1c3e5SBram Moolenaar let style1 = '' 1348bb1c3e5SBram Moolenaar if exists("b:html_indent_style1") 1358bb1c3e5SBram Moolenaar let style1 = b:html_indent_style1 1368bb1c3e5SBram Moolenaar elseif exists("g:html_indent_style1") 1378bb1c3e5SBram Moolenaar let style1 = g:html_indent_style1 1388bb1c3e5SBram Moolenaar endif 1398bb1c3e5SBram Moolenaar if len(style1) > 0 1408bb1c3e5SBram Moolenaar let b:hi_css1indent = get(indone, style1, indone.zero) 1418bb1c3e5SBram Moolenaar else 1428bb1c3e5SBram Moolenaar let b:hi_css1indent = 0 1438bb1c3e5SBram Moolenaar endif 1448bb1c3e5SBram Moolenaar 1458bb1c3e5SBram Moolenaar if !exists('b:html_indent_line_limit') 1468bb1c3e5SBram Moolenaar if exists('g:html_indent_line_limit') 1478bb1c3e5SBram Moolenaar let b:html_indent_line_limit = g:html_indent_line_limit 1488bb1c3e5SBram Moolenaar else 1498bb1c3e5SBram Moolenaar let b:html_indent_line_limit = 200 1508bb1c3e5SBram Moolenaar endif 151ec7944aaSBram Moolenaar endif 152ec7944aaSBram Moolenaarendfunc "}}} 153ec7944aaSBram Moolenaar 1548bb1c3e5SBram Moolenaar" Init Script Vars 1558bb1c3e5SBram Moolenaar"{{{ 1568bb1c3e5SBram Moolenaarlet b:hi_lasttick = 0 1578bb1c3e5SBram Moolenaarlet b:hi_newstate = {} 158ec7944aaSBram Moolenaarlet s:countonly = 0 159ec7944aaSBram Moolenaar "}}} 1608bb1c3e5SBram Moolenaar 1618bb1c3e5SBram Moolenaar" Fill the s:indent_tags dict with known tags. 1628bb1c3e5SBram Moolenaar" The key is "tagname" or "/tagname". {{{ 1638bb1c3e5SBram Moolenaar" The value is: 1648bb1c3e5SBram Moolenaar" 1 opening tag 1658bb1c3e5SBram Moolenaar" 2 "pre" 1668bb1c3e5SBram Moolenaar" 3 "script" 1678bb1c3e5SBram Moolenaar" 4 "style" 1688bb1c3e5SBram Moolenaar" 5 comment start 169ca63501fSBram Moolenaar" 6 conditional comment start 1708bb1c3e5SBram Moolenaar" -1 closing tag 1718bb1c3e5SBram Moolenaar" -2 "/pre" 1728bb1c3e5SBram Moolenaar" -3 "/script" 1738bb1c3e5SBram Moolenaar" -4 "/style" 1748bb1c3e5SBram Moolenaar" -5 comment end 175ca63501fSBram Moolenaar" -6 conditional comment end 1768bb1c3e5SBram Moolenaarlet s:indent_tags = {} 177ca63501fSBram Moolenaarlet s:endtags = [0,0,0,0,0,0,0] " long enough for the highest index 1788bb1c3e5SBram Moolenaar"}}} 1798bb1c3e5SBram Moolenaar 1808bb1c3e5SBram Moolenaar" Add a list of tag names for a pair of <tag> </tag> to "tags". 181*2346a637SBram Moolenaarfunc s:AddITags(tags, taglist) 1828bb1c3e5SBram Moolenaar "{{{ 183ec7944aaSBram Moolenaar for itag in a:taglist 1848bb1c3e5SBram Moolenaar let a:tags[itag] = 1 1858bb1c3e5SBram Moolenaar let a:tags['/' . itag] = -1 186ec7944aaSBram Moolenaar endfor 187ec7944aaSBram Moolenaarendfunc "}}} 1888bb1c3e5SBram Moolenaar 1898bb1c3e5SBram Moolenaar" Take a list of tag name pairs that are not to be used as tag pairs. 190*2346a637SBram Moolenaarfunc s:RemoveITags(tags, taglist) 1918bb1c3e5SBram Moolenaar "{{{ 1928bb1c3e5SBram Moolenaar for itag in a:taglist 1938bb1c3e5SBram Moolenaar let a:tags[itag] = 1 1948bb1c3e5SBram Moolenaar let a:tags['/' . itag] = 1 1958bb1c3e5SBram Moolenaar endfor 1968bb1c3e5SBram Moolenaarendfunc "}}} 1978bb1c3e5SBram Moolenaar 1988bb1c3e5SBram Moolenaar" Add a block tag, that is a tag with a different kind of indenting. 199*2346a637SBram Moolenaarfunc s:AddBlockTag(tag, id, ...) 2008bb1c3e5SBram Moolenaar "{{{ 2018bb1c3e5SBram Moolenaar if !(a:id >= 2 && a:id < len(s:endtags)) 2028bb1c3e5SBram Moolenaar echoerr 'AddBlockTag ' . a:id 203ec7944aaSBram Moolenaar return 204ec7944aaSBram Moolenaar endif 205ec7944aaSBram Moolenaar let s:indent_tags[a:tag] = a:id 206ec7944aaSBram Moolenaar if a:0 == 0 207ec7944aaSBram Moolenaar let s:indent_tags['/' . a:tag] = -a:id 2088bb1c3e5SBram Moolenaar let s:endtags[a:id] = "</" . a:tag . ">" 209ec7944aaSBram Moolenaar else 210ec7944aaSBram Moolenaar let s:indent_tags[a:1] = -a:id 2118bb1c3e5SBram Moolenaar let s:endtags[a:id] = a:1 212ec7944aaSBram Moolenaar endif 213ec7944aaSBram Moolenaarendfunc "}}} 214ec7944aaSBram Moolenaar 2158bb1c3e5SBram Moolenaar" Add known tag pairs. 2168bb1c3e5SBram Moolenaar" Self-closing tags and tags that are sometimes {{{ 2178bb1c3e5SBram Moolenaar" self-closing (e.g., <p>) are not here (when encountering </p> we can find 218d47d5223SBram Moolenaar" the matching <p>, but not the other way around). 219d47d5223SBram Moolenaar" Known self-closing tags: " 'p', 'img', 'source', 'area', 'keygen', 'track', 220d47d5223SBram Moolenaar" 'wbr'. 2218bb1c3e5SBram Moolenaar" Old HTML tags: 2228bb1c3e5SBram Moolenaarcall s:AddITags(s:indent_tags, [ 2238bb1c3e5SBram Moolenaar \ 'a', 'abbr', 'acronym', 'address', 'b', 'bdo', 'big', 2248bb1c3e5SBram Moolenaar \ 'blockquote', 'body', 'button', 'caption', 'center', 'cite', 'code', 22573fef330SBram Moolenaar \ 'colgroup', 'dd', 'del', 'dfn', 'dir', 'div', 'dl', 'dt', 'em', 'fieldset', 'font', 2268bb1c3e5SBram Moolenaar \ 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'html', 2278bb1c3e5SBram Moolenaar \ 'i', 'iframe', 'ins', 'kbd', 'label', 'legend', 'li', 2288bb1c3e5SBram Moolenaar \ 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', 229ec7944aaSBram Moolenaar \ 'optgroup', 'q', 's', 'samp', 'select', 'small', 'span', 'strong', 'sub', 230ec7944aaSBram Moolenaar \ 'sup', 'table', 'textarea', 'title', 'tt', 'u', 'ul', 'var', 'th', 'td', 2318bb1c3e5SBram Moolenaar \ 'tr', 'tbody', 'tfoot', 'thead']) 232ec7944aaSBram Moolenaar 233939a1abeSBram Moolenaar" New HTML5 elements: 2348bb1c3e5SBram Moolenaarcall s:AddITags(s:indent_tags, [ 235d47d5223SBram Moolenaar \ 'article', 'aside', 'audio', 'bdi', 'canvas', 'command', 'data', 236d47d5223SBram Moolenaar \ 'datalist', 'details', 'dialog', 'embed', 'figcaption', 'figure', 237d47d5223SBram Moolenaar \ 'footer', 'header', 'hgroup', 'main', 'mark', 'meter', 'nav', 'output', 238d47d5223SBram Moolenaar \ 'picture', 'progress', 'rp', 'rt', 'ruby', 'section', 'summary', 239d47d5223SBram Moolenaar \ 'svg', 'time', 'video']) 240d8b77f7dSBram Moolenaar 241d8b77f7dSBram Moolenaar" Tags added for web components: 242d8b77f7dSBram Moolenaarcall s:AddITags(s:indent_tags, [ 243d8b77f7dSBram Moolenaar \ 'content', 'shadow', 'template']) 244ec7944aaSBram Moolenaar"}}} 2458bb1c3e5SBram Moolenaar 2468bb1c3e5SBram Moolenaar" Add Block Tags: these contain alien content 2478bb1c3e5SBram Moolenaar"{{{ 248ec7944aaSBram Moolenaarcall s:AddBlockTag('pre', 2) 249ec7944aaSBram Moolenaarcall s:AddBlockTag('script', 3) 250ec7944aaSBram Moolenaarcall s:AddBlockTag('style', 4) 251ec7944aaSBram Moolenaarcall s:AddBlockTag('<!--', 5, '-->') 252ca63501fSBram Moolenaarcall s:AddBlockTag('<!--[', 6, '![endif]-->') 253ec7944aaSBram Moolenaar"}}} 254ec7944aaSBram Moolenaar 2558bb1c3e5SBram Moolenaar" Return non-zero when "tagname" is an opening tag, not being a block tag, for 2568bb1c3e5SBram Moolenaar" which there should be a closing tag. Can be used by scripts that include 2578bb1c3e5SBram Moolenaar" HTML indenting. 258*2346a637SBram Moolenaarfunc HtmlIndent_IsOpenTag(tagname) 2598bb1c3e5SBram Moolenaar "{{{ 2608bb1c3e5SBram Moolenaar if get(s:indent_tags, a:tagname) == 1 2618bb1c3e5SBram Moolenaar return 1 262ec7944aaSBram Moolenaar endif 2638bb1c3e5SBram Moolenaar return get(b:hi_tags, a:tagname) == 1 2648bb1c3e5SBram Moolenaarendfunc "}}} 2658bb1c3e5SBram Moolenaar 2668bb1c3e5SBram Moolenaar" Get the value for "tagname", taking care of buffer-local tags. 267*2346a637SBram Moolenaarfunc s:get_tag(tagname) 2688bb1c3e5SBram Moolenaar "{{{ 2698bb1c3e5SBram Moolenaar let i = get(s:indent_tags, a:tagname) 2708bb1c3e5SBram Moolenaar if (i == 1 || i == -1) && get(b:hi_removed_tags, a:tagname) != 0 2718bb1c3e5SBram Moolenaar return 0 2728bb1c3e5SBram Moolenaar endif 2738bb1c3e5SBram Moolenaar if i == 0 2748bb1c3e5SBram Moolenaar let i = get(b:hi_tags, a:tagname) 2758bb1c3e5SBram Moolenaar endif 2768bb1c3e5SBram Moolenaar return i 2778bb1c3e5SBram Moolenaarendfunc "}}} 2788bb1c3e5SBram Moolenaar 2798bb1c3e5SBram Moolenaar" Count the number of start and end tags in "text". 280*2346a637SBram Moolenaarfunc s:CountITags(text) 2818bb1c3e5SBram Moolenaar "{{{ 2828bb1c3e5SBram Moolenaar " Store the result in s:curind and s:nextrel. 2838bb1c3e5SBram Moolenaar let s:curind = 0 " relative indent steps for current line [unit &sw]: 2848bb1c3e5SBram Moolenaar let s:nextrel = 0 " relative indent steps for next line [unit &sw]: 285ec7944aaSBram Moolenaar let s:block = 0 " assume starting outside of a block 286ec7944aaSBram Moolenaar let s:countonly = 1 " don't change state 287b5b75624SBram Moolenaar call substitute(a:text, '<\zs/\=' . s:tagname . '\>\|<!--\[\|\[endif\]-->\|<!--\|-->', '\=s:CheckTag(submatch(0))', 'g') 288ec7944aaSBram Moolenaar let s:countonly = 0 289ec7944aaSBram Moolenaarendfunc "}}} 2908bb1c3e5SBram Moolenaar 2918bb1c3e5SBram Moolenaar" Count the number of start and end tags in text. 292*2346a637SBram Moolenaarfunc s:CountTagsAndState(text) 2938bb1c3e5SBram Moolenaar "{{{ 2948bb1c3e5SBram Moolenaar " Store the result in s:curind and s:nextrel. Update b:hi_newstate.block. 2958bb1c3e5SBram Moolenaar let s:curind = 0 " relative indent steps for current line [unit &sw]: 2968bb1c3e5SBram Moolenaar let s:nextrel = 0 " relative indent steps for next line [unit &sw]: 2978bb1c3e5SBram Moolenaar 2988bb1c3e5SBram Moolenaar let s:block = b:hi_newstate.block 299b5b75624SBram Moolenaar let tmp = substitute(a:text, '<\zs/\=' . s:tagname . '\>\|<!--\[\|\[endif\]-->\|<!--\|-->', '\=s:CheckTag(submatch(0))', 'g') 3008bb1c3e5SBram Moolenaar if s:block == 3 3018bb1c3e5SBram Moolenaar let b:hi_newstate.scripttype = s:GetScriptType(matchstr(tmp, '\C.*<SCRIPT\>\zs[^>]*')) 3028bb1c3e5SBram Moolenaar endif 3038bb1c3e5SBram Moolenaar let b:hi_newstate.block = s:block 3048bb1c3e5SBram Moolenaarendfunc "}}} 3058bb1c3e5SBram Moolenaar 3068bb1c3e5SBram Moolenaar" Used by s:CountITags() and s:CountTagsAndState(). 307*2346a637SBram Moolenaarfunc s:CheckTag(itag) 3088bb1c3e5SBram Moolenaar "{{{ 3098bb1c3e5SBram Moolenaar " Returns an empty string or "SCRIPT". 3108bb1c3e5SBram Moolenaar " a:itag can be "tag" or "/tag" or "<!--" or "-->" 311d8b77f7dSBram Moolenaar if (s:CheckCustomTag(a:itag)) 312d8b77f7dSBram Moolenaar return "" 313d8b77f7dSBram Moolenaar endif 3148bb1c3e5SBram Moolenaar let ind = s:get_tag(a:itag) 315ec7944aaSBram Moolenaar if ind == -1 316ec7944aaSBram Moolenaar " closing tag 317ec7944aaSBram Moolenaar if s:block != 0 318ec7944aaSBram Moolenaar " ignore itag within a block 3198bb1c3e5SBram Moolenaar return "" 320ec7944aaSBram Moolenaar endif 321ec7944aaSBram Moolenaar if s:nextrel == 0 322ec7944aaSBram Moolenaar let s:curind -= 1 323ec7944aaSBram Moolenaar else 324ec7944aaSBram Moolenaar let s:nextrel -= 1 325ec7944aaSBram Moolenaar endif 326ec7944aaSBram Moolenaar elseif ind == 1 327ec7944aaSBram Moolenaar " opening tag 328ec7944aaSBram Moolenaar if s:block != 0 3298bb1c3e5SBram Moolenaar return "" 330ec7944aaSBram Moolenaar endif 331ec7944aaSBram Moolenaar let s:nextrel += 1 332ec7944aaSBram Moolenaar elseif ind != 0 333ec7944aaSBram Moolenaar " block-tag (opening or closing) 3348bb1c3e5SBram Moolenaar return s:CheckBlockTag(a:itag, ind) 335ec7944aaSBram Moolenaar " else ind==0 (other tag found): keep indent 3368bb1c3e5SBram Moolenaar endif 3378bb1c3e5SBram Moolenaar return "" 338ec7944aaSBram Moolenaarendfunc "}}} 3398bb1c3e5SBram Moolenaar 3408bb1c3e5SBram Moolenaar" Used by s:CheckTag(). Returns an empty string or "SCRIPT". 341*2346a637SBram Moolenaarfunc s:CheckBlockTag(blocktag, ind) 3428bb1c3e5SBram Moolenaar "{{{ 343ec7944aaSBram Moolenaar if a:ind > 0 344ec7944aaSBram Moolenaar " a block starts here 345ec7944aaSBram Moolenaar if s:block != 0 346ec7944aaSBram Moolenaar " already in a block (nesting) - ignore 347ec7944aaSBram Moolenaar " especially ignore comments after other blocktags 3488bb1c3e5SBram Moolenaar return "" 349ec7944aaSBram Moolenaar endif 350ec7944aaSBram Moolenaar let s:block = a:ind " block type 351ec7944aaSBram Moolenaar if s:countonly 3528bb1c3e5SBram Moolenaar return "" 353ec7944aaSBram Moolenaar endif 3548bb1c3e5SBram Moolenaar let b:hi_newstate.blocklnr = v:lnum 355ec7944aaSBram Moolenaar " save allover indent for the endtag 3563ec574f2SBram Moolenaar let b:hi_newstate.blocktagind = b:hi_indent.baseindent + (s:nextrel + s:curind) * shiftwidth() 357ec7944aaSBram Moolenaar if a:ind == 3 358ec7944aaSBram Moolenaar return "SCRIPT" " all except this must be lowercase 359ec7944aaSBram Moolenaar " line is to be checked again for the type attribute 360ec7944aaSBram Moolenaar endif 361ec7944aaSBram Moolenaar else 362ec7944aaSBram Moolenaar let s:block = 0 3638bb1c3e5SBram Moolenaar " we get here if starting and closing a block-tag on the same line 364ec7944aaSBram Moolenaar endif 3658bb1c3e5SBram Moolenaar return "" 366ec7944aaSBram Moolenaarendfunc "}}} 3678bb1c3e5SBram Moolenaar 368d8b77f7dSBram Moolenaar" Used by s:CheckTag(). 369*2346a637SBram Moolenaarfunc s:CheckCustomTag(ctag) 370d8b77f7dSBram Moolenaar "{{{ 371d8b77f7dSBram Moolenaar " Returns 1 if ctag is the tag for a custom element, 0 otherwise. 372d8b77f7dSBram Moolenaar " a:ctag can be "tag" or "/tag" or "<!--" or "-->" 373d8b77f7dSBram Moolenaar let pattern = '\%\(\w\+-\)\+\w\+' 374d8b77f7dSBram Moolenaar if match(a:ctag, pattern) == -1 375d8b77f7dSBram Moolenaar return 0 376d8b77f7dSBram Moolenaar endif 377d8b77f7dSBram Moolenaar if matchstr(a:ctag, '\/\ze.\+') == "/" 378d8b77f7dSBram Moolenaar " closing tag 379d8b77f7dSBram Moolenaar if s:block != 0 380d8b77f7dSBram Moolenaar " ignore ctag within a block 381d8b77f7dSBram Moolenaar return 1 382d8b77f7dSBram Moolenaar endif 383d8b77f7dSBram Moolenaar if s:nextrel == 0 384d8b77f7dSBram Moolenaar let s:curind -= 1 385d8b77f7dSBram Moolenaar else 386d8b77f7dSBram Moolenaar let s:nextrel -= 1 387d8b77f7dSBram Moolenaar endif 388d8b77f7dSBram Moolenaar else 389d8b77f7dSBram Moolenaar " opening tag 390d8b77f7dSBram Moolenaar if s:block != 0 391d8b77f7dSBram Moolenaar return 1 392d8b77f7dSBram Moolenaar endif 393d8b77f7dSBram Moolenaar let s:nextrel += 1 394d8b77f7dSBram Moolenaar endif 395d8b77f7dSBram Moolenaar return 1 396d8b77f7dSBram Moolenaarendfunc "}}} 397d8b77f7dSBram Moolenaar 3988bb1c3e5SBram Moolenaar" Return the <script> type: either "javascript" or "" 399*2346a637SBram Moolenaarfunc s:GetScriptType(str) 4008bb1c3e5SBram Moolenaar "{{{ 401ec7944aaSBram Moolenaar if a:str == "" || a:str =~ "java" 402ec7944aaSBram Moolenaar return "javascript" 403ec7944aaSBram Moolenaar else 404ec7944aaSBram Moolenaar return "" 405ec7944aaSBram Moolenaar endif 406ec7944aaSBram Moolenaarendfunc "}}} 407ec7944aaSBram Moolenaar 4088bb1c3e5SBram Moolenaar" Look back in the file, starting at a:lnum - 1, to compute a state for the 4098bb1c3e5SBram Moolenaar" start of line a:lnum. Return the new state. 410*2346a637SBram Moolenaarfunc s:FreshState(lnum) 4118bb1c3e5SBram Moolenaar "{{{ 4128bb1c3e5SBram Moolenaar " A state is to know ALL relevant details about the 4138bb1c3e5SBram Moolenaar " lines 1..a:lnum-1, initial calculating (here!) can be slow, but updating is 414ec7944aaSBram Moolenaar " fast (incremental). 4158bb1c3e5SBram Moolenaar " TODO: this should be split up in detecting the block type and computing the 4168bb1c3e5SBram Moolenaar " indent for the block type, so that when we do not know the indent we do 4178bb1c3e5SBram Moolenaar " not need to clear the whole state and re-detect the block type again. 418ec7944aaSBram Moolenaar " State: 419ec7944aaSBram Moolenaar " lnum last indented line == prevnonblank(a:lnum - 1) 420ec7944aaSBram Moolenaar " block = 0 a:lnum located within special tag: 0:none, 2:<pre>, 421ca63501fSBram Moolenaar " 3:<script>, 4:<style>, 5:<!--, 6:<!--[ 422ec7944aaSBram Moolenaar " baseindent use this indent for line a:lnum as a start - kind of 423ec7944aaSBram Moolenaar " autoindent (if block==0) 424ec7944aaSBram Moolenaar " scripttype = '' type attribute of a script tag (if block==3) 425ec7944aaSBram Moolenaar " blocktagind indent for current opening (get) and closing (set) 426ec7944aaSBram Moolenaar " blocktag (if block!=0) 427ec7944aaSBram Moolenaar " blocklnr lnum of starting blocktag (if block!=0) 428ec7944aaSBram Moolenaar " inattr line {lnum} starts with attributes of a tag 429ec7944aaSBram Moolenaar let state = {} 430ec7944aaSBram Moolenaar let state.lnum = prevnonblank(a:lnum - 1) 431ec7944aaSBram Moolenaar let state.scripttype = "" 432ec7944aaSBram Moolenaar let state.blocktagind = -1 433ec7944aaSBram Moolenaar let state.block = 0 434ec7944aaSBram Moolenaar let state.baseindent = 0 435ec7944aaSBram Moolenaar let state.blocklnr = 0 436ec7944aaSBram Moolenaar let state.inattr = 0 437ec7944aaSBram Moolenaar 438ec7944aaSBram Moolenaar if state.lnum == 0 439ec7944aaSBram Moolenaar return state 440ec7944aaSBram Moolenaar endif 441ec7944aaSBram Moolenaar 442ec7944aaSBram Moolenaar " Heuristic: 443ec7944aaSBram Moolenaar " remember startline state.lnum 444ec7944aaSBram Moolenaar " look back for <pre, </pre, <script, </script, <style, </style tags 445ec7944aaSBram Moolenaar " remember stopline 446ec7944aaSBram Moolenaar " if opening tag found, 447ec7944aaSBram Moolenaar " assume a:lnum within block 448ec7944aaSBram Moolenaar " else 449ec7944aaSBram Moolenaar " look back in result range (stopline, startline) for comment 450ec7944aaSBram Moolenaar " \ delimiters (<!--, -->) 451ec7944aaSBram Moolenaar " if comment opener found, 452ec7944aaSBram Moolenaar " assume a:lnum within comment 453ec7944aaSBram Moolenaar " else 454ec7944aaSBram Moolenaar " assume usual html for a:lnum 455ec7944aaSBram Moolenaar " if a:lnum-1 has a closing comment 456ec7944aaSBram Moolenaar " look back to get indent of comment opener 457ec7944aaSBram Moolenaar " FI 458ec7944aaSBram Moolenaar 4598bb1c3e5SBram Moolenaar " look back for a blocktag 460ca63501fSBram Moolenaar let stopline2 = v:lnum + 1 461ca63501fSBram Moolenaar if has_key(b:hi_indent, 'block') && b:hi_indent.block > 5 462ca63501fSBram Moolenaar let [stopline2, stopcol2] = searchpos('<!--', 'bnW') 463ca63501fSBram Moolenaar endif 464ca63501fSBram Moolenaar let [stopline, stopcol] = searchpos('\c<\zs\/\=\%(pre\>\|script\>\|style\>\)', "bnW") 465ca63501fSBram Moolenaar if stopline > 0 && stopline < stopline2 466ca63501fSBram Moolenaar " ugly ... why isn't there searchstr() 467ec7944aaSBram Moolenaar let tagline = tolower(getline(stopline)) 468ec7944aaSBram Moolenaar let blocktag = matchstr(tagline, '\/\=\%(pre\>\|script\>\|style\>\)', stopcol - 1) 4698bb1c3e5SBram Moolenaar if blocktag[0] != "/" 470ec7944aaSBram Moolenaar " opening tag found, assume a:lnum within block 471ec7944aaSBram Moolenaar let state.block = s:indent_tags[blocktag] 472ec7944aaSBram Moolenaar if state.block == 3 473ec7944aaSBram Moolenaar let state.scripttype = s:GetScriptType(matchstr(tagline, '\>[^>]*', stopcol)) 474ec7944aaSBram Moolenaar endif 475ec7944aaSBram Moolenaar let state.blocklnr = stopline 476ec7944aaSBram Moolenaar " check preceding tags in the line: 4778bb1c3e5SBram Moolenaar call s:CountITags(tagline[: stopcol-2]) 4783ec574f2SBram Moolenaar let state.blocktagind = indent(stopline) + (s:curind + s:nextrel) * shiftwidth() 479ec7944aaSBram Moolenaar return state 480ec7944aaSBram Moolenaar elseif stopline == state.lnum 481ec7944aaSBram Moolenaar " handle special case: previous line (= state.lnum) contains a 482ec7944aaSBram Moolenaar " closing blocktag which is preceded by line-noise; 483ec7944aaSBram Moolenaar " blocktag == "/..." 484ec7944aaSBram Moolenaar let swendtag = match(tagline, '^\s*</') >= 0 485ec7944aaSBram Moolenaar if !swendtag 486ca63501fSBram Moolenaar let [bline, bcol] = searchpos('<'.blocktag[1:].'\>', "bnW") 4878bb1c3e5SBram Moolenaar call s:CountITags(tolower(getline(bline)[: bcol-2])) 4883ec574f2SBram Moolenaar let state.baseindent = indent(bline) + (s:curind + s:nextrel) * shiftwidth() 489ec7944aaSBram Moolenaar return state 490ec7944aaSBram Moolenaar endif 491ec7944aaSBram Moolenaar endif 4928bb1c3e5SBram Moolenaar endif 493ca63501fSBram Moolenaar if stopline > stopline2 494ca63501fSBram Moolenaar let stopline = stopline2 495ca63501fSBram Moolenaar let stopcol = stopcol2 496ca63501fSBram Moolenaar endif 497ec7944aaSBram Moolenaar 498ec7944aaSBram Moolenaar " else look back for comment 499ca63501fSBram Moolenaar let [comlnum, comcol, found] = searchpos('\(<!--\[\)\|\(<!--\)\|-->', 'bpnW', stopline) 500ca63501fSBram Moolenaar if found == 2 || found == 3 501ec7944aaSBram Moolenaar " comment opener found, assume a:lnum within comment 502ca63501fSBram Moolenaar let state.block = (found == 3 ? 5 : 6) 5038bb1c3e5SBram Moolenaar let state.blocklnr = comlnum 504ec7944aaSBram Moolenaar " check preceding tags in the line: 5058bb1c3e5SBram Moolenaar call s:CountITags(tolower(getline(comlnum)[: comcol-2])) 506ca63501fSBram Moolenaar if found == 2 507ca63501fSBram Moolenaar let state.baseindent = b:hi_indent.baseindent 508ca63501fSBram Moolenaar endif 5093ec574f2SBram Moolenaar let state.blocktagind = indent(comlnum) + (s:curind + s:nextrel) * shiftwidth() 510ec7944aaSBram Moolenaar return state 511ec7944aaSBram Moolenaar endif 512ec7944aaSBram Moolenaar 5138bb1c3e5SBram Moolenaar " else within usual HTML 5148bb1c3e5SBram Moolenaar let text = tolower(getline(state.lnum)) 515946e27abSBram Moolenaar 5168bb1c3e5SBram Moolenaar " Check a:lnum-1 for closing comment (we need indent from the opening line). 5178bb1c3e5SBram Moolenaar " Not when other tags follow (might be --> inside a string). 5188bb1c3e5SBram Moolenaar let comcol = stridx(text, '-->') 5198bb1c3e5SBram Moolenaar if comcol >= 0 && match(text, '[<>]', comcol) <= 0 520ec7944aaSBram Moolenaar call cursor(state.lnum, comcol + 1) 5218bb1c3e5SBram Moolenaar let [comlnum, comcol] = searchpos('<!--', 'bW') 5228bb1c3e5SBram Moolenaar if comlnum == state.lnum 5238bb1c3e5SBram Moolenaar let text = text[: comcol-2] 524ec7944aaSBram Moolenaar else 5258bb1c3e5SBram Moolenaar let text = tolower(getline(comlnum)[: comcol-2]) 526ec7944aaSBram Moolenaar endif 5278bb1c3e5SBram Moolenaar call s:CountITags(text) 5283ec574f2SBram Moolenaar let state.baseindent = indent(comlnum) + (s:curind + s:nextrel) * shiftwidth() 529ec7944aaSBram Moolenaar " TODO check tags that follow "-->" 5308bb1c3e5SBram Moolenaar return state 531ec7944aaSBram Moolenaar endif 532ec7944aaSBram Moolenaar 533946e27abSBram Moolenaar " Check if the previous line starts with end tag. 5348bb1c3e5SBram Moolenaar let swendtag = match(text, '^\s*</') >= 0 535946e27abSBram Moolenaar 536946e27abSBram Moolenaar " If previous line ended in a closing tag, line up with the opening tag. 537b5b75624SBram Moolenaar if !swendtag && text =~ '</' . s:tagname . '\s*>\s*$' 538946e27abSBram Moolenaar call cursor(state.lnum, 99999) 5397b61a546SBram Moolenaar normal! F< 5408bb1c3e5SBram Moolenaar let start_lnum = HtmlIndent_FindStartTag() 5418bb1c3e5SBram Moolenaar if start_lnum > 0 5428bb1c3e5SBram Moolenaar let state.baseindent = indent(start_lnum) 5438bb1c3e5SBram Moolenaar if col('.') > 2 5448bb1c3e5SBram Moolenaar " check for tags before the matching opening tag. 5458bb1c3e5SBram Moolenaar let text = getline(start_lnum) 5468bb1c3e5SBram Moolenaar let swendtag = match(text, '^\s*</') >= 0 5478bb1c3e5SBram Moolenaar call s:CountITags(text[: col('.') - 2]) 5483ec574f2SBram Moolenaar let state.baseindent += s:nextrel * shiftwidth() 5498bb1c3e5SBram Moolenaar if !swendtag 5503ec574f2SBram Moolenaar let state.baseindent += s:curind * shiftwidth() 5518bb1c3e5SBram Moolenaar endif 5528bb1c3e5SBram Moolenaar endif 553946e27abSBram Moolenaar return state 554946e27abSBram Moolenaar endif 555946e27abSBram Moolenaar endif 556946e27abSBram Moolenaar 5578bb1c3e5SBram Moolenaar " Else: no comments. Skip backwards to find the tag we're inside. 5588bb1c3e5SBram Moolenaar let [state.lnum, found] = HtmlIndent_FindTagStart(state.lnum) 5598bb1c3e5SBram Moolenaar " Check if that line starts with end tag. 5608bb1c3e5SBram Moolenaar let text = getline(state.lnum) 5618bb1c3e5SBram Moolenaar let swendtag = match(text, '^\s*</') >= 0 5628bb1c3e5SBram Moolenaar call s:CountITags(tolower(text)) 5633ec574f2SBram Moolenaar let state.baseindent = indent(state.lnum) + s:nextrel * shiftwidth() 564ec7944aaSBram Moolenaar if !swendtag 5653ec574f2SBram Moolenaar let state.baseindent += s:curind * shiftwidth() 566ec7944aaSBram Moolenaar endif 567ec7944aaSBram Moolenaar return state 568ec7944aaSBram Moolenaarendfunc "}}} 569ec7944aaSBram Moolenaar 5708bb1c3e5SBram Moolenaar" Indent inside a <pre> block: Keep indent as-is. 571*2346a637SBram Moolenaarfunc s:Alien2() 5728bb1c3e5SBram Moolenaar "{{{ 573ec7944aaSBram Moolenaar return -1 574ec7944aaSBram Moolenaarendfunc "}}} 5758bb1c3e5SBram Moolenaar 5768bb1c3e5SBram Moolenaar" Return the indent inside a <script> block for javascript. 577*2346a637SBram Moolenaarfunc s:Alien3() 5788bb1c3e5SBram Moolenaar "{{{ 5798bb1c3e5SBram Moolenaar let lnum = prevnonblank(v:lnum - 1) 5808bb1c3e5SBram Moolenaar while lnum > 1 && getline(lnum) =~ '^\s*/[/*]' 5818bb1c3e5SBram Moolenaar " Skip over comments to avoid that cindent() aligns with the <script> tag 5828bb1c3e5SBram Moolenaar let lnum = prevnonblank(lnum - 1) 5838bb1c3e5SBram Moolenaar endwhile 584*2346a637SBram Moolenaar if lnum < b:hi_indent.blocklnr 585*2346a637SBram Moolenaar " indent for <script> itself 586*2346a637SBram Moolenaar return b:hi_indent.blocktagind 587*2346a637SBram Moolenaar endif 5888bb1c3e5SBram Moolenaar if lnum == b:hi_indent.blocklnr 589ec7944aaSBram Moolenaar " indent for the first line after <script> 5908bb1c3e5SBram Moolenaar return eval(b:hi_js1indent) 591ec7944aaSBram Moolenaar endif 5928bb1c3e5SBram Moolenaar if b:hi_indent.scripttype == "javascript" 593*2346a637SBram Moolenaar " indent for further lines 5947ff78465SBram Moolenaar return eval(b:hi_js1indent) + GetJavascriptIndent() 595ec7944aaSBram Moolenaar else 596071d4279SBram Moolenaar return -1 597071d4279SBram Moolenaar endif 598ec7944aaSBram Moolenaarendfunc "}}} 5998bb1c3e5SBram Moolenaar 6008bb1c3e5SBram Moolenaar" Return the indent inside a <style> block. 601*2346a637SBram Moolenaarfunc s:Alien4() 6028bb1c3e5SBram Moolenaar "{{{ 6038bb1c3e5SBram Moolenaar if prevnonblank(v:lnum-1) == b:hi_indent.blocklnr 604ec7944aaSBram Moolenaar " indent for first content line 6058bb1c3e5SBram Moolenaar return eval(b:hi_css1indent) 60691170f8aSBram Moolenaar endif 607ec7944aaSBram Moolenaar return s:CSSIndent() 6088bb1c3e5SBram Moolenaarendfunc "}}} 609ec7944aaSBram Moolenaar 6108bb1c3e5SBram Moolenaar" Indending inside a <style> block. Returns the indent. 611*2346a637SBram Moolenaarfunc s:CSSIndent() 6128bb1c3e5SBram Moolenaar "{{{ 6138bb1c3e5SBram Moolenaar " This handles standard CSS and also Closure stylesheets where special lines 6148bb1c3e5SBram Moolenaar " start with @. 6158bb1c3e5SBram Moolenaar " When the line starts with '*' or the previous line starts with "/*" 6168bb1c3e5SBram Moolenaar " and does not end in "*/", use C indenting to format the comment. 6178bb1c3e5SBram Moolenaar " Adopted $VIMRUNTIME/indent/css.vim 6188bb1c3e5SBram Moolenaar let curtext = getline(v:lnum) 6198bb1c3e5SBram Moolenaar if curtext =~ '^\s*[*]' 6208bb1c3e5SBram Moolenaar \ || (v:lnum > 1 && getline(v:lnum - 1) =~ '\s*/\*' 6218bb1c3e5SBram Moolenaar \ && getline(v:lnum - 1) !~ '\*/\s*$') 622ec7944aaSBram Moolenaar return cindent(v:lnum) 623071d4279SBram Moolenaar endif 6248bb1c3e5SBram Moolenaar 6258bb1c3e5SBram Moolenaar let min_lnum = b:hi_indent.blocklnr 6268bb1c3e5SBram Moolenaar let prev_lnum = s:CssPrevNonComment(v:lnum - 1, min_lnum) 6278bb1c3e5SBram Moolenaar let [prev_lnum, found] = HtmlIndent_FindTagStart(prev_lnum) 6288bb1c3e5SBram Moolenaar if prev_lnum <= min_lnum 6298bb1c3e5SBram Moolenaar " Just below the <style> tag, indent for first content line after comments. 6308bb1c3e5SBram Moolenaar return eval(b:hi_css1indent) 631ec7944aaSBram Moolenaar endif 6328bb1c3e5SBram Moolenaar 633ba3ff539SBram Moolenaar " If the current line starts with "}" align with its match. 6348bb1c3e5SBram Moolenaar if curtext =~ '^\s*}' 6358bb1c3e5SBram Moolenaar call cursor(v:lnum, 1) 6368bb1c3e5SBram Moolenaar try 6378bb1c3e5SBram Moolenaar normal! % 6388bb1c3e5SBram Moolenaar " Found the matching "{", align with it after skipping unfinished lines. 6398bb1c3e5SBram Moolenaar let align_lnum = s:CssFirstUnfinished(line('.'), min_lnum) 6408bb1c3e5SBram Moolenaar return indent(align_lnum) 6418bb1c3e5SBram Moolenaar catch 6428bb1c3e5SBram Moolenaar " can't find it, try something else, but it's most likely going to be 6438bb1c3e5SBram Moolenaar " wrong 6448bb1c3e5SBram Moolenaar endtry 645ec7944aaSBram Moolenaar endif 6468bb1c3e5SBram Moolenaar 6478bb1c3e5SBram Moolenaar " add indent after { 6488bb1c3e5SBram Moolenaar let brace_counts = HtmlIndent_CountBraces(prev_lnum) 6493ec574f2SBram Moolenaar let extra = brace_counts.c_open * shiftwidth() 6508bb1c3e5SBram Moolenaar 6518bb1c3e5SBram Moolenaar let prev_text = getline(prev_lnum) 6528bb1c3e5SBram Moolenaar let below_end_brace = prev_text =~ '}\s*$' 6538bb1c3e5SBram Moolenaar 6548bb1c3e5SBram Moolenaar " Search back to align with the first line that's unfinished. 6558bb1c3e5SBram Moolenaar let align_lnum = s:CssFirstUnfinished(prev_lnum, min_lnum) 6568bb1c3e5SBram Moolenaar 6578bb1c3e5SBram Moolenaar " Handle continuation lines if aligning with previous line and not after a 6588bb1c3e5SBram Moolenaar " "}". 6598bb1c3e5SBram Moolenaar if extra == 0 && align_lnum == prev_lnum && !below_end_brace 6608bb1c3e5SBram Moolenaar let prev_hasfield = prev_text =~ '^\s*[a-zA-Z0-9-]\+:' 6618bb1c3e5SBram Moolenaar let prev_special = prev_text =~ '^\s*\(/\*\|@\)' 6628bb1c3e5SBram Moolenaar if curtext =~ '^\s*\(/\*\|@\)' 6638bb1c3e5SBram Moolenaar " if the current line is not a comment or starts with @ (used by template 6648bb1c3e5SBram Moolenaar " systems) reduce indent if previous line is a continuation line 6658bb1c3e5SBram Moolenaar if !prev_hasfield && !prev_special 6663ec574f2SBram Moolenaar let extra = -shiftwidth() 6678bb1c3e5SBram Moolenaar endif 6688bb1c3e5SBram Moolenaar else 6698bb1c3e5SBram Moolenaar let cur_hasfield = curtext =~ '^\s*[a-zA-Z0-9-]\+:' 6708bb1c3e5SBram Moolenaar let prev_unfinished = s:CssUnfinished(prev_text) 671fc65cabbSBram Moolenaar if prev_unfinished 6728bb1c3e5SBram Moolenaar " Continuation line has extra indent if the previous line was not a 6738bb1c3e5SBram Moolenaar " continuation line. 6743ec574f2SBram Moolenaar let extra = shiftwidth() 6758bb1c3e5SBram Moolenaar " Align with @if 6768bb1c3e5SBram Moolenaar if prev_text =~ '^\s*@if ' 6778bb1c3e5SBram Moolenaar let extra = 4 6788bb1c3e5SBram Moolenaar endif 6798bb1c3e5SBram Moolenaar elseif cur_hasfield && !prev_hasfield && !prev_special 6808bb1c3e5SBram Moolenaar " less indent below a continuation line 6813ec574f2SBram Moolenaar let extra = -shiftwidth() 6828bb1c3e5SBram Moolenaar endif 6838bb1c3e5SBram Moolenaar endif 6848bb1c3e5SBram Moolenaar endif 6858bb1c3e5SBram Moolenaar 6868bb1c3e5SBram Moolenaar if below_end_brace 6878bb1c3e5SBram Moolenaar " find matching {, if that line starts with @ it's not the start of a rule 6888bb1c3e5SBram Moolenaar " but something else from a template system 6898bb1c3e5SBram Moolenaar call cursor(prev_lnum, 1) 6908bb1c3e5SBram Moolenaar call search('}\s*$') 6918bb1c3e5SBram Moolenaar try 6928bb1c3e5SBram Moolenaar normal! % 6938bb1c3e5SBram Moolenaar " Found the matching "{", align with it. 6948bb1c3e5SBram Moolenaar let align_lnum = s:CssFirstUnfinished(line('.'), min_lnum) 6958bb1c3e5SBram Moolenaar let special = getline(align_lnum) =~ '^\s*@' 6968bb1c3e5SBram Moolenaar catch 6978bb1c3e5SBram Moolenaar let special = 0 6988bb1c3e5SBram Moolenaar endtry 6998bb1c3e5SBram Moolenaar if special 7008bb1c3e5SBram Moolenaar " do not reduce indent below @{ ... } 7018bb1c3e5SBram Moolenaar if extra < 0 7023ec574f2SBram Moolenaar let extra += shiftwidth() 7038bb1c3e5SBram Moolenaar endif 7048bb1c3e5SBram Moolenaar else 7053ec574f2SBram Moolenaar let extra -= (brace_counts.c_close - (prev_text =~ '^\s*}')) * shiftwidth() 7068bb1c3e5SBram Moolenaar endif 7078bb1c3e5SBram Moolenaar endif 7088bb1c3e5SBram Moolenaar 7098bb1c3e5SBram Moolenaar " if no extra indent yet... 7108bb1c3e5SBram Moolenaar if extra == 0 7118bb1c3e5SBram Moolenaar if brace_counts.p_open > brace_counts.p_close 7128bb1c3e5SBram Moolenaar " previous line has more ( than ): add a shiftwidth 7133ec574f2SBram Moolenaar let extra = shiftwidth() 7148bb1c3e5SBram Moolenaar elseif brace_counts.p_open < brace_counts.p_close 7158bb1c3e5SBram Moolenaar " previous line has more ) than (: subtract a shiftwidth 7163ec574f2SBram Moolenaar let extra = -shiftwidth() 7178bb1c3e5SBram Moolenaar endif 7188bb1c3e5SBram Moolenaar endif 7198bb1c3e5SBram Moolenaar 7208bb1c3e5SBram Moolenaar return indent(align_lnum) + extra 721ec7944aaSBram Moolenaarendfunc "}}} 7228bb1c3e5SBram Moolenaar 7238bb1c3e5SBram Moolenaar" Inside <style>: Whether a line is unfinished. 724fc65cabbSBram Moolenaar" tag: 725fc65cabbSBram Moolenaar" tag: blah 726fc65cabbSBram Moolenaar" tag: blah && 727fc65cabbSBram Moolenaar" tag: blah || 728*2346a637SBram Moolenaarfunc s:CssUnfinished(text) 7298bb1c3e5SBram Moolenaar "{{{ 730fc65cabbSBram Moolenaar return a:text =~ '\(||\|&&\|:\|\k\)\s*$' 7318bb1c3e5SBram Moolenaarendfunc "}}} 7328bb1c3e5SBram Moolenaar 7338bb1c3e5SBram Moolenaar" Search back for the first unfinished line above "lnum". 734*2346a637SBram Moolenaarfunc s:CssFirstUnfinished(lnum, min_lnum) 7358bb1c3e5SBram Moolenaar "{{{ 7368bb1c3e5SBram Moolenaar let align_lnum = a:lnum 7378bb1c3e5SBram Moolenaar while align_lnum > a:min_lnum && s:CssUnfinished(getline(align_lnum - 1)) 7388bb1c3e5SBram Moolenaar let align_lnum -= 1 7398bb1c3e5SBram Moolenaar endwhile 7408bb1c3e5SBram Moolenaar return align_lnum 7418bb1c3e5SBram Moolenaarendfunc "}}} 7428bb1c3e5SBram Moolenaar 7438bb1c3e5SBram Moolenaar" Find the non-empty line at or before "lnum" that is not a comment. 744*2346a637SBram Moolenaarfunc s:CssPrevNonComment(lnum, stopline) 7458bb1c3e5SBram Moolenaar "{{{ 7468bb1c3e5SBram Moolenaar " caller starts from a line a:lnum + 1 that is not a comment 747ec7944aaSBram Moolenaar let lnum = prevnonblank(a:lnum) 7488bb1c3e5SBram Moolenaar while 1 749ec7944aaSBram Moolenaar let ccol = match(getline(lnum), '\*/') 750ec7944aaSBram Moolenaar if ccol < 0 7513e496b0eSBram Moolenaar " No comment end thus it's something else. 752ec7944aaSBram Moolenaar return lnum 753ec7944aaSBram Moolenaar endif 754ec7944aaSBram Moolenaar call cursor(lnum, ccol + 1) 7558bb1c3e5SBram Moolenaar " Search back for the /* that starts the comment 756ec7944aaSBram Moolenaar let lnum = search('/\*', 'bW', a:stopline) 757ec7944aaSBram Moolenaar if indent(".") == virtcol(".") - 1 7588bb1c3e5SBram Moolenaar " The found /* is at the start of the line. Now go back to the line 7598bb1c3e5SBram Moolenaar " above it and again check if it is a comment. 7608bb1c3e5SBram Moolenaar let lnum = prevnonblank(lnum - 1) 761ec7944aaSBram Moolenaar else 7628bb1c3e5SBram Moolenaar " /* is after something else, thus it's not a comment line. 763ec7944aaSBram Moolenaar return lnum 764ec7944aaSBram Moolenaar endif 7658bb1c3e5SBram Moolenaar endwhile 766ec7944aaSBram Moolenaarendfunc "}}} 7678bb1c3e5SBram Moolenaar 7688bb1c3e5SBram Moolenaar" Check the number of {} and () in line "lnum". Return a dict with the counts. 769*2346a637SBram Moolenaarfunc HtmlIndent_CountBraces(lnum) 7708bb1c3e5SBram Moolenaar "{{{ 7718bb1c3e5SBram Moolenaar let brs = substitute(getline(a:lnum), '[''"].\{-}[''"]\|/\*.\{-}\*/\|/\*.*$\|[^{}()]', '', 'g') 7728bb1c3e5SBram Moolenaar let c_open = 0 7738bb1c3e5SBram Moolenaar let c_close = 0 7748bb1c3e5SBram Moolenaar let p_open = 0 7758bb1c3e5SBram Moolenaar let p_close = 0 776ec7944aaSBram Moolenaar for brace in split(brs, '\zs') 777ec7944aaSBram Moolenaar if brace == "{" 7788bb1c3e5SBram Moolenaar let c_open += 1 779ec7944aaSBram Moolenaar elseif brace == "}" 7808bb1c3e5SBram Moolenaar if c_open > 0 7818bb1c3e5SBram Moolenaar let c_open -= 1 782ec7944aaSBram Moolenaar else 7838bb1c3e5SBram Moolenaar let c_close += 1 7848bb1c3e5SBram Moolenaar endif 7858bb1c3e5SBram Moolenaar elseif brace == '(' 7868bb1c3e5SBram Moolenaar let p_open += 1 7878bb1c3e5SBram Moolenaar elseif brace == ')' 7888bb1c3e5SBram Moolenaar if p_open > 0 7898bb1c3e5SBram Moolenaar let p_open -= 1 7908bb1c3e5SBram Moolenaar else 7918bb1c3e5SBram Moolenaar let p_close += 1 792ec7944aaSBram Moolenaar endif 793ec7944aaSBram Moolenaar endif 794ec7944aaSBram Moolenaar endfor 7958bb1c3e5SBram Moolenaar return {'c_open': c_open, 7968bb1c3e5SBram Moolenaar \ 'c_close': c_close, 7978bb1c3e5SBram Moolenaar \ 'p_open': p_open, 7988bb1c3e5SBram Moolenaar \ 'p_close': p_close} 799ec7944aaSBram Moolenaarendfunc "}}} 800ec7944aaSBram Moolenaar 8018bb1c3e5SBram Moolenaar" Return the indent for a comment: <!-- --> 802*2346a637SBram Moolenaarfunc s:Alien5() 8038bb1c3e5SBram Moolenaar "{{{ 8048bb1c3e5SBram Moolenaar let curtext = getline(v:lnum) 8058bb1c3e5SBram Moolenaar if curtext =~ '^\s*\zs-->' 8068bb1c3e5SBram Moolenaar " current line starts with end of comment, line up with comment start. 8078bb1c3e5SBram Moolenaar call cursor(v:lnum, 0) 8088bb1c3e5SBram Moolenaar let lnum = search('<!--', 'b') 8098bb1c3e5SBram Moolenaar if lnum > 0 8108bb1c3e5SBram Moolenaar " TODO: what if <!-- is not at the start of the line? 8118bb1c3e5SBram Moolenaar return indent(lnum) 8128bb1c3e5SBram Moolenaar endif 8138bb1c3e5SBram Moolenaar 8148bb1c3e5SBram Moolenaar " Strange, can't find it. 8158bb1c3e5SBram Moolenaar return -1 8168bb1c3e5SBram Moolenaar endif 8178bb1c3e5SBram Moolenaar 8188bb1c3e5SBram Moolenaar let prevlnum = prevnonblank(v:lnum - 1) 8198bb1c3e5SBram Moolenaar let prevtext = getline(prevlnum) 8208bb1c3e5SBram Moolenaar let idx = match(prevtext, '^\s*\zs<!--') 8218bb1c3e5SBram Moolenaar if idx >= 0 8228bb1c3e5SBram Moolenaar " just below comment start, add a shiftwidth 8234072ba57SBram Moolenaar return indent(prevlnum) + shiftwidth() 8248bb1c3e5SBram Moolenaar endif 8258bb1c3e5SBram Moolenaar 8268bb1c3e5SBram Moolenaar " Some files add 4 spaces just below a TODO line. It's difficult to detect 8278bb1c3e5SBram Moolenaar " the end of the TODO, so let's not do that. 8288bb1c3e5SBram Moolenaar 8298bb1c3e5SBram Moolenaar " Align with the previous non-blank line. 8308bb1c3e5SBram Moolenaar return indent(prevlnum) 8318bb1c3e5SBram Moolenaarendfunc "}}} 8328bb1c3e5SBram Moolenaar 833ca63501fSBram Moolenaar" Return the indent for conditional comment: <!--[ ![endif]--> 834*2346a637SBram Moolenaarfunc s:Alien6() 835ca63501fSBram Moolenaar "{{{ 836ca63501fSBram Moolenaar let curtext = getline(v:lnum) 837ca63501fSBram Moolenaar if curtext =~ '\s*\zs<!\[endif\]-->' 838ca63501fSBram Moolenaar " current line starts with end of comment, line up with comment start. 839ca63501fSBram Moolenaar let lnum = search('<!--', 'bn') 840ca63501fSBram Moolenaar if lnum > 0 841ca63501fSBram Moolenaar return indent(lnum) 842ca63501fSBram Moolenaar endif 843ca63501fSBram Moolenaar endif 8443ec574f2SBram Moolenaar return b:hi_indent.baseindent + shiftwidth() 845ca63501fSBram Moolenaarendfunc "}}} 846ca63501fSBram Moolenaar 8478bb1c3e5SBram Moolenaar" When the "lnum" line ends in ">" find the line containing the matching "<". 848*2346a637SBram Moolenaarfunc HtmlIndent_FindTagStart(lnum) 8498bb1c3e5SBram Moolenaar "{{{ 8508bb1c3e5SBram Moolenaar " Avoids using the indent of a continuation line. 8518bb1c3e5SBram Moolenaar " Moves the cursor. 8528bb1c3e5SBram Moolenaar " Return two values: 8538bb1c3e5SBram Moolenaar " - the matching line number or "lnum". 8548bb1c3e5SBram Moolenaar " - a flag indicating whether we found the end of a tag. 8558bb1c3e5SBram Moolenaar " This method is global so that HTML-like indenters can use it. 8568bb1c3e5SBram Moolenaar " To avoid matching " > " or " < " inside a string require that the opening 8578bb1c3e5SBram Moolenaar " "<" is followed by a word character and the closing ">" comes after a 8588bb1c3e5SBram Moolenaar " non-white character. 8598bb1c3e5SBram Moolenaar let idx = match(getline(a:lnum), '\S>\s*$') 8608bb1c3e5SBram Moolenaar if idx > 0 8618bb1c3e5SBram Moolenaar call cursor(a:lnum, idx) 8628bb1c3e5SBram Moolenaar let lnum = searchpair('<\w', '' , '\S>', 'bW', '', max([a:lnum - b:html_indent_line_limit, 0])) 8638bb1c3e5SBram Moolenaar if lnum > 0 8648bb1c3e5SBram Moolenaar return [lnum, 1] 8658bb1c3e5SBram Moolenaar endif 8668bb1c3e5SBram Moolenaar endif 8678bb1c3e5SBram Moolenaar return [a:lnum, 0] 8688bb1c3e5SBram Moolenaarendfunc "}}} 8698bb1c3e5SBram Moolenaar 8708bb1c3e5SBram Moolenaar" Find the unclosed start tag from the current cursor position. 871*2346a637SBram Moolenaarfunc HtmlIndent_FindStartTag() 8728bb1c3e5SBram Moolenaar "{{{ 8738bb1c3e5SBram Moolenaar " The cursor must be on or before a closing tag. 8748bb1c3e5SBram Moolenaar " If found, positions the cursor at the match and returns the line number. 8758bb1c3e5SBram Moolenaar " Otherwise returns 0. 876b5b75624SBram Moolenaar let tagname = matchstr(getline('.')[col('.') - 1:], '</\zs' . s:tagname . '\ze') 8778bb1c3e5SBram Moolenaar let start_lnum = searchpair('<' . tagname . '\>', '', '</' . tagname . '\>', 'bW') 8788bb1c3e5SBram Moolenaar if start_lnum > 0 8798bb1c3e5SBram Moolenaar return start_lnum 8808bb1c3e5SBram Moolenaar endif 8818bb1c3e5SBram Moolenaar return 0 8828bb1c3e5SBram Moolenaarendfunc "}}} 8838bb1c3e5SBram Moolenaar 8848bb1c3e5SBram Moolenaar" Moves the cursor from a "<" to the matching ">". 885*2346a637SBram Moolenaarfunc HtmlIndent_FindTagEnd() 8868bb1c3e5SBram Moolenaar "{{{ 8878bb1c3e5SBram Moolenaar " Call this with the cursor on the "<" of a start tag. 8888bb1c3e5SBram Moolenaar " This will move the cursor to the ">" of the matching end tag or, when it's 8898bb1c3e5SBram Moolenaar " a self-closing tag, to the matching ">". 8908bb1c3e5SBram Moolenaar " Limited to look up to b:html_indent_line_limit lines away. 8918bb1c3e5SBram Moolenaar let text = getline('.') 892b5b75624SBram Moolenaar let tagname = matchstr(text, s:tagname . '\|!--', col('.')) 8938bb1c3e5SBram Moolenaar if tagname == '!--' 8948bb1c3e5SBram Moolenaar call search('--\zs>') 8958bb1c3e5SBram Moolenaar elseif s:get_tag('/' . tagname) != 0 8968bb1c3e5SBram Moolenaar " tag with a closing tag, find matching "</tag>" 8978bb1c3e5SBram Moolenaar call searchpair('<' . tagname, '', '</' . tagname . '\zs>', 'W', '', line('.') + b:html_indent_line_limit) 8988bb1c3e5SBram Moolenaar else 8998bb1c3e5SBram Moolenaar " self-closing tag, find the ">" 9008bb1c3e5SBram Moolenaar call search('\S\zs>') 9018bb1c3e5SBram Moolenaar endif 9028bb1c3e5SBram Moolenaarendfunc "}}} 9038bb1c3e5SBram Moolenaar 9048bb1c3e5SBram Moolenaar" Indenting inside a start tag. Return the correct indent or -1 if unknown. 905*2346a637SBram Moolenaarfunc s:InsideTag(foundHtmlString) 9068bb1c3e5SBram Moolenaar "{{{ 9078bb1c3e5SBram Moolenaar if a:foundHtmlString 9088bb1c3e5SBram Moolenaar " Inside an attribute string. 90963b74a83SBram Moolenaar " Align with the opening quote or use an external function. 9108bb1c3e5SBram Moolenaar let lnum = v:lnum - 1 9118bb1c3e5SBram Moolenaar if lnum > 1 9128bb1c3e5SBram Moolenaar if exists('b:html_indent_tag_string_func') 9138bb1c3e5SBram Moolenaar return b:html_indent_tag_string_func(lnum) 9148bb1c3e5SBram Moolenaar endif 91563b74a83SBram Moolenaar " If there is a double quote in the previous line, indent with the 91663b74a83SBram Moolenaar " character after it. 91763b74a83SBram Moolenaar if getline(lnum) =~ '"' 91863b74a83SBram Moolenaar call cursor(lnum, 0) 91963b74a83SBram Moolenaar normal f" 92063b74a83SBram Moolenaar return virtcol('.') 92163b74a83SBram Moolenaar endif 9228bb1c3e5SBram Moolenaar return indent(lnum) 9238bb1c3e5SBram Moolenaar endif 9248bb1c3e5SBram Moolenaar endif 9258bb1c3e5SBram Moolenaar 9268bb1c3e5SBram Moolenaar " Should be another attribute: " attr="val". Align with the previous 9278bb1c3e5SBram Moolenaar " attribute start. 9288bb1c3e5SBram Moolenaar let lnum = v:lnum 9298bb1c3e5SBram Moolenaar while lnum > 1 9308bb1c3e5SBram Moolenaar let lnum -= 1 9318bb1c3e5SBram Moolenaar let text = getline(lnum) 9328bb1c3e5SBram Moolenaar " Find a match with one of these, align with "attr": 9338bb1c3e5SBram Moolenaar " attr= 9348bb1c3e5SBram Moolenaar " <tag attr= 9358bb1c3e5SBram Moolenaar " text<tag attr= 9368bb1c3e5SBram Moolenaar " <tag>text</tag>text<tag attr= 9378bb1c3e5SBram Moolenaar " For long lines search for the first match, finding the last match 9388bb1c3e5SBram Moolenaar " gets very slow. 9398bb1c3e5SBram Moolenaar if len(text) < 300 9408bb1c3e5SBram Moolenaar let idx = match(text, '.*\s\zs[_a-zA-Z0-9-]\+="') 9418bb1c3e5SBram Moolenaar else 9428bb1c3e5SBram Moolenaar let idx = match(text, '\s\zs[_a-zA-Z0-9-]\+="') 9438bb1c3e5SBram Moolenaar endif 944b5b75624SBram Moolenaar if idx == -1 945b5b75624SBram Moolenaar " try <tag attr 946b5b75624SBram Moolenaar let idx = match(text, '<' . s:tagname . '\s\+\zs\w') 947b5b75624SBram Moolenaar endif 948b5b75624SBram Moolenaar if idx == -1 949942db23cSBram Moolenaar " after just "<tag" indent two levels more 950b5b75624SBram Moolenaar let idx = match(text, '<' . s:tagname . '$') 951b5b75624SBram Moolenaar if idx >= 0 952942db23cSBram Moolenaar call cursor(lnum, idx + 1) 953942db23cSBram Moolenaar return virtcol('.') - 1 + shiftwidth() * 2 954b5b75624SBram Moolenaar endif 955b5b75624SBram Moolenaar endif 9568bb1c3e5SBram Moolenaar if idx > 0 957b5b75624SBram Moolenaar " Found the attribute to align with. 958b5b75624SBram Moolenaar call cursor(lnum, idx) 959b5b75624SBram Moolenaar return virtcol('.') 9608bb1c3e5SBram Moolenaar endif 9618bb1c3e5SBram Moolenaar endwhile 962ec7944aaSBram Moolenaar return -1 963ec7944aaSBram Moolenaarendfunc "}}} 964ec7944aaSBram Moolenaar 9658bb1c3e5SBram Moolenaar" THE MAIN INDENT FUNCTION. Return the amount of indent for v:lnum. 966*2346a637SBram Moolenaarfunc HtmlIndent() 9678bb1c3e5SBram Moolenaar "{{{ 9689da7ff70SBram Moolenaar if prevnonblank(v:lnum - 1) < 1 9698bb1c3e5SBram Moolenaar " First non-blank line has no indent. 9708bb1c3e5SBram Moolenaar return 0 971946e27abSBram Moolenaar endif 972946e27abSBram Moolenaar 9738bb1c3e5SBram Moolenaar let curtext = tolower(getline(v:lnum)) 9743ec574f2SBram Moolenaar let indentunit = shiftwidth() 975ec7944aaSBram Moolenaar 9768bb1c3e5SBram Moolenaar let b:hi_newstate = {} 9778bb1c3e5SBram Moolenaar let b:hi_newstate.lnum = v:lnum 9788bb1c3e5SBram Moolenaar 9798bb1c3e5SBram Moolenaar " When syntax HL is enabled, detect we are inside a tag. Indenting inside 9808bb1c3e5SBram Moolenaar " a tag works very differently. Do not do this when the line starts with 9818bb1c3e5SBram Moolenaar " "<", it gets the "htmlTag" ID but we are not inside a tag then. 9828bb1c3e5SBram Moolenaar if curtext !~ '^\s*<' 9837b61a546SBram Moolenaar normal! ^ 9848bb1c3e5SBram Moolenaar let stack = synstack(v:lnum, col('.')) " assumes there are no tabs 9858bb1c3e5SBram Moolenaar let foundHtmlString = 0 9868bb1c3e5SBram Moolenaar for synid in reverse(stack) 9878bb1c3e5SBram Moolenaar let name = synIDattr(synid, "name") 9888bb1c3e5SBram Moolenaar if index(b:hi_insideStringNames, name) >= 0 9898bb1c3e5SBram Moolenaar let foundHtmlString = 1 9908bb1c3e5SBram Moolenaar elseif index(b:hi_insideTagNames, name) >= 0 9918bb1c3e5SBram Moolenaar " Yes, we are inside a tag. 9928bb1c3e5SBram Moolenaar let indent = s:InsideTag(foundHtmlString) 9938bb1c3e5SBram Moolenaar if indent >= 0 9948bb1c3e5SBram Moolenaar " Do not keep the state. TODO: could keep the block type. 9958bb1c3e5SBram Moolenaar let b:hi_indent.lnum = 0 9968bb1c3e5SBram Moolenaar return indent 9978bb1c3e5SBram Moolenaar endif 9988bb1c3e5SBram Moolenaar endif 9998bb1c3e5SBram Moolenaar endfor 10008bb1c3e5SBram Moolenaar endif 1001ec7944aaSBram Moolenaar 100252b91d80SBram Moolenaar " does the line start with a closing tag? 10038bb1c3e5SBram Moolenaar let swendtag = match(curtext, '^\s*</') >= 0 1004ec7944aaSBram Moolenaar 10058bb1c3e5SBram Moolenaar if prevnonblank(v:lnum - 1) == b:hi_indent.lnum && b:hi_lasttick == b:changedtick - 1 1006ec7944aaSBram Moolenaar " use state (continue from previous line) 1007ec7944aaSBram Moolenaar else 1008ec7944aaSBram Moolenaar " start over (know nothing) 10098bb1c3e5SBram Moolenaar let b:hi_indent = s:FreshState(v:lnum) 1010071d4279SBram Moolenaar endif 1011071d4279SBram Moolenaar 10128bb1c3e5SBram Moolenaar if b:hi_indent.block >= 2 1013ec7944aaSBram Moolenaar " within block 10148bb1c3e5SBram Moolenaar let endtag = s:endtags[b:hi_indent.block] 10158bb1c3e5SBram Moolenaar let blockend = stridx(curtext, endtag) 1016ec7944aaSBram Moolenaar if blockend >= 0 1017ec7944aaSBram Moolenaar " block ends here 10188bb1c3e5SBram Moolenaar let b:hi_newstate.block = 0 1019ec7944aaSBram Moolenaar " calc indent for REST OF LINE (may start more blocks): 10208bb1c3e5SBram Moolenaar call s:CountTagsAndState(strpart(curtext, blockend + strlen(endtag))) 10218bb1c3e5SBram Moolenaar if swendtag && b:hi_indent.block != 5 10228bb1c3e5SBram Moolenaar let indent = b:hi_indent.blocktagind + s:curind * indentunit 10238bb1c3e5SBram Moolenaar let b:hi_newstate.baseindent = indent + s:nextrel * indentunit 1024ec7944aaSBram Moolenaar else 10258bb1c3e5SBram Moolenaar let indent = s:Alien{b:hi_indent.block}() 10268bb1c3e5SBram Moolenaar let b:hi_newstate.baseindent = b:hi_indent.blocktagind + s:nextrel * indentunit 102791170f8aSBram Moolenaar endif 1028ec7944aaSBram Moolenaar else 1029ec7944aaSBram Moolenaar " block continues 1030ec7944aaSBram Moolenaar " indent this line with alien method 10318bb1c3e5SBram Moolenaar let indent = s:Alien{b:hi_indent.block}() 1032071d4279SBram Moolenaar endif 1033ec7944aaSBram Moolenaar else 1034ec7944aaSBram Moolenaar " not within a block - within usual html 10358bb1c3e5SBram Moolenaar let b:hi_newstate.block = b:hi_indent.block 1036ec7944aaSBram Moolenaar if swendtag 10378bb1c3e5SBram Moolenaar " The current line starts with an end tag, align with its start tag. 10388bb1c3e5SBram Moolenaar call cursor(v:lnum, 1) 10398bb1c3e5SBram Moolenaar let start_lnum = HtmlIndent_FindStartTag() 10408bb1c3e5SBram Moolenaar if start_lnum > 0 10418bb1c3e5SBram Moolenaar " check for the line starting with something inside a tag: 10428bb1c3e5SBram Moolenaar " <sometag <- align here 10438bb1c3e5SBram Moolenaar " attr=val><open> not here 10448bb1c3e5SBram Moolenaar let text = getline(start_lnum) 10458bb1c3e5SBram Moolenaar let angle = matchstr(text, '[<>]') 10468bb1c3e5SBram Moolenaar if angle == '>' 10478bb1c3e5SBram Moolenaar call cursor(start_lnum, 1) 10488bb1c3e5SBram Moolenaar normal! f>% 10498bb1c3e5SBram Moolenaar let start_lnum = line('.') 10508bb1c3e5SBram Moolenaar let text = getline(start_lnum) 1051ec7944aaSBram Moolenaar endif 1052071d4279SBram Moolenaar 10538bb1c3e5SBram Moolenaar let indent = indent(start_lnum) 10548bb1c3e5SBram Moolenaar if col('.') > 2 10558bb1c3e5SBram Moolenaar let swendtag = match(text, '^\s*</') >= 0 10568bb1c3e5SBram Moolenaar call s:CountITags(text[: col('.') - 2]) 10573ec574f2SBram Moolenaar let indent += s:nextrel * shiftwidth() 10588bb1c3e5SBram Moolenaar if !swendtag 10593ec574f2SBram Moolenaar let indent += s:curind * shiftwidth() 10608bb1c3e5SBram Moolenaar endif 10618bb1c3e5SBram Moolenaar endif 10628bb1c3e5SBram Moolenaar else 10638bb1c3e5SBram Moolenaar " not sure what to do 10648bb1c3e5SBram Moolenaar let indent = b:hi_indent.baseindent 10658bb1c3e5SBram Moolenaar endif 10668bb1c3e5SBram Moolenaar let b:hi_newstate.baseindent = indent 10678bb1c3e5SBram Moolenaar else 10688bb1c3e5SBram Moolenaar call s:CountTagsAndState(curtext) 10698bb1c3e5SBram Moolenaar let indent = b:hi_indent.baseindent 10708bb1c3e5SBram Moolenaar let b:hi_newstate.baseindent = indent + (s:curind + s:nextrel) * indentunit 10718bb1c3e5SBram Moolenaar endif 10728bb1c3e5SBram Moolenaar endif 10738bb1c3e5SBram Moolenaar 10748bb1c3e5SBram Moolenaar let b:hi_lasttick = b:changedtick 10758bb1c3e5SBram Moolenaar call extend(b:hi_indent, b:hi_newstate, "force") 10768bb1c3e5SBram Moolenaar return indent 1077ec7944aaSBram Moolenaarendfunc "}}} 1078071d4279SBram Moolenaar 10798bb1c3e5SBram Moolenaar" Check user settings when loading this script the first time. 1080ec7944aaSBram Moolenaarcall HtmlIndent_CheckUserSettings() 1081071d4279SBram Moolenaar 108291170f8aSBram Moolenaarlet &cpo = s:cpo_save 108391170f8aSBram Moolenaarunlet s:cpo_save 108491170f8aSBram Moolenaar 10858bb1c3e5SBram Moolenaar" vim: fdm=marker ts=8 sw=2 tw=78 1086