1f75a963eSBram Moolenaar" Vim completion script 2fc1421ebSBram Moolenaar" Language: HTML and XHTML 3f75a963eSBram Moolenaar" Maintainer: Mikolaj Machowski ( mikmach AT wp DOT pl ) 45be4ceecSBram Moolenaar" Last Change: 2019 Sep 27 5946e27abSBram Moolenaar 6946e27abSBram Moolenaar" Distinguish between HTML versions. 7946e27abSBram Moolenaar" To use with other HTML versions add another "elseif" condition to match 8946e27abSBram Moolenaar" proper DOCTYPE. 9946e27abSBram Moolenaarfunction! htmlcomplete#DetectOmniFlavor() 10946e27abSBram Moolenaar if &filetype == 'xhtml' 11946e27abSBram Moolenaar let b:html_omni_flavor = 'xhtml10s' 12946e27abSBram Moolenaar else 13946e27abSBram Moolenaar let b:html_omni_flavor = 'html401t' 14946e27abSBram Moolenaar endif 15946e27abSBram Moolenaar let i = 1 16946e27abSBram Moolenaar let line = "" 17946e27abSBram Moolenaar while i < 10 && i < line("$") 18946e27abSBram Moolenaar let line = getline(i) 19946e27abSBram Moolenaar if line =~ '<!DOCTYPE.*\<DTD ' 20946e27abSBram Moolenaar break 21946e27abSBram Moolenaar endif 22946e27abSBram Moolenaar let i += 1 23946e27abSBram Moolenaar endwhile 24946e27abSBram Moolenaar if line =~ '<!DOCTYPE.*\<DTD ' " doctype line found above 25946e27abSBram Moolenaar if line =~ ' HTML 3\.2' 26946e27abSBram Moolenaar let b:html_omni_flavor = 'html32' 27946e27abSBram Moolenaar elseif line =~ ' XHTML 1\.1' 28946e27abSBram Moolenaar let b:html_omni_flavor = 'xhtml11' 29946e27abSBram Moolenaar else " two-step detection with strict/frameset/transitional 30946e27abSBram Moolenaar if line =~ ' XHTML 1\.0' 31946e27abSBram Moolenaar let b:html_omni_flavor = 'xhtml10' 32946e27abSBram Moolenaar elseif line =~ ' HTML 4\.01' 33946e27abSBram Moolenaar let b:html_omni_flavor = 'html401' 34946e27abSBram Moolenaar elseif line =~ ' HTML 4.0\>' 35946e27abSBram Moolenaar let b:html_omni_flavor = 'html40' 36946e27abSBram Moolenaar endif 37946e27abSBram Moolenaar if line =~ '\<Transitional\>' 38946e27abSBram Moolenaar let b:html_omni_flavor .= 't' 39946e27abSBram Moolenaar elseif line =~ '\<Frameset\>' 40946e27abSBram Moolenaar let b:html_omni_flavor .= 'f' 41946e27abSBram Moolenaar else 42946e27abSBram Moolenaar let b:html_omni_flavor .= 's' 43946e27abSBram Moolenaar endif 44946e27abSBram Moolenaar endif 45946e27abSBram Moolenaar endif 46946e27abSBram Moolenaarendfunction 47f75a963eSBram Moolenaar 48f75a963eSBram Moolenaarfunction! htmlcomplete#CompleteTags(findstart, base) 49f75a963eSBram Moolenaar if a:findstart 50f75a963eSBram Moolenaar " locate the start of the word 51f75a963eSBram Moolenaar let line = getline('.') 52f75a963eSBram Moolenaar let start = col('.') - 1 5328c258fdSBram Moolenaar let curline = line('.') 54d5cdbeb8SBram Moolenaar let compl_begin = col('.') - 2 554a85b415SBram Moolenaar while start >= 0 && line[start - 1] =~ '\(\k\|[!:.-]\)' 56f75a963eSBram Moolenaar let start -= 1 57f75a963eSBram Moolenaar endwhile 588b6144bdSBram Moolenaar " Handling of entities {{{ 59d5cdbeb8SBram Moolenaar if start >= 0 && line[start - 1] =~ '&' 60d5cdbeb8SBram Moolenaar let b:entitiescompl = 1 61d5cdbeb8SBram Moolenaar let b:compl_context = '' 62d5cdbeb8SBram Moolenaar return start 63d5cdbeb8SBram Moolenaar endif 648b6144bdSBram Moolenaar " }}} 658b6144bdSBram Moolenaar " Handling of <style> tag {{{ 66bfd8fc05SBram Moolenaar let stylestart = searchpair('<style\>', '', '<\/style\>', "bnW") 67bfd8fc05SBram Moolenaar let styleend = searchpair('<style\>', '', '<\/style\>', "nW") 68bfd8fc05SBram Moolenaar if stylestart != 0 && styleend != 0 6928c258fdSBram Moolenaar if stylestart <= curline && styleend >= curline 70d5cdbeb8SBram Moolenaar let start = col('.') - 1 71bfd8fc05SBram Moolenaar let b:csscompl = 1 72d5cdbeb8SBram Moolenaar while start >= 0 && line[start - 1] =~ '\(\k\|-\)' 73d5cdbeb8SBram Moolenaar let start -= 1 74d5cdbeb8SBram Moolenaar endwhile 75bfd8fc05SBram Moolenaar endif 76bfd8fc05SBram Moolenaar endif 778b6144bdSBram Moolenaar " }}} 788b6144bdSBram Moolenaar " Handling of <script> tag {{{ 79b8a7b560SBram Moolenaar let scriptstart = searchpair('<script\>', '', '<\/script\>', "bnW") 80b8a7b560SBram Moolenaar let scriptend = searchpair('<script\>', '', '<\/script\>', "nW") 81b8a7b560SBram Moolenaar if scriptstart != 0 && scriptend != 0 82b8a7b560SBram Moolenaar if scriptstart <= curline && scriptend >= curline 83b8a7b560SBram Moolenaar let start = col('.') - 1 84b8a7b560SBram Moolenaar let b:jscompl = 1 85b8a7b560SBram Moolenaar let b:jsrange = [scriptstart, scriptend] 861d2ba7faSBram Moolenaar while start >= 0 && line[start - 1] =~ '\k' 87b8a7b560SBram Moolenaar let start -= 1 88b8a7b560SBram Moolenaar endwhile 898b6144bdSBram Moolenaar " We are inside of <script> tag. But we should also get contents 908b6144bdSBram Moolenaar " of all linked external files and (secondary, less probably) other <script> tags 918b6144bdSBram Moolenaar " This logic could possible be done in separate function - may be 928b6144bdSBram Moolenaar " reused in events scripting (also with option could be reused for 938b6144bdSBram Moolenaar " CSS 948b6144bdSBram Moolenaar let b:js_extfiles = [] 958b6144bdSBram Moolenaar let l = line('.') 968b6144bdSBram Moolenaar let c = col('.') 978b6144bdSBram Moolenaar call cursor(1,1) 988b6144bdSBram Moolenaar while search('<\@<=script\>', 'W') && line('.') <= l 998b6144bdSBram Moolenaar if synIDattr(synID(line('.'),col('.')-1,0),"name") !~? 'comment' 1008b6144bdSBram Moolenaar let sname = matchstr(getline('.'), '<script[^>]*src\s*=\s*\([''"]\)\zs.\{-}\ze\1') 1018b6144bdSBram Moolenaar if filereadable(sname) 1028b6144bdSBram Moolenaar let b:js_extfiles += readfile(sname) 103b8a7b560SBram Moolenaar endif 104b8a7b560SBram Moolenaar endif 1058b6144bdSBram Moolenaar endwhile 1068b6144bdSBram Moolenaar call cursor(1,1) 1078b6144bdSBram Moolenaar let js_scripttags = [] 1088b6144bdSBram Moolenaar while search('<script\>', 'W') && line('.') < l 1098b6144bdSBram Moolenaar if matchstr(getline('.'), '<script[^>]*src') == '' 1108b6144bdSBram Moolenaar let js_scripttag = getline(line('.'), search('</script>', 'W')) 1118b6144bdSBram Moolenaar let js_scripttags += js_scripttag 1128b6144bdSBram Moolenaar endif 1138b6144bdSBram Moolenaar endwhile 1148b6144bdSBram Moolenaar let b:js_extfiles += js_scripttags 1158b6144bdSBram Moolenaar call cursor(l,c) 1168b6144bdSBram Moolenaar unlet! l c 1178b6144bdSBram Moolenaar endif 1188b6144bdSBram Moolenaar endif 1198b6144bdSBram Moolenaar " }}} 120b8a7b560SBram Moolenaar if !exists("b:csscompl") && !exists("b:jscompl") 121d5cdbeb8SBram Moolenaar let b:compl_context = getline('.')[0:(compl_begin)] 12228c258fdSBram Moolenaar if b:compl_context !~ '<[^>]*$' 1238b6144bdSBram Moolenaar " Look like we may have broken tag. Check previous lines. 12428c258fdSBram Moolenaar let i = 1 12528c258fdSBram Moolenaar while 1 12628c258fdSBram Moolenaar let context_line = getline(curline-i) 12728c258fdSBram Moolenaar if context_line =~ '<[^>]*$' 12828c258fdSBram Moolenaar " Yep, this is this line 129d5ab34bdSBram Moolenaar let context_lines = getline(curline-i, curline-1) + [b:compl_context] 13028c258fdSBram Moolenaar let b:compl_context = join(context_lines, ' ') 13128c258fdSBram Moolenaar break 132e0fa560eSBram Moolenaar elseif context_line =~ '>[^<]*$' || i == curline 133e0fa560eSBram Moolenaar " We are in normal tag line, no need for completion at all 134e0fa560eSBram Moolenaar " OR reached first line without tag at all 13528c258fdSBram Moolenaar let b:compl_context = '' 13628c258fdSBram Moolenaar break 13728c258fdSBram Moolenaar endif 13828c258fdSBram Moolenaar let i += 1 13928c258fdSBram Moolenaar endwhile 14028c258fdSBram Moolenaar " Make sure we don't have counter 14128c258fdSBram Moolenaar unlet! i 14228c258fdSBram Moolenaar endif 14309df3127SBram Moolenaar let b:compl_context = matchstr(b:compl_context, '.*\zs<.*') 144e0fa560eSBram Moolenaar 1458b6144bdSBram Moolenaar " Return proper start for on-events. Without that beginning of 1468b6144bdSBram Moolenaar " completion will be badly reported 1478b6144bdSBram Moolenaar if b:compl_context =~? 'on[a-z]*\s*=\s*\(''[^'']*\|"[^"]*\)$' 1488b6144bdSBram Moolenaar let start = col('.') - 1 1491d2ba7faSBram Moolenaar while start >= 0 && line[start - 1] =~ '\k' 1508b6144bdSBram Moolenaar let start -= 1 1518b6144bdSBram Moolenaar endwhile 1528b6144bdSBram Moolenaar endif 153e0fa560eSBram Moolenaar " If b:compl_context begins with <? we are inside of PHP code. It 154e0fa560eSBram Moolenaar " wasn't closed so PHP completion passed it to HTML 155e0fa560eSBram Moolenaar if &filetype =~? 'php' && b:compl_context =~ '^<?' 156e0fa560eSBram Moolenaar let b:phpcompl = 1 157e0fa560eSBram Moolenaar let start = col('.') - 1 158e0fa560eSBram Moolenaar while start >= 0 && line[start - 1] =~ '[a-zA-Z_0-9\x7f-\xff$]' 159e0fa560eSBram Moolenaar let start -= 1 160e0fa560eSBram Moolenaar endwhile 161e0fa560eSBram Moolenaar endif 162d5cdbeb8SBram Moolenaar else 163d5cdbeb8SBram Moolenaar let b:compl_context = getline('.')[0:compl_begin] 164bfd8fc05SBram Moolenaar endif 165f75a963eSBram Moolenaar return start 166f75a963eSBram Moolenaar else 167d5cdbeb8SBram Moolenaar " Initialize base return lists 168d5cdbeb8SBram Moolenaar let res = [] 169d5cdbeb8SBram Moolenaar let res2 = [] 170d5cdbeb8SBram Moolenaar " a:base is very short - we need context 171d5cdbeb8SBram Moolenaar let context = b:compl_context 172bfd8fc05SBram Moolenaar " Check if we should do CSS completion inside of <style> tag 173e0fa560eSBram Moolenaar " or JS completion inside of <script> tag or PHP completion in case of <? 174e0fa560eSBram Moolenaar " tag AND &ft==php 175bfd8fc05SBram Moolenaar if exists("b:csscompl") 176bfd8fc05SBram Moolenaar unlet! b:csscompl 17709df3127SBram Moolenaar let context = b:compl_context 1788b6144bdSBram Moolenaar unlet! b:compl_context 179d5cdbeb8SBram Moolenaar return csscomplete#CompleteCSS(0, context) 180b8a7b560SBram Moolenaar elseif exists("b:jscompl") 181b8a7b560SBram Moolenaar unlet! b:jscompl 1828b6144bdSBram Moolenaar return javascriptcomplete#CompleteJS(0, a:base) 183e0fa560eSBram Moolenaar elseif exists("b:phpcompl") 184e0fa560eSBram Moolenaar unlet! b:phpcompl 185e0fa560eSBram Moolenaar let context = b:compl_context 186e0fa560eSBram Moolenaar return phpcomplete#CompletePHP(0, a:base) 18709df3127SBram Moolenaar else 18809df3127SBram Moolenaar if len(b:compl_context) == 0 && !exists("b:entitiescompl") 18909df3127SBram Moolenaar return [] 190bfd8fc05SBram Moolenaar endif 19109df3127SBram Moolenaar let context = matchstr(b:compl_context, '.\zs.*') 19209df3127SBram Moolenaar endif 19309df3127SBram Moolenaar unlet! b:compl_context 1948b6144bdSBram Moolenaar " Entities completion {{{ 195d5cdbeb8SBram Moolenaar if exists("b:entitiescompl") 196d5cdbeb8SBram Moolenaar unlet! b:entitiescompl 197d5cdbeb8SBram Moolenaar 198f193fffdSBram Moolenaar if !exists("b:html_doctype") 199f193fffdSBram Moolenaar call htmlcomplete#CheckDoctype() 200f193fffdSBram Moolenaar endif 201fc1421ebSBram Moolenaar if !exists("b:html_omni") 202c1e37901SBram Moolenaar "runtime! autoload/xml/xhtml10s.vim 203c1e37901SBram Moolenaar call htmlcomplete#LoadData() 204a5792f58SBram Moolenaar endif 205d5cdbeb8SBram Moolenaar 206fc1421ebSBram Moolenaar let entities = b:html_omni['vimxmlentities'] 207a5792f58SBram Moolenaar 20809df3127SBram Moolenaar if len(a:base) == 1 209a5792f58SBram Moolenaar for m in entities 2108349fd7cSBram Moolenaar if m =~ '^'.a:base 211d5cdbeb8SBram Moolenaar call add(res, m.';') 212d5cdbeb8SBram Moolenaar endif 213d5cdbeb8SBram Moolenaar endfor 2148349fd7cSBram Moolenaar return res 21509df3127SBram Moolenaar else 21609df3127SBram Moolenaar for m in entities 21709df3127SBram Moolenaar if m =~? '^'.a:base 21809df3127SBram Moolenaar call add(res, m.';') 21909df3127SBram Moolenaar elseif m =~? a:base 22009df3127SBram Moolenaar call add(res2, m.';') 22109df3127SBram Moolenaar endif 22209df3127SBram Moolenaar endfor 22309df3127SBram Moolenaar 22409df3127SBram Moolenaar return res + res2 22509df3127SBram Moolenaar endif 22609df3127SBram Moolenaar 227d5cdbeb8SBram Moolenaar 228d5cdbeb8SBram Moolenaar endif 2298b6144bdSBram Moolenaar " }}} 230d5cdbeb8SBram Moolenaar if context =~ '>' 231d5cdbeb8SBram Moolenaar " Generally if context contains > it means we are outside of tag and 232bfd8fc05SBram Moolenaar " should abandon action - with one exception: <style> span { bo 233d5cdbeb8SBram Moolenaar if context =~ 'style[^>]\{-}>[^<]\{-}$' 234d5cdbeb8SBram Moolenaar return csscomplete#CompleteCSS(0, context) 235b8a7b560SBram Moolenaar elseif context =~ 'script[^>]\{-}>[^<]\{-}$' 236b8a7b560SBram Moolenaar let b:jsrange = [line('.'), search('<\/script\>', 'nW')] 237b8a7b560SBram Moolenaar return javascriptcomplete#CompleteJS(0, context) 238bfd8fc05SBram Moolenaar else 239f75a963eSBram Moolenaar return [] 240f75a963eSBram Moolenaar endif 241bfd8fc05SBram Moolenaar endif 242bfd8fc05SBram Moolenaar 243d5cdbeb8SBram Moolenaar " If context contains > it means we are already outside of tag and we 244bfd8fc05SBram Moolenaar " should abandon action 245d5cdbeb8SBram Moolenaar " If context contains white space it is attribute. 2468b6144bdSBram Moolenaar " It can be also value of attribute. 2478b6144bdSBram Moolenaar " We have to get first word to offer proper completions 2485be4ceecSBram Moolenaar if context =~ '^\s*$' 2495be4ceecSBram Moolenaar " empty or whitespace line 250d5cdbeb8SBram Moolenaar let tag = '' 251d5cdbeb8SBram Moolenaar else 252d5cdbeb8SBram Moolenaar let tag = split(context)[0] 2534a85b415SBram Moolenaar " Detect if tag is uppercase to return in proper case, 2544a85b415SBram Moolenaar " we need to make it lowercase for processing 2554a85b415SBram Moolenaar if tag =~ '^[A-Z]*$' 2568424a624SBram Moolenaar let uppercase_tag = 1 2578424a624SBram Moolenaar let tag = tolower(tag) 2588424a624SBram Moolenaar else 2598424a624SBram Moolenaar let uppercase_tag = 0 260d5cdbeb8SBram Moolenaar endif 2618424a624SBram Moolenaar endif 262bfd8fc05SBram Moolenaar " Get last word, it should be attr name 263d5cdbeb8SBram Moolenaar let attr = matchstr(context, '.*\s\zs.*') 264f75a963eSBram Moolenaar " Possible situations where any prediction would be difficult: 265f75a963eSBram Moolenaar " 1. Events attributes 266d5cdbeb8SBram Moolenaar if context =~ '\s' 267f75a963eSBram Moolenaar " Sort out style, class, and on* cases 2688b6144bdSBram Moolenaar if context =~? "\\(on[a-z]*\\|id\\|style\\|class\\)\\s*=\\s*[\"']" 2698b6144bdSBram Moolenaar " Id, class completion {{{ 2708b6144bdSBram Moolenaar if context =~? "\\(id\\|class\\)\\s*=\\s*[\"'][a-zA-Z0-9_ -]*$" 2718b6144bdSBram Moolenaar if context =~? "class\\s*=\\s*[\"'][a-zA-Z0-9_ -]*$" 2721e015460SBram Moolenaar let search_for = "class" 2738b6144bdSBram Moolenaar elseif context =~? "id\\s*=\\s*[\"'][a-zA-Z0-9_ -]*$" 2741e015460SBram Moolenaar let search_for = "id" 2751e015460SBram Moolenaar endif 276bfd8fc05SBram Moolenaar " Handle class name completion 277bfd8fc05SBram Moolenaar " 1. Find lines of <link stylesheet> 278bfd8fc05SBram Moolenaar " 1a. Check file for @import 279bfd8fc05SBram Moolenaar " 2. Extract filename(s?) of stylesheet, 280bfd8fc05SBram Moolenaar call cursor(1,1) 281bfd8fc05SBram Moolenaar let head = getline(search('<head\>'), search('<\/head>')) 282bfd8fc05SBram Moolenaar let headjoined = join(copy(head), ' ') 283bfd8fc05SBram Moolenaar if headjoined =~ '<style' 284a5792f58SBram Moolenaar " Remove possibly confusing CSS operators 2851e015460SBram Moolenaar let stylehead = substitute(headjoined, '+>\*[,', ' ', 'g') 2861e015460SBram Moolenaar if search_for == 'class' 287bfd8fc05SBram Moolenaar let styleheadlines = split(stylehead) 288bfd8fc05SBram Moolenaar let headclasslines = filter(copy(styleheadlines), "v:val =~ '\\([a-zA-Z0-9:]\\+\\)\\?\\.[a-zA-Z0-9_-]\\+'") 2891e015460SBram Moolenaar else 2901e015460SBram Moolenaar let stylesheet = split(headjoined, '[{}]') 2911e015460SBram Moolenaar " Get all lines which fit id syntax 2921e015460SBram Moolenaar let classlines = filter(copy(stylesheet), "v:val =~ '#[a-zA-Z0-9_-]\\+'") 2931e015460SBram Moolenaar " Filter out possible color definitions 2941e015460SBram Moolenaar call filter(classlines, "v:val !~ ':\\s*#[a-zA-Z0-9_-]\\+'") 2951e015460SBram Moolenaar " Filter out complex border definitions 2961e015460SBram Moolenaar call filter(classlines, "v:val !~ '\\(none\\|hidden\\|dotted\\|dashed\\|solid\\|double\\|groove\\|ridge\\|inset\\|outset\\)\\s*#[a-zA-Z0-9_-]\\+'") 2971e015460SBram Moolenaar let templines = join(classlines, ' ') 2981e015460SBram Moolenaar let headclasslines = split(templines) 2991e015460SBram Moolenaar call filter(headclasslines, "v:val =~ '#[a-zA-Z0-9_-]\\+'") 3001e015460SBram Moolenaar endif 301bfd8fc05SBram Moolenaar let internal = 1 302bfd8fc05SBram Moolenaar else 303bfd8fc05SBram Moolenaar let internal = 0 304bfd8fc05SBram Moolenaar endif 305bfd8fc05SBram Moolenaar let styletable = [] 306bfd8fc05SBram Moolenaar let secimportfiles = [] 307bfd8fc05SBram Moolenaar let filestable = filter(copy(head), "v:val =~ '\\(@import\\|link.*stylesheet\\)'") 308bfd8fc05SBram Moolenaar for line in filestable 309bfd8fc05SBram Moolenaar if line =~ "@import" 310bfd8fc05SBram Moolenaar let styletable += [matchstr(line, "import\\s\\+\\(url(\\)\\?[\"']\\?\\zs\\f\\+\\ze")] 311bfd8fc05SBram Moolenaar elseif line =~ "<link" 312bfd8fc05SBram Moolenaar let styletable += [matchstr(line, "href\\s*=\\s*[\"']\\zs\\f\\+\\ze")] 313bfd8fc05SBram Moolenaar endif 314bfd8fc05SBram Moolenaar endfor 3151e015460SBram Moolenaar for file in styletable 316bfd8fc05SBram Moolenaar if filereadable(file) 317bfd8fc05SBram Moolenaar let stylesheet = readfile(file) 318bfd8fc05SBram Moolenaar let secimport = filter(copy(stylesheet), "v:val =~ '@import'") 319bfd8fc05SBram Moolenaar if len(secimport) > 0 320bfd8fc05SBram Moolenaar for line in secimport 3211e015460SBram Moolenaar let secfile = matchstr(line, "import\\s\\+\\(url(\\)\\?[\"']\\?\\zs\\f\\+\\ze") 3221e015460SBram Moolenaar let secfile = fnamemodify(file, ":p:h").'/'.secfile 3231e015460SBram Moolenaar let secimportfiles += [secfile] 324bfd8fc05SBram Moolenaar endfor 325bfd8fc05SBram Moolenaar endif 326bfd8fc05SBram Moolenaar endif 327bfd8fc05SBram Moolenaar endfor 328bfd8fc05SBram Moolenaar let cssfiles = styletable + secimportfiles 329bfd8fc05SBram Moolenaar let classes = [] 330bfd8fc05SBram Moolenaar for file in cssfiles 3318e5af3e5SBram Moolenaar let classlines = [] 332bfd8fc05SBram Moolenaar if filereadable(file) 333bfd8fc05SBram Moolenaar let stylesheet = readfile(file) 3341e015460SBram Moolenaar let stylefile = join(stylesheet, ' ') 3351e015460SBram Moolenaar let stylefile = substitute(stylefile, '+>\*[,', ' ', 'g') 3361e015460SBram Moolenaar if search_for == 'class' 337bfd8fc05SBram Moolenaar let stylesheet = split(stylefile) 338bfd8fc05SBram Moolenaar let classlines = filter(copy(stylesheet), "v:val =~ '\\([a-zA-Z0-9:]\\+\\)\\?\\.[a-zA-Z0-9_-]\\+'") 3391e015460SBram Moolenaar else 3401e015460SBram Moolenaar let stylesheet = split(stylefile, '[{}]') 3411e015460SBram Moolenaar " Get all lines which fit id syntax 3421e015460SBram Moolenaar let classlines = filter(copy(stylesheet), "v:val =~ '#[a-zA-Z0-9_-]\\+'") 3431e015460SBram Moolenaar " Filter out possible color definitions 3441e015460SBram Moolenaar call filter(classlines, "v:val !~ ':\\s*#[a-zA-Z0-9_-]\\+'") 3451e015460SBram Moolenaar " Filter out complex border definitions 3461e015460SBram Moolenaar call filter(classlines, "v:val !~ '\\(none\\|hidden\\|dotted\\|dashed\\|solid\\|double\\|groove\\|ridge\\|inset\\|outset\\)\\s*#[a-zA-Z0-9_-]\\+'") 3471e015460SBram Moolenaar let templines = join(classlines, ' ') 3481e015460SBram Moolenaar let stylelines = split(templines) 3491e015460SBram Moolenaar let classlines = filter(stylelines, "v:val =~ '#[a-zA-Z0-9_-]\\+'") 3501e015460SBram Moolenaar 3511e015460SBram Moolenaar endif 352bfd8fc05SBram Moolenaar endif 353bfd8fc05SBram Moolenaar " We gathered classes definitions from all external files 354bfd8fc05SBram Moolenaar let classes += classlines 355bfd8fc05SBram Moolenaar endfor 356bfd8fc05SBram Moolenaar if internal == 1 357bfd8fc05SBram Moolenaar let classes += headclasslines 358bfd8fc05SBram Moolenaar endif 3591e015460SBram Moolenaar 3601e015460SBram Moolenaar if search_for == 'class' 361bfd8fc05SBram Moolenaar let elements = {} 362bfd8fc05SBram Moolenaar for element in classes 363bfd8fc05SBram Moolenaar if element =~ '^\.' 364bfd8fc05SBram Moolenaar let class = matchstr(element, '^\.\zs[a-zA-Z][a-zA-Z0-9_-]*\ze') 365bfd8fc05SBram Moolenaar let class = substitute(class, ':.*', '', '') 3661e015460SBram Moolenaar if has_key(elements, 'common') 3671e015460SBram Moolenaar let elements['common'] .= ' '.class 368bfd8fc05SBram Moolenaar else 3691e015460SBram Moolenaar let elements['common'] = class 370bfd8fc05SBram Moolenaar endif 371bfd8fc05SBram Moolenaar else 372bfd8fc05SBram Moolenaar let class = matchstr(element, '[a-zA-Z1-6]*\.\zs[a-zA-Z][a-zA-Z0-9_-]*\ze') 373bfd8fc05SBram Moolenaar let tagname = tolower(matchstr(element, '[a-zA-Z1-6]*\ze.')) 374bfd8fc05SBram Moolenaar if tagname != '' 375bfd8fc05SBram Moolenaar if has_key(elements, tagname) 3761e015460SBram Moolenaar let elements[tagname] .= ' '.class 377bfd8fc05SBram Moolenaar else 378bfd8fc05SBram Moolenaar let elements[tagname] = class 379bfd8fc05SBram Moolenaar endif 380bfd8fc05SBram Moolenaar endif 381bfd8fc05SBram Moolenaar endif 382bfd8fc05SBram Moolenaar endfor 383bfd8fc05SBram Moolenaar 3841e015460SBram Moolenaar if has_key(elements, tag) && has_key(elements, 'common') 3851e015460SBram Moolenaar let values = split(elements[tag]." ".elements['common']) 3861e015460SBram Moolenaar elseif has_key(elements, tag) && !has_key(elements, 'common') 387bfd8fc05SBram Moolenaar let values = split(elements[tag]) 3881e015460SBram Moolenaar elseif !has_key(elements, tag) && has_key(elements, 'common') 3891e015460SBram Moolenaar let values = split(elements['common']) 390bfd8fc05SBram Moolenaar else 391bfd8fc05SBram Moolenaar return [] 392bfd8fc05SBram Moolenaar endif 393bfd8fc05SBram Moolenaar 3941e015460SBram Moolenaar elseif search_for == 'id' 3951e015460SBram Moolenaar " Find used IDs 3961e015460SBram Moolenaar " 1. Catch whole file 3971e015460SBram Moolenaar let filelines = getline(1, line('$')) 3981e015460SBram Moolenaar " 2. Find lines with possible id 3991e015460SBram Moolenaar let used_id_lines = filter(filelines, 'v:val =~ "id\\s*=\\s*[\"''][a-zA-Z0-9_-]\\+"') 4001e015460SBram Moolenaar " 3a. Join all filtered lines 4011e015460SBram Moolenaar let id_string = join(used_id_lines, ' ') 4021e015460SBram Moolenaar " 3b. And split them to be sure each id is in separate item 4031e015460SBram Moolenaar let id_list = split(id_string, 'id\s*=\s*') 4041e015460SBram Moolenaar " 4. Extract id values 4051e015460SBram Moolenaar let used_id = map(id_list, 'matchstr(v:val, "[\"'']\\zs[a-zA-Z0-9_-]\\+\\ze")') 4061e015460SBram Moolenaar let joined_used_id = ','.join(used_id, ',').',' 4071e015460SBram Moolenaar 4081e015460SBram Moolenaar let allvalues = map(classes, 'matchstr(v:val, ".*#\\zs[a-zA-Z0-9_-]\\+")') 4091e015460SBram Moolenaar 4101e015460SBram Moolenaar let values = [] 4111e015460SBram Moolenaar 4121e015460SBram Moolenaar for element in classes 4131e015460SBram Moolenaar if joined_used_id !~ ','.element.',' 4141e015460SBram Moolenaar let values += [element] 4151e015460SBram Moolenaar endif 4161e015460SBram Moolenaar 4171e015460SBram Moolenaar endfor 4181e015460SBram Moolenaar 4191e015460SBram Moolenaar endif 4201e015460SBram Moolenaar 421bfd8fc05SBram Moolenaar " We need special version of sbase 422d5cdbeb8SBram Moolenaar let classbase = matchstr(context, ".*[\"']") 423bfd8fc05SBram Moolenaar let classquote = matchstr(classbase, '.$') 424bfd8fc05SBram Moolenaar 425bfd8fc05SBram Moolenaar let entered_class = matchstr(attr, ".*=\\s*[\"']\\zs.*") 426bfd8fc05SBram Moolenaar 427bfd8fc05SBram Moolenaar for m in sort(values) 428bfd8fc05SBram Moolenaar if m =~? '^'.entered_class 429d5cdbeb8SBram Moolenaar call add(res, m . classquote) 430bfd8fc05SBram Moolenaar elseif m =~? entered_class 431d5cdbeb8SBram Moolenaar call add(res2, m . classquote) 432bfd8fc05SBram Moolenaar endif 433bfd8fc05SBram Moolenaar endfor 434bfd8fc05SBram Moolenaar 435bfd8fc05SBram Moolenaar return res + res2 436bfd8fc05SBram Moolenaar 4378b6144bdSBram Moolenaar elseif context =~? "style\\s*=\\s*[\"'][^\"']*$" 438d5cdbeb8SBram Moolenaar return csscomplete#CompleteCSS(0, context) 439bfd8fc05SBram Moolenaar 440bfd8fc05SBram Moolenaar endif 4418b6144bdSBram Moolenaar " }}} 4428b6144bdSBram Moolenaar " Complete on-events {{{ 4438b6144bdSBram Moolenaar if context =~? 'on[a-z]*\s*=\s*\(''[^'']*\|"[^"]*\)$' 4448b6144bdSBram Moolenaar " We have to: 4458b6144bdSBram Moolenaar " 1. Find external files 4468b6144bdSBram Moolenaar let b:js_extfiles = [] 4478b6144bdSBram Moolenaar let l = line('.') 4488b6144bdSBram Moolenaar let c = col('.') 4498b6144bdSBram Moolenaar call cursor(1,1) 4508b6144bdSBram Moolenaar while search('<\@<=script\>', 'W') && line('.') <= l 4518b6144bdSBram Moolenaar if synIDattr(synID(line('.'),col('.')-1,0),"name") !~? 'comment' 4528b6144bdSBram Moolenaar let sname = matchstr(getline('.'), '<script[^>]*src\s*=\s*\([''"]\)\zs.\{-}\ze\1') 4538b6144bdSBram Moolenaar if filereadable(sname) 4548b6144bdSBram Moolenaar let b:js_extfiles += readfile(sname) 4558b6144bdSBram Moolenaar endif 4568b6144bdSBram Moolenaar endif 4578b6144bdSBram Moolenaar endwhile 4588b6144bdSBram Moolenaar " 2. Find at least one <script> tag 4598b6144bdSBram Moolenaar call cursor(1,1) 4608b6144bdSBram Moolenaar let js_scripttags = [] 4618b6144bdSBram Moolenaar while search('<script\>', 'W') && line('.') < l 4628b6144bdSBram Moolenaar if matchstr(getline('.'), '<script[^>]*src') == '' 4638b6144bdSBram Moolenaar let js_scripttag = getline(line('.'), search('</script>', 'W')) 4648b6144bdSBram Moolenaar let js_scripttags += js_scripttag 4658b6144bdSBram Moolenaar endif 4668b6144bdSBram Moolenaar endwhile 4678b6144bdSBram Moolenaar let b:js_extfiles += js_scripttags 4688b6144bdSBram Moolenaar 4698b6144bdSBram Moolenaar " 3. Proper call for javascriptcomplete#CompleteJS 4708b6144bdSBram Moolenaar call cursor(l,c) 4711d2ba7faSBram Moolenaar let js_context = matchstr(a:base, '\k\+$') 4728b6144bdSBram Moolenaar let js_shortcontext = substitute(a:base, js_context.'$', '', '') 4738b6144bdSBram Moolenaar let b:compl_context = context 4748b6144bdSBram Moolenaar let b:jsrange = [l, l] 4758b6144bdSBram Moolenaar unlet! l c 4768b6144bdSBram Moolenaar return javascriptcomplete#CompleteJS(0, js_context) 4778b6144bdSBram Moolenaar 4788b6144bdSBram Moolenaar endif 4798b6144bdSBram Moolenaar 4808b6144bdSBram Moolenaar " }}} 4818b6144bdSBram Moolenaar let stripbase = matchstr(context, ".*\\(on[a-zA-Z]*\\|style\\|class\\)\\s*=\\s*[\"']\\zs.*") 482d5cdbeb8SBram Moolenaar " Now we have context stripped from all chars up to style/class. 483f75a963eSBram Moolenaar " It may fail with some strange style value combinations. 484f75a963eSBram Moolenaar if stripbase !~ "[\"']" 485f75a963eSBram Moolenaar return [] 486f75a963eSBram Moolenaar endif 487f75a963eSBram Moolenaar endif 4888b6144bdSBram Moolenaar " Value of attribute completion {{{ 489*6c391a74SBram Moolenaar " If attr contains =\s*[\"'] we match value of attribute 4908424a624SBram Moolenaar if attr =~ "=\s*[\"']" || attr =~ "=\s*$" 491f75a963eSBram Moolenaar " Let do attribute specific completion 492f75a963eSBram Moolenaar let attrname = matchstr(attr, '.*\ze\s*=') 4938424a624SBram Moolenaar let entered_value = matchstr(attr, ".*=\\s*[\"']\\?\\zs.*") 494f75a963eSBram Moolenaar let values = [] 495d5ab34bdSBram Moolenaar " Load data {{{ 496d5ab34bdSBram Moolenaar if !exists("b:html_doctype") 497d5ab34bdSBram Moolenaar call htmlcomplete#CheckDoctype() 498d5ab34bdSBram Moolenaar endif 499d5ab34bdSBram Moolenaar if !exists("b:html_omni") 500d5ab34bdSBram Moolenaar "runtime! autoload/xml/xhtml10s.vim 501d5ab34bdSBram Moolenaar call htmlcomplete#LoadData() 502d5ab34bdSBram Moolenaar endif 503d5ab34bdSBram Moolenaar " }}} 504c1e37901SBram Moolenaar if attrname == 'href' 505f75a963eSBram Moolenaar " Now we are looking for local anchors defined by name or id 506f75a963eSBram Moolenaar if entered_value =~ '^#' 507f75a963eSBram Moolenaar let file = join(getline(1, line('$')), ' ') 508f75a963eSBram Moolenaar " Split it be sure there will be one id/name element in 509f75a963eSBram Moolenaar " item, it will be also first word [a-zA-Z0-9_-] in element 510f75a963eSBram Moolenaar let oneelement = split(file, "\\(meta \\)\\@<!\\(name\\|id\\)\\s*=\\s*[\"']") 511f75a963eSBram Moolenaar for i in oneelement 512f75a963eSBram Moolenaar let values += ['#'.matchstr(i, "^[a-zA-Z][a-zA-Z0-9%_-]*")] 513f75a963eSBram Moolenaar endfor 514f75a963eSBram Moolenaar endif 515c1e37901SBram Moolenaar else 516fc1421ebSBram Moolenaar if has_key(b:html_omni, tag) && has_key(b:html_omni[tag][1], attrname) 517fc1421ebSBram Moolenaar let values = b:html_omni[tag][1][attrname] 518f75a963eSBram Moolenaar else 519f75a963eSBram Moolenaar return [] 520f75a963eSBram Moolenaar endif 521c1e37901SBram Moolenaar endif 522f75a963eSBram Moolenaar 523f75a963eSBram Moolenaar if len(values) == 0 524f75a963eSBram Moolenaar return [] 525f75a963eSBram Moolenaar endif 526f75a963eSBram Moolenaar 527f75a963eSBram Moolenaar " We need special version of sbase 528d5cdbeb8SBram Moolenaar let attrbase = matchstr(context, ".*[\"']") 529bfd8fc05SBram Moolenaar let attrquote = matchstr(attrbase, '.$') 5308424a624SBram Moolenaar if attrquote !~ "['\"]" 5318424a624SBram Moolenaar let attrquoteopen = '"' 5328424a624SBram Moolenaar let attrquote = '"' 5338424a624SBram Moolenaar else 5348424a624SBram Moolenaar let attrquoteopen = '' 5358424a624SBram Moolenaar endif 536f75a963eSBram Moolenaar 537f75a963eSBram Moolenaar for m in values 538bfd8fc05SBram Moolenaar " This if is needed to not offer all completions as-is 539bfd8fc05SBram Moolenaar " alphabetically but sort them. Those beginning with entered 540bfd8fc05SBram Moolenaar " part will be as first choices 541bfd8fc05SBram Moolenaar if m =~ '^'.entered_value 542f9393ef5SBram Moolenaar call add(res, attrquoteopen . m . attrquote) 543bfd8fc05SBram Moolenaar elseif m =~ entered_value 544f9393ef5SBram Moolenaar call add(res2, attrquoteopen . m . attrquote) 545f75a963eSBram Moolenaar endif 546f75a963eSBram Moolenaar endfor 547bfd8fc05SBram Moolenaar 548bfd8fc05SBram Moolenaar return res + res2 549bfd8fc05SBram Moolenaar 550f75a963eSBram Moolenaar endif 5518b6144bdSBram Moolenaar " }}} 5528b6144bdSBram Moolenaar " Attribute completion {{{ 553d5cdbeb8SBram Moolenaar " Shorten context to not include last word 554d5cdbeb8SBram Moolenaar let sbase = matchstr(context, '.*\ze\s.*') 5551d2ba7faSBram Moolenaar 5561d2ba7faSBram Moolenaar " Load data {{{ 557f193fffdSBram Moolenaar if !exists("b:html_doctype") 558f193fffdSBram Moolenaar call htmlcomplete#CheckDoctype() 559f193fffdSBram Moolenaar endif 560f193fffdSBram Moolenaar if !exists("b:html_omni") 561c1e37901SBram Moolenaar call htmlcomplete#LoadData() 562f75a963eSBram Moolenaar endif 5631d2ba7faSBram Moolenaar " }}} 5648424a624SBram Moolenaar 565fc1421ebSBram Moolenaar if has_key(b:html_omni, tag) 566fc1421ebSBram Moolenaar let attrs = keys(b:html_omni[tag][1]) 5678424a624SBram Moolenaar else 5688424a624SBram Moolenaar return [] 5698424a624SBram Moolenaar endif 570f75a963eSBram Moolenaar 571f75a963eSBram Moolenaar for m in sort(attrs) 572bfd8fc05SBram Moolenaar if m =~ '^'.attr 573d5cdbeb8SBram Moolenaar call add(res, m) 574bfd8fc05SBram Moolenaar elseif m =~ attr 575d5cdbeb8SBram Moolenaar call add(res2, m) 576f75a963eSBram Moolenaar endif 577f75a963eSBram Moolenaar endfor 5781d2ba7faSBram Moolenaar let menu = res + res2 579fc1421ebSBram Moolenaar if has_key(b:html_omni, 'vimxmlattrinfo') 5801d2ba7faSBram Moolenaar let final_menu = [] 5811d2ba7faSBram Moolenaar for i in range(len(menu)) 5821d2ba7faSBram Moolenaar let item = menu[i] 583fc1421ebSBram Moolenaar if has_key(b:html_omni['vimxmlattrinfo'], item) 584fc1421ebSBram Moolenaar let m_menu = b:html_omni['vimxmlattrinfo'][item][0] 585fc1421ebSBram Moolenaar let m_info = b:html_omni['vimxmlattrinfo'][item][1] 5861d2ba7faSBram Moolenaar else 5871d2ba7faSBram Moolenaar let m_menu = '' 5881d2ba7faSBram Moolenaar let m_info = '' 589f193fffdSBram Moolenaar endif 590f193fffdSBram Moolenaar if len(b:html_omni[tag][1][item]) > 0 && b:html_omni[tag][1][item][0] =~ '^\(BOOL\|'.item.'\)$' 591f193fffdSBram Moolenaar let item = item 592f193fffdSBram Moolenaar let m_menu = 'Bool' 593f193fffdSBram Moolenaar else 5941d2ba7faSBram Moolenaar let item .= '="' 5951d2ba7faSBram Moolenaar endif 5961d2ba7faSBram Moolenaar let final_menu += [{'word':item, 'menu':m_menu, 'info':m_info}] 5971d2ba7faSBram Moolenaar endfor 5981d2ba7faSBram Moolenaar else 599f193fffdSBram Moolenaar let final_menu = [] 600f193fffdSBram Moolenaar for i in range(len(menu)) 601f193fffdSBram Moolenaar let item = menu[i] 602f193fffdSBram Moolenaar if len(b:html_omni[tag][1][item]) > 0 && b:html_omni[tag][1][item][0] =~ '^\(BOOL\|'.item.'\)$' 603f193fffdSBram Moolenaar let item = item 604f193fffdSBram Moolenaar else 605f193fffdSBram Moolenaar let item .= '="' 606f193fffdSBram Moolenaar endif 607f193fffdSBram Moolenaar let final_menu += [item] 608f193fffdSBram Moolenaar endfor 609f193fffdSBram Moolenaar return final_menu 610f193fffdSBram Moolenaar 6111d2ba7faSBram Moolenaar endif 6121d2ba7faSBram Moolenaar return final_menu 613bfd8fc05SBram Moolenaar 614f75a963eSBram Moolenaar endif 6158b6144bdSBram Moolenaar " }}} 6168b6144bdSBram Moolenaar " Close tag {{{ 6174c903f98SBram Moolenaar let b:unaryTagsStack = "base meta link hr br param img area input col" 618d5cdbeb8SBram Moolenaar if context =~ '^\/' 619362e1a30SBram Moolenaar if context =~ '^\/.' 620362e1a30SBram Moolenaar return [] 621362e1a30SBram Moolenaar else 622a5792f58SBram Moolenaar let opentag = xmlcomplete#GetLastOpenTag("b:unaryTagsStack") 623d5cdbeb8SBram Moolenaar return [opentag.">"] 6244c903f98SBram Moolenaar endif 625362e1a30SBram Moolenaar endif 6268424a624SBram Moolenaar " }}} 6278b6144bdSBram Moolenaar " Load data {{{ 628f193fffdSBram Moolenaar if !exists("b:html_doctype") 629f193fffdSBram Moolenaar call htmlcomplete#CheckDoctype() 630f193fffdSBram Moolenaar endif 631fc1421ebSBram Moolenaar if !exists("b:html_omni") 632c1e37901SBram Moolenaar "runtime! autoload/xml/xhtml10s.vim 633c1e37901SBram Moolenaar call htmlcomplete#LoadData() 6344c903f98SBram Moolenaar endif 6358b6144bdSBram Moolenaar " }}} 6368b6144bdSBram Moolenaar " Tag completion {{{ 6377e8fd636SBram Moolenaar " Deal with tag completion. 6388424a624SBram Moolenaar let opentag = tolower(xmlcomplete#GetLastOpenTag("b:unaryTagsStack")) 639362e1a30SBram Moolenaar " MM: TODO: GLOT works always the same but with some weird situation it 640362e1a30SBram Moolenaar " behaves as intended in HTML but screws in PHP 6414a85b415SBram Moolenaar if opentag == '' || &filetype == 'php' && !has_key(b:html_omni, opentag) 6427e8fd636SBram Moolenaar " Hack for sometimes failing GetLastOpenTag. 6437e8fd636SBram Moolenaar " As far as I tested fail isn't GLOT fault but problem 6447e8fd636SBram Moolenaar " of invalid document - not properly closed tags and other mish-mash. 6457e8fd636SBram Moolenaar " Also when document is empty. Return list of *all* tags. 646fc1421ebSBram Moolenaar let tags = keys(b:html_omni) 6477e8fd636SBram Moolenaar call filter(tags, 'v:val !~ "^vimxml"') 6487e8fd636SBram Moolenaar else 649fc1421ebSBram Moolenaar if has_key(b:html_omni, opentag) 650fc1421ebSBram Moolenaar let tags = b:html_omni[opentag][0] 6518424a624SBram Moolenaar else 6528424a624SBram Moolenaar return [] 6538424a624SBram Moolenaar endif 6547e8fd636SBram Moolenaar endif 6557e8fd636SBram Moolenaar " }}} 6567e8fd636SBram Moolenaar 6578424a624SBram Moolenaar if exists("uppercase_tag") && uppercase_tag == 1 6588424a624SBram Moolenaar let context = tolower(context) 6598424a624SBram Moolenaar endif 660d5ab34bdSBram Moolenaar " Handle XML keywords: DOCTYPE 661f193fffdSBram Moolenaar if opentag == '' 6624a85b415SBram Moolenaar let tags += [ 663d5ab34bdSBram Moolenaar \ '!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">', 664d5ab34bdSBram Moolenaar \ '!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">', 665d5ab34bdSBram Moolenaar \ '!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">', 666d5ab34bdSBram Moolenaar \ '!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" "http://www.w3.org/TR/REC-html40/frameset.dtd">', 667d5ab34bdSBram Moolenaar \ '!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">', 668d5ab34bdSBram Moolenaar \ '!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">', 669d5ab34bdSBram Moolenaar \ '!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">', 670d5ab34bdSBram Moolenaar \ '!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">', 671d5ab34bdSBram Moolenaar \ '!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">', 672d5ab34bdSBram Moolenaar \ '!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">', 673d5ab34bdSBram Moolenaar \ '!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/1999/xhtml">' 6744a85b415SBram Moolenaar \ ] 6754a85b415SBram Moolenaar endif 6768424a624SBram Moolenaar 677cef9dcc3SBram Moolenaar for m in sort(tags) 678d5cdbeb8SBram Moolenaar if m =~ '^'.context 6794c903f98SBram Moolenaar call add(res, m) 680d5cdbeb8SBram Moolenaar elseif m =~ context 681bfd8fc05SBram Moolenaar call add(res2, m) 6824c903f98SBram Moolenaar endif 6834c903f98SBram Moolenaar endfor 6841d2ba7faSBram Moolenaar let menu = res + res2 685fc1421ebSBram Moolenaar if has_key(b:html_omni, 'vimxmltaginfo') 6861d2ba7faSBram Moolenaar let final_menu = [] 6871d2ba7faSBram Moolenaar for i in range(len(menu)) 6881d2ba7faSBram Moolenaar let item = menu[i] 689fc1421ebSBram Moolenaar if has_key(b:html_omni['vimxmltaginfo'], item) 690fc1421ebSBram Moolenaar let m_menu = b:html_omni['vimxmltaginfo'][item][0] 691fc1421ebSBram Moolenaar let m_info = b:html_omni['vimxmltaginfo'][item][1] 6921d2ba7faSBram Moolenaar else 6931d2ba7faSBram Moolenaar let m_menu = '' 6941d2ba7faSBram Moolenaar let m_info = '' 6951d2ba7faSBram Moolenaar endif 6964a85b415SBram Moolenaar if &filetype == 'html' && exists("uppercase_tag") && uppercase_tag == 1 && item !~ 'DOCTYPE' 697fc1421ebSBram Moolenaar let item = toupper(item) 698fc1421ebSBram Moolenaar endif 6994a85b415SBram Moolenaar if item =~ 'DOCTYPE' 7004a85b415SBram Moolenaar let abbr = 'DOCTYPE '.matchstr(item, 'DTD \zsX\?HTML .\{-}\ze\/\/') 7014a85b415SBram Moolenaar else 7024a85b415SBram Moolenaar let abbr = item 7034a85b415SBram Moolenaar endif 7044a85b415SBram Moolenaar let final_menu += [{'abbr':abbr, 'word':item, 'menu':m_menu, 'info':m_info}] 7051d2ba7faSBram Moolenaar endfor 7061d2ba7faSBram Moolenaar else 7071d2ba7faSBram Moolenaar let final_menu = menu 7081d2ba7faSBram Moolenaar endif 7091d2ba7faSBram Moolenaar return final_menu 7106b730e11SBram Moolenaar 7118b6144bdSBram Moolenaar " }}} 7124c903f98SBram Moolenaar endif 7136b730e11SBram Moolenaarendfunction 714c1e37901SBram Moolenaar 715c1e37901SBram Moolenaarfunction! htmlcomplete#LoadData() " {{{ 716fc1421ebSBram Moolenaar if !exists("b:html_omni_flavor") 7174a85b415SBram Moolenaar if &filetype == 'html' 718fc1421ebSBram Moolenaar let b:html_omni_flavor = 'html401t' 719fc1421ebSBram Moolenaar else 720fc1421ebSBram Moolenaar let b:html_omni_flavor = 'xhtml10s' 721c1e37901SBram Moolenaar endif 722fc1421ebSBram Moolenaar endif 723fc1421ebSBram Moolenaar " With that if we still have bloated memory but create new buffer 724fc1421ebSBram Moolenaar " variables only by linking to existing g:variable, not sourcing whole 725fc1421ebSBram Moolenaar " file. 726fc1421ebSBram Moolenaar if exists('g:xmldata_'.b:html_omni_flavor) 727fc1421ebSBram Moolenaar exe 'let b:html_omni = g:xmldata_'.b:html_omni_flavor 728fc1421ebSBram Moolenaar else 729fc1421ebSBram Moolenaar exe 'runtime! autoload/xml/'.b:html_omni_flavor.'.vim' 730f193fffdSBram Moolenaar exe 'let b:html_omni = g:xmldata_'.b:html_omni_flavor 731fc1421ebSBram Moolenaar endif 732f193fffdSBram Moolenaarendfunction 733f193fffdSBram Moolenaar" }}} 734f193fffdSBram Moolenaarfunction! htmlcomplete#CheckDoctype() " {{{ 735f193fffdSBram Moolenaar if exists('b:html_omni_flavor') 736f193fffdSBram Moolenaar let old_flavor = b:html_omni_flavor 737fc1421ebSBram Moolenaar else 738f193fffdSBram Moolenaar let old_flavor = '' 739f193fffdSBram Moolenaar endif 740f193fffdSBram Moolenaar let i = 1 741f193fffdSBram Moolenaar while i < 10 && i < line("$") 742f193fffdSBram Moolenaar let line = getline(i) 743f193fffdSBram Moolenaar if line =~ '<!DOCTYPE.*\<DTD HTML 3\.2' 744f193fffdSBram Moolenaar let b:html_omni_flavor = 'html32' 745f193fffdSBram Moolenaar let b:html_doctype = 1 746f193fffdSBram Moolenaar break 747f193fffdSBram Moolenaar elseif line =~ '<!DOCTYPE.*\<DTD HTML 4\.0 Transitional' 748f193fffdSBram Moolenaar let b:html_omni_flavor = 'html40t' 749f193fffdSBram Moolenaar let b:html_doctype = 1 750f193fffdSBram Moolenaar break 751f193fffdSBram Moolenaar elseif line =~ '<!DOCTYPE.*\<DTD HTML 4\.0 Frameset' 752f193fffdSBram Moolenaar let b:html_omni_flavor = 'html40f' 753f193fffdSBram Moolenaar let b:html_doctype = 1 754f193fffdSBram Moolenaar break 755f193fffdSBram Moolenaar elseif line =~ '<!DOCTYPE.*\<DTD HTML 4\.0' 756f193fffdSBram Moolenaar let b:html_omni_flavor = 'html40s' 757f193fffdSBram Moolenaar let b:html_doctype = 1 758f193fffdSBram Moolenaar break 759f193fffdSBram Moolenaar elseif line =~ '<!DOCTYPE.*\<DTD HTML 4\.01 Transitional' 760f193fffdSBram Moolenaar let b:html_omni_flavor = 'html401t' 761f193fffdSBram Moolenaar let b:html_doctype = 1 762f193fffdSBram Moolenaar break 763f193fffdSBram Moolenaar elseif line =~ '<!DOCTYPE.*\<DTD HTML 4\.01 Frameset' 764f193fffdSBram Moolenaar let b:html_omni_flavor = 'html401f' 765f193fffdSBram Moolenaar let b:html_doctype = 1 766f193fffdSBram Moolenaar break 767f193fffdSBram Moolenaar elseif line =~ '<!DOCTYPE.*\<DTD HTML 4\.01' 768f193fffdSBram Moolenaar let b:html_omni_flavor = 'html401s' 769f193fffdSBram Moolenaar let b:html_doctype = 1 770f193fffdSBram Moolenaar break 771f193fffdSBram Moolenaar elseif line =~ '<!DOCTYPE.*\<DTD XHTML 1\.0 Transitional' 772f193fffdSBram Moolenaar let b:html_omni_flavor = 'xhtml10t' 773f193fffdSBram Moolenaar let b:html_doctype = 1 774f193fffdSBram Moolenaar break 775f193fffdSBram Moolenaar elseif line =~ '<!DOCTYPE.*\<DTD XHTML 1\.0 Frameset' 776f193fffdSBram Moolenaar let b:html_omni_flavor = 'xhtml10f' 777f193fffdSBram Moolenaar let b:html_doctype = 1 778f193fffdSBram Moolenaar break 779f193fffdSBram Moolenaar elseif line =~ '<!DOCTYPE.*\<DTD XHTML 1\.0 Strict' 780fc1421ebSBram Moolenaar let b:html_omni_flavor = 'xhtml10s' 781f193fffdSBram Moolenaar let b:html_doctype = 1 782f193fffdSBram Moolenaar break 783f193fffdSBram Moolenaar elseif line =~ '<!DOCTYPE.*\<DTD XHTML 1\.1' 784f193fffdSBram Moolenaar let b:html_omni_flavor = 'xhtml11' 785f193fffdSBram Moolenaar let b:html_doctype = 1 786f193fffdSBram Moolenaar break 787c1e37901SBram Moolenaar endif 788f193fffdSBram Moolenaar let i += 1 789f193fffdSBram Moolenaar endwhile 790f193fffdSBram Moolenaar if !exists("b:html_doctype") 791f193fffdSBram Moolenaar return 792f193fffdSBram Moolenaar else 793f193fffdSBram Moolenaar " Tie g:xmldata with b:html_omni this way we need to sourca data file only 794f193fffdSBram Moolenaar " once, not every time per buffer. 795f193fffdSBram Moolenaar if old_flavor == b:html_omni_flavor 796f193fffdSBram Moolenaar return 797f193fffdSBram Moolenaar else 798fc1421ebSBram Moolenaar if exists('g:xmldata_'.b:html_omni_flavor) 799fc1421ebSBram Moolenaar exe 'let b:html_omni = g:xmldata_'.b:html_omni_flavor 800fc1421ebSBram Moolenaar else 801fc1421ebSBram Moolenaar exe 'runtime! autoload/xml/'.b:html_omni_flavor.'.vim' 802fc1421ebSBram Moolenaar exe 'let b:html_omni = g:xmldata_'.b:html_omni_flavor 803fc1421ebSBram Moolenaar endif 804f193fffdSBram Moolenaar return 805f193fffdSBram Moolenaar endif 806f193fffdSBram Moolenaar endif 807c1e37901SBram Moolenaarendfunction 808c1e37901SBram Moolenaar" }}} 8098b6144bdSBram Moolenaar" vim:set foldmethod=marker: 810