xaizek / vim-inccomplete (License: Vim) (since 2018-12-07)
Vim plugin for #include directive completion in C family of languages.
Commit 928e9d61de00df0089d6c032ffea91d89f4637da

Make plugin load faster via autoload directory
Author: xaizek
Author date (UTC): 2020-01-16 22:46
Committer name: xaizek
Committer date (UTC): 2020-01-16 22:46
Parent(s): cf6ea41d35eed1901869bd83e5f2418de58280c2
Signing key: 99DC5E4DB05F6BE2
Tree: e32b3c02982309f9d5ecd213ba2e1909bba734d8
File Lines added Lines deleted
autoload/inccomplete.vim 2 17
plugin/inccomplete.vim 1 614
File autoload/inccomplete.vim copied from file plugin/inccomplete.vim (similarity 97%) (mode: 100644) (index c4edf0e..a099346)
1 1 " Name: inccomplete " Name: inccomplete
2 2 " Author: xaizek <xaizek@posteo.net> " Author: xaizek <xaizek@posteo.net>
3 " Version: 1.8.53
4 3 " License: Same terms as Vim itself (see :help license) " License: Same terms as Vim itself (see :help license)
5 4 " "
6 5 " See :help inccomplete for documentation. " See :help inccomplete for documentation.
7 6
8 if exists('g:loaded_inccomplete')
9 finish
10 endif
11
12 let g:loaded_inccomplete = 1
13 7 let g:inccomplete_cache = {} let g:inccomplete_cache = {}
14 8
15 9 if !exists('g:inccomplete_autoselect') if !exists('g:inccomplete_autoselect')
 
... ... if !exists('g:inccomplete_localsources')
40 34 let g:inccomplete_localsources = [ 'relative-paths' ] let g:inccomplete_localsources = [ 'relative-paths' ]
41 35 endif endif
42 36
43 " initialize inccomplete after all other plugins are loaded
44 augroup inccompleteDeferredInit
45 autocmd!
46 autocmd VimEnter * call s:ICInstallAutocommands()
47 augroup END
48
49 function s:ICInstallAutocommands()
37 function! inccomplete#ICInstallAutocommands()
50 38 augroup inccomplete augroup inccomplete
51 autocmd!
52 autocmd BufRead,BufEnter,FileType * call s:ICInit()
39 autocmd! BufRead,BufEnter,FileType * call s:ICInit()
53 40 augroup END augroup END
54 41
55 42 " VimEnter autocommand is executed after other autocommands we're " VimEnter autocommand is executed after other autocommands we're
 
