blob: 79d913d637764394166be64d92357bb7c0f4e5b0 [file] [log] [blame]
Bram Moolenaara5792f52005-11-23 21:25:05 +00001" Vim completion script
Bram Moolenaard12f5c12006-01-25 22:10:52 +00002" Language: XML
Bram Moolenaara5792f52005-11-23 21:25:05 +00003" Maintainer: Mikolaj Machowski ( mikmach AT wp DOT pl )
Bram Moolenaar9964e462007-05-05 17:54:07 +00004" Last Change: 2006 Jul 18
5" Version: 1.8
6"
7" Changelog:
8" 1.8 - 2006 Jul 18
9" - allow for closing of xml tags even when data file isn't available
Bram Moolenaara5792f52005-11-23 21:25:05 +000010
11" This function will create Dictionary with users namespace strings and values
12" canonical (system) names of data files. Names should be lowercase,
13" descriptive to avoid any future conflicts. For example 'xhtml10s' should be
14" name for data of XHTML 1.0 Strict and 'xhtml10t' for XHTML 1.0 Transitional
Bram Moolenaar910f66f2006-04-05 20:41:53 +000015" User interface will be provided by XMLns command defined in ftplugin/xml.vim
Bram Moolenaara5792f52005-11-23 21:25:05 +000016" Currently supported canonicals are:
17" xhtml10s - XHTML 1.0 Strict
18" xsl - XSL
Bram Moolenaar18144c82006-04-12 21:52:12 +000019function! xmlcomplete#CreateConnection(canonical, ...) " {{{
Bram Moolenaara5792f52005-11-23 21:25:05 +000020
21 " When only one argument provided treat name as default namespace (without
22 " 'prefix:').
23 if exists("a:1")
24 let users = a:1
25 else
26 let users = 'DEFAULT'
27 endif
28
29 " Source data file. Due to suspected errors in autoload do it with
Bram Moolenaarc9b4b052006-04-30 18:54:39 +000030 " :runtime.
Bram Moolenaara5792f52005-11-23 21:25:05 +000031 " TODO: make it properly (using autoload, that is) later
32 exe "runtime autoload/xml/".a:canonical.".vim"
33
34 " Remove all traces of unexisting files to return [] when trying
35 " omnicomplete something
36 " TODO: give warning about non-existing canonicals - should it be?
37 if !exists("g:xmldata_".a:canonical)
38 unlet! g:xmldata_connection
39 return 0
40 endif
41
42 " We need to initialize Dictionary to add key-value pair
43 if !exists("g:xmldata_connection")
44 let g:xmldata_connection = {}
45 endif
46
47 let g:xmldata_connection[users] = a:canonical
48
49endfunction
Bram Moolenaar18144c82006-04-12 21:52:12 +000050" }}}
Bram Moolenaara5792f52005-11-23 21:25:05 +000051
Bram Moolenaar18144c82006-04-12 21:52:12 +000052function! xmlcomplete#CreateEntConnection(...) " {{{
Bram Moolenaara5792f52005-11-23 21:25:05 +000053 if a:0 > 0
54 let g:xmldata_entconnect = a:1
55 else
56 let g:xmldata_entconnect = 'DEFAULT'
57 endif
58endfunction
Bram Moolenaar18144c82006-04-12 21:52:12 +000059" }}}
Bram Moolenaara5792f52005-11-23 21:25:05 +000060
61function! xmlcomplete#CompleteTags(findstart, base)
62 if a:findstart
63 " locate the start of the word
Bram Moolenaard12f5c12006-01-25 22:10:52 +000064 let curline = line('.')
Bram Moolenaara5792f52005-11-23 21:25:05 +000065 let line = getline('.')
66 let start = col('.') - 1
67 let compl_begin = col('.') - 2
68
69 while start >= 0 && line[start - 1] =~ '\(\k\|[:.-]\)'
70 let start -= 1
71 endwhile
72
73 if start >= 0 && line[start - 1] =~ '&'
74 let b:entitiescompl = 1
75 let b:compl_context = ''
76 return start
77 endif
78
79 let b:compl_context = getline('.')[0:(compl_begin)]
Bram Moolenaard12f5c12006-01-25 22:10:52 +000080 if b:compl_context !~ '<[^>]*$'
81 " Look like we may have broken tag. Check previous lines. Up to
82 " 10?
83 let i = 1
84 while 1
85 let context_line = getline(curline-i)
86 if context_line =~ '<[^>]*$'
87 " Yep, this is this line
Bram Moolenaar9964e462007-05-05 17:54:07 +000088 let context_lines = getline(curline-i, curline-1) + [b:compl_context]
Bram Moolenaard12f5c12006-01-25 22:10:52 +000089 let b:compl_context = join(context_lines, ' ')
90 break
Bram Moolenaarc15ef302006-03-19 22:11:16 +000091 elseif context_line =~ '>[^<]*$' || i == curline
Bram Moolenaard12f5c12006-01-25 22:10:52 +000092 " Normal tag line, no need for completion at all
Bram Moolenaarc15ef302006-03-19 22:11:16 +000093 " OR reached first line without tag at all
Bram Moolenaard12f5c12006-01-25 22:10:52 +000094 let b:compl_context = ''
95 break
96 endif
97 let i += 1
98 endwhile
99 " Make sure we don't have counter
100 unlet! i
101 endif
102 let b:compl_context = matchstr(b:compl_context, '.*\zs<.*')
Bram Moolenaara5792f52005-11-23 21:25:05 +0000103
104 " Make sure we will have only current namespace
105 unlet! b:xml_namespace
Bram Moolenaard12f5c12006-01-25 22:10:52 +0000106 let b:xml_namespace = matchstr(b:compl_context, '^<\zs\k*\ze:')
Bram Moolenaara5792f52005-11-23 21:25:05 +0000107 if b:xml_namespace == ''
108 let b:xml_namespace = 'DEFAULT'
109 endif
110
111 return start
112
113 else
Bram Moolenaara5792f52005-11-23 21:25:05 +0000114 " Initialize base return lists
115 let res = []
116 let res2 = []
117 " a:base is very short - we need context
Bram Moolenaard12f5c12006-01-25 22:10:52 +0000118 if len(b:compl_context) == 0 && !exists("b:entitiescompl")
119 return []
120 endif
121 let context = matchstr(b:compl_context, '^<\zs.*')
Bram Moolenaara5792f52005-11-23 21:25:05 +0000122 unlet! b:compl_context
Bram Moolenaar9964e462007-05-05 17:54:07 +0000123 " There is no connection of namespace and data file.
124 if !exists("g:xmldata_connection") || g:xmldata_connection == {}
125 " There is still possibility we may do something - eg. close tag
126 let b:unaryTagsStack = "base meta link hr br param img area input col"
127 if context =~ '^\/'
128 let opentag = xmlcomplete#GetLastOpenTag("b:unaryTagsStack")
129 return [opentag.">"]
130 else
131 return []
132 endif
133 endif
Bram Moolenaara5792f52005-11-23 21:25:05 +0000134
135 " Make entities completion
136 if exists("b:entitiescompl")
137 unlet! b:entitiescompl
138
139 if !exists("g:xmldata_entconnect") || g:xmldata_entconnect == 'DEFAULT'
140 let values = g:xmldata{'_'.g:xmldata_connection['DEFAULT']}['vimxmlentities']
141 else
142 let values = g:xmldata{'_'.g:xmldata_entconnect}['vimxmlentities']
143 endif
144
145 " Get only lines with entity declarations but throw out
146 " parameter-entities - they may be completed in future
147 let entdecl = filter(getline(1, "$"), 'v:val =~ "<!ENTITY\\s\\+[^%]"')
148
149 if len(entdecl) > 0
150 let intent = map(copy(entdecl), 'matchstr(v:val, "<!ENTITY\\s\\+\\zs\\(\\k\\|[.-:]\\)\\+\\ze")')
151 let values = intent + values
152 endif
153
Bram Moolenaard12f5c12006-01-25 22:10:52 +0000154 if len(a:base) == 1
155 for m in values
156 if m =~ '^'.a:base
157 call add(res, m.';')
158 endif
159 endfor
160 return res
161 else
162 for m in values
163 if m =~? '^'.a:base
164 call add(res, m.';')
165 elseif m =~? a:base
166 call add(res2, m.';')
167 endif
168 endfor
Bram Moolenaara5792f52005-11-23 21:25:05 +0000169
Bram Moolenaard12f5c12006-01-25 22:10:52 +0000170 return res + res2
171 endif
Bram Moolenaara5792f52005-11-23 21:25:05 +0000172
173 endif
174 if context =~ '>'
175 " Generally if context contains > it means we are outside of tag and
176 " should abandon action
177 return []
178 endif
179
180 " find tags matching with "a:base"
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000181 " If a:base contains white space it is attribute.
Bram Moolenaara5792f52005-11-23 21:25:05 +0000182 " It could be also value of attribute...
183 " We have to get first word to offer
184 " proper completions
185 if context == ''
186 let tag = ''
187 else
188 let tag = split(context)[0]
189 endif
190 " Get rid of namespace
191 let tag = substitute(tag, '^'.b:xml_namespace.':', '', '')
192
193
194 " Get last word, it should be attr name
195 let attr = matchstr(context, '.*\s\zs.*')
196 " Possible situations where any prediction would be difficult:
197 " 1. Events attributes
198 if context =~ '\s'
199
200 " If attr contains =\s*[\"'] we catched value of attribute
Bram Moolenaar8424a622006-04-19 21:23:36 +0000201 if attr =~ "=\s*[\"']" || attr =~ "=\s*$"
Bram Moolenaara5792f52005-11-23 21:25:05 +0000202 " Let do attribute specific completion
203 let attrname = matchstr(attr, '.*\ze\s*=')
Bram Moolenaar8424a622006-04-19 21:23:36 +0000204 let entered_value = matchstr(attr, ".*=\\s*[\"']\\?\\zs.*")
Bram Moolenaara5792f52005-11-23 21:25:05 +0000205
206 if tag =~ '^[?!]'
207 " Return nothing if we are inside of ! or ? tag
208 return []
209 else
Bram Moolenaar8424a622006-04-19 21:23:36 +0000210 if has_key(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}, tag) && has_key(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1], attrname)
211 let values = g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1][attrname]
212 else
213 return []
214 endif
Bram Moolenaara5792f52005-11-23 21:25:05 +0000215 endif
216
217 if len(values) == 0
218 return []
219 endif
220
221 " We need special version of sbase
222 let attrbase = matchstr(context, ".*[\"']")
223 let attrquote = matchstr(attrbase, '.$')
Bram Moolenaar8424a622006-04-19 21:23:36 +0000224 if attrquote !~ "['\"]"
225 let attrquoteopen = '"'
226 let attrquote = '"'
227 else
228 let attrquoteopen = ''
229 endif
Bram Moolenaara5792f52005-11-23 21:25:05 +0000230
231 for m in values
232 " This if is needed to not offer all completions as-is
233 " alphabetically but sort them. Those beginning with entered
234 " part will be as first choices
235 if m =~ '^'.entered_value
Bram Moolenaar8424a622006-04-19 21:23:36 +0000236 call add(res, attrquoteopen . m . attrquote.' ')
Bram Moolenaara5792f52005-11-23 21:25:05 +0000237 elseif m =~ entered_value
Bram Moolenaar8424a622006-04-19 21:23:36 +0000238 call add(res2, attrquoteopen . m . attrquote.' ')
Bram Moolenaara5792f52005-11-23 21:25:05 +0000239 endif
240 endfor
241
242 return res + res2
243
244 endif
245
246 if tag =~ '?xml'
247 " Two possible arguments for <?xml> plus variation
248 let attrs = ['encoding', 'version="1.0"', 'version']
249 elseif tag =~ '^!'
250 " Don't make completion at all
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000251 "
Bram Moolenaara5792f52005-11-23 21:25:05 +0000252 return []
253 else
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000254 if !has_key(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}, tag)
255 " Abandon when data file isn't complete
256 return []
257 endif
Bram Moolenaara5792f52005-11-23 21:25:05 +0000258 let attrs = keys(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1])
259 endif
260
261 for m in sort(attrs)
262 if m =~ '^'.attr
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000263 call add(res, m)
Bram Moolenaara5792f52005-11-23 21:25:05 +0000264 elseif m =~ attr
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000265 call add(res2, m)
Bram Moolenaara5792f52005-11-23 21:25:05 +0000266 endif
267 endfor
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000268 let menu = res + res2
269 let final_menu = []
270 if has_key(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}, 'vimxmlattrinfo')
271 for i in range(len(menu))
272 let item = menu[i]
273 if has_key(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}['vimxmlattrinfo'], item)
274 let m_menu = g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}['vimxmlattrinfo'][item][0]
275 let m_info = g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}['vimxmlattrinfo'][item][1]
276 else
277 let m_menu = ''
278 let m_info = ''
279 endif
280 if tag !~ '^[?!]' && len(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1][item]) > 0 && g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1][item][0] =~ '^\(BOOL\|'.item.'\)$'
281 let item = item
282 else
283 let item .= '="'
284 endif
285 let final_menu += [{'word':item, 'menu':m_menu, 'info':m_info}]
286 endfor
287 else
288 for i in range(len(menu))
289 let item = menu[i]
290 if tag !~ '^[?!]' && len(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1][item]) > 0 && g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[tag][1][item][0] =~ '^\(BOOL\|'.item.'\)$'
291 let item = item
292 else
293 let item .= '="'
294 endif
295 let final_menu += [item]
296 endfor
297 endif
298 return final_menu
Bram Moolenaara5792f52005-11-23 21:25:05 +0000299
300 endif
301 " Close tag
302 let b:unaryTagsStack = "base meta link hr br param img area input col"
303 if context =~ '^\/'
304 let opentag = xmlcomplete#GetLastOpenTag("b:unaryTagsStack")
305 return [opentag.">"]
306 endif
307
308 " Complete elements of XML structure
309 " TODO: #REQUIRED, #IMPLIED, #FIXED, #PCDATA - but these should be detected like
310 " entities - in first run
311 " keywords: CDATA, ID, IDREF, IDREFS, ENTITY, ENTITIES, NMTOKEN, NMTOKENS
312 " are hardly recognizable but keep it in reserve
313 " also: EMPTY ANY SYSTEM PUBLIC DATA
314 if context =~ '^!'
315 let tags = ['!ELEMENT', '!DOCTYPE', '!ATTLIST', '!ENTITY', '!NOTATION', '![CDATA[', '![INCLUDE[', '![IGNORE[']
316
317 for m in tags
318 if m =~ '^'.context
319 let m = substitute(m, '^!\[\?', '', '')
320 call add(res, m)
321 elseif m =~ context
322 let m = substitute(m, '^!\[\?', '', '')
323 call add(res2, m)
324 endif
325 endfor
326
327 return res + res2
328
329 endif
330
331 " Complete text declaration
Bram Moolenaara5792f52005-11-23 21:25:05 +0000332 if context =~ '^?'
333 let tags = ['?xml']
334
335 for m in tags
336 if m =~ '^'.context
337 call add(res, substitute(m, '^?', '', ''))
338 elseif m =~ context
339 call add(res, substitute(m, '^?', '', ''))
340 endif
341 endfor
342
343 return res + res2
344
345 endif
346
347 " Deal with tag completion.
348 let opentag = xmlcomplete#GetLastOpenTag("b:unaryTagsStack")
349 let opentag = substitute(opentag, '^\k*:', '', '')
Bram Moolenaard12f5c12006-01-25 22:10:52 +0000350 if opentag == ''
Bram Moolenaar7e8fd632006-02-18 22:14:51 +0000351 "return []
352 let tags = keys(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]})
353 call filter(tags, 'v:val !~ "^vimxml"')
354 else
Bram Moolenaar18144c82006-04-12 21:52:12 +0000355 if !has_key(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}, opentag)
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000356 " Abandon when data file isn't complete
357 return []
358 endif
Bram Moolenaar7e8fd632006-02-18 22:14:51 +0000359 let tags = g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[opentag][0]
Bram Moolenaard12f5c12006-01-25 22:10:52 +0000360 endif
Bram Moolenaara5792f52005-11-23 21:25:05 +0000361
Bram Moolenaara5792f52005-11-23 21:25:05 +0000362 let context = substitute(context, '^\k*:', '', '')
363
Bram Moolenaara5792f52005-11-23 21:25:05 +0000364 for m in tags
365 if m =~ '^'.context
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000366 call add(res, m)
Bram Moolenaara5792f52005-11-23 21:25:05 +0000367 elseif m =~ context
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000368 call add(res2, m)
Bram Moolenaara5792f52005-11-23 21:25:05 +0000369 endif
370 endfor
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000371 let menu = res + res2
Bram Moolenaar18144c82006-04-12 21:52:12 +0000372 if b:xml_namespace == 'DEFAULT'
373 let xml_namespace = ''
374 else
375 let xml_namespace = b:xml_namespace.':'
376 endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000377 if has_key(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}, 'vimxmltaginfo')
378 let final_menu = []
379 for i in range(len(menu))
380 let item = menu[i]
381 if has_key(g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}['vimxmltaginfo'], item)
382 let m_menu = g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}['vimxmltaginfo'][item][0]
383 let m_info = g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}['vimxmltaginfo'][item][1]
384 else
385 let m_menu = ''
386 let m_info = ''
387 endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000388 let final_menu += [{'word':xml_namespace.item, 'menu':m_menu, 'info':m_info}]
389 endfor
390 else
Bram Moolenaar18144c82006-04-12 21:52:12 +0000391 let final_menu = map(menu, 'xml_namespace.v:val')
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000392 endif
Bram Moolenaar18144c82006-04-12 21:52:12 +0000393
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000394 return final_menu
Bram Moolenaara5792f52005-11-23 21:25:05 +0000395
396 endif
397endfunction
398
Bram Moolenaar18144c82006-04-12 21:52:12 +0000399" MM: This is severely reduced closetag.vim used with kind permission of Steven
Bram Moolenaara5792f52005-11-23 21:25:05 +0000400" Mueller
401" Changes: strip all comments; delete error messages; add checking for
402" namespace
403" Author: Steven Mueller <diffusor@ugcs.caltech.edu>
404" Last Modified: Tue May 24 13:29:48 PDT 2005
405" Version: 0.9.1
406
407function! xmlcomplete#GetLastOpenTag(unaryTagsStack)
408 let linenum=line('.')
409 let lineend=col('.') - 1 " start: cursor position
410 let first=1 " flag for first line searched
411 let b:TagStack='' " main stack of tags
412 let startInComment=s:InComment()
413
414 if exists("b:xml_namespace")
415 if b:xml_namespace == 'DEFAULT'
416 let tagpat='</\=\(\k\|[.-]\)\+\|/>'
417 else
418 let tagpat='</\='.b:xml_namespace.':\(\k\|[.-]\)\+\|/>'
419 endif
420 else
Bram Moolenaar9372a112005-12-06 19:59:18 +0000421 let tagpat='</\=\(\k\|[.-]\)\+\|/>'
Bram Moolenaara5792f52005-11-23 21:25:05 +0000422 endif
423 while (linenum>0)
424 let line=getline(linenum)
425 if first
426 let line=strpart(line,0,lineend)
427 else
428 let lineend=strlen(line)
429 endif
430 let b:lineTagStack=''
431 let mpos=0
432 let b:TagCol=0
433 while (mpos > -1)
434 let mpos=matchend(line,tagpat)
435 if mpos > -1
436 let b:TagCol=b:TagCol+mpos
437 let tag=matchstr(line,tagpat)
438
439 if exists('b:closetag_disable_synID') || startInComment==s:InCommentAt(linenum, b:TagCol)
440 let b:TagLine=linenum
441 call s:Push(matchstr(tag,'[^<>]\+'),'b:lineTagStack')
442 endif
443 let lineend=lineend-mpos
444 let line=strpart(line,mpos,lineend)
445 endif
446 endwhile
447 while (!s:EmptystackP('b:lineTagStack'))
448 let tag=s:Pop('b:lineTagStack')
449 if match(tag, '^/') == 0 "found end tag
450 call s:Push(tag,'b:TagStack')
451 elseif s:EmptystackP('b:TagStack') && !s:Instack(tag, a:unaryTagsStack) "found unclosed tag
452 return tag
453 else
454 let endtag=s:Peekstack('b:TagStack')
455 if endtag == '/'.tag || endtag == '/'
456 call s:Pop('b:TagStack') "found a open/close tag pair
457 elseif !s:Instack(tag, a:unaryTagsStack) "we have a mismatch error
458 return ''
459 endif
460 endif
461 endwhile
462 let linenum=linenum-1 | let first=0
463 endwhile
464return ''
465endfunction
466
467function! s:InComment()
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000468 return synIDattr(synID(line('.'), col('.'), 0), 'name') =~ 'Comment\|String'
Bram Moolenaara5792f52005-11-23 21:25:05 +0000469endfunction
470
471function! s:InCommentAt(line, col)
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000472 return synIDattr(synID(a:line, a:col, 0), 'name') =~ 'Comment\|String'
Bram Moolenaara5792f52005-11-23 21:25:05 +0000473endfunction
474
475function! s:SetKeywords()
476 let g:IsKeywordBak=&iskeyword
477 let &iskeyword='33-255'
478endfunction
479
480function! s:RestoreKeywords()
481 let &iskeyword=g:IsKeywordBak
482endfunction
483
484function! s:Push(el, sname)
485 if !s:EmptystackP(a:sname)
486 exe 'let '.a:sname."=a:el.' '.".a:sname
487 else
488 exe 'let '.a:sname.'=a:el'
489 endif
490endfunction
491
492function! s:EmptystackP(sname)
493 exe 'let stack='.a:sname
494 if match(stack,'^ *$') == 0
495 return 1
496 else
497 return 0
498 endif
499endfunction
500
501function! s:Instack(el, sname)
502 exe 'let stack='.a:sname
503 call s:SetKeywords()
504 let m=match(stack, '\<'.a:el.'\>')
505 call s:RestoreKeywords()
506 if m < 0
507 return 0
508 else
509 return 1
510 endif
511endfunction
512
513function! s:Peekstack(sname)
514 call s:SetKeywords()
515 exe 'let stack='.a:sname
516 let top=matchstr(stack, '\<.\{-1,}\>')
517 call s:RestoreKeywords()
518 return top
519endfunction
520
521function! s:Pop(sname)
522 if s:EmptystackP(a:sname)
523 return ''
524 endif
525 exe 'let stack='.a:sname
526 call s:SetKeywords()
527 let loc=matchend(stack,'\<.\{-1,}\>')
528 exe 'let '.a:sname.'=strpart(stack, loc+1, strlen(stack))'
529 let top=strpart(stack, match(stack, '\<'), loc)
530 call s:RestoreKeywords()
531 return top
532endfunction
533
534function! s:Clearstack(sname)
535 exe 'let '.a:sname."=''"
536endfunction
Bram Moolenaar18144c82006-04-12 21:52:12 +0000537" vim:set foldmethod=marker: