blob: a6295373ed7c6ffd24fc0f3f33656b293834c317 [file] [log] [blame]
Bram Moolenaarf75a9632005-09-13 21:20:47 +00001" Vim completion script
2" Language: XHTML 1.0 Strict
3" Maintainer: Mikolaj Machowski ( mikmach AT wp DOT pl )
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00004" Last Change: 2006 Feb 6
Bram Moolenaarf75a9632005-09-13 21:20:47 +00005
6function! htmlcomplete#CompleteTags(findstart, base)
7 if a:findstart
8 " locate the start of the word
9 let line = getline('.')
10 let start = col('.') - 1
Bram Moolenaar28c258f2006-01-25 22:02:51 +000011 let curline = line('.')
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +000012 let compl_begin = col('.') - 2
13 while start >= 0 && line[start - 1] =~ '\(\k\|[:.-]\)'
14 let start -= 1
Bram Moolenaarf75a9632005-09-13 21:20:47 +000015 endwhile
Bram Moolenaar8b6144b2006-02-08 09:20:24 +000016 " Handling of entities {{{
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +000017 if start >= 0 && line[start - 1] =~ '&'
18 let b:entitiescompl = 1
19 let b:compl_context = ''
20 return start
21 endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +000022 " }}}
23 " Handling of <style> tag {{{
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +000024 let stylestart = searchpair('<style\>', '', '<\/style\>', "bnW")
25 let styleend = searchpair('<style\>', '', '<\/style\>', "nW")
26 if stylestart != 0 && styleend != 0
Bram Moolenaar28c258f2006-01-25 22:02:51 +000027 if stylestart <= curline && styleend >= curline
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +000028 let start = col('.') - 1
29 let b:csscompl = 1
30 while start >= 0 && line[start - 1] =~ '\(\k\|-\)'
31 let start -= 1
32 endwhile
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +000033 endif
34 endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +000035 " }}}
36 " Handling of <script> tag {{{
Bram Moolenaarb8a7b562006-02-01 21:47:16 +000037 let scriptstart = searchpair('<script\>', '', '<\/script\>', "bnW")
38 let scriptend = searchpair('<script\>', '', '<\/script\>', "nW")
39 if scriptstart != 0 && scriptend != 0
40 if scriptstart <= curline && scriptend >= curline
41 let start = col('.') - 1
42 let b:jscompl = 1
43 let b:jsrange = [scriptstart, scriptend]
Bram Moolenaar8b6144b2006-02-08 09:20:24 +000044 while start >= 0 && line[start - 1] =~ '\w'
Bram Moolenaarb8a7b562006-02-01 21:47:16 +000045 let start -= 1
46 endwhile
Bram Moolenaar8b6144b2006-02-08 09:20:24 +000047 " We are inside of <script> tag. But we should also get contents
48 " of all linked external files and (secondary, less probably) other <script> tags
49 " This logic could possible be done in separate function - may be
50 " reused in events scripting (also with option could be reused for
51 " CSS
52 let b:js_extfiles = []
53 let l = line('.')
54 let c = col('.')
55 call cursor(1,1)
56 while search('<\@<=script\>', 'W') && line('.') <= l
57 if synIDattr(synID(line('.'),col('.')-1,0),"name") !~? 'comment'
58 let sname = matchstr(getline('.'), '<script[^>]*src\s*=\s*\([''"]\)\zs.\{-}\ze\1')
59 if filereadable(sname)
60 let b:js_extfiles += readfile(sname)
61 endif
62 endif
63 endwhile
64 call cursor(1,1)
65 let js_scripttags = []
66 while search('<script\>', 'W') && line('.') < l
67 if matchstr(getline('.'), '<script[^>]*src') == ''
68 let js_scripttag = getline(line('.'), search('</script>', 'W'))
69 let js_scripttags += js_scripttag
70 endif
71 endwhile
72 let b:js_extfiles += js_scripttags
73 call cursor(l,c)
74 unlet! l c
Bram Moolenaarb8a7b562006-02-01 21:47:16 +000075 endif
76 endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +000077 " }}}
Bram Moolenaarb8a7b562006-02-01 21:47:16 +000078 if !exists("b:csscompl") && !exists("b:jscompl")
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +000079 let b:compl_context = getline('.')[0:(compl_begin)]
Bram Moolenaar28c258f2006-01-25 22:02:51 +000080 if b:compl_context !~ '<[^>]*$'
Bram Moolenaar8b6144b2006-02-08 09:20:24 +000081 " Look like we may have broken tag. Check previous lines.
Bram Moolenaar28c258f2006-01-25 22:02:51 +000082 let i = 1
83 while 1
84 let context_line = getline(curline-i)
85 if context_line =~ '<[^>]*$'
86 " Yep, this is this line
87 let context_lines = getline(curline-i, curline)
88 let b:compl_context = join(context_lines, ' ')
89 break
90 elseif context_line =~ '>[^<]*$'
91 " Normal tag line, no need for completion at all
92 let b:compl_context = ''
93 break
94 endif
95 let i += 1
96 endwhile
97 " Make sure we don't have counter
98 unlet! i
99 endif
Bram Moolenaar09df3122006-01-23 22:23:09 +0000100 let b:compl_context = matchstr(b:compl_context, '.*\zs<.*')
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000101 " Return proper start for on-events. Without that beginning of
102 " completion will be badly reported
103 if b:compl_context =~? 'on[a-z]*\s*=\s*\(''[^'']*\|"[^"]*\)$'
104 let start = col('.') - 1
105 while start >= 0 && line[start - 1] =~ '\w'
106 let start -= 1
107 endwhile
108 endif
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000109 else
110 let b:compl_context = getline('.')[0:compl_begin]
111 endif
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000112 return start
113 else
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000114 " Initialize base return lists
115 let res = []
116 let res2 = []
117 " a:base is very short - we need context
118 let context = b:compl_context
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000119 " Check if we should do CSS completion inside of <style> tag
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000120 " or JS completion inside of <script> tag
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000121 if exists("b:csscompl")
122 unlet! b:csscompl
Bram Moolenaar09df3122006-01-23 22:23:09 +0000123 let context = b:compl_context
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000124 unlet! b:compl_context
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000125 return csscomplete#CompleteCSS(0, context)
Bram Moolenaarb8a7b562006-02-01 21:47:16 +0000126 elseif exists("b:jscompl")
127 unlet! b:jscompl
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000128 return javascriptcomplete#CompleteJS(0, a:base)
Bram Moolenaar09df3122006-01-23 22:23:09 +0000129 else
130 if len(b:compl_context) == 0 && !exists("b:entitiescompl")
131 return []
132 endif
133 let context = matchstr(b:compl_context, '.\zs.*')
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000134 endif
Bram Moolenaar09df3122006-01-23 22:23:09 +0000135 unlet! b:compl_context
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000136 " Entities completion {{{
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000137 if exists("b:entitiescompl")
138 unlet! b:entitiescompl
139
Bram Moolenaara5792f52005-11-23 21:25:05 +0000140 if !exists("g:xmldata_xhtml10s")
141 runtime! autoload/xml/xhtml10s.vim
142 endif
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000143
Bram Moolenaara5792f52005-11-23 21:25:05 +0000144 let entities = g:xmldata_xhtml10s['vimxmlentities']
145
Bram Moolenaar09df3122006-01-23 22:23:09 +0000146 if len(a:base) == 1
147 for m in entities
148 if m =~ '^'.a:base
149 call add(res, m.';')
150 endif
151 endfor
152 return res
153 else
154 for m in entities
155 if m =~? '^'.a:base
156 call add(res, m.';')
157 elseif m =~? a:base
158 call add(res2, m.';')
159 endif
160 endfor
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000161
Bram Moolenaar09df3122006-01-23 22:23:09 +0000162 return res + res2
163 endif
164
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000165
166 endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000167 " }}}
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000168 if context =~ '>'
169 " Generally if context contains > it means we are outside of tag and
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000170 " should abandon action - with one exception: <style> span { bo
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000171 if context =~ 'style[^>]\{-}>[^<]\{-}$'
172 return csscomplete#CompleteCSS(0, context)
Bram Moolenaarb8a7b562006-02-01 21:47:16 +0000173 elseif context =~ 'script[^>]\{-}>[^<]\{-}$'
174 let b:jsrange = [line('.'), search('<\/script\>', 'nW')]
175 return javascriptcomplete#CompleteJS(0, context)
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000176 else
177 return []
178 endif
179 endif
180
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000181 " Set attribute groups
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000182 let coreattrs = ["id", "class", "style", "title"]
183 let i18n = ["lang", "xml:lang", "dir=\"ltr\" ", "dir=\"rtl\" "]
184 let events = ["onclick", "ondblclick", "onmousedown", "onmouseup", "onmousemove",
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000185 \ "onmouseover", "onmouseout", "onkeypress", "onkeydown", "onkeyup"]
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000186 let focus = ["accesskey", "tabindex", "onfocus", "onblur"]
187 let coregroup = coreattrs + i18n + events
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000188 " If context contains > it means we are already outside of tag and we
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000189 " should abandon action
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000190 " If context contains white space it is attribute.
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000191 " It can be also value of attribute.
192 " We have to get first word to offer proper completions
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000193 if context == ''
194 let tag = ''
195 else
196 let tag = split(context)[0]
197 endif
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000198 " Get last word, it should be attr name
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000199 let attr = matchstr(context, '.*\s\zs.*')
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000200 " Possible situations where any prediction would be difficult:
201 " 1. Events attributes
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000202 if context =~ '\s'
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000203 " Sort out style, class, and on* cases
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000204 if context =~? "\\(on[a-z]*\\|id\\|style\\|class\\)\\s*=\\s*[\"']"
205 " Id, class completion {{{
206 if context =~? "\\(id\\|class\\)\\s*=\\s*[\"'][a-zA-Z0-9_ -]*$"
207 if context =~? "class\\s*=\\s*[\"'][a-zA-Z0-9_ -]*$"
Bram Moolenaar1e015462005-09-25 22:16:38 +0000208 let search_for = "class"
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000209 elseif context =~? "id\\s*=\\s*[\"'][a-zA-Z0-9_ -]*$"
Bram Moolenaar1e015462005-09-25 22:16:38 +0000210 let search_for = "id"
211 endif
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000212 " Handle class name completion
213 " 1. Find lines of <link stylesheet>
214 " 1a. Check file for @import
215 " 2. Extract filename(s?) of stylesheet,
216 call cursor(1,1)
217 let head = getline(search('<head\>'), search('<\/head>'))
218 let headjoined = join(copy(head), ' ')
219 if headjoined =~ '<style'
Bram Moolenaara5792f52005-11-23 21:25:05 +0000220 " Remove possibly confusing CSS operators
Bram Moolenaar1e015462005-09-25 22:16:38 +0000221 let stylehead = substitute(headjoined, '+>\*[,', ' ', 'g')
222 if search_for == 'class'
223 let styleheadlines = split(stylehead)
224 let headclasslines = filter(copy(styleheadlines), "v:val =~ '\\([a-zA-Z0-9:]\\+\\)\\?\\.[a-zA-Z0-9_-]\\+'")
225 else
226 let stylesheet = split(headjoined, '[{}]')
227 " Get all lines which fit id syntax
228 let classlines = filter(copy(stylesheet), "v:val =~ '#[a-zA-Z0-9_-]\\+'")
229 " Filter out possible color definitions
230 call filter(classlines, "v:val !~ ':\\s*#[a-zA-Z0-9_-]\\+'")
231 " Filter out complex border definitions
232 call filter(classlines, "v:val !~ '\\(none\\|hidden\\|dotted\\|dashed\\|solid\\|double\\|groove\\|ridge\\|inset\\|outset\\)\\s*#[a-zA-Z0-9_-]\\+'")
233 let templines = join(classlines, ' ')
234 let headclasslines = split(templines)
235 call filter(headclasslines, "v:val =~ '#[a-zA-Z0-9_-]\\+'")
236 endif
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000237 let internal = 1
238 else
239 let internal = 0
240 endif
241 let styletable = []
242 let secimportfiles = []
243 let filestable = filter(copy(head), "v:val =~ '\\(@import\\|link.*stylesheet\\)'")
244 for line in filestable
245 if line =~ "@import"
246 let styletable += [matchstr(line, "import\\s\\+\\(url(\\)\\?[\"']\\?\\zs\\f\\+\\ze")]
247 elseif line =~ "<link"
248 let styletable += [matchstr(line, "href\\s*=\\s*[\"']\\zs\\f\\+\\ze")]
249 endif
250 endfor
Bram Moolenaar1e015462005-09-25 22:16:38 +0000251 for file in styletable
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000252 if filereadable(file)
253 let stylesheet = readfile(file)
254 let secimport = filter(copy(stylesheet), "v:val =~ '@import'")
255 if len(secimport) > 0
256 for line in secimport
Bram Moolenaar1e015462005-09-25 22:16:38 +0000257 let secfile = matchstr(line, "import\\s\\+\\(url(\\)\\?[\"']\\?\\zs\\f\\+\\ze")
258 let secfile = fnamemodify(file, ":p:h").'/'.secfile
259 let secimportfiles += [secfile]
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000260 endfor
261 endif
262 endif
263 endfor
264 let cssfiles = styletable + secimportfiles
265 let classes = []
266 for file in cssfiles
267 if filereadable(file)
268 let stylesheet = readfile(file)
Bram Moolenaar1e015462005-09-25 22:16:38 +0000269 let stylefile = join(stylesheet, ' ')
270 let stylefile = substitute(stylefile, '+>\*[,', ' ', 'g')
271 if search_for == 'class'
272 let stylesheet = split(stylefile)
273 let classlines = filter(copy(stylesheet), "v:val =~ '\\([a-zA-Z0-9:]\\+\\)\\?\\.[a-zA-Z0-9_-]\\+'")
274 else
275 let stylesheet = split(stylefile, '[{}]')
276 " Get all lines which fit id syntax
277 let classlines = filter(copy(stylesheet), "v:val =~ '#[a-zA-Z0-9_-]\\+'")
278 " Filter out possible color definitions
279 call filter(classlines, "v:val !~ ':\\s*#[a-zA-Z0-9_-]\\+'")
280 " Filter out complex border definitions
281 call filter(classlines, "v:val !~ '\\(none\\|hidden\\|dotted\\|dashed\\|solid\\|double\\|groove\\|ridge\\|inset\\|outset\\)\\s*#[a-zA-Z0-9_-]\\+'")
282 let templines = join(classlines, ' ')
283 let stylelines = split(templines)
284 let classlines = filter(stylelines, "v:val =~ '#[a-zA-Z0-9_-]\\+'")
285
286 endif
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000287 endif
288 " We gathered classes definitions from all external files
289 let classes += classlines
290 endfor
291 if internal == 1
292 let classes += headclasslines
293 endif
Bram Moolenaar1e015462005-09-25 22:16:38 +0000294
295 if search_for == 'class'
296 let elements = {}
297 for element in classes
298 if element =~ '^\.'
299 let class = matchstr(element, '^\.\zs[a-zA-Z][a-zA-Z0-9_-]*\ze')
300 let class = substitute(class, ':.*', '', '')
301 if has_key(elements, 'common')
302 let elements['common'] .= ' '.class
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000303 else
Bram Moolenaar1e015462005-09-25 22:16:38 +0000304 let elements['common'] = class
305 endif
306 else
307 let class = matchstr(element, '[a-zA-Z1-6]*\.\zs[a-zA-Z][a-zA-Z0-9_-]*\ze')
308 let tagname = tolower(matchstr(element, '[a-zA-Z1-6]*\ze.'))
309 if tagname != ''
310 if has_key(elements, tagname)
311 let elements[tagname] .= ' '.class
312 else
313 let elements[tagname] = class
314 endif
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000315 endif
316 endif
Bram Moolenaar1e015462005-09-25 22:16:38 +0000317 endfor
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000318
Bram Moolenaar1e015462005-09-25 22:16:38 +0000319 if has_key(elements, tag) && has_key(elements, 'common')
320 let values = split(elements[tag]." ".elements['common'])
321 elseif has_key(elements, tag) && !has_key(elements, 'common')
322 let values = split(elements[tag])
323 elseif !has_key(elements, tag) && has_key(elements, 'common')
324 let values = split(elements['common'])
325 else
326 return []
327 endif
328
329 elseif search_for == 'id'
330 " Find used IDs
331 " 1. Catch whole file
332 let filelines = getline(1, line('$'))
333 " 2. Find lines with possible id
334 let used_id_lines = filter(filelines, 'v:val =~ "id\\s*=\\s*[\"''][a-zA-Z0-9_-]\\+"')
335 " 3a. Join all filtered lines
336 let id_string = join(used_id_lines, ' ')
337 " 3b. And split them to be sure each id is in separate item
338 let id_list = split(id_string, 'id\s*=\s*')
339 " 4. Extract id values
340 let used_id = map(id_list, 'matchstr(v:val, "[\"'']\\zs[a-zA-Z0-9_-]\\+\\ze")')
341 let joined_used_id = ','.join(used_id, ',').','
342
343 let allvalues = map(classes, 'matchstr(v:val, ".*#\\zs[a-zA-Z0-9_-]\\+")')
344
345 let values = []
346
347 for element in classes
348 if joined_used_id !~ ','.element.','
349 let values += [element]
350 endif
351
352 endfor
353
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000354 endif
355
356 " We need special version of sbase
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000357 let classbase = matchstr(context, ".*[\"']")
Bram Moolenaar1e015462005-09-25 22:16:38 +0000358 let classquote = matchstr(classbase, '.$')
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000359
360 let entered_class = matchstr(attr, ".*=\\s*[\"']\\zs.*")
361
362 for m in sort(values)
363 if m =~? '^'.entered_class
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000364 call add(res, m . classquote)
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000365 elseif m =~? entered_class
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000366 call add(res2, m . classquote)
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000367 endif
368 endfor
369
370 return res + res2
371
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000372 elseif context =~? "style\\s*=\\s*[\"'][^\"']*$"
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000373 return csscomplete#CompleteCSS(0, context)
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000374
375 endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000376 " }}}
377 " Complete on-events {{{
378 if context =~? 'on[a-z]*\s*=\s*\(''[^'']*\|"[^"]*\)$'
379 " We have to:
380 " 1. Find external files
381 let b:js_extfiles = []
382 let l = line('.')
383 let c = col('.')
384 call cursor(1,1)
385 while search('<\@<=script\>', 'W') && line('.') <= l
386 if synIDattr(synID(line('.'),col('.')-1,0),"name") !~? 'comment'
387 let sname = matchstr(getline('.'), '<script[^>]*src\s*=\s*\([''"]\)\zs.\{-}\ze\1')
388 if filereadable(sname)
389 let b:js_extfiles += readfile(sname)
390 endif
391 endif
392 endwhile
393 " 2. Find at least one <script> tag
394 call cursor(1,1)
395 let js_scripttags = []
396 while search('<script\>', 'W') && line('.') < l
397 if matchstr(getline('.'), '<script[^>]*src') == ''
398 let js_scripttag = getline(line('.'), search('</script>', 'W'))
399 let js_scripttags += js_scripttag
400 endif
401 endwhile
402 let b:js_extfiles += js_scripttags
403
404 " 3. Proper call for javascriptcomplete#CompleteJS
405 call cursor(l,c)
406 let js_context = matchstr(a:base, '\w\+$')
407 let js_shortcontext = substitute(a:base, js_context.'$', '', '')
408 let b:compl_context = context
409 let b:jsrange = [l, l]
410 unlet! l c
411 "return map(javascriptcomplete#CompleteJS(0, js_context), 'js_shortcontext.v:val')
412 return javascriptcomplete#CompleteJS(0, js_context)
413
414 endif
415
416 " }}}
417 let stripbase = matchstr(context, ".*\\(on[a-zA-Z]*\\|style\\|class\\)\\s*=\\s*[\"']\\zs.*")
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000418 " Now we have context stripped from all chars up to style/class.
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000419 " It may fail with some strange style value combinations.
420 if stripbase !~ "[\"']"
421 return []
422 endif
423 endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000424 " Value of attribute completion {{{
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000425 " If attr contains =\s*[\"'] we catched value of attribute
426 if attr =~ "=\s*[\"']"
427 " Let do attribute specific completion
428 let attrname = matchstr(attr, '.*\ze\s*=')
429 let entered_value = matchstr(attr, ".*=\\s*[\"']\\zs.*")
430 let values = []
431 if attrname == 'media'
432 let values = ["screen", "tty", "tv", "projection", "handheld", "print", "braille", "aural", "all"]
433 elseif attrname == 'xml:space'
434 let values = ["preserve"]
435 elseif attrname == 'shape'
Bram Moolenaar8349fd72005-10-12 20:52:20 +0000436 let values = ["rect", "circle", "poly", "default"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000437 elseif attrname == 'valuetype'
438 let values = ["data", "ref", "object"]
439 elseif attrname == 'method'
440 let values = ["get", "post"]
Bram Moolenaar4c903f92005-09-14 21:32:32 +0000441 elseif attrname == 'dir'
442 let values = ["ltr", "rtl"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000443 elseif attrname == 'frame'
444 let values = ["void", "above", "below", "hsides", "lhs", "rhs", "vsides", "box", "border"]
445 elseif attrname == 'rules'
446 let values = ["none", "groups", "rows", "all"]
447 elseif attrname == 'align'
448 let values = ["left", "center", "right", "justify", "char"]
449 elseif attrname == 'valign'
450 let values = ["top", "middle", "bottom", "baseline"]
451 elseif attrname == 'scope'
452 let values = ["row", "col", "rowgroup", "colgroup"]
453 elseif attrname == 'href'
454 " Now we are looking for local anchors defined by name or id
455 if entered_value =~ '^#'
456 let file = join(getline(1, line('$')), ' ')
457 " Split it be sure there will be one id/name element in
458 " item, it will be also first word [a-zA-Z0-9_-] in element
459 let oneelement = split(file, "\\(meta \\)\\@<!\\(name\\|id\\)\\s*=\\s*[\"']")
460 for i in oneelement
461 let values += ['#'.matchstr(i, "^[a-zA-Z][a-zA-Z0-9%_-]*")]
462 endfor
463 endif
464 elseif attrname == 'type'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000465 if context =~ '^input'
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000466 let values = ["text", "password", "checkbox", "radio", "submit", "reset", "file", "hidden", "image", "button"]
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000467 elseif context =~ '^button'
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000468 let values = ["button", "submit", "reset"]
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000469 elseif context =~ '^style'
Bram Moolenaar1e015462005-09-25 22:16:38 +0000470 let values = ["text/css"]
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000471 elseif context =~ '^script'
Bram Moolenaar1e015462005-09-25 22:16:38 +0000472 let values = ["text/javascript"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000473 endif
474 else
475 return []
476 endif
477
478 if len(values) == 0
479 return []
480 endif
481
482 " We need special version of sbase
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000483 let attrbase = matchstr(context, ".*[\"']")
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000484 let attrquote = matchstr(attrbase, '.$')
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000485
486 for m in values
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000487 " This if is needed to not offer all completions as-is
488 " alphabetically but sort them. Those beginning with entered
489 " part will be as first choices
490 if m =~ '^'.entered_value
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000491 call add(res, m . attrquote.' ')
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000492 elseif m =~ entered_value
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000493 call add(res2, m . attrquote.' ')
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000494 endif
495 endfor
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000496
497 return res + res2
498
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000499 endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000500 " }}}
501 " Attribute completion {{{
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000502 " Shorten context to not include last word
503 let sbase = matchstr(context, '.*\ze\s.*')
504 if tag =~ '^\(abbr\|acronym\|address\|b\|bdo\|big\|caption\|cite\|code\|dd\|dfn\|div\|dl\|dt\|em\|fieldset\|h\d\|hr\|i\|kbd\|li\|noscript\|ol\|p\|samp\|small\|span\|strong\|sub\|sup\|tt\|ul\|var\)$'
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000505 let attrs = coregroup
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000506 elseif tag == 'a'
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000507 let attrs = coregroup + focus + ["charset", "type", "name", "href", "hreflang", "rel", "rev", "shape", "coords"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000508 elseif tag == 'area'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000509 let attrs = coregroup + focus + ["shape", "coords", "href", "nohref", "alt"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000510 elseif tag == 'base'
511 let attrs = ["href", "id"]
512 elseif tag == 'blockquote'
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000513 let attrs = coregroup + ["cite"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000514 elseif tag == 'body'
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000515 let attrs = coregroup + ["onload", "onunload"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000516 elseif tag == 'br'
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000517 let attrs = coreattrs
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000518 elseif tag == 'button'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000519 let attrs = coregroup + focus + ["name", "value", "type"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000520 elseif tag == '^\(col\|colgroup\)$'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000521 let attrs = coregroup + ["span", "width", "align", "char", "charoff", "valign"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000522 elseif tag =~ '^\(del\|ins\)$'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000523 let attrs = coregroup + ["cite", "datetime"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000524 elseif tag == 'form'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000525 let attrs = coregroup + ["action", "method=\"get\" ", "method=\"post\" ", "enctype", "onsubmit", "onreset", "accept", "accept-charset"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000526 elseif tag == 'head'
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000527 let attrs = i18n + ["id", "profile"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000528 elseif tag == 'html'
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000529 let attrs = i18n + ["id", "xmlns"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000530 elseif tag == 'img'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000531 let attrs = coregroup + ["src", "alt", "longdesc", "height", "width", "usemap", "ismap"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000532 elseif tag == 'input'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000533 let attrs = coregroup + ["type", "name", "value", "checked", "disabled", "readonly", "size", "maxlength", "src", "alt", "usemap", "onselect", "onchange", "accept"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000534 elseif tag == 'label'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000535 let attrs = coregroup + ["for", "accesskey", "onfocus", "onblur"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000536 elseif tag == 'legend'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000537 let attrs = coregroup + ["accesskey"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000538 elseif tag == 'link'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000539 let attrs = coregroup + ["charset", "href", "hreflang", "type", "rel", "rev", "media"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000540 elseif tag == 'map'
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000541 let attrs = i18n + events + ["id", "class", "style", "title", "name"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000542 elseif tag == 'meta'
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000543 let attrs = i18n + ["id", "http-equiv", "content", "scheme", "name"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000544 elseif tag == 'title'
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000545 let attrs = i18n + ["id"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000546 elseif tag == 'object'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000547 let attrs = coregroup + ["declare", "classid", "codebase", "data", "type", "codetype", "archive", "standby", "height", "width", "usemap", "name", "tabindex"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000548 elseif tag == 'optgroup'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000549 let attrs = coregroup + ["disbled", "label"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000550 elseif tag == 'option'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000551 let attrs = coregroup + ["disbled", "selected", "value", "label"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000552 elseif tag == 'param'
553 let attrs = ["id", "name", "value", "valuetype", "type"]
554 elseif tag == 'pre'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000555 let attrs = coregroup + ["xml:space"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000556 elseif tag == 'q'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000557 let attrs = coregroup + ["cite"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000558 elseif tag == 'script'
Bram Moolenaar1e015462005-09-25 22:16:38 +0000559 let attrs = ["id", "charset", "type=\"text/javascript\"", "type", "src", "defer", "xml:space"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000560 elseif tag == 'select'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000561 let attrs = coregroup + ["name", "size", "multiple", "disabled", "tabindex", "onfocus", "onblur", "onchange"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000562 elseif tag == 'style'
Bram Moolenaar1e015462005-09-25 22:16:38 +0000563 let attrs = coreattrs + ["id", "type=\"text/css\"", "type", "media", "title", "xml:space"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000564 elseif tag == 'table'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000565 let attrs = coregroup + ["summary", "width", "border", "frame", "rules", "cellspacing", "cellpadding"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000566 elseif tag =~ '^\(thead\|tfoot\|tbody\|tr\)$'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000567 let attrs = coregroup + ["align", "char", "charoff", "valign"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000568 elseif tag == 'textarea'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000569 let attrs = coregroup + ["name", "rows", "cols", "disabled", "readonly", "onselect", "onchange"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000570 elseif tag =~ '^\(th\|td\)$'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000571 let attrs = coregroup + ["abbr", "headers", "scope", "rowspan", "colspan", "align", "char", "charoff", "valign"]
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000572 else
573 return []
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000574 endif
575
576 for m in sort(attrs)
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000577 if m =~ '^'.attr
578 if m =~ '^\(ismap\|defer\|declare\|nohref\|checked\|disabled\|selected\|readonly\)$' || m =~ '='
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000579 call add(res, m)
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000580 else
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000581 call add(res, m.'="')
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000582 endif
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000583 elseif m =~ attr
584 if m =~ '^\(ismap\|defer\|declare\|nohref\|checked\|disabled\|selected\|readonly\)$' || m =~ '='
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000585 call add(res2, m)
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000586 else
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000587 call add(res2, m.'="')
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000588 endif
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000589 endif
590 endfor
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000591
592 return res + res2
593
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000594 endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000595 " }}}
596 " Close tag {{{
Bram Moolenaar6b730e12005-09-16 21:47:57 +0000597 let b:unaryTagsStack = "base meta link hr br param img area input col"
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000598 if context =~ '^\/'
Bram Moolenaara5792f52005-11-23 21:25:05 +0000599 let opentag = xmlcomplete#GetLastOpenTag("b:unaryTagsStack")
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000600 return [opentag.">"]
Bram Moolenaar4c903f92005-09-14 21:32:32 +0000601 endif
602 " Deal with tag completion.
Bram Moolenaara5792f52005-11-23 21:25:05 +0000603 let opentag = xmlcomplete#GetLastOpenTag("b:unaryTagsStack")
Bram Moolenaar09df3122006-01-23 22:23:09 +0000604 if opentag == ''
605 " Hack for sometimes failing GetLastOpenTag.
606 " As far as I tested fail isn't GLOT fault but problem
607 " of invalid document - not properly closed tags and other mish-mash.
608 " If returns empty string assume <body>. Safe bet.
609 let opentag = 'body'
610 endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000611 " }}}
612 " Load data {{{
Bram Moolenaara5792f52005-11-23 21:25:05 +0000613 if !exists("g:xmldata_xhtml10s")
614 runtime! autoload/xml/xhtml10s.vim
Bram Moolenaar4c903f92005-09-14 21:32:32 +0000615 endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000616 " }}}
617 " Tag completion {{{
Bram Moolenaar4c903f92005-09-14 21:32:32 +0000618
Bram Moolenaara5792f52005-11-23 21:25:05 +0000619 let tags = g:xmldata_xhtml10s[opentag][0]
620
Bram Moolenaarcef9dcc2005-12-06 19:50:41 +0000621 for m in sort(tags)
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000622 if m =~ '^'.context
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000623 call add(res, m)
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000624 elseif m =~ context
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000625 call add(res2, m)
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000626 endif
Bram Moolenaar6b730e12005-09-16 21:47:57 +0000627 endfor
628
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000629 return res + res2
Bram Moolenaar6b730e12005-09-16 21:47:57 +0000630
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000631 " }}}
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000632 endif
633endfunction
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000634" vim:set foldmethod=marker: