" Vim script file                                           vim600:fdm=marker:
" FileType:     XML
" Author:       Rene de Zwart <renez (at) lightcon.xs4all.nl> 
" Maintainer:   Rene de Zwart <renez (at) lightcon.xs4all.nl>
" Last Change:  Date: 2009-11-12 
" Version:      Revision: 1.37
" 
" Licence:      This program is free software; you can redistribute it
"               and/or modify it under the terms of the GNU General Public
"               License.  See http://www.gnu.org/copyleft/gpl.txt
" Credits:      Devin Weaver <vim (at) tritarget.com>  et all
"               for the original code.  Guo-Peng Wen for the self
"               install documentation code.
"               Bart vam Deenen for makeElement function
"               Rene de Zwart


" Observation   - If you want to do something to a match pair most of the time
"               you must do first the close tag. Because doing first the open
"               tag could change the close tag position.

" NOTE          with filetype index on de standard indent/html.vim interferes
"               with xml.vim. You can
"                 1) set filetype indent off in .vimrc
"                 2) echo "let b:did_indent = 1" > .vim/indent/html.vim


" Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
  finish
endif
let b:did_ftplugin = 1

setlocal commentstring=<!--%s-->

" XML:  thanks to Johannes Zellner and Akbar Ibrahim
" - case sensitive
" - don't match empty tags <fred/>
" - match <!--, --> style comments (but not --, --)
" - match <!, > inlined dtd's. This is not perfect, as it
"   gets confused for example by
"       <!ENTITY gt ">">
if exists("loaded_matchit")
    let b:match_ignorecase=0
    let b:match_words =
     \  '<:>,' .
     \  '<\@<=!\[CDATA\[:]]>,'.
     \  '<\@<=!--:-->,'.
     \  '<\@<=?\k\+:?>,'.
     \  '<\@<=\([^ \t>/]\+\)\%(\s\+[^>]*\%([^/]>\|$\)\|>\|$\):<\@<=/\1>,'.
     \  '<\@<=\%([^ \t>/]\+\)\%(\s\+[^/>]*\|$\):/>'
endif

" Script rgular expresion used. Documents those nasty criters      {{{1
let s:NoSlashBeforeGt = '\(\/\)\@\<!>'
" Don't check for quotes around attributes!!!
let s:Attrib =  '\(\(\s\|\n\)\+\([^>= \t]\+=[^>&]\+\)\(\s\|\n\)*\)'
let s:OptAttrib = s:Attrib . '*'. s:NoSlashBeforeGt
let s:ReqAttrib = s:Attrib . '\+'. s:NoSlashBeforeGt
let s:OpenTag = '<[^!/?][^>]*' . s:OptAttrib
let s:OpenOrCloseTag = '<[^!?][^>]*'. s:OptAttrib
let s:CloseTag = '<\/[^>]*'. s:NoSlashBeforeGt
let s:SpaceInfront = '^\s*<'
let s:EndofName = '\($\|\s\|>\)'

" Buffer variables                                                  {{{1
let b:emptyTags='^\(area\|base\|br\|col\|command\|embed\|hr\|img\|input\|keygen\|link\|meta\|param\|source\|track\|wbr\)$'
let b:firstWasEndTag = 0
let b:html_mode =((&filetype =~ 'x\?html') && !exists("g:xml_no_html"))
let b:haveAtt = 0
let b:lastTag = ""
let b:lastAtt = ""
let b:suffix = (exists('g:makeElementSuf') ? g:makeElementSuf : ';;')
let b:xml_use_xhtml = 0
if exists('g:xml_use_xhtml')
	let b:xml_use_xhtml = g:xml_use_xhtml
elseif &filetype == 'xhtml'
	let b:xml_use_xhtml = 1
en

let b:undo_ftplugin = "setlocal cms< isk<"
  \ . "| unlet b:match_ignorecase b:match_words"



" NewFileXML -> Inserts <?xml?> at top of new file.                  {{{1
if !exists("*NewFileXML")
function! NewFileXML( )
    " Where is g:did_xhtmlcf_inits defined?
    if &filetype == 'xml' || 
			\ (!exists ("g:did_xhtmlcf_inits") &&
			\ b:xml_use_xhtml &&
			\ (&filetype =~ 'x\?html'))
        if append (0, '<?xml version="1.0"?>')
            normal! G
        endif
    endif
endfunction
endif



" Callback -> Checks for tag callbacks and executes them.            {{{1
if !exists("*s:Callback")
function! s:Callback( xml_tag, isHtml )
    let text = 0
    if a:isHtml == 1 && exists ("*HtmlAttribCallback")
        let text = HtmlAttribCallback (a:xml_tag)
    elseif exists ("*XmlAttribCallback")
        let text = XmlAttribCallback (a:xml_tag)
    endif       
    if text != '0'
        execute "normal! i " . text ."\<Esc>l"
    endif
endfunction
endif

" SavePos() saves position  in bufferwide variable                        {{{1
fun! s:SavePos()	
	retu 'call cursor('.line('.').','. col('.'). ')'
endf

" findOpenTag()                         {{{1
fun! s:findOpenTag(flag)	
	call search(s:OpenTag,a:flag)
endf

" findCloseTag()                         {{{1
fun! s:findCloseTag(flag)	
	call search(s:CloseTag,a:flag)
endf

" GetTagName() Gets the tagname from start position                     {{{1
"Now lets go for the name part. The namepart are xmlnamechars which
"is quite a big range. We assume that everything after '<' or '</' 
"until the first 'space', 'forward slash' or '>' ends de name part.
if !exists('*s:GetTagName')
fun! s:GetTagName(from)
	  let l:end = match(getline('.'), s:EndofName,a:from)
	  return strpart(getline('.'),a:from, l:end - a:from )
endf
en
" hasAtt() Looks for attribute in open tag                           {{{1
" expect cursor to be on <
fun! s:hasAtt()
	"Check if this open tag has attributes
	let l:line = line('.') | let l:col = col('.') 
	if search(b:tagName . s:ReqAttrib,'W') > 0
    if l:line == line('.') && l:col == (col('.')-1)
			let b:haveAtt = 1
		en
	en
endf
 

" TagUnderCursor()  Is there a tag under the cursor?               {{{1
" Set bufer wide variable
"  - b:firstWasEndTag
"  - b:tagName
"  - b:endcol & b:endline only used by Match()
"  - b:gotoCloseTag (if the tag under the cursor is one)
"  - b:gotoOpenTag  (if the tag under the cursor is one)
" on exit
"    - returns 1 (true)  or 0 (false)
"    - position is at '<'
if !exists('*s:TagUnderCursor')
fun! s:TagUnderCursor()
	let b:firstWasEndTag = 0
	let l:haveTag = 0
	let b:haveAtt = 0
	
	"Lets find forward a < or a >.  If we first find a > we might be in a tag.
	"If we find a < first or nothing we are definitly not in a tag

	if getline('.')[col('.') - 1] == '>'
		let b:endcol  = col('.')
		let b:endline = line('.')
		if getline('.')[col('.')-2] == '/'
				"we don't work with empty tags
			retu l:haveTag
		en
    " begin: gwang customization for JSP development
		if getline('.')[col('.')-2] == '%'
				"we don't work with jsp %> tags
			retu l:haveTag
		en
    " end: gwang customization for JSP development
    " begin: gwang customization for PHP development
		if getline('.')[col('.')-2] == '?'
				"we don't work with php ?> tags
			retu l:haveTag
		en
    " end: gwang customization for PHP development
	elseif search('[<>]','W') >0
		if getline('.')[col('.')-1] == '>'
			let b:endcol  = col('.')
			let b:endline = line('.')
			if getline('.')[col('.')-2] == '-'
				"we don't work with comment tags
				retu l:haveTag
			en
			if getline('.')[col('.')-2] == '/'
				"we don't work with empty tags
				retu l:haveTag
			en
		el
			retu l:haveTag
		en
	el
		retu l:haveTag
	en
	
	if search('[<>]','bW' ) >=0
		if getline('.')[col('.')-1] == '<'
			if getline('.')[col('.')] == '/'
				let b:firstWasEndTag = 1
				let b:gotoCloseTag = s:SavePos()
			elseif getline('.')[col('.')] == '?' ||  getline('.')[col('.')] == '!'
				"we don't deal with processing instructions or dtd
				"related definitions
				retu l:haveTag
			el
				let b:gotoOpenTag = s:SavePos()
			en
		el
			retu l:haveTag
		en
	el
		retu l:haveTag
	en

	"we have established that we are between something like
	"'</\?[^>]*>'
	
	let b:tagName = s:GetTagName(col('.') + b:firstWasEndTag)
	"echo 'Tag ' . b:tagName 

  "begin: gwang customization, do not work with an empty tag name
  if b:tagName == '' 
		retu l:haveTag
  en
  "end: gwang customization, do not work with an empty tag name

	let l:haveTag = 1
	if b:firstWasEndTag == 0
		call s:hasAtt()
		exe b:gotoOpenTag
	en
	retu l:haveTag
endf
en
 
" Match(tagname) Looks for open or close tag of tagname               {{{1
" Set buffer wide variable
"  - b:gotoCloseTag (if the Match tag is one)
"  - b:gotoOpenTag  (if the Match tag is one)
" on exit
"    - returns 1 (true) or 0 (false)
"    - position is at '<'
if !exists('*s:Match')
fun! s:Match(name)
	let l:pat = '</\=' . a:name . s:OptAttrib
	if  b:firstWasEndTag
		exe b:gotoCloseTag
		let l:flags='bW'
		let l:level = -1
	el
		exe  'normal! '.b:endline.'G0'.(b:endcol-1).'l'
		let l:flags='W'
		let l:level = 1
	en
	while l:level &&  search(l:pat,l:flags) > 0
		let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
	endwhile
	if l:level
		echo "no matching tag!!!!!"
		retu l:level
	en
	if b:firstWasEndTag
		let b:gotoOpenTag = s:SavePos()
		call s:hasAtt()
		exe b:gotoOpenTag
	el
		let b:gotoCloseTag = s:SavePos()
	en
	retu l:level == 0
endf
en

" InComment()  Is there a Comment under the cursor?               {{{1
"    - returns 1 (true)  or 0 (false)

if !exists('*s:InComment')
fun! s:InComment()
let b:endcom=0
let b:begcom=0

	"Lets find forward a < or a >.  If we first find a > we might be in a comment.
	"If we find a < first or nothing we are definitly not in a Comment

	if getline('.')[col('.') - 1] == '>'
		if getline('.')[col('.')-2] == '-' && getline('.')[col('.')-3] == '-'
			let b:endcomcol=col('.')
			let b:endcomline=line('.')
			let b:endcom=1
			retu 1
		en
	elseif  getline('.')[col('.')-1] == '<' && getline('.')[col('.')]   == '!'
		 \ && getline('.')[col('.')+1] == '-' && getline('.')[col('.')+2] == '-' 
			let b:begcomcol= col('.')
			let b:begcomline=line('.')
			let b:begcom=1
			retu 1
	en
	"We are not standing on a begin/end comment
	"Is the first > an ending comment?
	if search('[<>]','W') >0
		if getline('.')[col('.')-1] == '>'
			if getline('.')[col('.')-2] == '-' && getline('.')[col('.')-3] == '-'
			let b:endcomcol=col('.')
			let b:endcomline=line('.')
			let b:endcom=1
				retu 1
			en
		en
	en
	"Forward is not a ending comment
	"is backward a starting comment
	
	if search('[<>]','bW' ) >=0
		if getline('.')[col('.')-1] == '<' && getline('.')[col('.')]   == '!'
		 \ && getline('.')[col('.')+1] == '-' && getline('.')[col('.')+2] == '-' 
			let b:begcomcol=col('.')
			let b:begcomline=line('.')
			let b:begcom=1
			retu 1
		en
	en
	retu 0
endf
en
 
" DelComment()  Is there a Comment under the cursor?               {{{1
"    - returns 1 (true)  or 0 (false)

if !exists('*s:DelComment')
fun! s:DelComment()
	
	let l:restore =  s:SavePos()
	if s:InComment()
		if b:begcom
			if search('-->','W' ) >=0
				normal! hh3x	
		   	call cursor(b:begcomline,b:begcomcol)
				normal! 4x
				retu 1
			en
		el
			if search('<!--','bW' ) >=0
				normal! 4x
		   	call cursor(b:endcomline,b:endcomcol)
				normal! hh3x	
				retu 1
			en
		en
	en
	exe l:restore
	retu 0
endf
en
 
" DelCommentSection()  Is there a Comment under the cursor?               {{{1
"    - returns 1 (true)  or 0 (false)

if !exists('*s:DelCommentSection')
fun! s:DelCommentSection()
	
	let l:restore =  s:SavePos()
	if s:InComment()
		let l:sentinel = 'XmLSeNtInElXmL'
		let l:len = strlen(l:sentinel)
		if b:begcom
			if search('-->','W' ) >=0
				exe "normal! f>a".l:sentinel."\<Esc>"
		   	call cursor(b:begcomline,b:begcomcol)
				exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
				exe "normal! ".l:len."x"
				retu 1
			en
		el
			if search('<!--','bW' ) >=0
				let l:restore =  s:SavePos()
		   	call cursor(b:endcomline,b:endcomcol)
				exe "normal! a".l:sentinel."\<Esc>"
				exe l:restore
				exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
				exe "normal! ".l:len."x"
				retu 1
			en
		en
	en
	exe l:restore
	retu 0
endf
en
 
" DelCData()  Is there a CData under the cursor?               {{{1
"    - returns 1 (true)  or 0 (false)

if !exists('*s:DelCData')
fun! s:DelCData()
	
	let l:restore =  s:SavePos()
	if s:InCData()
		if b:begdat
			if search(']]>','W' ) >=0
				normal! hh3x	
		   	call cursor(b:begdatline,b:begdatcol)
				normal! 9x
				retu 1
			en
		el
			if search('<![CDATA[','bW' ) >=0
				normal! 9x
		   	call cursor(b:enddatline,b:enddatcol)
				normal! hh3x	
				retu 1
			en
		en
	en
	exe l:restore
	retu 0
endf
en
 
" InCData()  Is there a CData under the cursor?               {{{1
"    - returns 1 (true)  or 0 (false)

if !exists('*s:InCData')
fun! s:InCData()
let b:enddat=0
let b:begdat=0

	"Lets find forward a < or a >.  If we first find a > we might be in a comment.
	"If we find a < first or nothing we are definitly not in a Comment

	if getline('.')[col('.') - 1] == '>'
		if getline('.')[col('.')-2] == ']' && getline('.')[col('.')-3] == ']'
			let b:enddatcol=col('.')
			let b:enddatline=line('.')
			let b:enddat=1
			retu 1
		en
	elseif  getline('.')[col('.')-1] == '<' 
		if  match(getline('.'),'<![CDATA[') > 0
			let b:begdatcol= col('.')
			let b:begdatline=line('.')
			let b:begdat=1
			retu 1
		en
	en
	"We are not standing on a begin/end comment
	"Is the first > aending comment?
	if search('[<>]','W') >0
		if getline('.')[col('.')-1] == '>'
			if getline('.')[col('.')-2] == ']' && getline('.')[col('.')-3] == ']'
			let b:enddatcol=col('.')
			let b:enddatline=line('.')
			let b:enddat=1
				retu 1
			en
		en
	en
	"Forward is not a ending datment
	"is backward a starting comment
	
	if search('[<>]','bW' ) >=0
		if getline('.')[col('.')-1] == '<' 
			if  match(getline('.'),'<![CDATA[') > 0
		let l:newname = inputdialog('Found CDATA')
				let b:begdatcol=col('.')
				let b:begdatline=line('.')
				let b:begdat=1
				retu 1
			en
		en
	en
	retu 0
endf
en
 
 
" DelCDataSection()  Is there a CData under the cursor?               {{{1
"    - returns 1 (true)  or 0 (false)

