blob: 61d2a09d9b3d13b05076ba4ea11b5c116f0e4162 [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 Moolenaar3991dab2006-03-27 17:01:56 +00004" Last Change: 2006 Mar 25
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 Moolenaar1d2ba7f2006-02-14 22:29:30 +000044 while start >= 0 && line[start - 1] =~ '\k'
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
Bram Moolenaare0fa5602006-03-19 22:08:37 +000090 elseif context_line =~ '>[^<]*$' || i == curline
91 " We are in normal tag line, no need for completion at all
92 " OR reached first line without tag at all
Bram Moolenaar28c258f2006-01-25 22:02:51 +000093 let b:compl_context = ''
94 break
95 endif
96 let i += 1
Bram Moolenaare0fa5602006-03-19 22:08:37 +000097 " We reached first line and no tag approached
98 " Prevents endless loop
99 "if i > curline
100 "let b:compl_context = ''
101 "break
102 "endif
Bram Moolenaar28c258f2006-01-25 22:02:51 +0000103 endwhile
104 " Make sure we don't have counter
105 unlet! i
106 endif
Bram Moolenaar09df3122006-01-23 22:23:09 +0000107 let b:compl_context = matchstr(b:compl_context, '.*\zs<.*')
Bram Moolenaare0fa5602006-03-19 22:08:37 +0000108
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000109 " Return proper start for on-events. Without that beginning of
110 " completion will be badly reported
111 if b:compl_context =~? 'on[a-z]*\s*=\s*\(''[^'']*\|"[^"]*\)$'
112 let start = col('.') - 1
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000113 while start >= 0 && line[start - 1] =~ '\k'
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000114 let start -= 1
115 endwhile
116 endif
Bram Moolenaare0fa5602006-03-19 22:08:37 +0000117 " If b:compl_context begins with <? we are inside of PHP code. It
118 " wasn't closed so PHP completion passed it to HTML
119 if &filetype =~? 'php' && b:compl_context =~ '^<?'
120 let b:phpcompl = 1
121 let start = col('.') - 1
122 while start >= 0 && line[start - 1] =~ '[a-zA-Z_0-9\x7f-\xff$]'
123 let start -= 1
124 endwhile
125 endif
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000126 else
127 let b:compl_context = getline('.')[0:compl_begin]
128 endif
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000129 return start
130 else
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000131 " Initialize base return lists
132 let res = []
133 let res2 = []
134 " a:base is very short - we need context
135 let context = b:compl_context
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000136 " Check if we should do CSS completion inside of <style> tag
Bram Moolenaare0fa5602006-03-19 22:08:37 +0000137 " or JS completion inside of <script> tag or PHP completion in case of <?
138 " tag AND &ft==php
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000139 if exists("b:csscompl")
140 unlet! b:csscompl
Bram Moolenaar09df3122006-01-23 22:23:09 +0000141 let context = b:compl_context
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000142 unlet! b:compl_context
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000143 return csscomplete#CompleteCSS(0, context)
Bram Moolenaarb8a7b562006-02-01 21:47:16 +0000144 elseif exists("b:jscompl")
145 unlet! b:jscompl
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000146 return javascriptcomplete#CompleteJS(0, a:base)
Bram Moolenaare0fa5602006-03-19 22:08:37 +0000147 elseif exists("b:phpcompl")
148 unlet! b:phpcompl
149 let context = b:compl_context
150 return phpcomplete#CompletePHP(0, a:base)
Bram Moolenaar09df3122006-01-23 22:23:09 +0000151 else
152 if len(b:compl_context) == 0 && !exists("b:entitiescompl")
153 return []
154 endif
155 let context = matchstr(b:compl_context, '.\zs.*')
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000156 endif
Bram Moolenaar09df3122006-01-23 22:23:09 +0000157 unlet! b:compl_context
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000158 " Entities completion {{{
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000159 if exists("b:entitiescompl")
160 unlet! b:entitiescompl
161
Bram Moolenaara5792f52005-11-23 21:25:05 +0000162 if !exists("g:xmldata_xhtml10s")
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +0000163 runtime! autoload/xml/xhtml10s.vim
164 "call htmlcomplete#LoadData()
Bram Moolenaara5792f52005-11-23 21:25:05 +0000165 endif
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000166
Bram Moolenaara5792f52005-11-23 21:25:05 +0000167 let entities = g:xmldata_xhtml10s['vimxmlentities']
168
Bram Moolenaar09df3122006-01-23 22:23:09 +0000169 if len(a:base) == 1
170 for m in entities
171 if m =~ '^'.a:base
172 call add(res, m.';')
173 endif
174 endfor
175 return res
176 else
177 for m in entities
178 if m =~? '^'.a:base
179 call add(res, m.';')
180 elseif m =~? a:base
181 call add(res2, m.';')
182 endif
183 endfor
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000184
Bram Moolenaar09df3122006-01-23 22:23:09 +0000185 return res + res2
186 endif
187
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000188
189 endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000190 " }}}
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000191 if context =~ '>'
192 " Generally if context contains > it means we are outside of tag and
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000193 " should abandon action - with one exception: <style> span { bo
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000194 if context =~ 'style[^>]\{-}>[^<]\{-}$'
195 return csscomplete#CompleteCSS(0, context)
Bram Moolenaarb8a7b562006-02-01 21:47:16 +0000196 elseif context =~ 'script[^>]\{-}>[^<]\{-}$'
197 let b:jsrange = [line('.'), search('<\/script\>', 'nW')]
198 return javascriptcomplete#CompleteJS(0, context)
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000199 else
200 return []
201 endif
202 endif
203
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000204 " If context contains > it means we are already outside of tag and we
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000205 " should abandon action
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000206 " If context contains white space it is attribute.
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000207 " It can be also value of attribute.
208 " We have to get first word to offer proper completions
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000209 if context == ''
210 let tag = ''
211 else
212 let tag = split(context)[0]
213 endif
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000214 " Get last word, it should be attr name
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000215 let attr = matchstr(context, '.*\s\zs.*')
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000216 " Possible situations where any prediction would be difficult:
217 " 1. Events attributes
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000218 if context =~ '\s'
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000219 " Sort out style, class, and on* cases
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000220 if context =~? "\\(on[a-z]*\\|id\\|style\\|class\\)\\s*=\\s*[\"']"
221 " Id, class completion {{{
222 if context =~? "\\(id\\|class\\)\\s*=\\s*[\"'][a-zA-Z0-9_ -]*$"
223 if context =~? "class\\s*=\\s*[\"'][a-zA-Z0-9_ -]*$"
Bram Moolenaar1e015462005-09-25 22:16:38 +0000224 let search_for = "class"
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000225 elseif context =~? "id\\s*=\\s*[\"'][a-zA-Z0-9_ -]*$"
Bram Moolenaar1e015462005-09-25 22:16:38 +0000226 let search_for = "id"
227 endif
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000228 " Handle class name completion
229 " 1. Find lines of <link stylesheet>
230 " 1a. Check file for @import
231 " 2. Extract filename(s?) of stylesheet,
232 call cursor(1,1)
233 let head = getline(search('<head\>'), search('<\/head>'))
234 let headjoined = join(copy(head), ' ')
235 if headjoined =~ '<style'
Bram Moolenaara5792f52005-11-23 21:25:05 +0000236 " Remove possibly confusing CSS operators
Bram Moolenaar1e015462005-09-25 22:16:38 +0000237 let stylehead = substitute(headjoined, '+>\*[,', ' ', 'g')
238 if search_for == 'class'
239 let styleheadlines = split(stylehead)
240 let headclasslines = filter(copy(styleheadlines), "v:val =~ '\\([a-zA-Z0-9:]\\+\\)\\?\\.[a-zA-Z0-9_-]\\+'")
241 else
242 let stylesheet = split(headjoined, '[{}]')
243 " Get all lines which fit id syntax
244 let classlines = filter(copy(stylesheet), "v:val =~ '#[a-zA-Z0-9_-]\\+'")
245 " Filter out possible color definitions
246 call filter(classlines, "v:val !~ ':\\s*#[a-zA-Z0-9_-]\\+'")
247 " Filter out complex border definitions
248 call filter(classlines, "v:val !~ '\\(none\\|hidden\\|dotted\\|dashed\\|solid\\|double\\|groove\\|ridge\\|inset\\|outset\\)\\s*#[a-zA-Z0-9_-]\\+'")
249 let templines = join(classlines, ' ')
250 let headclasslines = split(templines)
251 call filter(headclasslines, "v:val =~ '#[a-zA-Z0-9_-]\\+'")
252 endif
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000253 let internal = 1
254 else
255 let internal = 0
256 endif
257 let styletable = []
258 let secimportfiles = []
259 let filestable = filter(copy(head), "v:val =~ '\\(@import\\|link.*stylesheet\\)'")
260 for line in filestable
261 if line =~ "@import"
262 let styletable += [matchstr(line, "import\\s\\+\\(url(\\)\\?[\"']\\?\\zs\\f\\+\\ze")]
263 elseif line =~ "<link"
264 let styletable += [matchstr(line, "href\\s*=\\s*[\"']\\zs\\f\\+\\ze")]
265 endif
266 endfor
Bram Moolenaar1e015462005-09-25 22:16:38 +0000267 for file in styletable
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000268 if filereadable(file)
269 let stylesheet = readfile(file)
270 let secimport = filter(copy(stylesheet), "v:val =~ '@import'")
271 if len(secimport) > 0
272 for line in secimport
Bram Moolenaar1e015462005-09-25 22:16:38 +0000273 let secfile = matchstr(line, "import\\s\\+\\(url(\\)\\?[\"']\\?\\zs\\f\\+\\ze")
274 let secfile = fnamemodify(file, ":p:h").'/'.secfile
275 let secimportfiles += [secfile]
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000276 endfor
277 endif
278 endif
279 endfor
280 let cssfiles = styletable + secimportfiles
281 let classes = []
282 for file in cssfiles
283 if filereadable(file)
284 let stylesheet = readfile(file)
Bram Moolenaar1e015462005-09-25 22:16:38 +0000285 let stylefile = join(stylesheet, ' ')
286 let stylefile = substitute(stylefile, '+>\*[,', ' ', 'g')
287 if search_for == 'class'
288 let stylesheet = split(stylefile)
289 let classlines = filter(copy(stylesheet), "v:val =~ '\\([a-zA-Z0-9:]\\+\\)\\?\\.[a-zA-Z0-9_-]\\+'")
290 else
291 let stylesheet = split(stylefile, '[{}]')
292 " Get all lines which fit id syntax
293 let classlines = filter(copy(stylesheet), "v:val =~ '#[a-zA-Z0-9_-]\\+'")
294 " Filter out possible color definitions
295 call filter(classlines, "v:val !~ ':\\s*#[a-zA-Z0-9_-]\\+'")
296 " Filter out complex border definitions
297 call filter(classlines, "v:val !~ '\\(none\\|hidden\\|dotted\\|dashed\\|solid\\|double\\|groove\\|ridge\\|inset\\|outset\\)\\s*#[a-zA-Z0-9_-]\\+'")
298 let templines = join(classlines, ' ')
299 let stylelines = split(templines)
300 let classlines = filter(stylelines, "v:val =~ '#[a-zA-Z0-9_-]\\+'")
301
302 endif
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000303 endif
304 " We gathered classes definitions from all external files
305 let classes += classlines
306 endfor
307 if internal == 1
308 let classes += headclasslines
309 endif
Bram Moolenaar1e015462005-09-25 22:16:38 +0000310
311 if search_for == 'class'
312 let elements = {}
313 for element in classes
314 if element =~ '^\.'
315 let class = matchstr(element, '^\.\zs[a-zA-Z][a-zA-Z0-9_-]*\ze')
316 let class = substitute(class, ':.*', '', '')
317 if has_key(elements, 'common')
318 let elements['common'] .= ' '.class
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000319 else
Bram Moolenaar1e015462005-09-25 22:16:38 +0000320 let elements['common'] = class
321 endif
322 else
323 let class = matchstr(element, '[a-zA-Z1-6]*\.\zs[a-zA-Z][a-zA-Z0-9_-]*\ze')
324 let tagname = tolower(matchstr(element, '[a-zA-Z1-6]*\ze.'))
325 if tagname != ''
326 if has_key(elements, tagname)
327 let elements[tagname] .= ' '.class
328 else
329 let elements[tagname] = class
330 endif
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000331 endif
332 endif
Bram Moolenaar1e015462005-09-25 22:16:38 +0000333 endfor
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000334
Bram Moolenaar1e015462005-09-25 22:16:38 +0000335 if has_key(elements, tag) && has_key(elements, 'common')
336 let values = split(elements[tag]." ".elements['common'])
337 elseif has_key(elements, tag) && !has_key(elements, 'common')
338 let values = split(elements[tag])
339 elseif !has_key(elements, tag) && has_key(elements, 'common')
340 let values = split(elements['common'])
341 else
342 return []
343 endif
344
345 elseif search_for == 'id'
346 " Find used IDs
347 " 1. Catch whole file
348 let filelines = getline(1, line('$'))
349 " 2. Find lines with possible id
350 let used_id_lines = filter(filelines, 'v:val =~ "id\\s*=\\s*[\"''][a-zA-Z0-9_-]\\+"')
351 " 3a. Join all filtered lines
352 let id_string = join(used_id_lines, ' ')
353 " 3b. And split them to be sure each id is in separate item
354 let id_list = split(id_string, 'id\s*=\s*')
355 " 4. Extract id values
356 let used_id = map(id_list, 'matchstr(v:val, "[\"'']\\zs[a-zA-Z0-9_-]\\+\\ze")')
357 let joined_used_id = ','.join(used_id, ',').','
358
359 let allvalues = map(classes, 'matchstr(v:val, ".*#\\zs[a-zA-Z0-9_-]\\+")')
360
361 let values = []
362
363 for element in classes
364 if joined_used_id !~ ','.element.','
365 let values += [element]
366 endif
367
368 endfor
369
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000370 endif
371
372 " We need special version of sbase
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000373 let classbase = matchstr(context, ".*[\"']")
Bram Moolenaar1e015462005-09-25 22:16:38 +0000374 let classquote = matchstr(classbase, '.$')
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000375
376 let entered_class = matchstr(attr, ".*=\\s*[\"']\\zs.*")
377
378 for m in sort(values)
379 if m =~? '^'.entered_class
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000380 call add(res, m . classquote)
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000381 elseif m =~? entered_class
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000382 call add(res2, m . classquote)
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000383 endif
384 endfor
385
386 return res + res2
387
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000388 elseif context =~? "style\\s*=\\s*[\"'][^\"']*$"
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000389 return csscomplete#CompleteCSS(0, context)
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000390
391 endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000392 " }}}
393 " Complete on-events {{{
394 if context =~? 'on[a-z]*\s*=\s*\(''[^'']*\|"[^"]*\)$'
395 " We have to:
396 " 1. Find external files
397 let b:js_extfiles = []
398 let l = line('.')
399 let c = col('.')
400 call cursor(1,1)
401 while search('<\@<=script\>', 'W') && line('.') <= l
402 if synIDattr(synID(line('.'),col('.')-1,0),"name") !~? 'comment'
403 let sname = matchstr(getline('.'), '<script[^>]*src\s*=\s*\([''"]\)\zs.\{-}\ze\1')
404 if filereadable(sname)
405 let b:js_extfiles += readfile(sname)
406 endif
407 endif
408 endwhile
409 " 2. Find at least one <script> tag
410 call cursor(1,1)
411 let js_scripttags = []
412 while search('<script\>', 'W') && line('.') < l
413 if matchstr(getline('.'), '<script[^>]*src') == ''
414 let js_scripttag = getline(line('.'), search('</script>', 'W'))
415 let js_scripttags += js_scripttag
416 endif
417 endwhile
418 let b:js_extfiles += js_scripttags
419
420 " 3. Proper call for javascriptcomplete#CompleteJS
421 call cursor(l,c)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000422 let js_context = matchstr(a:base, '\k\+$')
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000423 let js_shortcontext = substitute(a:base, js_context.'$', '', '')
424 let b:compl_context = context
425 let b:jsrange = [l, l]
426 unlet! l c
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000427 return javascriptcomplete#CompleteJS(0, js_context)
428
429 endif
430
431 " }}}
432 let stripbase = matchstr(context, ".*\\(on[a-zA-Z]*\\|style\\|class\\)\\s*=\\s*[\"']\\zs.*")
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000433 " Now we have context stripped from all chars up to style/class.
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000434 " It may fail with some strange style value combinations.
435 if stripbase !~ "[\"']"
436 return []
437 endif
438 endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000439 " Value of attribute completion {{{
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000440 " If attr contains =\s*[\"'] we catched value of attribute
441 if attr =~ "=\s*[\"']"
442 " Let do attribute specific completion
443 let attrname = matchstr(attr, '.*\ze\s*=')
444 let entered_value = matchstr(attr, ".*=\\s*[\"']\\zs.*")
445 let values = []
446 if attrname == 'media'
447 let values = ["screen", "tty", "tv", "projection", "handheld", "print", "braille", "aural", "all"]
448 elseif attrname == 'xml:space'
449 let values = ["preserve"]
450 elseif attrname == 'shape'
Bram Moolenaar8349fd72005-10-12 20:52:20 +0000451 let values = ["rect", "circle", "poly", "default"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000452 elseif attrname == 'valuetype'
453 let values = ["data", "ref", "object"]
454 elseif attrname == 'method'
455 let values = ["get", "post"]
Bram Moolenaar4c903f92005-09-14 21:32:32 +0000456 elseif attrname == 'dir'
457 let values = ["ltr", "rtl"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000458 elseif attrname == 'frame'
459 let values = ["void", "above", "below", "hsides", "lhs", "rhs", "vsides", "box", "border"]
460 elseif attrname == 'rules'
461 let values = ["none", "groups", "rows", "all"]
462 elseif attrname == 'align'
463 let values = ["left", "center", "right", "justify", "char"]
464 elseif attrname == 'valign'
465 let values = ["top", "middle", "bottom", "baseline"]
466 elseif attrname == 'scope'
467 let values = ["row", "col", "rowgroup", "colgroup"]
468 elseif attrname == 'href'
469 " Now we are looking for local anchors defined by name or id
470 if entered_value =~ '^#'
471 let file = join(getline(1, line('$')), ' ')
472 " Split it be sure there will be one id/name element in
473 " item, it will be also first word [a-zA-Z0-9_-] in element
474 let oneelement = split(file, "\\(meta \\)\\@<!\\(name\\|id\\)\\s*=\\s*[\"']")
475 for i in oneelement
476 let values += ['#'.matchstr(i, "^[a-zA-Z][a-zA-Z0-9%_-]*")]
477 endfor
478 endif
479 elseif attrname == 'type'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000480 if context =~ '^input'
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000481 let values = ["text", "password", "checkbox", "radio", "submit", "reset", "file", "hidden", "image", "button"]
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000482 elseif context =~ '^button'
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000483 let values = ["button", "submit", "reset"]
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000484 elseif context =~ '^style'
Bram Moolenaar1e015462005-09-25 22:16:38 +0000485 let values = ["text/css"]
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000486 elseif context =~ '^script'
Bram Moolenaar1e015462005-09-25 22:16:38 +0000487 let values = ["text/javascript"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000488 endif
489 else
490 return []
491 endif
492
493 if len(values) == 0
494 return []
495 endif
496
497 " We need special version of sbase
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000498 let attrbase = matchstr(context, ".*[\"']")
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000499 let attrquote = matchstr(attrbase, '.$')
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000500
501 for m in values
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000502 " This if is needed to not offer all completions as-is
503 " alphabetically but sort them. Those beginning with entered
504 " part will be as first choices
505 if m =~ '^'.entered_value
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000506 call add(res, m . attrquote.' ')
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000507 elseif m =~ entered_value
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000508 call add(res2, m . attrquote.' ')
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000509 endif
510 endfor
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000511
512 return res + res2
513
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000514 endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000515 " }}}
516 " Attribute completion {{{
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000517 " Shorten context to not include last word
518 let sbase = matchstr(context, '.*\ze\s.*')
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000519
520 " Load data {{{
521 if !exists("g:xmldata_xhtml10s")
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +0000522 runtime! autoload/xml/xhtml10s.vim
523 "call htmlcomplete#LoadData()
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000524 endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000525 " }}}
526 "
527 let attrs = keys(g:xmldata_xhtml10s[tag][1])
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000528
529 for m in sort(attrs)
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000530 if m =~ '^'.attr
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000531 call add(res, m)
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000532 elseif m =~ attr
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000533 call add(res2, m)
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000534 endif
535 endfor
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000536 let menu = res + res2
537 if has_key(g:xmldata_xhtml10s, 'vimxmlattrinfo')
538 let final_menu = []
539 for i in range(len(menu))
540 let item = menu[i]
541 if has_key(g:xmldata_xhtml10s['vimxmlattrinfo'], item)
542 let m_menu = g:xmldata_xhtml10s['vimxmlattrinfo'][item][0]
543 let m_info = g:xmldata_xhtml10s['vimxmlattrinfo'][item][1]
544 if m_menu !~ 'Bool'
545 let item .= '="'
546 endif
547 else
548 let m_menu = ''
549 let m_info = ''
550 let item .= '="'
551 endif
552 let final_menu += [{'word':item, 'menu':m_menu, 'info':m_info}]
553 endfor
554 else
555 let final_menu = map(menu, 'v:val."=\""')
556 endif
557 return final_menu
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000558
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000559 endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000560 " }}}
561 " Close tag {{{
Bram Moolenaar6b730e12005-09-16 21:47:57 +0000562 let b:unaryTagsStack = "base meta link hr br param img area input col"
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000563 if context =~ '^\/'
Bram Moolenaar362e1a32006-03-06 23:29:24 +0000564 if context =~ '^\/.'
565 return []
566 else
567 let opentag = xmlcomplete#GetLastOpenTag("b:unaryTagsStack")
568 return [opentag.">"]
569 endif
Bram Moolenaar4c903f92005-09-14 21:32:32 +0000570 endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000571 " Load data {{{
Bram Moolenaara5792f52005-11-23 21:25:05 +0000572 if !exists("g:xmldata_xhtml10s")
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +0000573 runtime! autoload/xml/xhtml10s.vim
574 "call htmlcomplete#LoadData()
Bram Moolenaar4c903f92005-09-14 21:32:32 +0000575 endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000576 " }}}
577 " Tag completion {{{
Bram Moolenaar7e8fd632006-02-18 22:14:51 +0000578 " Deal with tag completion.
579 let opentag = xmlcomplete#GetLastOpenTag("b:unaryTagsStack")
Bram Moolenaar362e1a32006-03-06 23:29:24 +0000580 " MM: TODO: GLOT works always the same but with some weird situation it
581 " behaves as intended in HTML but screws in PHP
582 let g:ot = opentag
583 if opentag == '' || &ft == 'php' && !has_key(g:xmldata_xhtml10s, opentag)
Bram Moolenaar7e8fd632006-02-18 22:14:51 +0000584 " Hack for sometimes failing GetLastOpenTag.
585 " As far as I tested fail isn't GLOT fault but problem
586 " of invalid document - not properly closed tags and other mish-mash.
587 " Also when document is empty. Return list of *all* tags.
588 let tags = keys(g:xmldata_xhtml10s)
589 call filter(tags, 'v:val !~ "^vimxml"')
590 else
591 let tags = g:xmldata_xhtml10s[opentag][0]
592 endif
593 " }}}
Bram Moolenaar4c903f92005-09-14 21:32:32 +0000594
Bram Moolenaarcef9dcc2005-12-06 19:50:41 +0000595 for m in sort(tags)
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000596 if m =~ '^'.context
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000597 call add(res, m)
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +0000598 elseif m =~ context
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000599 call add(res2, m)
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000600 endif
Bram Moolenaar6b730e12005-09-16 21:47:57 +0000601 endfor
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000602 let menu = res + res2
603 if has_key(g:xmldata_xhtml10s, 'vimxmltaginfo')
604 let final_menu = []
605 for i in range(len(menu))
606 let item = menu[i]
607 if has_key(g:xmldata_xhtml10s['vimxmltaginfo'], item)
608 let m_menu = g:xmldata_xhtml10s['vimxmltaginfo'][item][0]
609 let m_info = g:xmldata_xhtml10s['vimxmltaginfo'][item][1]
610 else
611 let m_menu = ''
612 let m_info = ''
613 endif
614 let final_menu += [{'word':item, 'menu':m_menu, 'info':m_info}]
615 endfor
616 else
617 let final_menu = menu
618 endif
619 return final_menu
Bram Moolenaar6b730e12005-09-16 21:47:57 +0000620
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000621 " }}}
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000622 endif
623endfunction
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000624" vim:set foldmethod=marker: