523
|
1 " Vim completion script
|
|
2 " Language: XHTML 1.0 Strict
|
|
3 " Maintainer: Mikolaj Machowski ( mikmach AT wp DOT pl )
|
810
|
4 " Last Change: 2006 Mar 25
|
523
|
5
|
|
6 function! htmlcomplete#CompleteTags(findstart, base)
|
|
7 if a:findstart
|
|
8 " locate the start of the word
|
|
9 let line = getline('.')
|
|
10 let start = col('.') - 1
|
643
|
11 let curline = line('.')
|
548
|
12 let compl_begin = col('.') - 2
|
|
13 while start >= 0 && line[start - 1] =~ '\(\k\|[:.-]\)'
|
|
14 let start -= 1
|
523
|
15 endwhile
|
659
|
16 " Handling of entities {{{
|
548
|
17 if start >= 0 && line[start - 1] =~ '&'
|
|
18 let b:entitiescompl = 1
|
|
19 let b:compl_context = ''
|
|
20 return start
|
|
21 endif
|
659
|
22 " }}}
|
|
23 " Handling of <style> tag {{{
|
548
|
24 let stylestart = searchpair('<style\>', '', '<\/style\>', "bnW")
|
|
25 let styleend = searchpair('<style\>', '', '<\/style\>', "nW")
|
|
26 if stylestart != 0 && styleend != 0
|
643
|
27 if stylestart <= curline && styleend >= curline
|
548
|
28 let start = col('.') - 1
|
|
29 let b:csscompl = 1
|
|
30 while start >= 0 && line[start - 1] =~ '\(\k\|-\)'
|
|
31 let start -= 1
|
|
32 endwhile
|
531
|
33 endif
|
|
34 endif
|
659
|
35 " }}}
|
|
36 " Handling of <script> tag {{{
|
649
|
37 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]
|
667
|
44 while start >= 0 && line[start - 1] =~ '\k'
|
649
|
45 let start -= 1
|
|
46 endwhile
|
659
|
47 " 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
|
649
|
75 endif
|
|
76 endif
|
659
|
77 " }}}
|
649
|
78 if !exists("b:csscompl") && !exists("b:jscompl")
|
548
|
79 let b:compl_context = getline('.')[0:(compl_begin)]
|
643
|
80 if b:compl_context !~ '<[^>]*$'
|
659
|
81 " Look like we may have broken tag. Check previous lines.
|
643
|
82 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
|
784
|
90 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
|
643
|
93 let b:compl_context = ''
|
|
94 break
|
|
95 endif
|
|
96 let i += 1
|
784
|
97 " 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
|
643
|
103 endwhile
|
|
104 " Make sure we don't have counter
|
|
105 unlet! i
|
|
106 endif
|
641
|
107 let b:compl_context = matchstr(b:compl_context, '.*\zs<.*')
|
784
|
108
|
659
|
109 " 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
|
667
|
113 while start >= 0 && line[start - 1] =~ '\k'
|
659
|
114 let start -= 1
|
|
115 endwhile
|
|
116 endif
|
784
|
117 " 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
|
548
|
126 else
|
|
127 let b:compl_context = getline('.')[0:compl_begin]
|
|
128 endif
|
523
|
129 return start
|
|
130 else
|
548
|
131 " 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
|
531
|
136 " Check if we should do CSS completion inside of <style> tag
|
784
|
137 " or JS completion inside of <script> tag or PHP completion in case of <?
|
|
138 " tag AND &ft==php
|
531
|
139 if exists("b:csscompl")
|
|
140 unlet! b:csscompl
|
641
|
141 let context = b:compl_context
|
659
|
142 unlet! b:compl_context
|
548
|
143 return csscomplete#CompleteCSS(0, context)
|
649
|
144 elseif exists("b:jscompl")
|
|
145 unlet! b:jscompl
|
659
|
146 return javascriptcomplete#CompleteJS(0, a:base)
|
784
|
147 elseif exists("b:phpcompl")
|
|
148 unlet! b:phpcompl
|
|
149 let context = b:compl_context
|
|
150 return phpcomplete#CompletePHP(0, a:base)
|
641
|
151 else
|
|
152 if len(b:compl_context) == 0 && !exists("b:entitiescompl")
|
|
153 return []
|
|
154 endif
|
|
155 let context = matchstr(b:compl_context, '.\zs.*')
|
531
|
156 endif
|
641
|
157 unlet! b:compl_context
|
659
|
158 " Entities completion {{{
|
548
|
159 if exists("b:entitiescompl")
|
|
160 unlet! b:entitiescompl
|
|
161
|
557
|
162 if !exists("g:xmldata_xhtml10s")
|
829
|
163 runtime! autoload/xml/xhtml10s.vim
|
|
164 "call htmlcomplete#LoadData()
|
557
|
165 endif
|
548
|
166
|
557
|
167 let entities = g:xmldata_xhtml10s['vimxmlentities']
|
|
168
|
641
|
169 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
|
548
|
184
|
641
|
185 return res + res2
|
|
186 endif
|
|
187
|
548
|
188
|
|
189 endif
|
659
|
190 " }}}
|
548
|
191 if context =~ '>'
|
|
192 " Generally if context contains > it means we are outside of tag and
|
531
|
193 " should abandon action - with one exception: <style> span { bo
|
548
|
194 if context =~ 'style[^>]\{-}>[^<]\{-}$'
|
|
195 return csscomplete#CompleteCSS(0, context)
|
649
|
196 elseif context =~ 'script[^>]\{-}>[^<]\{-}$'
|
|
197 let b:jsrange = [line('.'), search('<\/script\>', 'nW')]
|
|
198 return javascriptcomplete#CompleteJS(0, context)
|
531
|
199 else
|
|
200 return []
|
|
201 endif
|
|
202 endif
|
|
203
|
548
|
204 " If context contains > it means we are already outside of tag and we
|
523
|
205 " should abandon action
|
548
|
206 " If context contains white space it is attribute.
|
659
|
207 " It can be also value of attribute.
|
|
208 " We have to get first word to offer proper completions
|
548
|
209 if context == ''
|
|
210 let tag = ''
|
|
211 else
|
|
212 let tag = split(context)[0]
|
|
213 endif
|
531
|
214 " Get last word, it should be attr name
|
548
|
215 let attr = matchstr(context, '.*\s\zs.*')
|
523
|
216 " Possible situations where any prediction would be difficult:
|
|
217 " 1. Events attributes
|
548
|
218 if context =~ '\s'
|
523
|
219 " Sort out style, class, and on* cases
|
659
|
220 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_ -]*$"
|
532
|
224 let search_for = "class"
|
659
|
225 elseif context =~? "id\\s*=\\s*[\"'][a-zA-Z0-9_ -]*$"
|
532
|
226 let search_for = "id"
|
|
227 endif
|
531
|
228 " 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'
|
557
|
236 " Remove possibly confusing CSS operators
|
532
|
237 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
|
531
|
253 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
|
532
|
267 for file in styletable
|
531
|
268 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
|
532
|
273 let secfile = matchstr(line, "import\\s\\+\\(url(\\)\\?[\"']\\?\\zs\\f\\+\\ze")
|
|
274 let secfile = fnamemodify(file, ":p:h").'/'.secfile
|
|
275 let secimportfiles += [secfile]
|
531
|
276 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)
|
532
|
285 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
|
531
|
303 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
|
532
|
310
|
|
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
|
|
319 else
|
|
320 let elements['common'] = class
|
|
321 endif
|
531
|
322 else
|
532
|
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
|
531
|
331 endif
|
|
332 endif
|
532
|
333 endfor
|
|
334
|
|
335 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 []
|
531
|
343 endif
|
|
344
|
532
|
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
|
531
|
370 endif
|
|
371
|
|
372 " We need special version of sbase
|
548
|
373 let classbase = matchstr(context, ".*[\"']")
|
532
|
374 let classquote = matchstr(classbase, '.$')
|
531
|
375
|
|
376 let entered_class = matchstr(attr, ".*=\\s*[\"']\\zs.*")
|
|
377
|
|
378 for m in sort(values)
|
|
379 if m =~? '^'.entered_class
|
548
|
380 call add(res, m . classquote)
|
531
|
381 elseif m =~? entered_class
|
548
|
382 call add(res2, m . classquote)
|
531
|
383 endif
|
|
384 endfor
|
|
385
|
|
386 return res + res2
|
|
387
|
659
|
388 elseif context =~? "style\\s*=\\s*[\"'][^\"']*$"
|
548
|
389 return csscomplete#CompleteCSS(0, context)
|
531
|
390
|
|
391 endif
|
659
|
392 " }}}
|
|
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)
|
667
|
422 let js_context = matchstr(a:base, '\k\+$')
|
659
|
423 let js_shortcontext = substitute(a:base, js_context.'$', '', '')
|
|
424 let b:compl_context = context
|
|
425 let b:jsrange = [l, l]
|
|
426 unlet! l c
|
|
427 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.*")
|
548
|
433 " Now we have context stripped from all chars up to style/class.
|
523
|
434 " It may fail with some strange style value combinations.
|
|
435 if stripbase !~ "[\"']"
|
|
436 return []
|
|
437 endif
|
|
438 endif
|
659
|
439 " Value of attribute completion {{{
|
523
|
440 " 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'
|
553
|
451 let values = ["rect", "circle", "poly", "default"]
|
523
|
452 elseif attrname == 'valuetype'
|
|
453 let values = ["data", "ref", "object"]
|
|
454 elseif attrname == 'method'
|
|
455 let values = ["get", "post"]
|
525
|
456 elseif attrname == 'dir'
|
|
457 let values = ["ltr", "rtl"]
|
523
|
458 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'
|
548
|
480 if context =~ '^input'
|
531
|
481 let values = ["text", "password", "checkbox", "radio", "submit", "reset", "file", "hidden", "image", "button"]
|
548
|
482 elseif context =~ '^button'
|
523
|
483 let values = ["button", "submit", "reset"]
|
548
|
484 elseif context =~ '^style'
|
532
|
485 let values = ["text/css"]
|
548
|
486 elseif context =~ '^script'
|
532
|
487 let values = ["text/javascript"]
|
523
|
488 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
|
548
|
498 let attrbase = matchstr(context, ".*[\"']")
|
531
|
499 let attrquote = matchstr(attrbase, '.$')
|
523
|
500
|
|
501 for m in values
|
531
|
502 " 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
|
548
|
506 call add(res, m . attrquote.' ')
|
531
|
507 elseif m =~ entered_value
|
548
|
508 call add(res2, m . attrquote.' ')
|
523
|
509 endif
|
|
510 endfor
|
531
|
511
|
|
512 return res + res2
|
|
513
|
523
|
514 endif
|
659
|
515 " }}}
|
|
516 " Attribute completion {{{
|
548
|
517 " Shorten context to not include last word
|
|
518 let sbase = matchstr(context, '.*\ze\s.*')
|
667
|
519
|
|
520 " Load data {{{
|
|
521 if !exists("g:xmldata_xhtml10s")
|
829
|
522 runtime! autoload/xml/xhtml10s.vim
|
|
523 "call htmlcomplete#LoadData()
|
523
|
524 endif
|
667
|
525 " }}}
|
|
526 "
|
|
527 let attrs = keys(g:xmldata_xhtml10s[tag][1])
|
523
|
528
|
|
529 for m in sort(attrs)
|
531
|
530 if m =~ '^'.attr
|
667
|
531 call add(res, m)
|
531
|
532 elseif m =~ attr
|
667
|
533 call add(res2, m)
|
523
|
534 endif
|
|
535 endfor
|
667
|
536 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
|
531
|
558
|
523
|
559 endif
|
659
|
560 " }}}
|
|
561 " Close tag {{{
|
529
|
562 let b:unaryTagsStack = "base meta link hr br param img area input col"
|
548
|
563 if context =~ '^\/'
|
714
|
564 if context =~ '^\/.'
|
|
565 return []
|
|
566 else
|
|
567 let opentag = xmlcomplete#GetLastOpenTag("b:unaryTagsStack")
|
|
568 return [opentag.">"]
|
|
569 endif
|
525
|
570 endif
|
674
|
571 " Load data {{{
|
|
572 if !exists("g:xmldata_xhtml10s")
|
829
|
573 runtime! autoload/xml/xhtml10s.vim
|
|
574 "call htmlcomplete#LoadData()
|
674
|
575 endif
|
|
576 " }}}
|
|
577 " Tag completion {{{
|
525
|
578 " Deal with tag completion.
|
557
|
579 let opentag = xmlcomplete#GetLastOpenTag("b:unaryTagsStack")
|
714
|
580 " 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)
|
641
|
584 " 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.
|
674
|
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]
|
641
|
592 endif
|
659
|
593 " }}}
|
525
|
594
|
573
|
595 for m in sort(tags)
|
548
|
596 if m =~ '^'.context
|
523
|
597 call add(res, m)
|
548
|
598 elseif m =~ context
|
531
|
599 call add(res2, m)
|
523
|
600 endif
|
529
|
601 endfor
|
667
|
602 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
|
529
|
620
|
659
|
621 " }}}
|
523
|
622 endif
|
|
623 endfunction
|
659
|
624 " vim:set foldmethod=marker:
|