if !exists('*s:DelCDataSection')
fun! s:DelCDataSection()
	
	let l:restore =  s:SavePos()
	if s:InCData()
		let l:sentinel = 'XmLSeNtInElXmL'
		let l:len = strlen(l:sentinel)
		if b:begdat
			if search(']]>','W' ) >=0
				exe "normal! f>a".l:sentinel."\<Esc>"
		   	call cursor(b:begdatline,b:begdatcol)
				exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
				exe "normal! ".l:len."x"
				retu 1
			en
		el
			if search('<![CDATA[','bW' ) >=0
				let l:restore =  s:SavePos()
		   	call cursor(b:enddatline,b:enddatcol)
				exe "normal! a".l:sentinel."\<Esc>"
				exe l:restore
				exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
				exe "normal! ".l:len."x"
				retu 1
			en
		en
	en
	exe l:restore
	retu 0
endf
en
 
 
" Matches()  Matches de tagname under de cursor                       {{{1
if !exists('*s:Matches')
fun! s:Matches()	
	let l:restore =  s:SavePos()
	if s:TagUnderCursor()
		if s:Match(b:tagName)
			retu
		en
	en
	exe l:restore
endf
en

" MatchesVisual()  Matches de tagname under de cursor                       {{{1
if !exists('*s:MatchesVisual')
fun! s:MatchesVisual()	
	let l:restore =  s:SavePos()
	if s:TagUnderCursor()
		if b:firstWasEndTag
			normal! f>
		en
		normal! gv
		if s:Match(b:tagName)
			if b:firstWasEndTag == 0
				normal! f>
			en 
			retu
		en
		normal! v
	en
	exe l:restore
endf
en

" makeElement() makes the previous woord an tag and close                {{{1
if !exists('*s:makeElement')
function! s:makeElement()
	let b:tagName = @@
	let b:haveAtt = 0
	let l:alone = (match(getline('.'),'^\s*>\s*$') >= 0)
	let l:endOfLine = ((col('.')+1) == col('$'))
	normal! i<pf>
	if b:html_mode && b:tagName =~? b:emptyTags
		if b:haveAtt == 0
			call s:Callback (b:tagName, b:html_mode)
		endif
		if b:xml_use_xhtml
			exe "normal! i/\<Esc>l"
		en
		if  l:endOfLine
			start!
		el
			normal! l
			start
		en
	el
		if b:haveAtt == 0
			call s:Callback (b:tagName, b:html_mode)
		end
		if l:alone
			exe 'normal! o</pa>Ox>>$x'
			start!
		el
			exe 'normal! a</pa>F<'
			start 
		en
	en
endfunction
en

" CloseTagFun() closing the tag which is being typed                  {{{1
if !exists('*s:CloseTagFun')
fun! s:CloseTagFun()	
	let l:restore =  s:SavePos()
	let l:endOfLine = ((col('.')+1) == col('$'))
	if col('.') > 1 && getline('.')[col('.')-2] == '>'
	"Multiline request. <t>></t> -->
	"<t>
	"	    cursor comes here
	"</t>
    normal! h
		if s:TagUnderCursor()
			if b:firstWasEndTag == 0
        if exists('b:did_indent') && b:did_indent == 1
          exe "normal! 2f>s\<Cr>\<Esc>Ox\<Esc>$x"
        else
          exe "normal! 2f>s\<Cr>\<Esc>Ox\<Esc>>>$x"
        en
				start!
				retu
			en
		en
	elseif s:TagUnderCursor()
		if b:firstWasEndTag == 0
			exe "normal! />\<Cr>"
			if b:html_mode && b:tagName =~?  b:emptyTags
				if b:haveAtt == 0
					call s:Callback (b:tagName, b:html_mode)
				en
				if b:xml_use_xhtml
					exe "normal! i/\<Esc>l"
				en
				if l:endOfLine
					start!
					retu
				el
					normal! l
					start
					retu
				en
			el
				if b:haveAtt == 0
					call s:Callback (b:tagName, b:html_mode)
				en
				exe "normal! a</" . b:tagName . ">\<Esc>F<"
				start
				retu
			en
		en
	en
	exe l:restore
	if (col('.')+1) == col("$")
		startinsert!
	else
		normal! l
		startinsert
	en
endf
en

" BlockTag() Surround a visual block with a tag                       {{{1
" Be carefull where You place the block 
" the top    is done with insert!
" the bottem is done with append!
if !exists('*s:BlockTag')
fun! s:BlockTag(multi)
	let l:newname = inputdialog('Surround block  with : ',b:lastTag)
	if strlen( l:newname) == 0
		retu
	en
	let b:lastTag =  l:newname
	let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
	if strlen(l:newatt)
		let b:lastAtt = l:newatt
	en

	"Get at the end of the block
	if col('.') == col("'<") && line('.') == line("'<")
		normal! gvov
	en
	if a:multi
		exe "normal! a\<Cr></".l:newname.">\<Cr>\<Esc>"
		let l:eline = line('.')
		normal! gvov
		if col('.') == col("'>") && line('.') == line("'>")
			normal! gvov
		en
		let l:sline = line(".") + 2
		exe "normal! i\<Cr><".l:newname.
			\ (strlen(l:newatt) ? ' '.l:newatt : '' )
			\ .">\<Cr>\<Esc>"
			let l:rep=&report
			let &report=999999
			exe l:sline.','.l:eline.'>'
			let &report= l:rep
			exe 'normal! '.l:sline.'G0mh'.l:eline."G$v'hgq"
	el
		exe "normal! a</".l:newname.">\<Esc>gvov"
		if col('.') == col("'>") && line('.') == line("'>")
			normal! gvov
		en
		exe "normal! i<".l:newname.
			\ (strlen(l:newatt) ? ' '.l:newatt : '' )
			\ .">\<Esc>"
	en
endf
en
" BlockWith() Surround a visual block with a open and a close          {{{1
" Be carefull where You place the block 
" the top    is done with insert!
" the bottem is done with append!
if !exists('*s:BlockWith')
fun! s:BlockWith(open,close)
	if col('.') == col("'<") && line('.') == line("'<")
		normal! gvov
	en
	exe "normal! a\<Cr>;x\<Esc>0cfx".a:close."\<Cr>\<Esc>"
	normal! gvov
	exe "normal! i\<Cr>;x\<Esc>0cfx".a:open."\<Cr>\<Esc>"
endf
en
" vlistitem() Surround a visual block with a listitem para tag      {{{1
" Be carefull where You place the block 
" the top    is done with insert!
" the bottem is done with append!
if !exists('*s:vlistitem')
fun! s:vlistitem()
	"Get at the end of the block
	if col('.') == col("'<") && line('.') == line("'<")
		normal! gvov
	en
	exe "normal! a</para>\<Cr></listitem>\<Esc>mh"
	normal! gvov
	exe "normal! i\<Cr><listitem>\<Cr>\<Tab><para>\<Esc>'h/listitem>/e+1\<Cr>"
endf
en
" Change() Only renames the tag                                         {{{1
if !exists('*s:Change')
fun! s:Change()
	let l:restore = s:SavePos()
	if s:TagUnderCursor()
		let l:newname = inputdialog('Change tag '.b:tagName.' to : ',b:lastTag) 
		if strlen( l:newname) == 0
			retu
		en
		let b:lastTag =  l:newname
		if s:Match(b:tagName)
			exe b:gotoCloseTag
			exe 'normal! 2lcw' . l:newname . "\<Esc>"
			exe b:gotoOpenTag
			exe 'normal! lcw' . l:newname . "\<Esc>"
		en
	en
endf
en

" Join() Joins two the same tag adjacent sections                    {{{1
if !exists('*s:Join')
fun! s:Join()
	let l:restore = s:SavePos()
	if s:TagUnderCursor()
		let l:pat = '<[^?!]\S\+\($\| \|\t\|>\)'
		let l:flags='W'
		if  b:firstWasEndTag == 0
			let l:flags='Wb'
		en
		if search(s:OpenOrCloseTag,l:flags) > 0

			let l:secondChar = getline('.')[col('.')]
			if l:secondChar == '/' && b:firstWasEndTag ||l:secondChar != '/' && !b:firstWasEndTag
				exe l:restore
				retu
			en
			let l:end = 0
			if l:secondChar == '/'
				let l:end = 1
			en
			let l:name = s:GetTagName(col('.') + l:end)
			if l:name == b:tagName
				if b:firstWasEndTag
					let b:gotoOpenTag = s:SavePos()
				el
					let b:gotoCloseTag = s:SavePos()
				en
				let l:DeleteTag  = "normal! d/>/e\<Cr>"
				exe b:gotoCloseTag
				exe l:DeleteTag
				exe b:gotoOpenTag
				exe l:DeleteTag
			en
		en
	en
	exe l:restore