... ... function! s:ICPrepPaths(lst)
628 615 call filter(a:lst, '!empty(v:val) && v:val != "."') call filter(a:lst, '!empty(v:val) && v:val != "."')
629 616 return map(a:lst, 'fnamemodify(v:val, ":p")') return map(a:lst, 'fnamemodify(v:val, ":p")')
630 617 endfunction endfunction
631
632 " vim: set foldmethod=syntax foldlevel=0 :
File plugin/inccomplete.vim changed (mode: 100644) (index c4edf0e..ef4a207)
... ... if exists('g:loaded_inccomplete')
10 10 endif endif
11 11
12 12 let g:loaded_inccomplete = 1 let g:loaded_inccomplete = 1
13 let g:inccomplete_cache = {}
14
15 if !exists('g:inccomplete_autoselect')
16 let g:inccomplete_autoselect = 1
17 endif
18
19 if !exists('g:inccomplete_findcmd')
20 let g:inccomplete_findcmd = ''
21 endif
22
23 if !exists('g:inccomplete_addclosebracket')
24 let g:inccomplete_addclosebracket = 'always'
25 endif
26
27 if !exists('g:inccomplete_sort')
28 let g:inccomplete_sort = ''
29 endif
30
31 if !exists('g:inccomplete_showdirs')
32 let g:inccomplete_showdirs = 0
33 endif
34
35 if !exists('g:inccomplete_appendslash')
36 let g:inccomplete_appendslash = 0
37 endif
38
39 if !exists('g:inccomplete_localsources')
40 let g:inccomplete_localsources = [ 'relative-paths' ]
41 endif
42 13
43 14 " initialize inccomplete after all other plugins are loaded " initialize inccomplete after all other plugins are loaded
44 15 augroup inccompleteDeferredInit augroup inccompleteDeferredInit
45 autocmd!
46 autocmd VimEnter * call s:ICInstallAutocommands()
16 autocmd! VimEnter * call inccomplete#ICInstallAutocommands()
47 17 augroup END augroup END
48 18
49 function s:ICInstallAutocommands()
50 augroup inccomplete
51 autocmd!
52 autocmd BufRead,BufEnter,FileType * call s:ICInit()
53 augroup END
54
55 " VimEnter autocommand is executed after other autocommands we're
56 " interested in, thus we need to do this for file passed on the command
57 " line manually
58 call s:ICInit()
59 endfunction
60
61 " maps <, ", / and \, sets 'omnifunc'
62 function! s:ICInit()
63 " leave fast if we don't need to do anything for the buffer
64 if !s:ICIsBufferSupported() || &l:omnifunc ==# 'ICComplete'
65 return
66 endif
67
68 " remap < and "
69 inoremap <expr> <buffer> < ICCompleteInc('<')
70 inoremap <expr> <buffer> " ICCompleteInc('"')
71 if g:inccomplete_showdirs
72 inoremap <expr> <buffer> / ICCompleteInc('/')
73 inoremap <expr> <buffer> \ ICCompleteInc('\')
74 endif
75
76 " save current 'omnifunc'
77 let l:curbuf = s:ICGetBufferName()
78 if !exists('s:oldomnifuncs')
79 let s:oldomnifuncs = {}
80 endif
81 let s:oldomnifuncs[l:curbuf] = &omnifunc
82
83 " force menuone. Without it, when there's only one completion result,
84 " it can be confusing (not completing and no popup)
85 if g:inccomplete_autoselect != 2
86 setlocal completeopt-=menu
87 setlocal completeopt+=menuone
88 endif
89
90 " set our omnifunc
91 setlocal omnifunc=ICComplete
92 endfunction
93
94 " checks whether the plugin should be active in current buffer
95 function s:ICIsBufferSupported()
96 for l:component in split(&l:filetype, '\.')
97 if index(['c', 'cpp'], l:component) != -1
98 return 1
99 endif
100 endfor
101 return 0
102 endfunction
103
104 " checks whether we need to do completion after <, ", / or \ and starts it when
105 " we do
106 function! ICCompleteInc(bracket)
107 let l:keycomp = "\<c-x>\<c-o>"
108 if g:inccomplete_autoselect != 2
109 let l:keycomp .= "\<c-p>"
110 if g:inccomplete_autoselect == 1
111 let l:keycomp .= "\<c-r>=(pumvisible() ? \"\\<down>\" : '')\<cr>"
112 endif
113 endif
114
115 if a:bracket == '/' || a:bracket == '\'
116 " complete when there are no closing character or we're right before
117 " it
118 let l:curline = getline('.')
119 if l:curline =~ '^\s*#\s*include\s*["<][^">]*$' ||
120 \ (l:curline =~ '^\s*#\s*include\s*["<][^">]*[">]$' &&
121 \ (l:curline[col('.') - 1] == '"' || l:curline[col('.') - 1 ] == '>'))
122 return a:bracket.l:keycomp
123 endif
124 endif
125
126 " is it #include directive?
127 if getline('.') !~ '^\s*#\s*include\s*$'
128 return a:bracket
129 endif
130
131 if g:inccomplete_addclosebracket == 'always'
132 " determine close bracket
133 let l:closebracket = ['"', '>'][a:bracket == '<']
134
135 " put brackets and start completion
136 return a:bracket.l:closebracket."\<left>".l:keycomp
137 else
138 " put bracket and start completion
139 return a:bracket.l:keycomp
140 endif
141 endfunction
142
143 " this is the 'omnifunc'
144 function! ICComplete(findstart, base)
145 let l:curbuf = s:ICGetBufferName()
146 if a:findstart
147 " did user request #include completion?
148 let s:passnext = getline('.') !~ '^\s*#\s*include\s*\%(<\|"\)'
149 if !s:passnext
150 return match(getline('.'), '<\|"') + 1
151 endif
152
153 " no, call other omnifunc if there is one
154 if !has_key(s:oldomnifuncs, l:curbuf)
155 return col('.') - 1
156 endif
157 return eval(s:oldomnifuncs[l:curbuf].
158 \ "(".a:findstart.",'".a:base."')")
159 elseif exists('s:passnext') && s:passnext
160 " call previous 'omnifunc' when needed
161 if !has_key(s:oldomnifuncs, l:curbuf)
162 return []
163 endif
164 return eval(s:oldomnifuncs[l:curbuf].
165 \ "(".a:findstart.",'".a:base."')")
166 else
167 let l:pos = match(getline('.'), '<\|"')
168 let l:bracket = getline('.')[l:pos : l:pos]
169
170 if empty(a:base) && l:bracket == '<' && exists('s:fullCached')
171 return s:fullCached
172 endif
173
174 let l:old_cwd = getcwd()
175 lcd %:p:h
176
177 " get list of all candidates and reduce it to those starts with a:base
178 let l:inclst = s:ICGetList(l:bracket == '"', a:base)
179 let l:inclst = s:ICFilterIncLst(l:bracket == '"', l:inclst, a:base)
180
181 if g:inccomplete_addclosebracket != 'always'
182 " determine close bracket
183 let l:closebracket = ['"', '>'][l:bracket == '<']
184 if getline('.')[l:pos + 1 :] =~ l:closebracket.'\s*$'
185 let l:closebracket = ''
186 endif
187 else
188 let l:closebracket = ''
189 endif
190
191 " form list of dictionaries
192 let [l:pos, l:sl1, l:sl2] = s:ICParsePath(a:base)
193 let l:comlst = []
194 for l:increc in l:inclst
195 if empty(l:increc[1])
196 continue
197 endif
198
199 let l:isdir = isdirectory(l:increc[0].'/'.l:increc[1])
200 if l:isdir
201 let l:slashidx = strridx(l:increc[1], l:sl2)
202 if l:increc[1][l:slashidx + 1] == '.'
203 continue
204 endif
205
206 let l:strend = g:inccomplete_appendslash ? l:sl2 : ''
207 let l:slash = l:sl2
208 else
209 let l:strend = l:closebracket
210 let l:slash = ''
211 endif
212
213 " XXX: set 'kind' to 'd'/'f' to indicate directory/file?
214 let l:item = {
215 \ 'word': l:increc[1].l:strend,
216 \ 'abbr': l:increc[1].l:slash,
217 \ 'menu': s:ICModifyPath(l:increc[0]),
218 \ 'dup': 0,
219 \ 'dir': l:isdir
220 \}
221 call add(l:comlst, l:item)
222 endfor
223
224 execute 'lcd' l:old_cwd
225
226 let l:result = s:SortList(l:comlst)
227
228 if empty(a:base) && l:bracket == '<'
229 let s:fullCached = l:result
230 endif
231
232 return l:result
233 endif
234 endfunction
235
236 " sorts completion list
237 function s:SortList(lst)
238 if g:inccomplete_sort == 'ignorecase'
239 return sort(a:lst, 's:IgnoreCaseComparer')
240 else
241 return sort(a:lst, 's:Comparer')
242 endif
243 endfunction
244 function s:IgnoreCaseComparer(i1, i2)
245 if a:i1['dir'] != a:i2['dir']
246 return a:i1['dir'] ? -1 : 1
247 endif
248 if a:i1['menu'] != a:i2['menu']
249 return a:i1['menu'] < a:i2['menu'] ? -1 : 1
250 endif
251 return a:i1['abbr'] == a:i2['abbr'] ? 0 :
252 \ (a:i1['abbr'] > a:i2['abbr'] ? 1 : -1)
253 endfunction
254 function s:Comparer(i1, i2)
255 if a:i1['dir'] != a:i2['dir']
256 return a:i1['dir'] ? -1 : 1
257 endif
258 if a:i1['menu'] != a:i2['menu']
259 return a:i1['menu'] < a:i2['menu'] ? -1 : 1
260 endif
261 return a:i1['abbr'] ==# a:i2['abbr'] ? 0 :
262 \ (a:i1['abbr'] ># a:i2['abbr'] ? 1 : -1)
263 endfunction
264
265 " modifies path correctly on Windows
266 function! s:ICModifyPath(path)
267 let l:drive_regexp = '\C^[a-zA-Z]:'
268 let l:modified = fnamemodify(a:path, ':p:.')
269 let l:prefix = ''
270 if has('win32') && a:path =~ l:drive_regexp && !empty(l:modified)
271 let l:prefix = matchstr(a:path, l:drive_regexp)
272 endif
273 return l:prefix.l:modified
274 endfunction
275
276 " filters search results
277 function! s:ICFilterIncLst(user, inclst, base)
278 let [l:pos, l:sl1, l:sl2] = s:ICParsePath(a:base)
279
280 " filter by filename
281 let l:filebegin = a:base[strridx(a:base, l:sl2) + 1:]
282 let l:inclst = filter(copy(a:inclst),
283 \ '!empty(v:val[1]) && v:val[1] =~ "^".l:filebegin')
284
285 " correct slashes in paths
286 if l:sl1 == '/'
287 call map(l:inclst, '[substitute(v:val[0], "\\\\", "/", "g"), v:val[1]]')
288 else
289 call map(l:inclst, '[substitute(v:val[0], "/", "\\\\", "g"), v:val[1]]')
290 endif
291
292 " handle multicomponent paths (e.g. "a/...", <boost/...>)
293 if l:pos >= 0
294 let l:lst = []
295 for l:dir in s:ICGetUserSources()
296 let l:lst += s:ICFilter(a:user, l:inclst, a:base, l:dir)
297 endfor
298 let l:inclst = l:lst
299 endif
300
301 return l:inclst
302 endfunction
303
304 " filters multicomponent paths
305 function! s:ICFilter(user, inclst, base, dir)
306 let [l:pos, l:sl1, l:sl2] = s:ICParsePath(a:base)
307
308 let l:inclst = copy(a:inclst)
309
310 " filter by subdirectory name
311 let l:dirend0 = a:base[:l:pos]
312 if a:user
313 let l:dirend1 = fnamemodify(s:ICChosp(a:dir).'/'.l:dirend0, ':p')
314 else
315 let l:dirend1 = l:dirend0
316 endif
317 if l:sl1 == '/'
318 let l:dirend2 = substitute(l:dirend1, "\\\\", "/", "g")
319 else
320 let l:dirend2 = escape(l:dirend1, '\')
321 endif
322 if a:user
323 " filter items by full path, leave only exact matches or direct children
324 " (match full pattern or have at most one more trailing path entry)
325 call filter(
326 \ l:inclst,
327 \ 'v:val[0]."/".v:val[1] =~ "^".l:dirend2."\\($\\|[\\/]*[^\\/]*$\\)"')
328 else
329 call filter(l:inclst, 'v:val[0] =~ "'.l:sl1.'".l:dirend2."\\?$"')
330 endif
331
332 " move end of each path to the beginning of filename
333 let l:cutidx = - (l:pos + 2)
334 if !empty(l:inclst) && l:inclst[0][0][l:cutidx + 1:] != l:dirend0
335 \ && a:user
336 let l:dir = s:ICGetDir()
337 let l:path = s:ICChosp(fnamemodify(l:dir.'/'.l:dirend0, ':p'))
338 call map(l:inclst, '[ v:val[0] == l:path ? l:dir : v:val[0][:l:cutidx],'
339 \.' l:dirend0.v:val[1] ]')
340 else
341 call map(l:inclst, '[v:val[0][:l:cutidx], l:dirend0.v:val[1]]')
342 endif
343
344 return l:inclst
345 endfunction
346
347 " drops all trailing slashes from path
348 function! s:ICChosp(path)
349 let l:path = a:path
350 while len(l:path) > 1 && (l:path[-1:] == '/' || l:path[-1:] == '\')
351 let l:path = l:path[:-2]
352 endwhile
353 return l:path
354 endfunction
355
356 " searches for files that can be included in path
357 " a:user determines search area, when it's not zero look only in '.', otherwise
358 " everywhere in path except '.'
359 function! s:ICGetList(user, base)
360 if a:user
361 let l:dirs = s:ICGetUserSources()
362 let l:dirs = s:ICAddNoDupPaths(l:dirs, s:ICGetSubDirs(l:dirs, a:base))
363 return s:ICFindIncludes(1, l:dirs)
364 endif
365
366 " prepare list of directories
367 let l:pathlst = s:ICAddNoDupPaths(split(&path, ','),
368 \ s:ICGetClangIncludes(2))
369 let l:pathlst = s:ICAddNoDupPaths(l:pathlst,
370 \ s:ICGetSubDirs(l:pathlst, a:base))
371 call reverse(sort(l:pathlst))
372
373 " divide it into sublists
374 let l:noncached = filter(copy(l:pathlst),
375 \ '!has_key(g:inccomplete_cache, v:val)')
376 let l:cached = filter(l:pathlst, 'has_key(g:inccomplete_cache, v:val)')
377
378 " add noncached entries
379 let l:result = s:ICFindIncludes(0, l:noncached)
380
381 " add cached entries
382 for l:incpath in l:cached
383 call map(copy(g:inccomplete_cache[l:incpath]),
384 \ 'add(l:result, [l:incpath, v:val])')
385 endfor
386
387 return l:result
388 endfunction
389
390 " returns list of paths to directories which should be searched for
391 " ""-completion
392 function! s:ICGetUserSources()
393 let l:dirs = []
394
395 for l:source in g:inccomplete_localsources
396 if l:source ==# 'relative-paths'
397 let l:dirs += [s:ICGetDir()]
398 elseif l:source ==# 'clang-buffer'
399 let l:dirs = s:ICAddNoDupPaths(l:dirs, s:ICGetClangIncludes(1))
400 elseif l:source ==# 'clang-global'
401 let l:dirs = s:ICAddNoDupPaths(l:dirs, s:ICGetClangIncludes(0))
402 elseif l:source ~= '/' && isdirectory(l:source)
403 let l:dirs += [ l:source ]
404 endif
405 endfor
406
407 if exists('b:inccomplete_root')
408 let l:dirs = s:ICAddNoDupPaths(l:dirs, [b:inccomplete_root])
409 endif
410
411 if exists('b:inccomplete_roots')
412 let l:dirs = s:ICAddNoDupPaths(l:dirs, b:inccomplete_roots)
413 endif
414
415 return l:dirs
416 endfunction
417
418 " gets directory of the current buffer
419 function! s:ICGetDir()
420 let l:curbuf = s:ICGetBufferName()
421 let l:dir = fnamemodify(l:curbuf, ':p:h')
422 return l:dir
423 endfunction
424
425 " gets name of the current buffer
426 function! s:ICGetBufferName()
427 let l:curbuf = expand('%:p')
428 if empty(l:curbuf)
429 let l:curbuf = getcwd() . '/vim_buffer_without_name_' . bufnr('%')
430 endif
431 return l:curbuf
432 endfunction
433
434 " gets list of header files using find
435 function! s:ICFindIncludes(user, pathlst)
436 " test arguments
437 if empty(a:pathlst)
438 return []
439 endif
440 let l:exts = '\('.escape(join(s:ICGetExtensions(a:user), '\|'), '.').'\)'
441 if !a:user
442 if empty(g:inccomplete_findcmd)
443 let l:regex = '.*[/\\][-_a-z0-9]\+'.l:exts.'$'
444 else
445 let l:regex = '.*[/\\][-_a-z0-9]+'.l:exts.'$'
446 endif
447 else
448 let l:regex = '.*'.l:exts.'$'
449 endif
450
451 " execute find
452 if empty(g:inccomplete_findcmd)
453 let l:pathstr = substitute(join(a:pathlst, ','), '\\', '/', 'g')
454 let l:found = globpath(l:pathstr, '*', 1)
455 let l:foundlst = split(l:found, '\n')
456
457 if g:inccomplete_showdirs
458 call filter(l:foundlst,
459 \ "v:val =~ '".l:regex."' || isdirectory(v:val)")
460 else
461 call filter(l:foundlst, "v:val =~ '".l:regex."'")
462 endif
463 else
464 " substitute in the next command is for Windows (it removes backslash in
465 " \" sequence, that can appear after escaping the path)
466 let l:substcmd = 'substitute(shellescape(v:val), ''\(.*\)\\\"$'','.
467 \ ' "\\1\"", "")'
468
469 let l:pathstr = join(map(copy(a:pathlst), l:substcmd), ' ')
470 let l:iregex = ' -iregex '.shellescape(l:regex)
471 let l:dirs = g:inccomplete_showdirs ? ' -or -type d' : ''
472 let l:found = system(g:inccomplete_findcmd.' -L '.
473 \ l:pathstr.' -maxdepth 1 -type f'.l:iregex.l:dirs)
474 let l:foundlst = split(l:found, '\n')
475 endif
476 unlet l:found " to free some memory
477
478 " prepare a:pathlst by forming regexps
479 for l:i in range(len(a:pathlst))
480 let l:path = a:pathlst[i]
481 if l:path != '/' && l:path[-1:] == '/'
482 let l:path = l:path[:-2]
483 endif
484 let g:inccomplete_cache[l:path] = []
485 let l:tmp = substitute(l:path, '\', '/', 'g')
486 let a:pathlst[i] = [l:path, '^'.escape(l:tmp, '.')]
487 endfor
488
489 " process the results of find
490 let l:result = []
491 for l:file in l:foundlst
492 let l:file = substitute(l:file, '\', '/', 'g')
493 if l:file[-1:] == '/'
494 let l:file = l:file[:-2]
495 endif
496 " find appropriate parent path ("." at the end forbids exact match)
497 let l:pathlst = filter(copy(a:pathlst),
498 \ 'fnamemodify(l:file, ":h") == v:val[0]')
499 if empty(l:pathlst)
500 continue
501 endif
502 let l:incpath = l:pathlst[0][0]
503 " add entry to list
504 let l:left = l:file[len(l:incpath):]
505 if l:left[0] == '/' || l:left[0] == '\'
506 let l:left = l:left[1:]
507 endif
508 call add(l:result, [l:incpath, l:left])
509 " and to cache
510 call add(g:inccomplete_cache[l:incpath], l:left)
511 endfor
512 return l:result
513 endfunction
514
515 " retrieves set of extensions acceptable for completion
516 function s:ICGetExtensions(user)
517 if s:ICIsCxxBuffer()
518 return a:user ? ['.hpp', '.h'] : ['.hpp', '.h', '']
519 endif
520 return ['.h']
521 endfunction
522
523 " checks whether current buffer is of C++ kind
524 function s:ICIsCxxBuffer()
525 return index(split(&l:filetype, '\.'), 'cpp') != -1
526 endfunction
527
528 " retrieves include directories from b:clang_user_options and
529 " g:clang_user_options
530 " possible values of which:
531 " - 0 -- only g:clang_user_options
532 " - 1 -- only b:clang_user_options
533 " - 2 -- both options
534 function! s:ICGetClangIncludes(which)
535 let l:opts = ''
536 if a:which != 0 && exists('b:clang_user_options')
537 let l:opts .= b:clang_user_options.' '
538 endif
539 if a:which != 1 && exists('g:clang_user_options')
540 let l:opts .= g:clang_user_options.' '
541 endif
542 if empty(l:opts)
543 return []
544 endif
545
546 let l:lst = split(l:opts, ' ')
547 let l:lst = filter(l:lst, 'v:val =~ "\\C^-I"')
548 let l:lst = map(l:lst, 'v:val[2:]')
549 let l:lst = map(l:lst, 'fnamemodify(v:val, ":p")')
550 let l:lst = map(l:lst, 'substitute(v:val, "\\\\", "/", "g")')
551
552 " While transforming relative paths into absolute ones clang_complete adds
553 " escaping in the form of single or double quotes, try to get rid of them.
554 " Otherwise we end up with list of paths some of which don't exist.
555 let l:result = []
556 for l:item in l:lst
557 if l:item[0] == "'"
558 let l:last = strridx(l:item, "'")
559 let l:item = l:item[1 : l:last - 1] . l:item[l:last + 1:]
560 elseif l:item[0] == '"'
561 let l:last = strridx(l:item, '"')
562 let l:item = l:item[1 : l:last - 1] . l:item[l:last + 1:]
563 endif
564 let l:result += [l:item]
565 endfor
566
567 return l:result
568 endfunction
569
570 " searches for existing subdirectories
571 function! s:ICGetSubDirs(pathlst, base)
572 let [l:pos, l:sl, l:sl2] = s:ICParsePath(a:base)
573 if l:pos < 0
574 return []
575 endif
576
577 " search
578 let l:dirend = a:base[:l:pos]
579 let l:pathlst = join(a:pathlst, ',')
580 " escape spaces in paths (seems to be needed on Windows, does not harm on
581 " other systems)
582 let l:pathlst = substitute(l:pathlst, ' ', '\\ ', 'g')
583 let l:subdirs = finddir(l:dirend, l:pathlst, -1)
584
585 " path expanding
586 call map(l:subdirs, 'fnamemodify(v:val, ":p:h")')
587
588 " ensure that path ends with slash
589 let l:mapcmd = 'substitute(v:val, "\\([^'.l:sl.']\\)$", "\\1'.l:sl.'", "g")'
590 call map(l:subdirs, l:mapcmd)
591
592 return l:subdirs
593 endfunction
594
595 " returns list of three elements: [name_pos, slash_for_regexps, ordinary_slash]
596 function! s:ICParsePath(path)
597 let l:iswindows = has('win16') || has('win32') || has('win64') ||
598 \ has('win95')
599
600 " determine type of slash
601 let l:path = a:path
602 let l:pos = strridx(a:path, '/')
603 let l:sl1 = '/'
604 let l:sl2 = '/'
605 if l:iswindows && (empty(a:path) || l:pos < 0)
606 let l:pos = strridx(a:path, '\')
607 let l:sl1 = '\\\\'
608 let l:sl2 = '\'
609 endif
610 return [l:pos, l:sl1, l:sl2]
611 endfunction
612
613 " adds one list of paths to another without duplicating items
614 function! s:ICAddNoDupPaths(lista, listb)
615 let l:result = []
616 call s:ICPrepPaths(a:lista)
617 call s:ICPrepPaths(a:listb)
618 for l:item in a:lista + a:listb
619 if index(l:result, l:item) == -1
620 call add(l:result, l:item)
621 endif
622 endfor
623 return l:result
624 endfunction
625
626 " converts list of paths to a list of absolute paths and excudes '.' directory
627 function! s:ICPrepPaths(lst)
628 call filter(a:lst, '!empty(v:val) && v:val != "."')
629 return map(a:lst, 'fnamemodify(v:val, ":p")')
630 endfunction
631
632 19 " vim: set foldmethod=syntax foldlevel=0 : " vim: set foldmethod=syntax foldlevel=0 :
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/vim-inccomplete

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/vim-inccomplete

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master