Advertisement
Guest User

html.vim on Ubuntu 13.10

a guest
Dec 18th, 2013
235
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
VIM 14.96 KB | None | 0 0
  1. " Vim indent script for HTML
  2. " General: "{{{
  3. " File:     html.vim (Vimscript #2075)
  4. " Author:   Andy Wokula <anwoku@yahoo.de>
  5. " Last Change:  2013 Jun 12
  6. " Rev Days:     13
  7. " Version:  0.9
  8. " Vim Version:  Vim7
  9. " Description:
  10. "   Improved version of the distributed html indent script, faster on a
  11. "   range of lines.
  12. "
  13. " Credits:
  14. "   indent/html.vim (2006 Jun 05) from J. Zellner
  15. "   indent/css.vim (2006 Dec 20) from N. Weibull
  16. "
  17. " History:
  18. " 2012 Oct 21   (v0.9) added support for shiftwidth()
  19. " 2011 Sep 09   (v0.8) added HTML5 tags (thx to J. Zuckerman)
  20. " 2008 Apr 28   (v0.6) revised customization
  21. " 2008 Mar 09   (v0.5) fixed 'indk' issue (thx to C.J. Robinson)
  22. " }}}
  23.  
  24. " Init Folklore, check user settings (2nd time ++) "{{{
  25. if exists("b:did_indent")
  26.     finish
  27. endif
  28. let b:did_indent = 1
  29.  
  30. setlocal indentexpr=HtmlIndent()
  31. setlocal indentkeys=o,O,<Return>,<>>,{,},!^F
  32.  
  33. let b:indent = {"lnum": -1}
  34. let b:undo_indent = "set inde< indk<| unlet b:indent"
  35.  
  36. " Load Once:
  37. if exists("*HtmlIndent")
  38.     call HtmlIndent_CheckUserSettings()
  39.     finish
  40. endif
  41.  
  42. " Patch 7.3.694
  43. if exists('*shiftwidth')
  44.     let s:ShiftWidth = function('shiftwidth')
  45. else
  46.     func! s:ShiftWidth()
  47.     return &shiftwidth
  48.     endfunc
  49. endif
  50.  
  51. let s:cpo_save = &cpo
  52. set cpo-=C
  53. "}}}
  54.  
  55. func! HtmlIndent_CheckUserSettings() "{{{
  56.     if exists("g:html_indent_inctags")
  57.     call s:AddITags(split(g:html_indent_inctags, ","))
  58.     endif
  59.     if exists("g:html_indent_autotags")
  60.     call s:RemoveITags(split(g:html_indent_autotags, ","))
  61.     endif
  62.  
  63.     let indone = {"zero": 0
  64.         \,"auto": "indent(prevnonblank(v:lnum-1))"
  65.         \,"inc": "b:indent.blocktagind + s:ShiftWidth()"}
  66.     if exists("g:html_indent_script1")
  67.     let s:js1indent = get(indone, g:html_indent_script1, indone.zero)
  68.     endif
  69.     if exists("g:html_indent_style1")
  70.     let s:css1indent = get(indone, g:html_indent_style1, indone.zero)
  71.     endif
  72. endfunc "}}}
  73.  
  74. " Init Script Vars  "{{{
  75. let s:usestate = 1
  76. let s:css1indent = 0
  77. let s:js1indent = 0
  78. " not to be changed:
  79. let s:endtags = [0,0,0,0,0,0,0,0]   " some places unused
  80. let s:newstate = {}
  81. let s:countonly = 0
  82.  "}}}
  83. func! s:AddITags(taglist) "{{{
  84.     for itag in a:taglist
  85.     let s:indent_tags[itag] = 1
  86.     let s:indent_tags['/'.itag] = -1
  87.     endfor
  88. endfunc "}}}
  89. func! s:AddBlockTag(tag, id, ...) "{{{
  90.     if !(a:id >= 2 && a:id < 2+len(s:endtags))
  91.     return
  92.     endif
  93.     let s:indent_tags[a:tag] = a:id
  94.     if a:0 == 0
  95.     let s:indent_tags['/'.a:tag] = -a:id
  96.     let s:endtags[a:id-2] = "</".a:tag.">"
  97.     else
  98.     let s:indent_tags[a:1] = -a:id
  99.     let s:endtags[a:id-2] = a:1
  100.     endif
  101. endfunc "}}}
  102. func! s:RemoveITags(taglist) "{{{
  103.     " remove itags (protect blocktags from being removed)
  104.     for itag in a:taglist
  105.     if !has_key(s:indent_tags, itag) || s:indent_tags[itag] != 1
  106.         continue
  107.     endif
  108.     unlet s:indent_tags[itag]
  109.     if itag =~ '^\w\+$'
  110.         unlet s:indent_tags["/".itag]
  111.     endif
  112.     endfor
  113. endfunc "}}}
  114. " Add Indent Tags: {{{
  115. if !exists("s:indent_tags")
  116.     let s:indent_tags = {}
  117. endif
  118.  
  119. " old tags:
  120. call s:AddITags(['a', 'abbr', 'acronym', 'address', 'b', 'bdo', 'big',
  121.     \ 'blockquote', 'button', 'caption', 'center', 'cite', 'code', 'colgroup',
  122.     \ 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', 'form',
  123.     \ 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'i', 'iframe', 'ins', 'kbd',
  124.     \ 'label', 'legend', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol',
  125.     \ 'optgroup', 'q', 's', 'samp', 'select', 'small', 'span', 'strong', 'sub',
  126.     \ 'sup', 'table', 'textarea', 'title', 'tt', 'u', 'ul', 'var', 'th', 'td',
  127.     \ 'tr', 'tfoot', 'thead'])
  128.  
  129. " tags added 2011 Sep 09 (especially HTML5 tags):
  130. call s:AddITags(['area', 'article', 'aside', 'audio', 'bdi', 'canvas',
  131.     \ 'command', 'datalist', 'details', 'embed', 'figure', 'footer',
  132.     \ 'header', 'group', 'keygen', 'mark', 'math', 'meter', 'nav', 'output',
  133.     \ 'progress', 'ruby', 'section', 'svg', 'texture', 'time', 'video',
  134.     \ 'wbr', 'text'])
  135.  
  136. "}}}
  137. " Add Block Tags: contain alien content "{{{
  138. call s:AddBlockTag('pre', 2)
  139. call s:AddBlockTag('script', 3)
  140. call s:AddBlockTag('style', 4)
  141. call s:AddBlockTag('<!--', 5, '-->')
  142. "}}}
  143.  
  144. func! s:CountITags(...) "{{{
  145.  
  146.     " relative indent steps for current line [unit &sw]:
  147.     let s:curind = 0
  148.     " relative indent steps for next line [unit &sw]:
  149.     let s:nextrel = 0
  150.  
  151.     if a:0==0
  152.     let s:block = s:newstate.block
  153.     let tmpline = substitute(s:curline, '<\zs\/\=\w\+\>\|<!--\|-->', '\=s:CheckTag(submatch(0))', 'g')
  154.     if s:block == 3
  155.         let s:newstate.scripttype = s:GetScriptType(matchstr(tmpline, '\C.*<SCRIPT\>\zs[^>]*'))
  156.     endif
  157.     let s:newstate.block = s:block
  158.     else
  159.     let s:block = 0     " assume starting outside of a block
  160.     let s:countonly = 1 " don't change state
  161.     let tmpline = substitute(s:altline, '<\zs\/\=\w\+\>\|<!--\|-->', '\=s:CheckTag(submatch(0))', 'g')
  162.     let s:countonly = 0
  163.     endif
  164. endfunc "}}}
  165. func! s:CheckTag(itag) "{{{
  166.     " "tag" or "/tag" or "<!--" or "-->"
  167.     let ind = get(s:indent_tags, a:itag)
  168.     if ind == -1
  169.     " closing tag
  170.     if s:block != 0
  171.         " ignore itag within a block
  172.         return "foo"
  173.     endif
  174.     if s:nextrel == 0
  175.         let s:curind -= 1
  176.     else
  177.         let s:nextrel -= 1
  178.     endif
  179.     " if s:curind >= 1
  180.     "     let s:curind -= 1
  181.     " else
  182.     "     let s:nextrel -= 1
  183.     " endif
  184.     elseif ind == 1
  185.     " opening tag
  186.     if s:block != 0
  187.         return "foo"
  188.     endif
  189.     let s:nextrel += 1
  190.     elseif ind != 0
  191.     " block-tag (opening or closing)
  192.     return s:Blocktag(a:itag, ind)
  193.     endif
  194.     " else ind==0 (other tag found): keep indent
  195.     return "foo"   " no matter
  196. endfunc "}}}
  197. func! s:Blocktag(blocktag, ind) "{{{
  198.     if a:ind > 0
  199.     " a block starts here
  200.     if s:block != 0
  201.         " already in a block (nesting) - ignore
  202.         " especially ignore comments after other blocktags
  203.         return "foo"
  204.     endif
  205.     let s:block = a:ind     " block type
  206.     if s:countonly
  207.         return "foo"
  208.     endif
  209.     let s:newstate.blocklnr = v:lnum
  210.     " save allover indent for the endtag
  211.     let s:newstate.blocktagind = b:indent.baseindent + (s:nextrel + s:curind) * s:ShiftWidth()
  212.     if a:ind == 3
  213.         return "SCRIPT"    " all except this must be lowercase
  214.         " line is to be checked again for the type attribute
  215.     endif
  216.     else
  217.     let s:block = 0
  218.     " we get here if starting and closing block-tag on same line
  219.     endif
  220.     return "foo"
  221. endfunc "}}}
  222. func! s:GetScriptType(str) "{{{
  223.     if a:str == "" || a:str =~ "java"
  224.     return "javascript"
  225.     else
  226.     return ""
  227.     endif
  228. endfunc "}}}
  229.  
  230. func! s:FreshState(lnum) "{{{
  231.     " Look back in the file (lines 1 to a:lnum-1) to calc a state for line
  232.     " a:lnum.  A state is to know ALL relevant details about the lines
  233.     " 1..a:lnum-1, initial calculating (here!) can be slow, but updating is
  234.     " fast (incremental).
  235.     " State:
  236.     "   lnum        last indented line == prevnonblank(a:lnum - 1)
  237.     "   block = 0   a:lnum located within special tag: 0:none, 2:<pre>,
  238.     "           3:<script>, 4:<style>, 5:<!--
  239.     "   baseindent  use this indent for line a:lnum as a start - kind of
  240.     "           autoindent (if block==0)
  241.     "   scripttype = '' type attribute of a script tag (if block==3)
  242.     "   blocktagind indent for current opening (get) and closing (set)
  243.     "           blocktag (if block!=0)
  244.     "   blocklnr    lnum of starting blocktag (if block!=0)
  245.     "   inattr      line {lnum} starts with attributes of a tag
  246.     let state = {}
  247.     let state.lnum = prevnonblank(a:lnum - 1)
  248.     let state.scripttype = ""
  249.     let state.blocktagind = -1
  250.     let state.block = 0
  251.     let state.baseindent = 0
  252.     let state.blocklnr = 0
  253.     let state.inattr = 0
  254.  
  255.     if state.lnum == 0
  256.     return state
  257.     endif
  258.  
  259.     " Heuristic:
  260.     " remember startline state.lnum
  261.     " look back for <pre, </pre, <script, </script, <style, </style tags
  262.     " remember stopline
  263.     " if opening tag found,
  264.     "   assume a:lnum within block
  265.     " else
  266.     "   look back in result range (stopline, startline) for comment
  267.     "       \ delimiters (<!--, -->)
  268.     "   if comment opener found,
  269.     "       assume a:lnum within comment
  270.     "   else
  271.     "       assume usual html for a:lnum
  272.     "       if a:lnum-1 has a closing comment
  273.     "       look back to get indent of comment opener
  274.     " FI
  275.  
  276.     " look back for blocktag
  277.     call cursor(a:lnum, 1)
  278.     let [stopline, stopcol] = searchpos('\c<\zs\/\=\%(pre\>\|script\>\|style\>\)', "bW")
  279.     " fugly ... why isn't there searchstr()
  280.     let tagline = tolower(getline(stopline))
  281.     let blocktag = matchstr(tagline, '\/\=\%(pre\>\|script\>\|style\>\)', stopcol-1)
  282.     if stopline > 0 && blocktag[0] != "/"
  283.     " opening tag found, assume a:lnum within block
  284.     let state.block = s:indent_tags[blocktag]
  285.     if state.block == 3
  286.         let state.scripttype = s:GetScriptType(matchstr(tagline, '\>[^>]*', stopcol))
  287.     endif
  288.     let state.blocklnr = stopline
  289.     " check preceding tags in the line:
  290.     let s:altline = tagline[: stopcol-2]
  291.     call s:CountITags(1)
  292.     let state.blocktagind = indent(stopline) + (s:curind + s:nextrel) * s:ShiftWidth()
  293.     return state
  294.     elseif stopline == state.lnum
  295.     " handle special case: previous line (= state.lnum) contains a
  296.     " closing blocktag which is preceded by line-noise;
  297.     " blocktag == "/..."
  298.     let swendtag = match(tagline, '^\s*</') >= 0
  299.     if !swendtag
  300.         let [bline, bcol] = searchpos('<'.blocktag[1:].'\>', "bW")
  301.         let s:altline = tolower(getline(bline)[: bcol-2])
  302.         call s:CountITags(1)
  303.         let state.baseindent = indent(bline) + (s:nextrel+s:curline) * s:ShiftWidth()
  304.         return state
  305.     endif
  306.     endif
  307.  
  308.     " else look back for comment
  309.     call cursor(a:lnum, 1)
  310.     let [comline, comcol, found] = searchpos('\(<!--\)\|-->', 'bpW', stopline)
  311.     if found == 2
  312.     " comment opener found, assume a:lnum within comment
  313.     let state.block = 5
  314.     let state.blocklnr = comline
  315.     " check preceding tags in the line:
  316.     let s:altline = tolower(getline(comline)[: comcol-2])
  317.     call s:CountITags(1)
  318.     let state.blocktagind = indent(comline) + (s:curind + s:nextrel) * s:ShiftWidth()
  319.     return state
  320.     endif
  321.  
  322.     " else within usual html
  323.     let s:altline = tolower(getline(state.lnum))
  324.     " check a:lnum-1 for closing comment (we need indent from the opening line)
  325.     let comcol = stridx(s:altline, '-->')
  326.     if comcol >= 0
  327.     call cursor(state.lnum, comcol+1)
  328.     let [comline, comcol] = searchpos('<!--', 'bW')
  329.     if comline == state.lnum
  330.         let s:altline = s:altline[: comcol-2]
  331.     else
  332.         let s:altline = tolower(getline(comline)[: comcol-2])
  333.     endif
  334.     call s:CountITags(1)
  335.     let state.baseindent = indent(comline) + (s:nextrel+s:curline) * s:ShiftWidth()
  336.     return state
  337.     " TODO check tags that follow "-->"
  338.     endif
  339.  
  340.     " else no comments
  341.     call s:CountITags(1)
  342.     let state.baseindent = indent(state.lnum) + s:nextrel * s:ShiftWidth()
  343.     " line starts with end tag
  344.     let swendtag = match(s:altline, '^\s*</') >= 0
  345.     if !swendtag
  346.     let state.baseindent += s:curind * s:ShiftWidth()
  347.     endif
  348.     return state
  349. endfunc "}}}
  350.  
  351. func! s:Alien2() "{{{
  352.     " <pre> block
  353.     return -1
  354. endfunc "}}}
  355. func! s:Alien3() "{{{
  356.     " <script> javascript
  357.     if prevnonblank(v:lnum-1) == b:indent.blocklnr
  358.     " indent for the first line after <script>
  359.     return eval(s:js1indent)
  360.     endif
  361.     if b:indent.scripttype == "javascript"
  362.     return cindent(v:lnum)
  363.     else
  364.     return -1
  365.     endif
  366. endfunc "}}}
  367. func! s:Alien4() "{{{
  368.     " <style>
  369.     if prevnonblank(v:lnum-1) == b:indent.blocklnr
  370.     " indent for first content line
  371.     return eval(s:css1indent)
  372.     endif
  373.     return s:CSSIndent()
  374. endfunc
  375.  
  376. func! s:CSSIndent() "{{{
  377.     " adopted $VIMRUNTIME/indent/css.vim
  378.     if getline(v:lnum) =~ '^\s*[*}]'
  379.     return cindent(v:lnum)
  380.     endif
  381.     let minline = b:indent.blocklnr
  382.     let pnum = s:css_prevnoncomment(v:lnum - 1, minline)
  383.     if pnum <= minline
  384.     " < is to catch errors
  385.     " indent for first content line after comments
  386.     return eval(s:css1indent)
  387.     endif
  388.     let ind = indent(pnum) + s:css_countbraces(pnum, 1) * s:ShiftWidth()
  389.     let pline = getline(pnum)
  390.     if pline =~ '}\s*$'
  391.     let ind -= (s:css_countbraces(pnum, 0) - (pline =~ '^\s*}')) * s:ShiftWidth()
  392.     endif
  393.     return ind
  394. endfunc "}}}
  395. func! s:css_prevnoncomment(lnum, stopline) "{{{
  396.     " caller starts from a line a:lnum-1 that is not a comment
  397.     let lnum = prevnonblank(a:lnum)
  398.     let ccol = match(getline(lnum), '\*/')
  399.     if ccol < 0
  400.     return lnum
  401.     endif
  402.     call cursor(lnum, ccol+1)
  403.     let lnum = search('/\*', 'bW', a:stopline)
  404.     if indent(".") == virtcol(".")-1
  405.     return prevnonblank(lnum-1)
  406.     else
  407.     return lnum
  408.     endif
  409. endfunc "}}}
  410. func! s:css_countbraces(lnum, count_open) "{{{
  411.     let brs = substitute(getline(a:lnum),'[''"].\{-}[''"]\|/\*.\{-}\*/\|/\*.*$\|[^{}]','','g')
  412.     let n_open = 0
  413.     let n_close = 0
  414.     for brace in split(brs, '\zs')
  415.     if brace == "{"
  416.         let n_open += 1
  417.     elseif brace == "}"
  418.         if n_open > 0
  419.         let n_open -= 1
  420.         else
  421.         let n_close += 1
  422.         endif
  423.     endif
  424.     endfor
  425.     return a:count_open ? n_open : n_close
  426. endfunc "}}}
  427.  
  428. "}}}
  429. func! s:Alien5() "{{{
  430.     " <!-- -->
  431.     return -1
  432. endfunc "}}}
  433.  
  434. func! HtmlIndent() "{{{
  435.     let s:curline = tolower(getline(v:lnum))
  436.     let indentunit = s:ShiftWidth()
  437.  
  438.     let s:newstate = {}
  439.     let s:newstate.lnum = v:lnum
  440.  
  441.     " does the line start with a closing tag?
  442.     let swendtag = match(s:curline, '^\s*</') >= 0
  443.  
  444.     if prevnonblank(v:lnum-1) == b:indent.lnum && s:usestate
  445.     " use state (continue from previous line)
  446.     else
  447.     " start over (know nothing)
  448.     let b:indent = s:FreshState(v:lnum)
  449.     endif
  450.  
  451.     if b:indent.block >= 2
  452.     " within block
  453.     let endtag = s:endtags[b:indent.block-2]
  454.     let blockend = stridx(s:curline, endtag)
  455.     if blockend >= 0
  456.         " block ends here
  457.         let s:newstate.block = 0
  458.         " calc indent for REST OF LINE (may start more blocks):
  459.         let s:curline = strpart(s:curline, blockend+strlen(endtag))
  460.         call s:CountITags()
  461.         if swendtag && b:indent.block != 5
  462.         let indent = b:indent.blocktagind + s:curind * indentunit
  463.         let s:newstate.baseindent = indent + s:nextrel * indentunit
  464.         else
  465.         let indent = s:Alien{b:indent.block}()
  466.         let s:newstate.baseindent = b:indent.blocktagind + s:nextrel * indentunit
  467.         endif
  468.         call extend(b:indent, s:newstate, "force")
  469.         return indent
  470.     else
  471.         " block continues
  472.         " indent this line with alien method
  473.         let indent = s:Alien{b:indent.block}()
  474.         call extend(b:indent, s:newstate, "force")
  475.         return indent
  476.     endif
  477.     else
  478.     " not within a block - within usual html
  479.     " if < 2 then always 0
  480.     let s:newstate.block = b:indent.block
  481.     call s:CountITags()
  482.     if swendtag
  483.         let indent = b:indent.baseindent + s:curind * indentunit
  484.         let s:newstate.baseindent = indent + s:nextrel * indentunit
  485.     else
  486.         let indent = b:indent.baseindent
  487.         let s:newstate.baseindent = indent + (s:curind + s:nextrel) * indentunit
  488.     endif
  489.     call extend(b:indent, s:newstate, "force")
  490.     return indent
  491.     endif
  492.  
  493. endfunc "}}}
  494.  
  495. " check user settings (first time), clear cpo, Modeline: {{{1
  496.  
  497. " DEBUG:
  498. com! -nargs=* IndHtmlLocal <args>
  499.  
  500. call HtmlIndent_CheckUserSettings()
  501.  
  502. let &cpo = s:cpo_save
  503. unlet s:cpo_save
  504.  
  505. " vim:set fdm=marker ts=8:
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement