1" Language: xml 2" Maintainer: Johannes Zellner <johannes@zellner.org> 3" Last Change: 2009-05-26 00:17: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 15 16" [-- local settings (must come before aborting the script) --] 17setlocal indentexpr=XmlIndentGet(v:lnum,1) 18setlocal indentkeys=o,O,*<Return>,<>>,<<>,/,{,} 19 20set cpo-=C 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 34" [-- finish, if the function already exists --] 35if exists('*XmlIndentGet') | finish | endif 36 37fun! <SID>XmlIndentWithPattern(line, pat) 38 let s = substitute('x'.a:line, a:pat, "\1", 'g') 39 return strlen(substitute(s, "[^\1].*$", '', '')) 40endfun 41 42" [-- check if it's xml --] 43fun! <SID>XmlIndentSynCheck(lnum) 44 if '' != &syntax 45 let syn1 = synIDattr(synID(a:lnum, 1, 1), 'name') 46 let syn2 = synIDattr(synID(a:lnum, strlen(getline(a:lnum)) - 1, 1), 'name') 47 if '' != syn1 && syn1 !~ 'xml' && '' != syn2 && syn2 !~ 'xml' 48 " don't indent pure non-xml code 49 return 0 50 elseif syn1 =~ '^xmlComment' && syn2 =~ '^xmlComment' 51 " indent comments specially 52 return -1 53 endif 54 endif 55 return 1 56endfun 57 58" [-- return the sum of indents of a:lnum --] 59fun! <SID>XmlIndentSum(lnum, style, add) 60 let line = getline(a:lnum) 61 if a:style == match(line, '^\s*</') 62 return (&sw * 63 \ (<SID>XmlIndentWithPattern(line, b:xml_indent_open) 64 \ - <SID>XmlIndentWithPattern(line, b:xml_indent_close) 65 \ - <SID>XmlIndentWithPattern(line, '.\{-}/>'))) + a:add 66 else 67 return a:add 68 endif 69endfun 70 71fun! XmlIndentGet(lnum, use_syntax_check) 72 " Find a non-empty line above the current line. 73 let lnum = prevnonblank(a:lnum - 1) 74 75 " Hit the start of the file, use zero indent. 76 if lnum == 0 77 return 0 78 endif 79 80 if a:use_syntax_check 81 let check_lnum = <SID>XmlIndentSynCheck(lnum) 82 let check_alnum = <SID>XmlIndentSynCheck(a:lnum) 83 if 0 == check_lnum || 0 == check_alnum 84 return indent(a:lnum) 85 elseif -1 == check_lnum || -1 == check_alnum 86 return -1 87 endif 88 endif 89 90 let ind = <SID>XmlIndentSum(lnum, -1, indent(lnum)) 91 let ind = <SID>XmlIndentSum(a:lnum, 0, ind) 92 93 return ind 94endfun 95 96" vim:ts=8 97