endf
en

" ChangeWholeTag() removes attributes and rename tag                     {{{1
if !exists('*s:ChangeWholeTag')
fun! s:ChangeWholeTag()
	if s:TagUnderCursor()
		let l:newname = inputdialog('Change whole tag '.b:tagName.' to : ',b:lastTag)
		if strlen(l:newname) == 0
			retu
		en
		let b:lastTag =  l:newname
		let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
		if strlen(l:newatt)
			let b:lastAtt = l:newatt
		en
		if s:Match(b:tagName)
			exe b:gotoCloseTag
			exe "normal! 2lc/>\<Cr>".l:newname."\<Esc>"
			exe b:gotoOpenTag
			exe "normal! lc/>/\<Cr>".l:newname.
			\ (strlen(l:newatt) ? ' '.l:newatt : '' )
			\."\<Esc>"
		en
	en
endf
en

" Delete() Removes a tag '<a id="a">blah</a>' --> 'blah'            {{{1
if !exists('*s:Delete')
fun! s:Delete()
	let l:restore = s:SavePos()
	if s:TagUnderCursor()
		if s:Match(b:tagName)
			let l:DeleteTag  = "normal! d/>/e\<Cr>"
			exe b:gotoCloseTag
			exe l:DeleteTag
			exe b:gotoOpenTag
			exe l:DeleteTag
		en
	else
		exe l:restore
	en
endf
en


" DeleteSection() Deletes everything between start of open tag and end of  {{{1
" closing tag
if !exists('*s:DeleteSection')
fun! s:DeleteSection()
	let l:restore = s:SavePos()
	if s:TagUnderCursor()
		if s:Match(b:tagName)
			let l:sentinel = 'XmLSeNtInElXmL'
			let l:len = strlen(l:sentinel)
			let l:rep=&report
			let &report=999999
			exe b:gotoCloseTag
			exe "normal! />\<Cr>a".l:sentinel."\<Esc>"
			exe b:gotoOpenTag
			exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
			exe "normal! ".l:len."x"
			let &report= l:rep
		en
	en
endf
en
"
" FoldTag() Fold the tag under the cursor                           {{{1
if !exists('*s:FoldTag')
fun! s:FoldTag()
	let l:restore = s:SavePos()
	if s:TagUnderCursor()
	let l:sline = line('.')
		if s:Match(b:tagName)
			if b:firstWasEndTag
				exe '.,'.l:sline.'fold'
			el
				exe l:sline.',.fold'
			en
		en
	el
		exe l:restore
	en
endf
en

" FoldTagAll() Fold all tags of under the cursor             {{{1
" If no tag under the cursor it asks for a tag
if !exists('*s:FoldTagAll')
fun! s:FoldTagAll()
	let l:restore = s:SavePos()
	if s:TagUnderCursor()
		let l:tname = b:tagName
	el
		let l:tname = inputdialog('Which tag to fold : ',b:lastTag)
		if strlen(l:tname) == 0
			exe l:restore
			retu
		en
		let b:lastTag =  l:tname
	en
	normal! G$
	let l:flag='w'
	while search('<'.l:tname.s:OptAttrib,l:flag) > 0
		let l:flag='W'
		let l:sline = line('.')
		let l:level = 1
		while l:level && search('</\='.l:tname.s:OptAttrib,'W') > 0
			let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
		endwhile
		if l:level == 0
			exe l:sline.',.fold'
		el
			let l:tmp = 
				\ inputdialog("The tag ".l:tname."(".l:sline.") doesn't have a closetag")
			break
		en
	endwhile
	exe l:restore
endf
en


" StartTag() provide the opening tag                                    {{{1
if !exists('*s:StartTag')
fun! s:StartTag()
	let l:restore = s:SavePos()
	let l:level = 1
	if getline('.')[col('.')-1] == '<'
	  if s:TagUnderCursor()
	    if b:firstWasEndTag 
				exe 'normal! i<'. b:tagName.">\<Esc>F<"
				retu
			el
	      let l:level = l:level + 1
	    en
		en
	  exe l:restore
	en
	while l:level && search(s:OpenOrCloseTag ,'W') > 0 
		let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
	endwhile
	if l:level == 0
	  let l:Name = s:GetTagName(col('.') + 1)
	  exe l:restore
	  exe 'normal! i<'. l:Name.">\<Esc>"
	en
	exe l:restore
endf
en



" EndTag() search for open tag and produce endtaf                 {{{1
if !exists('*s:EndTag')
fun! s:EndTag()
	let l:restore = s:SavePos()
	let l:level = -1
	while l:level && search(s:OpenOrCloseTag,'bW') > 0
		let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
	endwhile
	if l:level == 0
	  let l:Name = s:GetTagName(col('.'))
	  exe  l:restore
	  exe 'normal! a</'. l:Name.">\e"
	el
	  exe  l:restore
	en
endf
en


" BeforeTag() surrounds the current tag with a new one                   {{{1
if !exists('*s:BeforeTag')
fun! s:BeforeTag()
	let l:restore = s:SavePos()
	if s:TagUnderCursor()
		let l:newname =
			\ inputdialog('Surround Before Tag '.b:tagName.' with : ',b:lastTag)
		if strlen(l:newname) == 0
			retu
		en
		let b:lastTag = l:newname
		let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
		if strlen(l:newatt)
			let b:lastAtt = l:newatt
		en
		if s:Match(b:tagName)
			exe b:gotoCloseTag
			exe "normal! />\<Cr>a\<Cr></" . l:newname . ">\<Esc>"
			let l:To = line('.')
			exe b:gotoOpenTag
			exe 'normal! i<' . l:newname . 
				\ (strlen(l:newatt) ? ' '.l:newatt : '' )
				\.">\<Cr>\<Esc>"
			let l:rep=&report
			let &report=999999
			exe line('.').','.l:To.'>'
			let &report= l:rep
		en
		exe  l:restore
	en
endf
en

" CommentTag() surrounds the current tag with a new one                   {{{1
if !exists('*s:CommentTag')
fun! s:CommentTag()
	let l:restore = s:SavePos()
	if s:TagUnderCursor()
		if s:Match(b:tagName)
			exe b:gotoCloseTag
			exe "normal! />\<Cr>a\<Cr>-->\<Esc>"
			let l:To = line('.')
			exe b:gotoOpenTag
			exe "normal! i<!--\<Cr>\<Esc>"
			let l:rep=&report
			let &report=999999
			exe line('.').','.l:To.'>'
			let &report= l:rep
		en
	else
		exe  l:restore
	en
endf
en
" AfterTag() surrounds the tags after the current one with new      {{{1
if !exists('*s:AfterTag')
fun! s:AfterTag()
	let l:restore = s:SavePos()
	if s:TagUnderCursor()
		let l:newname =
			\ inputdialog('Add Tag After '.b:tagName.' with : ',b:lastTag)
		if strlen(l:newname) == 0
			retu
		en
		let b:lastTag = l:newname
		let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
		if strlen(l:newatt)
			let b:lastAtt = l:newatt
		en
		if s:Match(b:tagName)
			exe b:gotoCloseTag
			exe 'normal! i</' . l:newname . ">\<Cr>\<Esc>"
			let l:To = line('.')
			exe b:gotoOpenTag
			exe "normal! />\<Cr>a\<Cr><".l:newname.
				\ (strlen(l:newatt) ? ' '.l:newatt : '' )
				\.">\<Esc>"
			let l:rep=&report
			let &report=999999
			exe line('.').','.l:To.'>'
			let &report= l:rep
		en
	en
	exe  l:restore
endf
en
" ShiftRight() Shift the tag to the right                               {{{1
if !exists('*s:ShiftRight')
fun! s:ShiftRight()
	let l:restore = s:SavePos()
	if s:TagUnderCursor()
		let l:sline = line('.')
		if s:Match(b:tagName)
			let l:eline = line('.')
			if b:firstWasEndTag
				exe l:eline.','.l:sline.'>'
			el
				exe l:sline.','.l:eline.'>'
			en
		en
	en
