blob: 07eab945edd8846c168397738c1df1a3dae9ce39 [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 )
4" Last Change: 2005 Sep 13
5
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
11 while start >= 0 && line[start - 1] !~ '<'
12 let start -= 1
13 endwhile
Bram Moolenaarf75a9632005-09-13 21:20:47 +000014 return start
15 else
16 " Set attribute groups
17 let g:coreattrs = ["id", "class", "style", "title"]
18 let g:i18n = ["lang", "xml:lang", "dir"]
19 let g:events = ["onclick", "ondblclick", "onmousedown", "onmouseup", "onmousemove",
20 \ "onmouseout", "onkeypress", "onkeydown", "onkeyup"]
21 let g:focus = ["accesskey", "tabindex", "onfocus", "onblur"]
22 let g:coregroup = g:coreattrs
23 let g:coregroup = extend(g:coregroup, g:i18n)
24 let g:coregroup = extend(g:coregroup, g:events)
25 " find tags matching with "a:base"
26 let res = []
27 " If a:base contains > it means we are already outside of tag and we
28 " should abandon action
29 if a:base =~ '>'
30 return []
31 endif
32 " If a:base contains white space it is attribute.
33 " It could be also value of attribute...
34 " Possible situations where any prediction would be difficult:
35 " 1. Events attributes
36 if a:base =~ '\s'
37 " Sort out style, class, and on* cases
38 " Perfect solution for style would be switching for CSS completion. Is
39 " it possible?
40 " Also retrieving class names from current file and linked
41 " stylesheets.
42 if a:base =~ "\\(on[a-z]*\\|style\\|class\\)\\s*=\\s*[\"']"
43 let stripbase = matchstr(a:base, ".*\\(on[a-z]*\\|style\\|class\\)\\s*=\\s*[\"']\\zs.*")
44 " Now we have a:base stripped from all chars up to style/class.
45 " It may fail with some strange style value combinations.
46 if stripbase !~ "[\"']"
47 return []
48 endif
49 endif
50 " We have to get first word to offer
51 " proper attributes.
52 let tag = split(a:base)[0]
53 " Get last word, it should be attr name
54 let attr = matchstr(a:base, '.*\s\zs.*')
55 " If attr contains =\s*[\"'] we catched value of attribute
56 if attr =~ "=\s*[\"']"
57 " Let do attribute specific completion
58 let attrname = matchstr(attr, '.*\ze\s*=')
59 let entered_value = matchstr(attr, ".*=\\s*[\"']\\zs.*")
60 let values = []
61 if attrname == 'media'
62 let values = ["screen", "tty", "tv", "projection", "handheld", "print", "braille", "aural", "all"]
63 elseif attrname == 'xml:space'
64 let values = ["preserve"]
65 elseif attrname == 'shape'
66 if a:base =~ '^a\>'
67 let values = ["rect"]
68 else
69 let values = ["rect", "circle", "poly", "default"]
70 endif
71 elseif attrname == 'valuetype'
72 let values = ["data", "ref", "object"]
73 elseif attrname == 'method'
74 let values = ["get", "post"]
Bram Moolenaar4c903f92005-09-14 21:32:32 +000075 elseif attrname == 'dir'
76 let values = ["ltr", "rtl"]
Bram Moolenaarf75a9632005-09-13 21:20:47 +000077 elseif attrname == 'frame'
78 let values = ["void", "above", "below", "hsides", "lhs", "rhs", "vsides", "box", "border"]
79 elseif attrname == 'rules'
80 let values = ["none", "groups", "rows", "all"]
81 elseif attrname == 'align'
82 let values = ["left", "center", "right", "justify", "char"]
83 elseif attrname == 'valign'
84 let values = ["top", "middle", "bottom", "baseline"]
85 elseif attrname == 'scope'
86 let values = ["row", "col", "rowgroup", "colgroup"]
87 elseif attrname == 'href'
88 " Now we are looking for local anchors defined by name or id
89 if entered_value =~ '^#'
90 let file = join(getline(1, line('$')), ' ')
91 " Split it be sure there will be one id/name element in
92 " item, it will be also first word [a-zA-Z0-9_-] in element
93 let oneelement = split(file, "\\(meta \\)\\@<!\\(name\\|id\\)\\s*=\\s*[\"']")
94 for i in oneelement
95 let values += ['#'.matchstr(i, "^[a-zA-Z][a-zA-Z0-9%_-]*")]
96 endfor
97 endif
98 elseif attrname == 'type'
99 if a:base =~ '^input'
100 let values = ["input-text", "password", "checkbox", "radio", "submit", "reset", "input-file", "hidden", "input-image", "input-button"]
101 elseif a:base =~ '^button'
102 let values = ["button", "submit", "reset"]
103 endif
104 else
105 return []
106 endif
107
108 if len(values) == 0
109 return []
110 endif
111
112 " We need special version of sbase
113 let attrbase = matchstr(a:base, ".*[\"']")
114
115 for m in values
Bram Moolenaar4c903f92005-09-14 21:32:32 +0000116 if m =~ entered_value
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000117 call add(res, attrbase . m . '" ')
118 endif
119 endfor
120 endif
121 " Shorten a:base to not include last word
122 let sbase = matchstr(a:base, '.*\ze\s.*')
123 if tag =~ '^\(abbr\|acronym\|b\|bdo\|big\|caption\|cite\|code\|dd\|dfn\|div\|dl\|dt\|em\|fieldset\|h\d\|kbd\|li\|noscript\|ol\|p\|samp\|small\|span\|strong\|sub\|sup\|tt\|ul\|var\)$'
124 let attrs = g:coregroup
125 elseif tag == 'a'
126 let tagspec = ["charset", "type", "name", "href", "hreflang", "rel", "rev", "shape", "coords"]
127 let attrs = extend(tagspec, g:coregroup)
128 let attrs = extend(attrs, g:focus)
129 elseif tag == 'area'
130 let attrs = g:coregroup
131 elseif tag == 'base'
132 let attrs = ["href", "id"]
133 elseif tag == 'blockquote'
134 let attrs = g:coregroup
135 let attrs = extend(attrs, ["cite"])
136 elseif tag == 'body'
137 let attrs = g:coregroup
138 let attrs = extend(attrs, ["onload", "onunload"])
139 elseif tag == 'br'
140 let attrs = g:coreattrs
141 elseif tag == 'button'
142 let attrs = g:coreattrs
143 let attrs = extend(attrs, g:focus)
144 let attrs = extend(attrs, ["name", "value", "type"])
145 elseif tag == '^\(col\|colgroup\)$'
146 let attrs = g:coreattrs
147 let attrs = extend(attrs, ["span", "width", "align", "char", "charoff", "valign"])
148 elseif tag =~ '^\(del\|ins\)$'
149 let attrs = g:coreattrs
150 let attrs = extend(attrs, ["cite", "datetime"])
151 elseif tag == 'form'
152 let attrs = g:coreattrs
153 let attrs = extend(attrs, ["action", "method", "enctype", "onsubmit", "onreset", "accept", "accept-charset"])
154 elseif tag == 'head'
155 let attrs = g:i18n
156 let attrs = extend(attrs, ["id", "profile"])
157 elseif tag == 'html'
158 let attrs = g:i18n
159 let attrs = extend(attrs, ["id", "xmlns"])
160 elseif tag == 'img'
161 let attrs = g:coreattrs
162 let attrs = extend(attrs, ["src", "alt", "longdesc", "height", "width", "usemap", "ismap"])
163 elseif tag == 'input'
164 let attrs = g:coreattrs
165 let attrs = extend(attrs, g:focus)
166 let attrs = extend(attrs, ["type", "name", "value", "checked", "disabled", "readonly", "size", "maxlength", "src", "alt", "usemap", "onselect", "onchange", "accept"])
167 elseif tag == 'label'
168 let attrs = g:coreattrs
169 let attrs = extend(attrs, ["for", "accesskey", "onfocus", "onblur"])
170 elseif tag == 'legend'
171 let attrs = g:coreattrs
172 let attrs = extend(attrs, ["accesskey"])
173 elseif tag == 'link'
174 let attrs = g:coreattrs
175 let attrs = extend(attrs, ["charset", "href", "hreflang", "type", "rel", "rev", "media"])
176 elseif tag == 'map'
177 let attrs = g:i18n
178 let attrs = extend(attrs, g:events)
179 let attrs = extend(attrs, ["id", "class", "style", "title", "name"])
180 elseif tag == 'meta'
181 let attrs = g:i18n
182 let attrs = extend(attrs, ["id", "http-equiv", "content", "scheme", "name"])
183 elseif tag == 'title'
184 let attrs = g:i18n
185 let attrs = extend(attrs, ["id"])
186 elseif tag == 'object'
187 let attrs = g:coreattrs
188 let attrs = extend(attrs, ["declare", "classid", "codebase", "data", "type", "codetype", "archive", "standby", "height", "width", "usemap", "name", "tabindex"])
189 elseif tag == 'optgroup'
190 let attrs = g:coreattrs
191 let attrs = extend(attrs, ["disbled", "label"])
192 elseif tag == 'option'
193 let attrs = g:coreattrs
194 let attrs = extend(attrs, ["disbled", "selected", "value", "label"])
195 elseif tag == 'param'
196 let attrs = ["id", "name", "value", "valuetype", "type"]
197 elseif tag == 'pre'
198 let attrs = g:coreattrs
199 let attrs = extend(attrs, ["xml:space"])
200 elseif tag == 'q'
201 let attrs = g:coreattrs
202 let attrs = extend(attrs, ["cite"])
203 elseif tag == 'script'
204 let attrs = ["id", "charset", "type", "src", "defer", "xml:space"]
205 elseif tag == 'select'
206 let attrs = g:coreattrs
207 let attrs = extend(attrs, ["name", "size", "multiple", "disabled", "tabindex", "onfocus", "onblur", "onchange"])
208 elseif tag == 'style'
209 let attrs = g:coreattrs
210 let attrs = extend(attrs, ["id", "type", "media", "title", "xml:space"])
211 elseif tag == 'table'
212 let attrs = g:coreattrs
213 let attrs = extend(attrs, ["summary", "width", "border", "frame", "rules" "cellspacing", "cellpadding"])
214 elseif tag =~ '^\(thead\|tfoot\|tbody\|tr\)$'
215 let attrs = g:coreattrs
216 let attrs = extend(attrs, ["align", "char", "charoff", "valign"])
217 elseif tag == 'textarea'
218 let attrs = g:coreattrs
219 let attrs = extend(attrs, g:focus)
220 let attrs = extend(attrs, ["name", "rows", "cols", "disabled", "readonly", "onselect", "onchange"])
221 elseif tag =~ '^\(th\|td\)$'
222 let attrs = g:coreattrs
223 let attrs = extend(attrs, ["abbr", "headers", "scope", "rowspan", "colspan", "align", "char", "charoff", "valign"])
224 endif
225
226 for m in sort(attrs)
Bram Moolenaar4c903f92005-09-14 21:32:32 +0000227 if m =~ attr
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000228 if m =~ '^\(ismap\|defer\|declare\|nohref\|checked\|disabled\|selected\|readonly\)$'
229 call add(res, sbase.' '.m)
230 else
231 call add(res, sbase.' '.m.'="')
232 endif
233 endif
234 endfor
235 return res
236 endif
Bram Moolenaar4c903f92005-09-14 21:32:32 +0000237 " Close tag
238 if a:base =~ '^\/' && exists("*GetLastOpenTag")
239 let b:unaryTagsStack = "base meta link hr br param img area input col"
240 let opentag = GetLastOpenTag("b:unaryTagsStack")
241 return ["/".opentag.">"]
242 endif
243 " Deal with tag completion.
244 if exists("*GetLastOpenTag")
245 " set b:unaryTagsStack to proper value for xhtml 1.0 or html 4.01
246 let b:unaryTagsStack = "base meta link hr br param img area input col"
247 let opentag = GetLastOpenTag("b:unaryTagsStack")
248 " Clusters
249 let special = "br span bdo map object img"
250 let phrase = "em strong dfn code q samp kbd var cite abbr acronym sub sup"
251 let inlineforms = "input select textarea label button"
252 let miscinline = "ins del script"
253 let inline = "a ".special." ".phrase." ".inlineforms." tt i b big small"
254 let misc = "noscript ".miscinline
255 let block = "p h1 h2 h3 h4 h5 h6 div ul ol dl pre hr blockquote address fieldset table"
256
257 if opentag == 'a'
258 let tags = split("tt i b big small ".special." ".phrase." ".inlineforms." ".miscinline)
259 elseif opentag =~ '^\(abbr\|acronym\|address\|b\|p\|h\d\|dt\|span\|bdo\|em\|strong\|dfn\|code\|samp\|kbd\|var\|cite\|q\|sub\|sup\|tt\|i\|big\|small\|label\|caption\)$'
260 let tags = split(inline." ".miscinline)
261 elseif opentag == 'pre'
262 let tags = split("a tt i b big small br span bdo map ".phrase." ".miscinline." ".inlineforms)
263 elseif opentag == 'html'
264 let tags = split("head body")
265 elseif opentag == 'legend'
266 let tags = split(inline." ".miscinline)
267 elseif opentag == 'head'
268 let tags = split("title base scipt style meta link object")
269 elseif opentag =~ '^\(noscript\|body\|blockquote\)$'
270 let tags = split("form ".block." ".misc)
271 elseif opentag =~ '^\(ul\|ol\)$'
272 let tags = ["li"]
273 elseif opentag == 'dl'
274 let tags = split("dt dd")
275 elseif opentag =~ '^\(ins\|del\|th\|td\|dd\|div\|li\)$'
276 let tags = split("form ".block." ".inline." ".misc)
277 elseif opentag == 'object'
278 let tags = split("param form ".block." ".inline." ".misc)
279 elseif opentag == 'fieldset'
280 let tags = split("legend form ".block." ".inline." ".misc)
281 elseif opentag == 'map'
282 let tags = split("area form ".block." ".misc)
283 elseif opentag == 'form'
284 let tags = split(block." ".misc)
285 elseif opentag == 'select'
286 let tags = split("optgroup option")
287 elseif opentag == 'optgroup'
288 let tags = ["option"]
289 elseif opentag == 'colgroup'
290 let tags = ["col"]
291 elseif opentag == '^\(textarea\|option\|script\|style\|title\)$'
292 let tags = []
293 elseif opentag == 'button'
294 let tags = split("p h1 h2 h3 h4 h5 h6 div ul ol dl table")
295 elseif opentag =~ '^\(thead\|tfoot\|tbody)$'
296 let tags = ["tr"]
297 elseif opentag == 'tr'
298 let tags = split("th td")
299 elseif opentag == 'table'
300 let tags = split("caption col colgroup thead tfoot tbody tr")
301 endif
302
303 for m in tags
304 if m =~ a:base
305 call add(res, m)
306 endif
307 endfor
308 return res
309
310 endif
311
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000312 for m in split("a abbr acronym address area b base bdo big blockquote body br button caption cite code col colgroup dd del dfn div dl dt em fieldset form head h1 h2 h3 h4 h5 h6 hr html i img input ins kbd label legend li link map meta noscript object ol optgroup option p param pre q samp script select small span strong style sub sup table tbody td textarea tfoot th thead title tr tt ul var")
Bram Moolenaar4c903f92005-09-14 21:32:32 +0000313 if m =~ a:base
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000314 call add(res, m)
315 endif
316 endfor
317 return res
318 endif
319endfunction