1" Vim completion script
2" Language:	Java Script
3" Maintainer:	Mikolaj Machowski ( mikmach AT wp DOT pl )
4" Last Change:	2006 Jan 30
5
6function! javascriptcomplete#CompleteJS(findstart, base)
7  if a:findstart
8    " locate the start of the word
9    let line = getline('.')
10    let start = col('.') - 1
11	let curline = line('.')
12	let compl_begin = col('.') - 2
13	" Bit risky but JS is rather limited language and local chars shouldn't
14	" fint way into names
15    while start >= 0 && line[start - 1] =~ '\w'
16		let start -= 1
17    endwhile
18	let b:compl_context = getline('.')[0:compl_begin]
19    return start
20  else
21	" Initialize base return lists
22    let res = []
23    let res2 = []
24	" a:base is very short - we need context
25	let context = b:compl_context
26	" Shortcontext is context without a:base, useful for checking if we are
27	" looking for objects
28	let shortcontext = substitute(context, a:base.'$', '', '')
29	unlet! b:compl_context
30
31	if shortcontext =~ '\.$'
32		" Complete methods and properties for objects
33		" DOM separate
34		let doms = ['style.']
35		" Arrays
36		let arrayprop = ['constructor', 'index', 'input', 'length', 'prototype']
37		let arraymeth = ['concat', 'join', 'pop', 'push', 'reverse', 'shift',
38					\ 'splice', 'sort', 'toSource', 'toString', 'unshift', 'valueOf',
39					\ 'watch', 'unwatch']
40		call map(arraymeth, 'v:val."("')
41		let arrays = arrayprop + arraymeth
42
43		" Boolean - complete subset of array values
44		" properties - constructor, prototype
45		" methods    - toSource, toString, valueOf
46
47		" Date
48		" properties - constructor, prototype
49		let datemeth = ['getDate', 'getDay', 'getFullYear', 'getHours', 'getMilliseconds',
50					\ 'getMinutes', 'getMonth', 'getSeconds', 'getTime', 'getTimezoneOffset',
51					\ 'getUTCDate', 'getUTCDay', 'getUTCFullYear', 'getUTCHours', 'getUTCMilliseconds',
52					\ 'getUTCMinutes', 'getUTCMonth', 'getUTCSeconds',
53					\ 'getYear', 'parse', 'parse',
54					\ 'setDate', 'setDay', 'setFullYear', 'setHours', 'setMilliseconds',
55					\ 'setMinutes', 'setMonth', 'setSeconds',
56					\ 'setUTCDate', 'setUTCDay', 'setUTCFullYear', 'setUTCHours', 'setUTCMilliseconds',
57					\ 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds', 'setYear', 'setTime',
58					\ 'toGMTString', 'toLocaleString', 'toLocaleDateString', 'toLocaleTimeString',
59					\ 'toSource', 'toString', 'toUTCString', 'UTC', 'valueOf', 'watch', 'unwatch']
60		call map(datemeth, 'v:val."("')
61		let dates = datemeth
62
63		" Function
64		let funcprop = ['arguments', 'arguments.callee', 'arguments.caller', 'arguments.length',
65					\ 'arity', 'constructor', 'length', 'prototype']
66		let funcmeth = ['apply', 'call', 'toSource', 'toString', 'valueOf']
67		call map(funcmeth, 'v:val."("')
68		let funcs = funcprop + funcmeth
69
70		" Math
71		let mathprop = ['E', 'LN2', 'LN10', 'LOG2E', 'LOG10E', 'PI', 'SQRT1_2', 'SQRT']
72		let mathmeth = ['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor',
73					\ 'log', 'max', 'min', 'pow', 'random', 'round', 'sin', 'sqrt', 'tan',
74					\ 'watch', 'unwatch']
75		call map(mathmeth, 'v:val."("')
76		let maths = mathprop + mathmeth
77
78		" Number
79		let numbprop = ['MAX_VALUE', 'MIN_VALUE', 'NaN', 'NEGATIVE_INFINITY', 'POSITIVE_INFINITY',
80					\ 'constructor', 'prototype']
81		let numbmeth = ['toExponential', 'toFixed', 'toPrecision', 'toSource', 'toString', 'valueOf',
82					\ 'watch', 'unwatch']
83		call map(numbmeth, 'v:val."("')
84		let numbs = numbprop + numbmeth
85
86		" Object
87		let objeprop = ['constructor', 'prototype']
88		let objemeth = ['eval', 'toSource', 'toString', 'unwatch', 'watch', 'valueOf']
89		call map(objemeth, 'v:val."("')
90		let objes = objeprop + objemeth
91
92		" RegExp
93		let regeprop = ['constructor', 'global', 'ignoreCase', 'lastIndex', 'multiline', 'source', 'prototype']
94		let regemeth = ['exec', 'toSource', 'toString', 'test', 'watch', 'unwatch']
95		call map(regemeth, 'v:val."("')
96		let reges = regeprop + regemeth
97
98		" String
99		let striprop = ['constructor', 'length', 'prototype']
100		let strimeth = ['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'concat',
101					\ 'fixed', 'fontcolor', 'fontsize', 'fromCharCode', 'indexOf', 'italics',
102					\ 'lastIndexOf', 'link', 'match', 'replace', 'search', 'slice', 'small',
103					\ 'split', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLowerCase',
104					\ 'toSource', 'toString', 'toUpperCase', 'watch', 'unwatch']
105		call map(strimeth, 'v:val."("')
106		let stris = striprop + strimeth
107
108		" User created properties
109		if exists("b:jsrange")
110			let file = getline(b:jsrange[0],b:jsrange[1])
111			unlet! b:jsrange
112		else
113			let file = getline(1, '$')
114		endif
115		let user_props1 = filter(copy(file), 'v:val =~ "this\\.\\w"')
116		let juser_props1 = join(user_props1, ' ')
117		let user_props1 = split(juser_props1, '\zethis\.')
118		unlet! juser_props1
119		call map(user_props1, 'matchstr(v:val, "this\\.\\zs\\w\\+\\ze")')
120		let user_props2 = filter(copy(file), 'v:val =~ "\\.prototype\\.\\w"')
121		call map(user_props2, 'matchstr(v:val, "\\.prototype\\.\\zs\\w\\+\\ze")')
122		let user_props = user_props1 + user_props2
123
124		" HTML DOM properties
125		" Anchors - anchor.
126		let anchprop = ['accessKey', 'charset', 'coords', 'href', 'hreflang', 'id', 'innerHTML',
127					\ 'name', 'rel', 'rev', 'shape', 'tabIndex', 'target', 'type', 'onBlur', 'onFocus']
128		let anchmeth = ['blur', 'focus']
129		call map(anchmeth, 'v:val."("')
130		let anths = anchprop + anchmeth
131		" Area - area.
132		let areaprop = ['accessKey', 'alt', 'coords', 'hash', 'host', 'hostname', 'href', 'id',
133					\ 'noHref', 'pathname', 'port', 'protocol', 'search', 'shape', 'tabIndex', 'target']
134		let areameth = ['onClick', 'onDblClick', 'onMouseOut', 'onMouseOver']
135		call map(areameth, 'v:val."("')
136		let areas = areaprop + areameth
137		" Base - base.
138		let baseprop = ['href', 'id', 'target']
139		let bases = baseprop
140		" Body - body.
141		let bodyprop = ['aLink', 'background', 'gbColor', 'id', 'link', 'scrollLeft', 'scrollTop',
142					\ 'text', 'vLink']
143		let bodys = bodyprop
144		" Document - document.
145		let docuprop = ['anchors', 'applets', 'childNodes', 'embeds', 'forms', 'images', 'links', 'stylesheets',
146					\ 'body', 'cookie', 'documentElement', 'domain', 'lastModified', 'referrer', 'title', 'URL']
147		let documeth = ['close', 'createAttribute', 'createElement', 'createTextNode', 'focus', 'getElementById',
148					\ 'getElementsByName', 'getElementsByTagName', 'open', 'write', 'writeln',
149					\ 'onClick', 'onDblClick', 'onFocus', 'onKeyDown', 'onKeyPress', 'onKeyUp',
150					\ 'onMouseDown', 'onMouseMove', 'onMouseOut', 'onMouseOver', 'onMouseUp', 'onResize']
151		call map(documeth, 'v:val."("')
152		let docus = docuprop + documeth
153		" Form - form.
154		let formprop = ['elements', 'acceptCharset', 'action', 'encoding', 'enctype', 'id', 'length',
155					\ 'method', 'name', 'tabIndex', 'target']
156		let formmeth = ['reset', 'submit', 'onReset', 'onSubmit']
157		call map(formmeth, 'v:val."("')
158		let forms = formprop + formmeth
159		" Frame - frame.
160		let framprop = ['contentDocument', 'frameBorder', 'id', 'longDesc', 'marginHeight', 'marginWidth',
161					\ 'name', 'noResize', 'scrolling', 'src']
162		let frammeth = ['blur', 'focus']
163		call map(frammeth, 'v:val."("')
164		let frams = framprop + frammeth
165		" Frameset - frameset.
166		let fsetprop = ['cols', 'id', 'rows']
167		let fsetmeth = ['blur', 'focus']
168		call map(fsetmeth, 'v:val."("')
169		let fsets = fsetprop + fsetmeth
170		" History - history.
171		let histprop = ['length']
172		let histmeth = ['back', 'forward', 'go']
173		call map(histmeth, 'v:val."("')
174		let hists = histprop + histmeth
175		" Iframe - iframe.
176		let ifraprop = ['align', 'frameBorder', 'height', 'id', 'longDesc', 'marginHeight', 'marginWidth',
177					\ 'name', 'scrolling', 'src', 'width']
178		let ifras = ifraprop
179		" Image - image.
180		let imagprop = ['align', 'alt', 'border', 'complete', 'height', 'hspace', 'id', 'isMap', 'longDesc',
181					\ 'lowsrc', 'name', 'src', 'useMap', 'vspace', 'width']
182		let imagmeth = ['onAbort', 'onError', 'onLoad']
183		call map(imagmeth, 'v:val."("')
184		let imags = histprop + imagmeth
185		" Button - accessible only by other properties
186		let buttprop = ['accessKey', 'disabled', 'form', 'id', 'name', 'tabIndex', 'type', 'value']
187		let buttmeth = ['blur', 'click', 'focus', 'onBlur', 'onClick', 'onFocus', 'onMouseDown', 'onMouseUp']
188		call map(buttmeth, 'v:val."("')
189		let butts = buttprop + buttmeth
190		" Checkbox - accessible only by other properties
191		let checprop = ['accept', 'accessKey', 'align', 'alt', 'checked', 'defaultChecked',
192					\ 'disabled', 'form', 'id', 'name', 'tabIndex', 'type', 'value']
193		let checmeth = ['blur', 'click', 'focus', 'onBlur', 'onClick', 'onFocus', 'onMouseDown', 'onMouseUp']
194		call map(checmeth, 'v:val."("')
195		let checs = checprop + checmeth
196		" File upload - accessible only by other properties
197		let fileprop = ['accept', 'accessKey', 'align', 'alt', 'defaultValue',
198					\ 'disabled', 'form', 'id', 'name', 'tabIndex', 'type', 'value']
199		let filemeth = ['blur', 'focus', 'onBlur', 'onClick', 'onFocus', 'onMouseDown', 'onMouseUp']
200		call map(filemeth, 'v:val."("')
201		let files = fileprop + filemeth
202		" Hidden - accessible only by other properties
203		let hiddprop = ['defaultValue', 'form', 'id', 'name', 'type', 'value']
204		let hidds = hiddprop
205		" Password - accessible only by other properties
206		let passprop = ['accept', 'accessKey', 'defaultValue',
207					\ 'disabled', 'form', 'id', 'maxLength', 'name', 'readOnly', 'size', 'tabIndex',
208					\ 'type', 'value']
209		let passmeth = ['blur', 'click', 'focus', 'select', 'onBlur', 'onFocus', 'onKeyDown',
210					\ 'onKeyPress', 'onKeyUp']
211		call map(passmeth, 'v:val."("')
212		let passs = passprop + passmeth
213		" Radio - accessible only by other properties
214		let radiprop = ['accept', 'accessKey', 'align', 'alt', 'checked', 'defaultChecked',
215					\ 'disabled', 'form', 'id', 'name', 'tabIndex', 'type', 'value']
216		let radimeth = ['blur', 'click', 'focus', 'select', 'onBlur', 'onFocus']
217		call map(radimeth, 'v:val."("')
218		let radis = radiprop + radimeth
219		" Reset - accessible only by other properties
220		let reseprop = ['accept', 'accessKey', 'align', 'alt', 'defaultValue',
221					\ 'disabled', 'form', 'id', 'name', 'size', 'tabIndex', 'type', 'value']
222		let resemeth = ['blur', 'click', 'focus', 'select', 'onBlur', 'onFocus']
223		call map(resemeth, 'v:val."("')
224		let reses = reseprop + resemeth
225		" Submit - accessible only by other properties
226		let submprop = ['accept', 'accessKey', 'align', 'alt', 'defaultValue',
227					\ 'disabled', 'form', 'id', 'name', 'size', 'tabIndex', 'type', 'value']
228		let submmeth = ['blur', 'click', 'focus', 'select', 'onClick', 'onSelectStart']
229		call map(submmeth, 'v:val."("')
230		let subms = submprop + submmeth
231		" Text - accessible only by other properties
232		let textprop = ['accept', 'accessKey', 'align', 'alt', 'defaultValue',
233					\ 'disabled', 'form', 'id', 'maxLength', 'name', 'readOnly',
234					\ 'size', 'tabIndex', 'type', 'value']
235		let textmeth = ['blur', 'focus', 'select', 'onBlur', 'onChange', 'onFocus', 'onKeyDown',
236					\ 'onKeyPress', 'onKeyUp', 'onSelect']
237		call map(textmeth, 'v:val."("')
238		let texts = textprop + textmeth
239		" Link - link.
240		let linkprop = ['charset', 'disabled', 'href', 'hreflang', 'id', 'media',
241					\ 'rel', 'rev', 'target', 'type']
242		let linkmeth = ['onLoad']
243		call map(linkmeth, 'v:val."("')
244		let links = linkprop + linkmeth
245		" Location - location.
246		let locaprop = ['href', 'hash', 'host', 'hostname', 'pathname', 'port', 'protocol',
247					\ 'search']
248		let locameth = ['assign', 'reload', 'replace']
249		call map(locameth, 'v:val."("')
250		let locas = locaprop + locameth
251		" Meta - meta.
252		let metaprop = ['charset', 'content', 'disabled', 'httpEquiv', 'name', 'scheme']
253		let metas = metaprop
254		" Navigator - navigator.
255		let naviprop = ['plugins', 'appCodeName', 'appName', 'appVersion', 'cookieEnabled',
256					\ 'platform', 'userAgent']
257		let navimeth = ['javaEnabled', 'taintEnabled']
258		call map(navimeth, 'v:val."("')
259		let navis = naviprop + navimeth
260		" Object - object.
261		let objeprop = ['align', 'archive', 'border', 'code', 'codeBase', 'codeType', 'data',
262					\ 'declare', 'form', 'height', 'hspace', 'id', 'name', 'standby', 'tabIndex',
263					\ 'type', 'useMap', 'vspace', 'width']
264		let objes = objeprop
265		" Option - accessible only by other properties
266		let optiprop = ['defaultSelected',
267					\ 'disabled', 'form', 'id', 'index', 'label', 'selected', 'text', 'value']
268		let optis = optiprop
269		" Screen - screen.
270		let screprop = ['availHeight', 'availWidth', 'colorDepth', 'height', 'width']
271		let scres = screprop
272		" Select - accessible only by other properties
273		let seleprop = ['options', 'disabled', 'form', 'id', 'length', 'multiple', 'name',
274					\ 'selectedIndex', 'size', 'tabIndex', 'type', 'value']
275		let selemeth = ['blur', 'focus', 'remove', 'onBlur', 'onChange', 'onFocus']
276		call map(selemeth, 'v:val."("')
277		let seles = seleprop + selemeth
278		" Style - style.
279		let stylprop = ['background', 'backgroundAttachment', 'backgroundColor', 'backgroundImage',
280					\ 'backgroundPosition', 'backgroundRepeat',
281					\ 'border', 'borderBottom', 'borderLeft', 'borderRight', 'borderTop',
282					\ 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor',
283					\ 'borderBottomStyle', 'borderLeftStyle', 'borderRightStyle', 'borderTopStyle',
284					\ 'borderBottomWidth', 'borderLeftWidth', 'borderRightWidth', 'borderTopWidth',
285                    \ 'borderColor', 'borderStyle', 'borderWidth', 'margin', 'marginBottom',
286                    \ 'marginLeft', 'marginRight', 'marginTop', 'outline', 'outlineStyle', 'outlineWidth',
287                    \ 'outlineColor', 'outlineStyle', 'outlineWidth', 'padding', 'paddingBottom',
288                    \ 'paddingLeft', 'paddingRight', 'paddingTop',
289                    \ 'clear', 'clip', 'clipBottom', 'clipLeft', 'clipRight', 'clipTop', 'content',
290                    \ 'counterIncrement', 'counterReset', 'cssFloat', 'cursor', 'direction',
291                    \ 'display', 'markerOffset', 'marks', 'maxHeight', 'maxWidth', 'minHeight',
292					\ 'minWidth', 'overflow', 'overflowX', 'overflowY', 'verticalAlign', 'visibility',
293					\ 'width',
294					\ 'listStyle', 'listStyleImage', 'listStylePosition', 'listStyleType',
295					\ 'cssText', 'bottom', 'height', 'left', 'position', 'right', 'top', 'width', 'zindex',
296					\ 'orphans', 'widows', 'page', 'pageBreakAfter', 'pageBreakBefore', 'pageBreakInside',
297					\ 'borderCollapse', 'borderSpacing', 'captionSide', 'emptyCells', 'tableLayout',
298					\ 'color', 'font', 'fontFamily', 'fontSize', 'fontSizeAdjust', 'fontStretch',
299					\ 'fontStyle', 'fontVariant', 'fontWeight', 'letterSpacing', 'lineHeight', 'quotes',
300					\ 'textAlign', 'textIndent', 'textShadow', 'textTransform', 'textUnderlinePosition',
301					\ 'unicodeBidi', 'whiteSpace', 'wordSpacing']
302		let styls = stylprop
303		" Table - table.
304		let tablprop = ['rows', 'tBodies', 'align', 'bgColor', 'border', 'caption', 'cellPadding',
305					\ 'cellSpacing', 'frame', 'height', 'rules', 'summary', 'tFoot', 'tHead', 'width']
306		let tablmeth = ['createCaption', 'createTFoot', 'createTHead', 'deleteCaption', 'deleteRow',
307					\ 'deleteTFoot', 'deleteTHead', 'insertRow']
308		call map(tablmeth, 'v:val."("')
309		let tabls = tablprop + tablmeth
310		" Table data - TableData.
311		let tdatprop = ['abbr', 'align', 'axis', 'bgColor', 'cellIndex', 'ch', 'chOff',
312					\ 'colSpan', 'headers', 'noWrap', 'rowSpan', 'scope', 'vAlign', 'width']
313		let tdats = tdatprop
314		" Table row - TableRow.
315		let trowprop = ['cells', 'align', 'bgColor', 'ch', 'chOff', 'rowIndex', 'sectionRowIndex',
316					\ 'vAlign']
317		let trowmeth = ['deleteCell', 'insertCell']
318		call map(trowmeth, 'v:val."("')
319		let trows = trowprop + trowmeth
320		" Textarea - accessible only by other properties
321		let tareprop = ['accessKey', 'cols', 'defaultValue',
322					\ 'disabled', 'form', 'id', 'name', 'readOnly', 'rows',
323					\ 'tabIndex', 'type', 'value']
324		let taremeth = ['blur', 'focus', 'select', 'onBlur', 'onChange', 'onFocus']
325		call map(taremeth, 'v:val."("')
326		let tares = tareprop + taremeth
327		" Window - window.
328		let windprop = ['frames', 'closed', 'defaultStatus', 'length', 'name', 'opener', 'parent',
329					\ 'self', 'status', 'top']
330		let windmeth = ['alert', 'blur', 'clearInterval', 'clearTimeout', 'close', 'confirm', 'focus',
331					\ 'moveBy', 'moveTo', 'open', 'print', 'prompt', 'scrollBy', 'scrollTo', 'setInterval',
332					\ 'setTimeout']
333		call map(windmeth, 'v:val."("')
334		let winds = windprop + windmeth
335		" XMLHttpRequest - access by new xxx()
336		let xmlhprop = ['onreadystatechange', 'readyState', 'responseText', 'responseXML',
337					\ 'status', 'statusText']
338		let xmlhmeth = ['abort', 'getAllResponseHeaders', 'getResponseHeaders', 'open',
339					\ 'send', 'setRequestHeader']
340		call map(xmlhmeth, 'v:val."("')
341		let xmlhs = xmlhprop + xmlhmeth
342
343		let object = matchstr(shortcontext, '\zs\w\+\ze\(\[.\{-}\]\)\?\.$')
344		let decl_line = search(object.'.\{-}=\s*new\s*', 'bn')
345		let object_type = matchstr(getline(decl_line), object.'.\{-}=\s*new\s*\zs\w\+\ze')
346
347		if object_type == 'Date'
348			let values = dates
349		elseif object_type == 'Image'
350			let values = imags
351		elseif object_type == 'Array'
352			let values = arrays
353		elseif object_type == 'Boolean'
354			" TODO: a bit more than real boolean
355			let values = arrays
356		elseif object_type == 'XMLHttpRequest'
357			let values = xmlhs
358		elseif object_type == 'String'
359			let values = stris
360		endif
361
362		if !exists('values')
363		" List of properties
364		if shortcontext =~ 'Math\.$'
365			let values = maths
366		elseif shortcontext =~ 'anchor\.$'
367			let values = anths
368		elseif shortcontext =~ 'area\.$'
369			let values = areas
370		elseif shortcontext =~ 'base\.$'
371			let values = bases
372		elseif shortcontext =~ 'body\.$'
373			let values = bodys
374		elseif shortcontext =~ 'document\.$'
375			let values = docus
376		elseif shortcontext =~ 'form\.$'
377			let values = forms
378		elseif shortcontext =~ 'frameset\.$'
379			let values = fsets
380		elseif shortcontext =~ 'history\.$'
381			let values = hists
382		elseif shortcontext =~ 'iframe\.$'
383			let values = ifras
384		elseif shortcontext =~ 'image\.$'
385			let values = imags
386		elseif shortcontext =~ 'link\.$'
387			let values = links
388		elseif shortcontext =~ 'location\.$'
389			let values = locas
390		elseif shortcontext =~ 'meta\.$'
391			let values = metas
392		elseif shortcontext =~ 'navigator\.$'
393			let values = navis
394		elseif shortcontext =~ 'object\.$'
395			let values = objes
396		elseif shortcontext =~ 'screen\.$'
397			let values = scres
398		elseif shortcontext =~ 'style\.$'
399			let values = styls
400		elseif shortcontext =~ 'table\.$'
401			let values = tabls
402		elseif shortcontext =~ 'TableData\.$'
403			let values = tdats
404		elseif shortcontext =~ 'TableRow\.$'
405			let values = trows
406		elseif shortcontext =~ 'window\.$'
407			let values = winds
408		else
409			let values = user_props + arrays + dates + funcs + maths + numbs + objes + reges + stris
410			let values += doms + anths + areas + bases + bodys + docus + forms + frams + fsets + hists
411			let values += ifras + imags + links + locas + metas + navis + objes + scres + styls
412			let values += tabls + trows + winds
413		endif
414		endif
415
416		for m in values
417			if m =~? '^'.a:base
418				call add(res, m)
419			elseif m =~? a:base
420				call add(res2, m)
421			endif
422		endfor
423
424		unlet! values
425		return res + res2
426
427	endif
428
429	if exists("b:jsrange")
430		let file = getline(b:jsrange[0],b:jsrange[1])
431		unlet! b:jsrange
432	else
433		let file = getline(1, '$')
434	endif
435
436	" Get variables data.
437	let variables = filter(copy(file), 'v:val =~ "var\\s"')
438	call map(variables, 'matchstr(v:val, ".\\{-}var\\s\\+\\zs.*\\ze")')
439	call map(variables, 'substitute(v:val, ";\\|$", ",", "g")')
440	let vars = []
441	" This loop is necessary to get variable names from constructs like:
442	" var var1, var2, var3 = "something";
443	for i in range(len(variables))
444		let comma_separated = split(variables[i], ',\s*')
445		call map(comma_separated, 'matchstr(v:val, "\\w\\+")')
446		let vars += comma_separated
447	endfor
448
449	let variables = sort(vars)
450
451	" Add undeclared variables.
452	let undeclared_variables = filter(copy(file), 'v:val =~ "^\\s*\\w\\+\\s*="')
453	call map(undeclared_variables, 'matchstr(v:val, "^\\s*\\zs\\w\\+\\ze")')
454
455	let variables += sort(undeclared_variables)
456
457	" Get functions
458	let functions = filter(copy(file), 'v:val =~ "^\\s*function\\s"')
459	let arguments = copy(functions)
460	call map(functions, 'matchstr(v:val, "^\\s*function\\s\\+\\zs\\w\\+")')
461	call map(functions, 'v:val."("')
462
463	" Get functions arguments
464	call map(arguments, 'matchstr(v:val, "function.\\{-}(\\zs.\\{-}\\ze)")')
465	let jargs = join(arguments, ',')
466	let jargs = substitute(jargs, '\s', '', 'g')
467	let arguments = split(jargs, ',')
468
469	" Built-in functions
470	let builtin = []
471
472	" Top-level HTML DOM objects
473	let htmldom = ['document', 'anchor', 'area', 'base', 'body', 'document', 'event', 'form', 'frame', 'frameset', 'history', 'iframe', 'image', 'input', 'link', 'location', 'meta', 'navigator', 'object', 'option', 'screen', 'select', 'table', 'tableData', 'tableHeader', 'tableRow', 'textarea', 'window']
474	call map(htmldom, 'v:val."."')
475
476	" Top-level properties
477	let properties = ['decodeURI', 'decodeURIComponent', 'encodeURI', 'encodeURIComponent',
478				\ 'eval', 'Infinity', 'isFinite', 'isNaN', 'NaN', 'Number', 'parseFloat',
479				\ 'parseInt', 'String', 'undefined', 'escape', 'unescape']
480
481	" Keywords
482	let keywords = ["Array", "Boolean", "Date", "Function", "Math", "Number", "Object", "RegExp", "String", "XMLHttpRequest", "ActiveXObject", "abstract", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "debugger", "default", "delete", "do", "double ", "else", "enum", "export", "extends", "false", "final", "finally", "float", "for", "function", "goto", "if", "implements", "import", "in ", "instanceof", "int", "interface", "long", "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static", "super ", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "typeof", "var", "void", "volatile", "while", "with"]
483
484	let values = variables + functions + htmldom + arguments + builtin + properties + keywords
485
486	for m in values
487		if m =~? '^'.a:base
488			call add(res, m)
489		elseif m =~? a:base
490			call add(res2, m)
491		endif
492	endfor
493
494	return res + res2
495endfunction
496