endf
en

" ShiftLeft() Shift the tag to the left                                {{{1
if !exists('*s:ShiftLeft')
fun! s:ShiftLeft()
	let l:restore = s:SavePos()
	if s:TagUnderCursor()
		let l:sline = line('.')
		if s:Match(b:tagName)
			let l:eline = line('.')
			if b:firstWasEndTag
				exe l:eline.','.l:sline.'<'
			el
				exe l:sline.','.l:eline.'<'
			en
		en
	en
endf
en
" FormatTag() visual select the block and use gq                    {{{1
if !exists('*s:FormatTag')
fun! s:FormatTag()
	if s:TagUnderCursor()
		if s:Match(b:tagName)
			exe b:gotoCloseTag
			normal! hhmh
			exe b:gotoOpenTag
			exe "normal! />/e+1\<Cr>v'hgq"
		en
	en
endf
en




" FormatTagAll() Format all tags of name under the cursor             {{{1
" If no tag under the cursor it asks for a tag
if !exists('*s:FormatTagAll')
fun! s:FormatTagAll()
	let l:restore = s:SavePos()
	if s:TagUnderCursor()
		let l:tname = b:tagName
	el
		let l:tname = inputdialog('Format every tag : ')
		if strlen(l:tname) == 0
			exe l:restore
			retu
		en
	en
	normal! G$
	let l:flag = 'w'
	while search('<'.l:tname . s:OptAttrib, l:flag) > 0
		let l:flag = 'W'
		let l:sline = line('.')
		let l:level = 1
		exe "normal! />/e+1\<cr>mh"
		while l:level &&  search('</\='.l:tname . s:EndofName,'W') > 0
			let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
		endwhile
		if l:level == 0
			normal! hv'hogq
		el
			let l:tmp = 
				\ inputdialog("The tag ".l:tname."(".l:sline.") doesn't have a closetag")
			break
		en
	endwhile
	exe l:restore
endf
en


" IndentAll() indent all tags multiline                            {{{1
if !exists('*s:IndentAll')
fun! s:IndentAll()

	let l:restore = s:SavePos()
			let l:rep=&report
			let &report=999999
	"shift everything left
	normal! 1G<G<G<G<G<G<GG$
	if search(s:OpenTag,'w') > 0
		let l:level = 1
		normal! f>
		"if there is something after the tag move that to the next line
		if col('.')+1 != col('$')
			echo "after tag".line('.')
			exe "normal! a\<Cr>\<Esc>"
		el
			normal! j
		en
		normal! >Gk$
		while search(s:OpenOrCloseTag,'W') > 0
			"if there is text before the tag then move the tag to the next line
			if  match(getline('.'),s:SpaceInfront) == -1
				exe "normal! i\<Cr>\<Esc>l"
			en
			if getline('.')[col('.')] == '/'
				normal! <G0f>
				"if there is something after the tag move that to the next line
				if col('.')+1 != col('$')
					exe "normal! a\<Cr>\<Esc>"
				en
				let l:level = l:level - 1
			el
				normal! f>
				"if there is something after the tag move that to the next line
				if col('.')+1 != col('$')
					exe "normal! a\<Cr>\<Esc>"
				el
					normal! j0
				en
				normal! >Gk$
				let l:level = l:level + 1
			en
		endwhile
		if l:level 
			let l:tmp = 
			\ inputdialog("The tags opening and closing are unbalanced ".l:level)
		en
	en
	exe l:restore
	let &report= l:rep
endf
en


" Menu options: {{{1
augroup XML_menu_autos
au!
autocmd BufLeave,BufWinLeave *
 \ if &filetype == "xml" ||  &filetype == "html" ||  &filetype == "xhtml" |
   \ amenu disable Xml |
   \ amenu disable Xml.* |
 \ endif
autocmd BufEnter,BufWinEnter *
 \ if &filetype == "xml" ||  &filetype == "html" ||  &filetype == "xhtml" |
   \ amenu enable Xml |
   \ amenu enable Xml.* |
 \ endif
au BufNewFile *
 \ if &filetype == "xml" ||  &filetype == "html" ||  &filetype == "xhtml" |
		 \ call NewFileXML() |
	 \ endif
