updated for version 7.0158
This commit is contained in:
428
runtime/autoload/xmlcomplete.vim
Normal file
428
runtime/autoload/xmlcomplete.vim
Normal file
@ -0,0 +1,428 @@
|
||||
" Vim completion script
|
||||
" Language: XHTML 1.0 Strict
|
||||
" Maintainer: Mikolaj Machowski ( mikmach AT wp DOT pl )
|
||||
" Last Change: 2005 Nov 22
|
||||
|
||||
" This function will create Dictionary with users namespace strings and values
|
||||
" canonical (system) names of data files. Names should be lowercase,
|
||||
" descriptive to avoid any future conflicts. For example 'xhtml10s' should be
|
||||
" name for data of XHTML 1.0 Strict and 'xhtml10t' for XHTML 1.0 Transitional
|
||||
" User interface will be provided by XMLns command defined ...
|
||||
" Currently supported canonicals are:
|
||||
" xhtml10s - XHTML 1.0 Strict
|
||||
" xsl - XSL
|
||||
function! xmlcomplete#CreateConnection(canonical, ...)
|
||||
|
||||
" When only one argument provided treat name as default namespace (without
|
||||
" 'prefix:').
|
||||
if exists("a:1")
|
||||
let users = a:1
|
||||
else
|
||||
let users = 'DEFAULT'
|
||||
endif
|
||||
|
||||
" Source data file. Due to suspected errors in autoload do it with
|
||||
" :runtime.
|
||||
" TODO: make it properly (using autoload, that is) later
|
||||
exe "runtime autoload/xml/".a:canonical.".vim"
|
||||
|
||||
" Remove all traces of unexisting files to return [] when trying
|
||||
" omnicomplete something
|
||||
" TODO: give warning about non-existing canonicals - should it be?
|
||||
if !exists("g:xmldata_".a:canonical)
|
||||
unlet! g:xmldata_connection
|
||||
return 0
|
||||
endif
|
||||
|
||||
" We need to initialize Dictionary to add key-value pair
|
||||
if !exists("g:xmldata_connection")
|
||||
let g:xmldata_connection = {}
|
||||
endif
|
||||
|
||||
let g:xmldata_connection[users] = a:canonical
|
||||
|
||||
endfunction
|
||||
|
||||
function! xmlcomplete#CreateEntConnection(...)
|
||||
if a:0 > 0
|
||||
let g:xmldata_entconnect = a:1
|
||||
else
|
||||
let g:xmldata_entconnect = 'DEFAULT'
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! xmlcomplete#CompleteTags(findstart, base)
|
||||
if a:findstart
|
||||
" locate the start of the word
|
||||
let line = getline('.')
|
||||
let start = col('.') - 1
|
||||
let compl_begin = col('.') - 2
|
||||
|
||||
while start >= 0 && line[start - 1] =~ '\(\k\|[:.-]\)'
|
||||
let start -= 1
|
||||
endwhile
|
||||
|
||||
if start >= 0 && line[start - 1] =~ '&'
|
||||
let b:entitiescompl = 1
|
||||
let b:compl_context = ''
|
||||
return start
|
||||
endif
|
||||
|
||||
let b:compl_context = getline('.')[0:(compl_begin)]
|
||||
let b:compl_context = matchstr(b:compl_context, '.*<\zs.*')
|
||||
|
||||
" Make sure we will have only current namespace
|
||||
unlet! b:xml_namespace
|
||||
let b:xml_namespace = matchstr(b:compl_context, '^\k*\ze:')
|
||||
if b:xml_namespace == ''
|
||||
let b:xml_namespace = 'DEFAULT'
|
||||
endif
|
||||
|
||||
return start
|
||||
|
||||
else
|
||||
" There is no connction of namespace and data file. Abandon action
|
||||
if !exists("g:xmldata_connection") || g:xmldata_connection == {}
|
||||
return []
|
||||
endif
|
||||
" Initialize base return lists
|
||||
let res = []
|
||||
let res2 = []
|
||||
" a:base is very short - we need context
|
||||
let context = b:compl_context
|
||||
unlet! b:compl_context
|
||||
|
||||
" Make entities completion
|
||||
if exists("b:entitiescompl")
|
||||
unlet! b:entitiescompl
|
||||
|
||||
if !exists("g:xmldata_entconnect") || g:xmldata_entconnect == 'DEFAULT'
|
||||
let values = g:xmldata{'_'.g:xmldata_connection['DEFAULT']}['vimxmlentities']
|
||||
else
|
||||
let values = g:xmldata{'_'.g:xmldata_entconnect}['vimxmlentities']
|
||||
endif
|
||||
|
||||
" Get only lines with entity declarations but throw out
|
||||
" parameter-entities - they may be completed in future
|
||||
let entdecl = filter(getline(1, "$"), 'v:val =~ "<!ENTITY\\s\\+[^%]"')
|
||||
|
||||
if len(entdecl) > 0
|
||||
let intent = map(copy(entdecl), 'matchstr(v:val, "<!ENTITY\\s\\+\\zs\\(\\k\\|[.-:]\\)\\+\\ze")')
|
||||
let values = intent + values
|
||||
endif
|
||||
|
||||
for m in values
|
||||
if m =~ '^'.a:base
|
||||
call add(res, m.';')
|
||||
endif
|
||||
endfor
|
||||
|
||||
return res
|
||||
|
||||
endif
|
||||
if context =~ '>'
|
||||
" Generally if context contains > it means we are outside of tag and
|
||||
" should abandon action
|
||||
return []
|
||||
endif
|
||||
|
||||
" find tags matching with "a:base"
|
||||
" If a:base contains white space it is attribute.
|
||||
" It could be also value of attribute...
|
||||
" We have to get first word to offer
|
||||
" proper completions
|
||||
if context == ''
|
||||
let tag = ''
|
||||
else
|
||||
let tag = split(context)[0]
|
||||
endif
|
||||
" Get rid of namespace
|
||||
let tag = substitute(tag, '^'.b:xml_namespace.':', '', '')
|
||||
|
||||
|
||||
" Get last word, it should be attr name
|
||||
let attr = matchstr(context, '.*\s\zs.*')
|
||||
" Possible situations where any prediction would be difficult:
|
||||
" 1. Events attributes
|
||||
if context =~ '\s'
|
||||
|
||||
" If attr contains =\s*[\"'] we catched value of attribute
|
||||
if attr =~ "=\s*[\"']"
|
||||
" Let do attribute specific completion
|
||||
let attrname = matchstr(attr, '.*\ze\s*=')
|
||||
let entered_value = matchstr(attr, ".*=\\s*[\"']\\zs.*")
|
||||
|
||||
if tag =~ '^[?!]'
|
||||
" Return nothing if we are inside of ! or ? tag
|
||||
return []
|
||||
else
|
||||
let values = g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1][attrname]
|
||||
endif
|
||||
|
||||
if len(values) == 0
|
||||
return []
|
||||
endif
|
||||
|
||||
" We need special version of sbase
|
||||
let attrbase = matchstr(context, ".*[\"']")
|
||||
let attrquote = matchstr(attrbase, '.$')
|
||||
|
||||
for m in values
|
||||
" This if is needed to not offer all completions as-is
|
||||
" alphabetically but sort them. Those beginning with entered
|
||||
" part will be as first choices
|
||||
if m =~ '^'.entered_value
|
||||
call add(res, m . attrquote.' ')
|
||||
elseif m =~ entered_value
|
||||
call add(res2, m . attrquote.' ')
|
||||
endif
|
||||
endfor
|
||||
|
||||
return res + res2
|
||||
|
||||
endif
|
||||
|
||||
if tag =~ '?xml'
|
||||
" Two possible arguments for <?xml> plus variation
|
||||
let attrs = ['encoding', 'version="1.0"', 'version']
|
||||
elseif tag =~ '^!'
|
||||
" Don't make completion at all
|
||||
return []
|
||||
else
|
||||
let attrs = keys(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1])
|
||||
endif
|
||||
|
||||
for m in sort(attrs)
|
||||
if m =~ '^'.attr
|
||||
if tag !~ '^[?!]' && len(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1][m]) > 0 && g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1][m][0] =~ '^BOOL$'
|
||||
call add(res, m)
|
||||
elseif m =~ '='
|
||||
call add(res, m)
|
||||
else
|
||||
call add(res, m.'="')
|
||||
endif
|
||||
elseif m =~ attr
|
||||
if tag !~ '^[?!]' && len(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1][m]) > 0 && g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1][m][0] =~ '^BOOL$'
|
||||
call add(res, m)
|
||||
elseif m =~ '='
|
||||
call add(res, m)
|
||||
else
|
||||
call add(res2, m.'="')
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
|
||||
return res + res2
|
||||
|
||||
endif
|
||||
" Close tag
|
||||
let b:unaryTagsStack = "base meta link hr br param img area input col"
|
||||
if context =~ '^\/'
|
||||
let opentag = xmlcomplete#GetLastOpenTag("b:unaryTagsStack")
|
||||
return [opentag.">"]
|
||||
endif
|
||||
|
||||
" Complete elements of XML structure
|
||||
" TODO: #REQUIRED, #IMPLIED, #FIXED, #PCDATA - but these should be detected like
|
||||
" entities - in first run
|
||||
" keywords: CDATA, ID, IDREF, IDREFS, ENTITY, ENTITIES, NMTOKEN, NMTOKENS
|
||||
" are hardly recognizable but keep it in reserve
|
||||
" also: EMPTY ANY SYSTEM PUBLIC DATA
|
||||
if context =~ '^!'
|
||||
let tags = ['!ELEMENT', '!DOCTYPE', '!ATTLIST', '!ENTITY', '!NOTATION', '![CDATA[', '![INCLUDE[', '![IGNORE[']
|
||||
|
||||
for m in tags
|
||||
if m =~ '^'.context
|
||||
let m = substitute(m, '^!\[\?', '', '')
|
||||
call add(res, m)
|
||||
elseif m =~ context
|
||||
let m = substitute(m, '^!\[\?', '', '')
|
||||
call add(res2, m)
|
||||
endif
|
||||
endfor
|
||||
|
||||
return res + res2
|
||||
|
||||
endif
|
||||
|
||||
" Complete text declaration
|
||||
let g:co = context
|
||||
if context =~ '^?'
|
||||
let tags = ['?xml']
|
||||
|
||||
for m in tags
|
||||
if m =~ '^'.context
|
||||
call add(res, substitute(m, '^?', '', ''))
|
||||
elseif m =~ context
|
||||
call add(res, substitute(m, '^?', '', ''))
|
||||
endif
|
||||
endfor
|
||||
|
||||
return res + res2
|
||||
|
||||
endif
|
||||
|
||||
" Deal with tag completion.
|
||||
let opentag = xmlcomplete#GetLastOpenTag("b:unaryTagsStack")
|
||||
let opentag = substitute(opentag, '^\k*:', '', '')
|
||||
|
||||
let tags = g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[opentag][0]
|
||||
let context = substitute(context, '^\k*:', '', '')
|
||||
|
||||
if b:xml_namespace == 'DEFAULT'
|
||||
let b:xml_namespace = ''
|
||||
else
|
||||
let b:xml_namespace .= ':'
|
||||
endif
|
||||
|
||||
for m in tags
|
||||
if m =~ '^'.context
|
||||
call add(res, b:xml_namespace.m)
|
||||
elseif m =~ context
|
||||
call add(res2, b:xml_namespace.m)
|
||||
endif
|
||||
endfor
|
||||
|
||||
return res + res2
|
||||
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" MM: This is greatly reduced closetag.vim used with kind permission of Steven
|
||||
" Mueller
|
||||
" Changes: strip all comments; delete error messages; add checking for
|
||||
" namespace
|
||||
" Author: Steven Mueller <diffusor@ugcs.caltech.edu>
|
||||
" Last Modified: Tue May 24 13:29:48 PDT 2005
|
||||
" Version: 0.9.1
|
||||
|
||||
function! xmlcomplete#GetLastOpenTag(unaryTagsStack)
|
||||
let linenum=line('.')
|
||||
let lineend=col('.') - 1 " start: cursor position
|
||||
let first=1 " flag for first line searched
|
||||
let b:TagStack='' " main stack of tags
|
||||
let startInComment=s:InComment()
|
||||
|
||||
if exists("b:xml_namespace")
|
||||
if b:xml_namespace == 'DEFAULT'
|
||||
let tagpat='</\=\(\k\|[.-]\)\+\|/>'
|
||||
else
|
||||
let tagpat='</\='.b:xml_namespace.':\(\k\|[.-]\)\+\|/>'
|
||||
endif
|
||||
else
|
||||
let tagpat='</\=\(\k\|[.-:]\)\+\|/>'
|
||||
endif
|
||||
while (linenum>0)
|
||||
let line=getline(linenum)
|
||||
if first
|
||||
let line=strpart(line,0,lineend)
|
||||
else
|
||||
let lineend=strlen(line)
|
||||
endif
|
||||
let b:lineTagStack=''
|
||||
let mpos=0
|
||||
let b:TagCol=0
|
||||
while (mpos > -1)
|
||||
let mpos=matchend(line,tagpat)
|
||||
if mpos > -1
|
||||
let b:TagCol=b:TagCol+mpos
|
||||
let tag=matchstr(line,tagpat)
|
||||
|
||||
if exists('b:closetag_disable_synID') || startInComment==s:InCommentAt(linenum, b:TagCol)
|
||||
let b:TagLine=linenum
|
||||
call s:Push(matchstr(tag,'[^<>]\+'),'b:lineTagStack')
|
||||
endif
|
||||
let lineend=lineend-mpos
|
||||
let line=strpart(line,mpos,lineend)
|
||||
endif
|
||||
endwhile
|
||||
while (!s:EmptystackP('b:lineTagStack'))
|
||||
let tag=s:Pop('b:lineTagStack')
|
||||
if match(tag, '^/') == 0 "found end tag
|
||||
call s:Push(tag,'b:TagStack')
|
||||
elseif s:EmptystackP('b:TagStack') && !s:Instack(tag, a:unaryTagsStack) "found unclosed tag
|
||||
return tag
|
||||
else
|
||||
let endtag=s:Peekstack('b:TagStack')
|
||||
if endtag == '/'.tag || endtag == '/'
|
||||
call s:Pop('b:TagStack') "found a open/close tag pair
|
||||
elseif !s:Instack(tag, a:unaryTagsStack) "we have a mismatch error
|
||||
return ''
|
||||
endif
|
||||
endif
|
||||
endwhile
|
||||
let linenum=linenum-1 | let first=0
|
||||
endwhile
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! s:InComment()
|
||||
return synIDattr(synID(line('.'), col('.'), 0), 'name') =~ 'Comment'
|
||||
endfunction
|
||||
|
||||
function! s:InCommentAt(line, col)
|
||||
return synIDattr(synID(a:line, a:col, 0), 'name') =~ 'Comment'
|
||||
endfunction
|
||||
|
||||
function! s:SetKeywords()
|
||||
let g:IsKeywordBak=&iskeyword
|
||||
let &iskeyword='33-255'
|
||||
endfunction
|
||||
|
||||
function! s:RestoreKeywords()
|
||||
let &iskeyword=g:IsKeywordBak
|
||||
endfunction
|
||||
|
||||
function! s:Push(el, sname)
|
||||
if !s:EmptystackP(a:sname)
|
||||
exe 'let '.a:sname."=a:el.' '.".a:sname
|
||||
else
|
||||
exe 'let '.a:sname.'=a:el'
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:EmptystackP(sname)
|
||||
exe 'let stack='.a:sname
|
||||
if match(stack,'^ *$') == 0
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:Instack(el, sname)
|
||||
exe 'let stack='.a:sname
|
||||
call s:SetKeywords()
|
||||
let m=match(stack, '\<'.a:el.'\>')
|
||||
call s:RestoreKeywords()
|
||||
if m < 0
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:Peekstack(sname)
|
||||
call s:SetKeywords()
|
||||
exe 'let stack='.a:sname
|
||||
let top=matchstr(stack, '\<.\{-1,}\>')
|
||||
call s:RestoreKeywords()
|
||||
return top
|
||||
endfunction
|
||||
|
||||
function! s:Pop(sname)
|
||||
if s:EmptystackP(a:sname)
|
||||
return ''
|
||||
endif
|
||||
exe 'let stack='.a:sname
|
||||
call s:SetKeywords()
|
||||
let loc=matchend(stack,'\<.\{-1,}\>')
|
||||
exe 'let '.a:sname.'=strpart(stack, loc+1, strlen(stack))'
|
||||
let top=strpart(stack, match(stack, '\<'), loc)
|
||||
call s:RestoreKeywords()
|
||||
return top
|
||||
endfunction
|
||||
|
||||
function! s:Clearstack(sname)
|
||||
exe 'let '.a:sname."=''"
|
||||
endfunction
|
||||
Reference in New Issue
Block a user