1a5792f58SBram Moolenaar" Vim completion script 2d12f5c17SBram Moolenaar" Language: XML 3a5792f58SBram Moolenaar" Maintainer: Mikolaj Machowski ( mikmach AT wp DOT pl ) 414b6945eSBram Moolenaar" Last Change: 2013 Jun 29 53577c6faSBram Moolenaar" Version: 1.9 69964e468SBram Moolenaar" 79964e468SBram Moolenaar" Changelog: 83577c6faSBram Moolenaar" 1.9 - 2007 Aug 15 93577c6faSBram Moolenaar" - fix closing of namespaced tags (Johannes Weiss) 109964e468SBram Moolenaar" 1.8 - 2006 Jul 18 119964e468SBram Moolenaar" - allow for closing of xml tags even when data file isn't available 12a5792f58SBram Moolenaar 13a5792f58SBram Moolenaar" This function will create Dictionary with users namespace strings and values 14a5792f58SBram Moolenaar" canonical (system) names of data files. Names should be lowercase, 15a5792f58SBram Moolenaar" descriptive to avoid any future conflicts. For example 'xhtml10s' should be 16a5792f58SBram Moolenaar" name for data of XHTML 1.0 Strict and 'xhtml10t' for XHTML 1.0 Transitional 17910f66f9SBram Moolenaar" User interface will be provided by XMLns command defined in ftplugin/xml.vim 18a5792f58SBram Moolenaar" Currently supported canonicals are: 19a5792f58SBram Moolenaar" xhtml10s - XHTML 1.0 Strict 20a5792f58SBram Moolenaar" xsl - XSL 2118144c84SBram Moolenaarfunction! xmlcomplete#CreateConnection(canonical, ...) " {{{ 22a5792f58SBram Moolenaar 23a5792f58SBram Moolenaar " When only one argument provided treat name as default namespace (without 24a5792f58SBram Moolenaar " 'prefix:'). 25a5792f58SBram Moolenaar if exists("a:1") 26a5792f58SBram Moolenaar let users = a:1 27a5792f58SBram Moolenaar else 28a5792f58SBram Moolenaar let users = 'DEFAULT' 29a5792f58SBram Moolenaar endif 30a5792f58SBram Moolenaar 31a5792f58SBram Moolenaar " Source data file. Due to suspected errors in autoload do it with 32a5792f58SBram Moolenaar " :runtime. 33a5792f58SBram Moolenaar " TODO: make it properly (using autoload, that is) later 34a5792f58SBram Moolenaar exe "runtime autoload/xml/".a:canonical.".vim" 35a5792f58SBram Moolenaar 36a5792f58SBram Moolenaar " Remove all traces of unexisting files to return [] when trying 37a5792f58SBram Moolenaar " omnicomplete something 38a5792f58SBram Moolenaar " TODO: give warning about non-existing canonicals - should it be? 39a5792f58SBram Moolenaar if !exists("g:xmldata_".a:canonical) 40a5792f58SBram Moolenaar unlet! g:xmldata_connection 41a5792f58SBram Moolenaar return 0 42a5792f58SBram Moolenaar endif 43a5792f58SBram Moolenaar 44a5792f58SBram Moolenaar " We need to initialize Dictionary to add key-value pair 45a5792f58SBram Moolenaar if !exists("g:xmldata_connection") 46a5792f58SBram Moolenaar let g:xmldata_connection = {} 47a5792f58SBram Moolenaar endif 48a5792f58SBram Moolenaar 49a5792f58SBram Moolenaar let g:xmldata_connection[users] = a:canonical 50a5792f58SBram Moolenaar 51a5792f58SBram Moolenaarendfunction 5218144c84SBram Moolenaar" }}} 53a5792f58SBram Moolenaar 5418144c84SBram Moolenaarfunction! xmlcomplete#CreateEntConnection(...) " {{{ 55a5792f58SBram Moolenaar if a:0 > 0 56a5792f58SBram Moolenaar let g:xmldata_entconnect = a:1 57a5792f58SBram Moolenaar else 58a5792f58SBram Moolenaar let g:xmldata_entconnect = 'DEFAULT' 59a5792f58SBram Moolenaar endif 60a5792f58SBram Moolenaarendfunction 6118144c84SBram Moolenaar" }}} 62a5792f58SBram Moolenaar 63a5792f58SBram Moolenaarfunction! xmlcomplete#CompleteTags(findstart, base) 64a5792f58SBram Moolenaar if a:findstart 65a5792f58SBram Moolenaar " locate the start of the word 66d12f5c17SBram Moolenaar let curline = line('.') 67a5792f58SBram Moolenaar let line = getline('.') 68a5792f58SBram Moolenaar let start = col('.') - 1 69a5792f58SBram Moolenaar let compl_begin = col('.') - 2 70a5792f58SBram Moolenaar 71a5792f58SBram Moolenaar while start >= 0 && line[start - 1] =~ '\(\k\|[:.-]\)' 72a5792f58SBram Moolenaar let start -= 1 73a5792f58SBram Moolenaar endwhile 74a5792f58SBram Moolenaar 75a5792f58SBram Moolenaar if start >= 0 && line[start - 1] =~ '&' 76a5792f58SBram Moolenaar let b:entitiescompl = 1 77a5792f58SBram Moolenaar let b:compl_context = '' 78a5792f58SBram Moolenaar return start 79a5792f58SBram Moolenaar endif 80a5792f58SBram Moolenaar 81a5792f58SBram Moolenaar let b:compl_context = getline('.')[0:(compl_begin)] 82d12f5c17SBram Moolenaar if b:compl_context !~ '<[^>]*$' 83d12f5c17SBram Moolenaar " Look like we may have broken tag. Check previous lines. Up to 84d12f5c17SBram Moolenaar " 10? 85d12f5c17SBram Moolenaar let i = 1 86d12f5c17SBram Moolenaar while 1 87d12f5c17SBram Moolenaar let context_line = getline(curline-i) 88d12f5c17SBram Moolenaar if context_line =~ '<[^>]*$' 89d12f5c17SBram Moolenaar " Yep, this is this line 909964e468SBram Moolenaar let context_lines = getline(curline-i, curline-1) + [b:compl_context] 91d12f5c17SBram Moolenaar let b:compl_context = join(context_lines, ' ') 92d12f5c17SBram Moolenaar break 93c15ef30cSBram Moolenaar elseif context_line =~ '>[^<]*$' || i == curline 94d12f5c17SBram Moolenaar " Normal tag line, no need for completion at all 95c15ef30cSBram Moolenaar " OR reached first line without tag at all 96d12f5c17SBram Moolenaar let b:compl_context = '' 97d12f5c17SBram Moolenaar break 98d12f5c17SBram Moolenaar endif 99d12f5c17SBram Moolenaar let i += 1 100d12f5c17SBram Moolenaar endwhile 101d12f5c17SBram Moolenaar " Make sure we don't have counter 102d12f5c17SBram Moolenaar unlet! i 103d12f5c17SBram Moolenaar endif 104d12f5c17SBram Moolenaar let b:compl_context = matchstr(b:compl_context, '.*\zs<.*') 105a5792f58SBram Moolenaar 106a5792f58SBram Moolenaar " Make sure we will have only current namespace 107a5792f58SBram Moolenaar unlet! b:xml_namespace 108d12f5c17SBram Moolenaar let b:xml_namespace = matchstr(b:compl_context, '^<\zs\k*\ze:') 109a5792f58SBram Moolenaar if b:xml_namespace == '' 110a5792f58SBram Moolenaar let b:xml_namespace = 'DEFAULT' 111a5792f58SBram Moolenaar endif 112a5792f58SBram Moolenaar 113a5792f58SBram Moolenaar return start 114a5792f58SBram Moolenaar 115a5792f58SBram Moolenaar else 116a5792f58SBram Moolenaar " Initialize base return lists 117a5792f58SBram Moolenaar let res = [] 118a5792f58SBram Moolenaar let res2 = [] 119a5792f58SBram Moolenaar " a:base is very short - we need context 120d12f5c17SBram Moolenaar if len(b:compl_context) == 0 && !exists("b:entitiescompl") 121d12f5c17SBram Moolenaar return [] 122d12f5c17SBram Moolenaar endif 123d12f5c17SBram Moolenaar let context = matchstr(b:compl_context, '^<\zs.*') 124a5792f58SBram Moolenaar unlet! b:compl_context 1259964e468SBram Moolenaar " There is no connection of namespace and data file. 1269964e468SBram Moolenaar if !exists("g:xmldata_connection") || g:xmldata_connection == {} 1279964e468SBram Moolenaar " There is still possibility we may do something - eg. close tag 1289964e468SBram Moolenaar let b:unaryTagsStack = "base meta link hr br param img area input col" 1299964e468SBram Moolenaar if context =~ '^\/' 1309964e468SBram Moolenaar let opentag = xmlcomplete#GetLastOpenTag("b:unaryTagsStack") 1319964e468SBram Moolenaar return [opentag.">"] 1329964e468SBram Moolenaar else 1339964e468SBram Moolenaar return [] 1349964e468SBram Moolenaar endif 1359964e468SBram Moolenaar endif 136a5792f58SBram Moolenaar 137a5792f58SBram Moolenaar " Make entities completion 138a5792f58SBram Moolenaar if exists("b:entitiescompl") 139a5792f58SBram Moolenaar unlet! b:entitiescompl 140a5792f58SBram Moolenaar 141a5792f58SBram Moolenaar if !exists("g:xmldata_entconnect") || g:xmldata_entconnect == 'DEFAULT' 142a5792f58SBram Moolenaar let values = g:xmldata{'_'.g:xmldata_connection['DEFAULT']}['vimxmlentities'] 143a5792f58SBram Moolenaar else 144a5792f58SBram Moolenaar let values = g:xmldata{'_'.g:xmldata_entconnect}['vimxmlentities'] 145a5792f58SBram Moolenaar endif 146a5792f58SBram Moolenaar 147a5792f58SBram Moolenaar " Get only lines with entity declarations but throw out 148a5792f58SBram Moolenaar " parameter-entities - they may be completed in future 149a5792f58SBram Moolenaar let entdecl = filter(getline(1, "$"), 'v:val =~ "<!ENTITY\\s\\+[^%]"') 150a5792f58SBram Moolenaar 151a5792f58SBram Moolenaar if len(entdecl) > 0 152a5792f58SBram Moolenaar let intent = map(copy(entdecl), 'matchstr(v:val, "<!ENTITY\\s\\+\\zs\\(\\k\\|[.-:]\\)\\+\\ze")') 153a5792f58SBram Moolenaar let values = intent + values 154a5792f58SBram Moolenaar endif 155a5792f58SBram Moolenaar 156d12f5c17SBram Moolenaar if len(a:base) == 1 157a5792f58SBram Moolenaar for m in values 158a5792f58SBram Moolenaar if m =~ '^'.a:base 159a5792f58SBram Moolenaar call add(res, m.';') 160a5792f58SBram Moolenaar endif 161a5792f58SBram Moolenaar endfor 162a5792f58SBram Moolenaar return res 163d12f5c17SBram Moolenaar else 164d12f5c17SBram Moolenaar for m in values 165d12f5c17SBram Moolenaar if m =~? '^'.a:base 166d12f5c17SBram Moolenaar call add(res, m.';') 167d12f5c17SBram Moolenaar elseif m =~? a:base 168d12f5c17SBram Moolenaar call add(res2, m.';') 169d12f5c17SBram Moolenaar endif 170d12f5c17SBram Moolenaar endfor 171d12f5c17SBram Moolenaar 172d12f5c17SBram Moolenaar return res + res2 173d12f5c17SBram Moolenaar endif 174a5792f58SBram Moolenaar 175a5792f58SBram Moolenaar endif 176a5792f58SBram Moolenaar if context =~ '>' 177a5792f58SBram Moolenaar " Generally if context contains > it means we are outside of tag and 178a5792f58SBram Moolenaar " should abandon action 179a5792f58SBram Moolenaar return [] 180a5792f58SBram Moolenaar endif 181a5792f58SBram Moolenaar 182a5792f58SBram Moolenaar " find tags matching with "a:base" 183a5792f58SBram Moolenaar " If a:base contains white space it is attribute. 184a5792f58SBram Moolenaar " It could be also value of attribute... 185a5792f58SBram Moolenaar " We have to get first word to offer 186a5792f58SBram Moolenaar " proper completions 187a5792f58SBram Moolenaar if context == '' 188a5792f58SBram Moolenaar let tag = '' 189a5792f58SBram Moolenaar else 190a5792f58SBram Moolenaar let tag = split(context)[0] 191a5792f58SBram Moolenaar endif 192a5792f58SBram Moolenaar " Get rid of namespace 193a5792f58SBram Moolenaar let tag = substitute(tag, '^'.b:xml_namespace.':', '', '') 194a5792f58SBram Moolenaar 195a5792f58SBram Moolenaar 196a5792f58SBram Moolenaar " Get last word, it should be attr name 197a5792f58SBram Moolenaar let attr = matchstr(context, '.*\s\zs.*') 198a5792f58SBram Moolenaar " Possible situations where any prediction would be difficult: 199a5792f58SBram Moolenaar " 1. Events attributes 200a5792f58SBram Moolenaar if context =~ '\s' 201a5792f58SBram Moolenaar 202*6c391a74SBram Moolenaar " If attr contains =\s*[\"'] we catch value of attribute 2038424a624SBram Moolenaar if attr =~ "=\s*[\"']" || attr =~ "=\s*$" 204a5792f58SBram Moolenaar " Let do attribute specific completion 205a5792f58SBram Moolenaar let attrname = matchstr(attr, '.*\ze\s*=') 2068424a624SBram Moolenaar let entered_value = matchstr(attr, ".*=\\s*[\"']\\?\\zs.*") 207a5792f58SBram Moolenaar 208a5792f58SBram Moolenaar if tag =~ '^[?!]' 209a5792f58SBram Moolenaar " Return nothing if we are inside of ! or ? tag 210a5792f58SBram Moolenaar return [] 211a5792f58SBram Moolenaar else 2128424a624SBram Moolenaar if has_key(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}, tag) && has_key(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1], attrname) 213a5792f58SBram Moolenaar let values = g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1][attrname] 2148424a624SBram Moolenaar else 2158424a624SBram Moolenaar return [] 2168424a624SBram Moolenaar endif 217a5792f58SBram Moolenaar endif 218a5792f58SBram Moolenaar 219a5792f58SBram Moolenaar if len(values) == 0 220a5792f58SBram Moolenaar return [] 221a5792f58SBram Moolenaar endif 222a5792f58SBram Moolenaar 223a5792f58SBram Moolenaar " We need special version of sbase 224a5792f58SBram Moolenaar let attrbase = matchstr(context, ".*[\"']") 225a5792f58SBram Moolenaar let attrquote = matchstr(attrbase, '.$') 2268424a624SBram Moolenaar if attrquote !~ "['\"]" 2278424a624SBram Moolenaar let attrquoteopen = '"' 2288424a624SBram Moolenaar let attrquote = '"' 2298424a624SBram Moolenaar else 2308424a624SBram Moolenaar let attrquoteopen = '' 2318424a624SBram Moolenaar endif 232a5792f58SBram Moolenaar 233a5792f58SBram Moolenaar for m in values 234a5792f58SBram Moolenaar " This if is needed to not offer all completions as-is 235a5792f58SBram Moolenaar " alphabetically but sort them. Those beginning with entered 236a5792f58SBram Moolenaar " part will be as first choices 237a5792f58SBram Moolenaar if m =~ '^'.entered_value 2388424a624SBram Moolenaar call add(res, attrquoteopen . m . attrquote.' ') 239a5792f58SBram Moolenaar elseif m =~ entered_value 2408424a624SBram Moolenaar call add(res2, attrquoteopen . m . attrquote.' ') 241a5792f58SBram Moolenaar endif 242a5792f58SBram Moolenaar endfor 243a5792f58SBram Moolenaar 244a5792f58SBram Moolenaar return res + res2 245a5792f58SBram Moolenaar 246a5792f58SBram Moolenaar endif 247a5792f58SBram Moolenaar 248a5792f58SBram Moolenaar if tag =~ '?xml' 249a5792f58SBram Moolenaar " Two possible arguments for <?xml> plus variation 250a5792f58SBram Moolenaar let attrs = ['encoding', 'version="1.0"', 'version'] 251a5792f58SBram Moolenaar elseif tag =~ '^!' 252a5792f58SBram Moolenaar " Don't make completion at all 253910f66f9SBram Moolenaar " 254a5792f58SBram Moolenaar return [] 255a5792f58SBram Moolenaar else 256910f66f9SBram Moolenaar if !has_key(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}, tag) 257910f66f9SBram Moolenaar " Abandon when data file isn't complete 258910f66f9SBram Moolenaar return [] 259910f66f9SBram Moolenaar endif 260a5792f58SBram Moolenaar let attrs = keys(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1]) 261a5792f58SBram Moolenaar endif 262a5792f58SBram Moolenaar 263a5792f58SBram Moolenaar for m in sort(attrs) 264a5792f58SBram Moolenaar if m =~ '^'.attr 265a5792f58SBram Moolenaar call add(res, m) 266a5792f58SBram Moolenaar elseif m =~ attr 2671d2ba7faSBram Moolenaar call add(res2, m) 268a5792f58SBram Moolenaar endif 269a5792f58SBram Moolenaar endfor 2701d2ba7faSBram Moolenaar let menu = res + res2 2711d2ba7faSBram Moolenaar let final_menu = [] 2721d2ba7faSBram Moolenaar if has_key(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}, 'vimxmlattrinfo') 2731d2ba7faSBram Moolenaar for i in range(len(menu)) 2741d2ba7faSBram Moolenaar let item = menu[i] 2751d2ba7faSBram Moolenaar if has_key(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}['vimxmlattrinfo'], item) 2761d2ba7faSBram Moolenaar let m_menu = g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}['vimxmlattrinfo'][item][0] 2771d2ba7faSBram Moolenaar let m_info = g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}['vimxmlattrinfo'][item][1] 2781d2ba7faSBram Moolenaar else 2791d2ba7faSBram Moolenaar let m_menu = '' 2801d2ba7faSBram Moolenaar let m_info = '' 2811d2ba7faSBram Moolenaar endif 2821d2ba7faSBram Moolenaar if tag !~ '^[?!]' && len(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1][item]) > 0 && g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1][item][0] =~ '^\(BOOL\|'.item.'\)$' 2831d2ba7faSBram Moolenaar let item = item 2841d2ba7faSBram Moolenaar else 2851d2ba7faSBram Moolenaar let item .= '="' 2861d2ba7faSBram Moolenaar endif 2871d2ba7faSBram Moolenaar let final_menu += [{'word':item, 'menu':m_menu, 'info':m_info}] 2881d2ba7faSBram Moolenaar endfor 2891d2ba7faSBram Moolenaar else 2901d2ba7faSBram Moolenaar for i in range(len(menu)) 2911d2ba7faSBram Moolenaar let item = menu[i] 2921d2ba7faSBram Moolenaar if tag !~ '^[?!]' && len(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1][item]) > 0 && g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1][item][0] =~ '^\(BOOL\|'.item.'\)$' 2931d2ba7faSBram Moolenaar let item = item 2941d2ba7faSBram Moolenaar else 2951d2ba7faSBram Moolenaar let item .= '="' 2961d2ba7faSBram Moolenaar endif 2971d2ba7faSBram Moolenaar let final_menu += [item] 2981d2ba7faSBram Moolenaar endfor 2991d2ba7faSBram Moolenaar endif 3001d2ba7faSBram Moolenaar return final_menu 301a5792f58SBram Moolenaar 302a5792f58SBram Moolenaar endif 303a5792f58SBram Moolenaar " Close tag 304a5792f58SBram Moolenaar let b:unaryTagsStack = "base meta link hr br param img area input col" 305a5792f58SBram Moolenaar if context =~ '^\/' 306a5792f58SBram Moolenaar let opentag = xmlcomplete#GetLastOpenTag("b:unaryTagsStack") 307a5792f58SBram Moolenaar return [opentag.">"] 308a5792f58SBram Moolenaar endif 309a5792f58SBram Moolenaar 310a5792f58SBram Moolenaar " Complete elements of XML structure 311a5792f58SBram Moolenaar " TODO: #REQUIRED, #IMPLIED, #FIXED, #PCDATA - but these should be detected like 312a5792f58SBram Moolenaar " entities - in first run 313a5792f58SBram Moolenaar " keywords: CDATA, ID, IDREF, IDREFS, ENTITY, ENTITIES, NMTOKEN, NMTOKENS 314a5792f58SBram Moolenaar " are hardly recognizable but keep it in reserve 315a5792f58SBram Moolenaar " also: EMPTY ANY SYSTEM PUBLIC DATA 316a5792f58SBram Moolenaar if context =~ '^!' 317a5792f58SBram Moolenaar let tags = ['!ELEMENT', '!DOCTYPE', '!ATTLIST', '!ENTITY', '!NOTATION', '![CDATA[', '![INCLUDE[', '![IGNORE['] 318a5792f58SBram Moolenaar 319a5792f58SBram Moolenaar for m in tags 320a5792f58SBram Moolenaar if m =~ '^'.context 321a5792f58SBram Moolenaar let m = substitute(m, '^!\[\?', '', '') 322a5792f58SBram Moolenaar call add(res, m) 323a5792f58SBram Moolenaar elseif m =~ context 324a5792f58SBram Moolenaar let m = substitute(m, '^!\[\?', '', '') 325a5792f58SBram Moolenaar call add(res2, m) 326a5792f58SBram Moolenaar endif 327a5792f58SBram Moolenaar endfor 328a5792f58SBram Moolenaar 329a5792f58SBram Moolenaar return res + res2 330a5792f58SBram Moolenaar 331a5792f58SBram Moolenaar endif 332a5792f58SBram Moolenaar 333a5792f58SBram Moolenaar " Complete text declaration 334a5792f58SBram Moolenaar if context =~ '^?' 335a5792f58SBram Moolenaar let tags = ['?xml'] 336a5792f58SBram Moolenaar 337a5792f58SBram Moolenaar for m in tags 338a5792f58SBram Moolenaar if m =~ '^'.context 339a5792f58SBram Moolenaar call add(res, substitute(m, '^?', '', '')) 340a5792f58SBram Moolenaar elseif m =~ context 341a5792f58SBram Moolenaar call add(res, substitute(m, '^?', '', '')) 342a5792f58SBram Moolenaar endif 343a5792f58SBram Moolenaar endfor 344a5792f58SBram Moolenaar 345a5792f58SBram Moolenaar return res + res2 346a5792f58SBram Moolenaar 347a5792f58SBram Moolenaar endif 348a5792f58SBram Moolenaar 349a5792f58SBram Moolenaar " Deal with tag completion. 350a5792f58SBram Moolenaar let opentag = xmlcomplete#GetLastOpenTag("b:unaryTagsStack") 351a5792f58SBram Moolenaar let opentag = substitute(opentag, '^\k*:', '', '') 352d12f5c17SBram Moolenaar if opentag == '' 3537e8fd636SBram Moolenaar "return [] 3547e8fd636SBram Moolenaar let tags = keys(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}) 3557e8fd636SBram Moolenaar call filter(tags, 'v:val !~ "^vimxml"') 3567e8fd636SBram Moolenaar else 35718144c84SBram Moolenaar if !has_key(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}, opentag) 358910f66f9SBram Moolenaar " Abandon when data file isn't complete 359910f66f9SBram Moolenaar return [] 360910f66f9SBram Moolenaar endif 3617e8fd636SBram Moolenaar let tags = g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[opentag][0] 362d12f5c17SBram Moolenaar endif 363a5792f58SBram Moolenaar 364a5792f58SBram Moolenaar let context = substitute(context, '^\k*:', '', '') 365a5792f58SBram Moolenaar 366a5792f58SBram Moolenaar for m in tags 367a5792f58SBram Moolenaar if m =~ '^'.context 3681d2ba7faSBram Moolenaar call add(res, m) 369a5792f58SBram Moolenaar elseif m =~ context 3701d2ba7faSBram Moolenaar call add(res2, m) 371a5792f58SBram Moolenaar endif 372a5792f58SBram Moolenaar endfor 3731d2ba7faSBram Moolenaar let menu = res + res2 37418144c84SBram Moolenaar if b:xml_namespace == 'DEFAULT' 37518144c84SBram Moolenaar let xml_namespace = '' 37618144c84SBram Moolenaar else 37718144c84SBram Moolenaar let xml_namespace = b:xml_namespace.':' 37818144c84SBram Moolenaar endif 3791d2ba7faSBram Moolenaar if has_key(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}, 'vimxmltaginfo') 3801d2ba7faSBram Moolenaar let final_menu = [] 3811d2ba7faSBram Moolenaar for i in range(len(menu)) 3821d2ba7faSBram Moolenaar let item = menu[i] 3831d2ba7faSBram Moolenaar if has_key(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}['vimxmltaginfo'], item) 3841d2ba7faSBram Moolenaar let m_menu = g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}['vimxmltaginfo'][item][0] 3851d2ba7faSBram Moolenaar let m_info = g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}['vimxmltaginfo'][item][1] 3861d2ba7faSBram Moolenaar else 3871d2ba7faSBram Moolenaar let m_menu = '' 3881d2ba7faSBram Moolenaar let m_info = '' 3891d2ba7faSBram Moolenaar endif 3901d2ba7faSBram Moolenaar let final_menu += [{'word':xml_namespace.item, 'menu':m_menu, 'info':m_info}] 3911d2ba7faSBram Moolenaar endfor 3921d2ba7faSBram Moolenaar else 39318144c84SBram Moolenaar let final_menu = map(menu, 'xml_namespace.v:val') 3941d2ba7faSBram Moolenaar endif 39518144c84SBram Moolenaar 3961d2ba7faSBram Moolenaar return final_menu 397a5792f58SBram Moolenaar 398a5792f58SBram Moolenaar endif 399a5792f58SBram Moolenaarendfunction 400a5792f58SBram Moolenaar 40118144c84SBram Moolenaar" MM: This is severely reduced closetag.vim used with kind permission of Steven 402a5792f58SBram Moolenaar" Mueller 403a5792f58SBram Moolenaar" Changes: strip all comments; delete error messages; add checking for 404a5792f58SBram Moolenaar" namespace 405a5792f58SBram Moolenaar" Author: Steven Mueller <[email protected]> 406a5792f58SBram Moolenaar" Last Modified: Tue May 24 13:29:48 PDT 2005 407a5792f58SBram Moolenaar" Version: 0.9.1 408a5792f58SBram Moolenaar 409a5792f58SBram Moolenaarfunction! xmlcomplete#GetLastOpenTag(unaryTagsStack) 410a5792f58SBram Moolenaar let linenum=line('.') 411a5792f58SBram Moolenaar let lineend=col('.') - 1 " start: cursor position 412a5792f58SBram Moolenaar let first=1 " flag for first line searched 413a5792f58SBram Moolenaar let b:TagStack='' " main stack of tags 414a5792f58SBram Moolenaar let startInComment=s:InComment() 415a5792f58SBram Moolenaar 416a5792f58SBram Moolenaar if exists("b:xml_namespace") 417a5792f58SBram Moolenaar if b:xml_namespace == 'DEFAULT' 4183577c6faSBram Moolenaar let tagpat='</\=\(\k\|[.:-]\)\+\|/>' 419a5792f58SBram Moolenaar else 420a5792f58SBram Moolenaar let tagpat='</\='.b:xml_namespace.':\(\k\|[.-]\)\+\|/>' 421a5792f58SBram Moolenaar endif 422a5792f58SBram Moolenaar else 4233577c6faSBram Moolenaar let tagpat='</\=\(\k\|[.:-]\)\+\|/>' 424a5792f58SBram Moolenaar endif 425a5792f58SBram Moolenaar while (linenum>0) 426a5792f58SBram Moolenaar let line=getline(linenum) 427a5792f58SBram Moolenaar if first 428a5792f58SBram Moolenaar let line=strpart(line,0,lineend) 429a5792f58SBram Moolenaar else 430a5792f58SBram Moolenaar let lineend=strlen(line) 431a5792f58SBram Moolenaar endif 432a5792f58SBram Moolenaar let b:lineTagStack='' 433a5792f58SBram Moolenaar let mpos=0 434a5792f58SBram Moolenaar let b:TagCol=0 435a5792f58SBram Moolenaar while (mpos > -1) 436a5792f58SBram Moolenaar let mpos=matchend(line,tagpat) 437a5792f58SBram Moolenaar if mpos > -1 438a5792f58SBram Moolenaar let b:TagCol=b:TagCol+mpos 439a5792f58SBram Moolenaar let tag=matchstr(line,tagpat) 440a5792f58SBram Moolenaar 441a5792f58SBram Moolenaar if exists('b:closetag_disable_synID') || startInComment==s:InCommentAt(linenum, b:TagCol) 442a5792f58SBram Moolenaar let b:TagLine=linenum 443a5792f58SBram Moolenaar call s:Push(matchstr(tag,'[^<>]\+'),'b:lineTagStack') 444a5792f58SBram Moolenaar endif 445a5792f58SBram Moolenaar let lineend=lineend-mpos 446a5792f58SBram Moolenaar let line=strpart(line,mpos,lineend) 447a5792f58SBram Moolenaar endif 448a5792f58SBram Moolenaar endwhile 449a5792f58SBram Moolenaar while (!s:EmptystackP('b:lineTagStack')) 450a5792f58SBram Moolenaar let tag=s:Pop('b:lineTagStack') 451a5792f58SBram Moolenaar if match(tag, '^/') == 0 "found end tag 452a5792f58SBram Moolenaar call s:Push(tag,'b:TagStack') 453a5792f58SBram Moolenaar elseif s:EmptystackP('b:TagStack') && !s:Instack(tag, a:unaryTagsStack) "found unclosed tag 454a5792f58SBram Moolenaar return tag 455a5792f58SBram Moolenaar else 456a5792f58SBram Moolenaar let endtag=s:Peekstack('b:TagStack') 457a5792f58SBram Moolenaar if endtag == '/'.tag || endtag == '/' 458a5792f58SBram Moolenaar call s:Pop('b:TagStack') "found a open/close tag pair 459a5792f58SBram Moolenaar elseif !s:Instack(tag, a:unaryTagsStack) "we have a mismatch error 460a5792f58SBram Moolenaar return '' 461a5792f58SBram Moolenaar endif 462a5792f58SBram Moolenaar endif 463a5792f58SBram Moolenaar endwhile 464a5792f58SBram Moolenaar let linenum=linenum-1 | let first=0 465a5792f58SBram Moolenaar endwhile 466a5792f58SBram Moolenaarreturn '' 467a5792f58SBram Moolenaarendfunction 468a5792f58SBram Moolenaar 469a5792f58SBram Moolenaarfunction! s:InComment() 4708b6144bdSBram Moolenaar return synIDattr(synID(line('.'), col('.'), 0), 'name') =~ 'Comment\|String' 471a5792f58SBram Moolenaarendfunction 472a5792f58SBram Moolenaar 473a5792f58SBram Moolenaarfunction! s:InCommentAt(line, col) 4748b6144bdSBram Moolenaar return synIDattr(synID(a:line, a:col, 0), 'name') =~ 'Comment\|String' 475a5792f58SBram Moolenaarendfunction 476a5792f58SBram Moolenaar 477a5792f58SBram Moolenaarfunction! s:SetKeywords() 47814b6945eSBram Moolenaar let s:IsKeywordBak=&l:iskeyword 47914b6945eSBram Moolenaar let &l:iskeyword='33-255' 480a5792f58SBram Moolenaarendfunction 481a5792f58SBram Moolenaar 482a5792f58SBram Moolenaarfunction! s:RestoreKeywords() 48314b6945eSBram Moolenaar let &l:iskeyword=s:IsKeywordBak 484a5792f58SBram Moolenaarendfunction 485a5792f58SBram Moolenaar 486a5792f58SBram Moolenaarfunction! s:Push(el, sname) 487a5792f58SBram Moolenaar if !s:EmptystackP(a:sname) 488a5792f58SBram Moolenaar exe 'let '.a:sname."=a:el.' '.".a:sname 489a5792f58SBram Moolenaar else 490a5792f58SBram Moolenaar exe 'let '.a:sname.'=a:el' 491a5792f58SBram Moolenaar endif 492a5792f58SBram Moolenaarendfunction 493a5792f58SBram Moolenaar 494a5792f58SBram Moolenaarfunction! s:EmptystackP(sname) 495a5792f58SBram Moolenaar exe 'let stack='.a:sname 496a5792f58SBram Moolenaar if match(stack,'^ *$') == 0 497a5792f58SBram Moolenaar return 1 498a5792f58SBram Moolenaar else 499a5792f58SBram Moolenaar return 0 500a5792f58SBram Moolenaar endif 501a5792f58SBram Moolenaarendfunction 502a5792f58SBram Moolenaar 503a5792f58SBram Moolenaarfunction! s:Instack(el, sname) 504a5792f58SBram Moolenaar exe 'let stack='.a:sname 505a5792f58SBram Moolenaar call s:SetKeywords() 506a5792f58SBram Moolenaar let m=match(stack, '\<'.a:el.'\>') 507a5792f58SBram Moolenaar call s:RestoreKeywords() 508a5792f58SBram Moolenaar if m < 0 509a5792f58SBram Moolenaar return 0 510a5792f58SBram Moolenaar else 511a5792f58SBram Moolenaar return 1 512a5792f58SBram Moolenaar endif 513a5792f58SBram Moolenaarendfunction 514a5792f58SBram Moolenaar 515a5792f58SBram Moolenaarfunction! s:Peekstack(sname) 516a5792f58SBram Moolenaar call s:SetKeywords() 517a5792f58SBram Moolenaar exe 'let stack='.a:sname 518a5792f58SBram Moolenaar let top=matchstr(stack, '\<.\{-1,}\>') 519a5792f58SBram Moolenaar call s:RestoreKeywords() 520a5792f58SBram Moolenaar return top 521a5792f58SBram Moolenaarendfunction 522a5792f58SBram Moolenaar 523a5792f58SBram Moolenaarfunction! s:Pop(sname) 524a5792f58SBram Moolenaar if s:EmptystackP(a:sname) 525a5792f58SBram Moolenaar return '' 526a5792f58SBram Moolenaar endif 527a5792f58SBram Moolenaar exe 'let stack='.a:sname 528a5792f58SBram Moolenaar call s:SetKeywords() 529a5792f58SBram Moolenaar let loc=matchend(stack,'\<.\{-1,}\>') 530a5792f58SBram Moolenaar exe 'let '.a:sname.'=strpart(stack, loc+1, strlen(stack))' 531a5792f58SBram Moolenaar let top=strpart(stack, match(stack, '\<'), loc) 532a5792f58SBram Moolenaar call s:RestoreKeywords() 533a5792f58SBram Moolenaar return top 534a5792f58SBram Moolenaarendfunction 535a5792f58SBram Moolenaar 536a5792f58SBram Moolenaarfunction! s:Clearstack(sname) 537a5792f58SBram Moolenaar exe 'let '.a:sname."=''" 538a5792f58SBram Moolenaarendfunction 53918144c84SBram Moolenaar" vim:set foldmethod=marker: 540