augroup END
if !exists("g:did_xml_menu")
	let g:did_xml_menu = 1
	:1011 vmenu <script> &Xml.BlockTag\ multi<Tab>V  <Esc>:call <SID>BlockTag(1)<Cr>
	vmenu <script> Xml.BlockTag\ inline<Tab>v  <Esc>:call <SID>BlockTag(0)<CR>
	vmenu <script> Xml.Insert\ listitem<Tab>l <Esc>:call <SID>vlistitem()<CR>
	vmenu <script> Xml.Comment<Tab>< <Esc>:call <SID>BlockWith('<!--','-->')<Cr>
	vmenu <script> Xml.Comment\ With\ CData<Tab>c <Esc>:call <SID>BlockWith('<![CDATA[',']]>')<Cr>
	nmenu <script> Xml.Comment\ Tag<Tab>= <Esc>:call <SID>CommentTag()<Cr>
	imenu <script> Xml.Comment\ Tag<Tab>= <Esc>:call <SID>CommentTag()<Cr>
	nmenu <script> Xml.Change<Tab>c  :call <SID>Change()<CR>
	imenu <script> Xml.Change<Tab>c  <C-C>:call <SID>Change()<CR>
	nmenu <script> Xml.Change\ Whole\ Tag<Tab>C  :call <SID>ChangeWholeTag()<CR>
	imenu <script> Xml.Change\ Whole\ Tag<Tab>C  <C-C>:call <SID>ChangeWholeTag()<CR>
	nmenu <script> Xml.Delete\ Comment<Tab>]  :call <SID>DelComment()<CR>
	imenu <script> Xml.Delete\ Comment<Tab>]  <C-C>:call <SID>DelComment()<CR>
	nmenu <script> Xml.Delete\ Comment\ Section<Tab>}  :call <SID>DelCommentSection()<CR>
	imenu <script> Xml.Delete\ Comment\ Section<Tab>}  <C-C>:call <SID>DelCommentSection()<CR>
	nmenu <script> Xml.Delete\ CData<Tab>[  :call <SID>DelCData()<CR>
	imenu <script> Xml.Delete\ CData<Tab>[  <C-C>:call <SID>DelCData()<CR>
	nmenu <script> Xml.Delete\ CData\ Section<Tab>[  :call <SID>DelCDataSection()<CR>
	imenu <script> Xml.Delete\ CData\ Section<Tab>[  <C-C>:call <SID>DelCDataSection()<CR>
	nmenu <script> Xml.Delete\ Tag<Tab>d  :call <SID>Delete()<CR>
	imenu <script> Xml.Delete\ Tag<Tab>d  <C-C>:call <SID>Delete()<CR>
	nmenu <script> Xml.Delete\ Section<Tab>D  :call <SID>DeleteSection()<CR>
	imenu <script> Xml.Delete\ Section<Tab>D  <C-C>:call <SID>DeleteSection()<CR>
	nmenu <script> Xml.End\ Tag<Tab>e  :call <SID>EndTag()<CR>
	imenu <script> Xml.End\ Tag<Tab>e  <C-C>:call <SID>EndTag()<CR>
	nmenu <script> Xml.Fold\ Comment  :?<!--?,/-->/fo<CR>
	nmenu <script> Xml.Fold\ CData  :?<!\[CDATA\[?,/\]\]>/fo<CR>
	nmenu <script> Xml.Fold\ Processing\ instruc  :?<\?[a-zA-Z]*?,/?>/fo<CR>
	nmenu <script> Xml.Fold\ Tag<Tab>f  :call <SID>FoldTag()<CR>
	nmenu <script> Xml.Fold\ All\ Tags<Tab>F  :call <SID>FoldTagAll()<CR>
	nmenu <script> Xml.Format\ Tags<Tab>g  :call <SID>FormatTag()<CR>
	nmenu <script> Xml.Format\ All\ Tags<Tab>G  :call <SID>FormatTagAll()<CR>
	nmenu <script> Xml.Join<Tab>j  :call <SID>Join()<CR>
	imenu <script> Xml.Join<Tab>j  <C-C>:call <SID>Join()<CR>
	nmenu <script> Xml.Open\ After\ Tag<Tab>O  :call <SID>AfterTag()<CR>
	imenu <script> Xml.Open\ After\ Tag<Tab>O  <C-C>:call <SID>AfterTag()<CR>
	nmenu <script> Xml.open\ Before\ Tag<Tab>o  :call <SID>BeforeTag()<CR>
	imenu <script> Xml.open\ Before\ Tag<Tab>o  <C-C>:call <SID>BeforeTag()<CR>
	nmenu <script> Xml.Match<Tab>5  :call <SID>Matches()<CR>
	imenu <script> Xml.Match<Tab>5  <C-C>:call <SID>Matches()<CR><C-\><C-G>
	nmenu <script> Xml.Shift\ Left<Tab><  :call <SID>ShiftLeft()<CR>
	imenu <script> Xml.Shift\ Left<Tab><  <C-C>:call <SID>ShiftLeft()<CR><C-\><C-G>
	nmenu <script> Xml.Shift\ Right<Tab>>  :call <SID>ShiftRight()<CR>
	imenu <script> Xml.Shift\ Right<Tab>>  <C-C>:call <SID>ShiftRight()<CR><C-\><C-G>
	nmenu <script> Xml.Start\ Tag<Tab>s  :call <SID>StartTag()<CR>
	imenu <script> Xml.Start\ Tag<Tab>s  <C-C>:call <SID>StartTag()<CR><C-\><C-G>
en

" Section: Doc installation                                                {{{1
" Function: s:XmlInstallDocumentation(full_name, revision)              {{{2
"   Install help documentation.
" Arguments:
"   full_name: Full name of this vim plugin script, including path name.
"   revision:  Revision of the vim script. #version# mark in the document file
"              will be replaced with this string with 'v' prefix.
" Return:
"   1 if new document installed, 0 otherwise.
" Note: Cleaned and generalized by guo-peng Wen
"'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

function! s:XmlInstallDocumentation(full_name, revision)
    " Name of the document path based on the system we use:
    if (has("unix"))
        " On UNIX like system, using forward slash:
        let l:slash_char = '/'
        let l:mkdir_cmd  = ':silent !mkdir -p '
    else
        " On M$ system, use backslash. Also mkdir syntax is different.
        " This should only work on W2K and up.
        let l:slash_char = '\'
        let l:mkdir_cmd  = ':silent !mkdir '
    endif

    let l:doc_path = l:slash_char . 'doc'
    "let l:doc_home = l:slash_char . '.vim' . l:slash_char . 'doc'

    " Figure out document path based on full name of this script:
    let l:vim_plugin_path = fnamemodify(a:full_name, ':h')
    "let l:vim_doc_path   = fnamemodify(a:full_name, ':h:h') . l:doc_path
    let l:vim_doc_path    = matchstr(l:vim_plugin_path, 
            \ '.\{-}\ze\%(\%(ft\)\=plugin\|macros\)') . l:doc_path
    if (!(filewritable(l:vim_doc_path) == 2))
        echomsg "Doc path: " . l:vim_doc_path
        execute l:mkdir_cmd . l:vim_doc_path
        if (!(filewritable(l:vim_doc_path) == 2))
            " Try a default configuration in user home:
            "let l:vim_doc_path = expand("~") . l:doc_home
            let l:vim_doc_path = matchstr(&rtp,
                  \ escape($HOME, ' \') .'[/\\]\%(\.vim\|vimfiles\)')
            if (!(filewritable(l:vim_doc_path) == 2))
                execute l:mkdir_cmd . l:vim_doc_path
                if (!(filewritable(l:vim_doc_path) == 2))
                    " Put a warning:
                    echomsg "Unable to open documentation directory"
                    echomsg " type :help add-local-help for more informations."
                    return 0
                endif
            endif
        endif
    endif

    " Exit if we have problem to access the document directory:
    if (!isdirectory(l:vim_plugin_path)
        \ || !isdirectory(l:vim_doc_path)
        \ || filewritable(l:vim_doc_path) != 2)
        return 0
    endif

    " Full name of script and documentation file:
    let l:script_name = 'xml.vim'
    let l:doc_name    = 'xml-plugin.txt'
    let l:plugin_file = l:vim_plugin_path . l:slash_char . l:script_name
    let l:doc_file    = l:vim_doc_path    . l:slash_char . l:doc_name

    " Bail out if document file is still up to date:
    if (filereadable(l:doc_file)  &&
        \ getftime(l:plugin_file) < getftime(l:doc_file))
        return 0
    endif

    " Prepare window position restoring command:
    if (strlen(@%))
        let l:go_back = 'b ' . bufnr("%")
    else
        let l:go_back = 'enew!'
    endif

    " Create a new buffer & read in the plugin file (me):
    setl nomodeline
    exe 'enew!'
    exe 'r ' . l:plugin_file

    setl modeline
    let l:buf = bufnr("%")
    setl noswapfile modifiable

    norm zR
    norm gg

    " Delete from first line to a line starts with
    " === START_DOC
    1,/^=\{3,}\s\+START_DOC\C/ d

    " Delete from a line starts with
    " === END_DOC
    " to the end of the documents:
    /^=\{3,}\s\+END_DOC\C/,$ d

    " Remove fold marks:
    "% s/{\{3}[1-9]/    /

    " Add modeline for help doc: the modeline string is mangled intentionally
    " to avoid it be recognized by VIM:
    call append(line('$'), '')
    call append(line('$'), ' v' . 'im:tw=78:ts=8:fen:fdm=marker:ft=help:norl:')

    " Replace revision:
    exe "normal! :1,5s/#version#/ v" . a:revision . "/\<CR>"

    " Save the help document:
    exe 'w! ' . l:doc_file
    exe l:go_back
    exe 'bw ' . l:buf

    " Build help tags:
    exe 'helptags ' . l:vim_doc_path

    return 1
endfunction
" }}}2

let s:revision=
      \ substitute("$Revision: 1.36 $",'\$\S*: \([.0-9]\+\) \$','\1','')
silent! let s:install_status =
    \ s:XmlInstallDocumentation(expand('<sfile>:p'), s:revision)
if (s:install_status == 1)
    echom expand("<sfile>:t:r") . '-plugin v' . s:revision .
        \ ': Help-documentation installed.'
endif


" Mappings of keys to functions                                      {{{1
nnoremap <silent> <buffer> <LocalLeader>5 :call <SID>Matches()<Cr>
vnoremap <silent> <buffer> <LocalLeader>5 <Esc>:call <SID>MatchesVisual()<Cr>
nnoremap <silent> <buffer> <LocalLeader>% :call <SID>Matches()<Cr>
vnoremap <silent> <buffer> <LocalLeader>% <Esc>:call <SID>MatchesVisual()<Cr>
nnoremap <silent> <buffer> <LocalLeader>c :call <SID>Change()<Cr>
nnoremap <silent> <buffer> <LocalLeader>C :call <SID>ChangeWholeTag()<Cr>
nnoremap <silent> <buffer> <LocalLeader>d :call <SID>Delete()<Cr>
nnoremap <silent> <buffer> <LocalLeader>D :call <SID>DeleteSection()<Cr>
nnoremap <silent> <buffer> <LocalLeader>e :call <SID>EndTag()<Cr>
nnoremap <silent> <buffer> <LocalLeader>] :call <SID>DelComment()<Cr>
nnoremap <silent> <buffer> <LocalLeader>} :call <SID>DelCommentSection()<Cr>
nnoremap <silent> <buffer> <LocalLeader>f :call <SID>FoldTag()<Cr>
nnoremap <silent> <buffer> <LocalLeader>F :call <SID>FoldTagAll()<Cr>
nnoremap <silent> <buffer> <LocalLeader>g :call <SID>FormatTag()<Cr>
nnoremap <silent> <buffer> <LocalLeader>G :call <SID>FormatTagAll()<Cr>
nnoremap <silent> <buffer> <LocalLeader>I :call <SID>IndentAll()<Cr>
nnoremap <silent> <buffer> <LocalLeader>j :call <SID>Join()<Cr>
nnoremap <silent> <buffer> <LocalLeader>O :call <SID>BeforeTag()<Cr>
nnoremap <silent> <buffer> <LocalLeader>= :call <SID>CommentTag()<Cr>
nnoremap <silent> <buffer> <LocalLeader>o :call <SID>AfterTag()<Cr>
nnoremap <silent> <buffer> <LocalLeader>s :call <SID>StartTag()<Cr>
nnoremap <silent> <buffer> <LocalLeader>[ :call <SID>DelCData()<Cr>
nnoremap <silent> <buffer> <LocalLeader>{ :call <SID>DelCDataSection()<Cr>
nnoremap <silent> <buffer> <LocalLeader>> :call <SID>ShiftRight()<Cr>
nnoremap <silent> <buffer> <LocalLeader>< :call <SID>ShiftLeft()<Cr>
vnoremap <silent> <buffer> <LocalLeader>l <Esc>:call <SID>vlistitem()<Cr>
vnoremap <silent> <buffer> <LocalLeader>v <Esc>:call <SID>BlockTag(0)<Cr>
vnoremap <silent> <buffer> <LocalLeader>V <Esc>:call <SID>BlockTag(1)<Cr>
vnoremap <silent> <buffer> <LocalLeader>c <Esc>:call <SID>BlockWith('<![CDATA[',']]>')<Cr>
vnoremap <silent> <buffer> <LocalLeader>< <Esc>:call <SID>BlockWith('<!--','-->')<Cr>

" Move around functions.
noremap <silent><buffer> [[ m':call <SID>findOpenTag("bW")<CR>
noremap <silent><buffer> ]] m':call <SID>findOpenTag( "W")<CR>
noremap <silent><buffer> [] m':call <SID>findCloseTag( "bW")<CR>
noremap <silent><buffer> ][ m':call <SID>findCloseTag( "W")<CR>

" Move around comments
noremap <silent><buffer> ]" :call search('^\(\s*<!--.*\n\)\@<!\(\s*-->\)', "W")<CR>
noremap <silent><buffer> [" :call search('\%(^\s*<!--.*\n\)\%(^\s*-->\)\@!', "bW")<CR>


setlocal iskeyword=@,48-57,_,192-255,58  
exe 'inoremap <silent> <buffer> '.b:suffix. " ><Esc>db:call <SID>makeElement()<Cr>"
if !exists("g:xml_tag_completion_map")
    inoremap <silent> <buffer> > ><Esc>:call <SID>CloseTagFun()<Cr>
else
    execute "inoremap <silent> <buffer> " . g:xml_tag_completion_map . " ><Esc>:call <SID>CloseTagFun()<Cr>"
endif



finish

""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""/*}}}*/
" Section: Documentation content                                          {{{1
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
=== START_DOC
*xml-plugin.txt*  Help edit XML and SGML documents.                  #version#

				   XML Edit  ~

A filetype plugin to help edit XML and SGML documents.

This script provides some convenience when editing XML (and some SGML
including HTML) formated documents. It allows you to jump to the
beginning or end of the tag block your cursor is in. '%' will jump
between '<' and '>' within the tag your cursor is in. When in insert
mode and you finish a tag (pressing '>') the tag will be completed. If
you press '>' twice it will place the cursor in the middle of the tags
on it's own line (helps with nested tags).

Usage: Place this file into your ftplugin directory. To add html support
Sym-link or copy this file to html.vim in your ftplugin directory. To activte
the script place 'filetype plugin on' in your |.vimrc| file. See |ftplugins|
for more information on this topic.

If the file edited is of type "html" and "xml_use_html" is  defined then
the following tags will not auto complete: <img>, <input>, <param>,
<frame>, <br>, <hr>, <meta>, <link>, <base>, <area>
        
If the file edited is of type 'html' and 'xml_use_xhtml' is defined the
above tags will autocomplete the xml closing staying xhtml compatable.
ex. <hr> becomes <hr /> (see |xml-plugin-settings|)

Known Bugs {{{1 ~

- < & > marks inside of a CDATA section are interpreted as actual XML tags
  even if unmatched.
- The script can not handle leading spaces such as < tag></ tag> it is
  illegal XML syntax and considered very bad form.
- Placing a literal `>' in an attribute value will auto complete despite that
  the start tag isn't finished. This is poor XML anyway you should use
  &gt; instead.


------------------------------------------------------------------------------
                                                         *xml-plugin-settings*
Options {{{1

(All options must be placed in your |.vimrc| prior to the |ftplugin|
command.)

xml_tag_completion_map
	Use this setting to change the default mapping to auto complete a
	tag. By default typing a literal `>' will cause the tag your editing
	to auto complete; pressing twice will auto nest the tag. By using
	this setting the `>' will be a literal `>' and you must use the new
	mapping to perform auto completion and auto nesting. For example if
	you wanted Control-L to perform auto completion inmstead of typing a
	`>' place the following into your .vimrc: >
            let xml_tag_completion_map = "<C-l>"
<
xml_no_auto_nesting (Not Working!!!!!)
	This turns off the auto nesting feature. After a completion is made
	and another `>' is typed xml-edit automatically will break the tag
	accross multiple lines and indent the curser to make creating nested
	tqags easier. This feature turns it off. Enter the following in your
	.vimrc: >
            let xml_no_auto_nesting = 1
<
xml_use_xhtml
	When editing HTML this will auto close the short tags to make valid
	XML like <hr/> and <br/>. Enter the following in your vimrc to
	turn this option on: >
            let xml_use_xhtml = 1
	if the filetype is xhtml and g:xml_use_xhtml doesn't exists
	the script defines it to be 1. (This also assumes that you have linked
	xml.vim to xhtml.vim. Otherwise this item is moot)
	For a file to be of xhtml type there need to be a doctype declaration!!
	just naming a file something.xhtml doesn't make it type xhtml!
<
xml_no_html
	This turns of the support for HTML specific tags. Place this in your
        .vimrc: >
            let xml_no_html = 1
<
------------------------------------------------------------------------------
                                                        *xml-plugin-mappings*

Mapings and their functions {{{1

Typing '>' will start the tag closing routine.
Typing (Where | means cursor position)
           <para>|
results in
           <para>|</para>

Typing
           <para>>|</para>
results in
           <para>
                |
           </para>
typing a lone '>' and no '<' in front of it accepts the '>' (But having
lone '>' or '<' in a XML file is frown upon except in <!CDATA> sections,
and that will throw of the plugin!!).

Typing </tag> or <tag/> also results in na expanding. So when editing
html type <input .... />

The closing routing also ignores DTD tags '<!,,>' and processing
instructions '<?....?>'. Thus typing these result in no expansion.


<LocalLeader> is a setting in VIM that depicts a prefix for scripts and
plugins to use. By default this is the backslash key `\'. See |mapleader|
for details.

;;              make element out previous word and close it         {{{2
          - when typing a word;; wil create <word>|</word>
						when word on its own line it will be
						<word>
               |
						</word>
            the suffix can be changed by setting 
						let makeElementSuf = ',,,' in your .vimrc
						Thanks to Bart van Deenen
						(http://www.vim.org/scripts/script.php?script_id=632)
						
[ and ] mappings                            {{{2
          <LocalLeader>[        Delete <![CDATA[ ]]> delimiters
          <LocalLeader>{        Delete <![CDATA[ ]]> section
          <LocalLeader>]        Delete <!-- -->      delimiters
          <LocalLeader>}        Delete <!-- -->      section
          [[        Goto to the previous open tag 
          [[        Goto to the next open tag 
          []        Goto to the previous close tag 
          ][        Goto to the next  close tag 
          ["        Goto to the next  comment
          ]"        Goto the previous comment
<LocalLeader>5  Jump to the matching tag.                           {{{2
<LocalLeader>%  Jump to the matching tag.   


<LocalLeader>c  Rename tag                                          {{{2

<LocalLeader>C  Rename tag and remove attributes                    {{{2
		Will ask for attributes

<LocalLeader>d  Deletes the surrounding tags from the cursor.       {{{2
            <tag1>outter <tag2>inner text</tag2> text</tag1>
               |
       Turns to: 
            outter <tag2>inner text</tag2> text
            |

<LocalLeader>D  Deletes the tag and it contents                     {{{2
        - and put it in register x.
            <tag1>outter <tag2>inner text</tag2> text</tag1>
                           |
       Turns to: 
            <tag1>outter text</tag1>

<LocalLeader>e  provide endtag for open tags.                       {{{2
        - provide endtag for open tags. Watch where de cursor is
            <para><listitem>list item content
                                            |
        pressing \e twice produces
            <para><listitem>list item content</para></listitem>

<LocalLeader>f  fold the tag under the cursor                       {{{2
          <para>
            line 1
            line 2
            line 3
          </para>
        \f produces
        +--  5 lines: <para>--------------------------


<LocalLeader>F  all tags of name 'tag' will be fold.                {{{2
      - If there isn't a tag under
        the cursor you will be asked for one.
                  
<LocalLeader>g  Format (Vim's gq function)                          {{{2
			- will make a visual block of tag under cursor and then format using gq

                  
<LocalLeader>G  Format all tags under cursor (Vim's gq function)    {{{2
      - If there isn't a tag under
        the cursor you will be asked for one.

                  
<LocalLeader>I  Indent all tags     {{{2
      - will create a multiline layout every opening tag will be shifted out
				and every closing tag will be shifted in. Be aware that the rendering
				of the XML through XSLT and/or DSSSL, might be changed by this.
				Be aware tha if the file is big, more than 1000 lines, the reformatting
				takes a long time because vim has to make a big undo buffer.
				For example using \I on the example below:
        
				<chapter><title>Indent</title><para>The documentation</para></chapter>

			- Becomes

				<chapter>
					<title>
						Indent
					</title>
					<para>
						The documentation
					</para>
				</chapter>

                  
<LocalLeader>j  Joins two the SAME sections together.               {{{2
      -  The sections must be next to each other. 
			<para> This is line 1
			 of a paragraph. </para>
			<para> This is line 2
			|
			 of a paragraph. </para>
		\j produces
			<para> This is line 1
			 of a paragraph. 
			 This is line 2
			 of a paragraph. </para>

<LocalLeader>l  visual surround the block with listitem and para     {{{2 
				When marking up docbook tekst you have the issue that listitems
				consist of 2 item. This key combination inserts them both,

        blaah
          |
        \l produces
        <listitem>
            <para>blaah</para>
        </listitem>
    
<LocalLeader>o  Insert a tag inside the current one (like vim o)     {{{2
				You are asked for tag and attributes.

        <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
          |
        \o produces
        <tag1>
            <aftertag><tag2><tag3>blaah</tag3></tag2></aftertag>
        </tag1>
    
<LocalLeader>O  Insert a tag outside the current one (like vim O)     {{{2
				You are asked for tag and attributes.
        <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
          |
    \O produces
        <beforetag>
          <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
        </beforetag>

<LocalLeader>s  Insert an opening tag for an closing tag.           {{{2
            list item content</para></listitem>
            |
        pressing \s twice produces
            <para><listitem>list item content</para></listitem>

<LocalLeader>[        Delete <![CDATA[ ]]> delimiters               {{{2
								Removes Only <CDATA[ and •]•]> 
								handy when you want	to uncomment a section.
								You need to stand in the tag and not on an other tag
								<![CDATA[  <tag> ]]>
								if you  cursor is outside <tag> but inside the
								CDATA tag the delition works.
<LocalLeader>{        Delete <![CDATA[ ]]> section                  {{{2
								Removes everything tag and Content
<LocalLeader>]        Delete <!-- -->      delimiters               {{{2
								Uncommnet a block.
<LocalLeader>}        Delete <!--  -->      section                  {{{2
								Removes everything tag and Content
<LocalLeader>>  shift right opening tag and closing tag.           {{{2
                shift everything between the tags 1 shiftwide right
<LocalLeader><  shift left opening tag and closing tag.           {{{2
                shift everything between the tags 1 shiftwide left
<LocalLeader>c  Visual Place a CDATA section around the selected text.  {{{2
			Place Cdata section around the block
<LocalLeader><  Visual Place a Comment around the selected text.  {{{2
			Place comment around the block
<LocalLeader>5  Extend the visual selection to the matching tag.  {{{2
<LocalLeader>%  
			Extend the visual selection to the matching tag. Make sure you are at
			the start of the opening tag or the end of the closing tag.
<LocalLeader>v  Visual Place a tag around the selected text.       {{{2
        - You are asked for tag and attributes. You
        need to have selected text in visual mode before you can use this
        mapping. See |visual-mode| for details.
        Be careful where you place the marks.
        The top uses append
        The bottom uses append
        Useful when marking up a text file

------------------------------------------------------------------------------
                                                        *xml-plugin-callbacks*

Callback Functions {{{2 ~

A callback function is a function used to customize features on a per tag
basis. For example say you wish to have a default set of attributs when you
type an empty tag like this:
    You type: <tag>
    You get:  <tag default="attributes"></tag>

This is for any script programmers who wish to add xml-plugin support to
there own filetype plugins.

Callback functions recive one attribute variable which is the tag name. The
all must return either a string or the number zero. If it returns a string
the plugin will place the string in the proper location. If it is a zero the
plugin will ignore and continue as if no callback existed.

The following are implemented callback functions:

HtmlAttribCallback
	This is used to add default attributes to html tag. It is intended
	for HTML files only.

XmlAttribCallback
	This is a generic callback for xml tags intended to add attributes.

							     *xml-plugin-html*
Callback Example {{{2 ~

The following is an example of using XmlAttribCallback in your .vimrc
>
        function XmlAttribCallback (xml_tag)
            if a:xml_tag ==? "my-xml-tag"
                return "attributes=\"my xml attributes\""
            else
                return 0
            endif
        endfunction
<
The following is a sample html.vim file type plugin you could use:
>
  " Vim script file                                       vim600:fdm=marker:
  " FileType:   HTML
  " Maintainer: Devin Weaver <vim (at) tritarget.com>
  " Location:   http://www.vim.org/scripts/script.php?script_id=301

  " This is a wrapper script to add extra html support to xml documents.
  " Original script can be seen in xml-plugin documentation.

  " Only do this when not done yet for this buffer
  if exists("b:did_ftplugin")
    finish
  endif
  " Don't set 'b:did_ftplugin = 1' because that is xml.vim's responsability.

  let b:html_mode = 1

  if !exists("*HtmlAttribCallback")
  function HtmlAttribCallback( xml_tag )
      if a:xml_tag ==? "table"
          return "cellpadding=\"0\" cellspacing=\"0\" border=\"0\""
      elseif a:xml_tag ==? "link"
          return "href=\"/site.css\" rel=\"StyleSheet\" type=\"text/css\""
      elseif a:xml_tag ==? "body"
          return "bgcolor=\"white\""
      elseif a:xml_tag ==? "frame"
          return "name=\"NAME\" src=\"/\" scrolling=\"auto\" noresize"
      elseif a:xml_tag ==? "frameset"
          return "rows=\"0,*\" cols=\"*,0\" border=\"0\""
      elseif a:xml_tag ==? "img"
          return "src=\"\" width=\"0\" height=\"0\" border=\"0\" alt=\"\""
      elseif a:xml_tag ==? "a"
          if has("browse")
	      " Look up a file to fill the href. Used in local relative file
	      " links. typeing your own href before closing the tag with `>'
	      " will override this.
              let cwd = getcwd()
              let cwd = substitute (cwd, "\\", "/", "g")
              let href = browse (0, "Link to href...", getcwd(), "")
              let href = substitute (href, cwd . "/", "", "")
              let href = substitute (href, " ", "%20", "g")
          else
              let href = ""
          endif
          return "href=\"" . href . "\""
      else
          return 0
      endif
  endfunction
  endif

  " On to loading xml.vim
  runtime ftplugin/xml.vim
<
=== END_DOC
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" v im:tw=78:ts=8:ft=help:norl:
" vim600: set foldmethod=marker  tabstop=8 shiftwidth=2 softtabstop=2 smartindent smarttab  :
"fileencoding=iso-8859-15 
=== END_DOC
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""






" Vim settingѕ                                                            {{{1
" vim:tw=78:ts=2:ft=help:norl:
" vim: set foldmethod=marker  tabstop=2 shiftwidth=2 softtabstop=2 smartindent smarttab  :
"fileencoding=utf-8