1" Language: xml 2" Maintainer: Johannes Zellner <[email protected]> 3" Last Change: 2012 Jul 25 4" Notes: 1) does not indent pure non-xml code (e.g. embedded scripts) 5" 2) will be confused by unbalanced tags in comments 6" or CDATA sections. 7" 2009-05-26 patch by Nikolai Weibull 8" TODO: implement pre-like tags, see xml_indent_open / xml_indent_close 9 10" Only load this indent file when no other was loaded. 11if exists("b:did_indent") 12 finish 13endif 14let b:did_indent = 1 15let s:keepcpo= &cpo 16set cpo&vim 17 18" [-- local settings (must come before aborting the script) --] 19setlocal indentexpr=XmlIndentGet(v:lnum,1) 20setlocal indentkeys=o,O,*<Return>,<>>,<<>,/,{,} 21 22if !exists('b:xml_indent_open') 23 let b:xml_indent_open = '.\{-}<\a' 24 " pre tag, e.g. <address> 25 " let b:xml_indent_open = '.\{-}<[/]\@!\(address\)\@!' 26endif 27 28if !exists('b:xml_indent_close') 29 let b:xml_indent_close = '.\{-}</' 30 " end pre tag, e.g. </address> 31 " let b:xml_indent_close = '.\{-}</\(address\)\@!' 32endif 33 34let &cpo = s:keepcpo 35unlet s:keepcpo 36 37" [-- finish, if the function already exists --] 38if exists('*XmlIndentGet') 39 finish 40endif 41 42let s:keepcpo= &cpo 43set cpo&vim 44 45fun! <SID>XmlIndentWithPattern(line, pat) 46 let s = substitute('x'.a:line, a:pat, "\1", 'g') 47 return strlen(substitute(s, "[^\1].*$", '', '')) 48endfun 49 50" [-- check if it's xml --] 51fun! <SID>XmlIndentSynCheck(lnum) 52 if '' != &syntax 53 let syn1 = synIDattr(synID(a:lnum, 1, 1), 'name') 54 let syn2 = synIDattr(synID(a:lnum, strlen(getline(a:lnum)) - 1, 1), 'name') 55 if '' != syn1 && syn1 !~ 'xml' && '' != syn2 && syn2 !~ 'xml' 56 " don't indent pure non-xml code 57 return 0 58 elseif syn1 =~ '^xmlComment' && syn2 =~ '^xmlComment' 59 " indent comments specially 60 return -1 61 endif 62 endif 63 return 1 64endfun 65 66" [-- return the sum of indents of a:lnum --] 67fun! <SID>XmlIndentSum(lnum, style, add) 68 let line = getline(a:lnum) 69 if a:style == match(line, '^\s*</') 70 return (&sw * 71 \ (<SID>XmlIndentWithPattern(line, b:xml_indent_open) 72 \ - <SID>XmlIndentWithPattern(line, b:xml_indent_close) 73 \ - <SID>XmlIndentWithPattern(line, '.\{-}/>'))) + a:add 74 else 75 return a:add 76 endif 77endfun 78 79fun! XmlIndentGet(lnum, use_syntax_check) 80 " Find a non-empty line above the current line. 81 let lnum = prevnonblank(a:lnum - 1) 82 83 " Hit the start of the file, use zero indent. 84 if lnum == 0 85 return 0 86 endif 87 88 if a:use_syntax_check 89 let check_lnum = <SID>XmlIndentSynCheck(lnum) 90 let check_alnum = <SID>XmlIndentSynCheck(a:lnum) 91 if 0 == check_lnum || 0 == check_alnum 92 return indent(a:lnum) 93 elseif -1 == check_lnum || -1 == check_alnum 94 return -1 95 endif 96 endif 97 98 let ind = <SID>XmlIndentSum(lnum, -1, indent(lnum)) 99 let ind = <SID>XmlIndentSum(a:lnum, 0, ind) 100 101 return ind 102endfun 103 104let &cpo = s:keepcpo 105unlet s:keepcpo 106 107" vim:ts=8 108