Mercurial > vim
comparison runtime/plugin/explorer.vim @ 7:3fc0f57ecb91 v7.0001
updated for version 7.0001
author | vimboss |
---|---|
date | Sun, 13 Jun 2004 20:20:40 +0000 |
parents | |
children | 4e2284e71352 |
comparison
equal
deleted
inserted
replaced
6:c2daee826b8f | 7:3fc0f57ecb91 |
---|---|
1 "============================================================================= | |
2 " File: explorer.vim | |
3 " Author: M A Aziz Ahmed (aziz@acorn-networks.com - doesn't work) | |
4 " Last Change: 2004 May 13 | |
5 " Version: 2.5 + changes | |
6 " Additions by Mark Waggoner (waggoner@aracnet.com) et al. | |
7 "----------------------------------------------------------------------------- | |
8 " This file implements a file explorer. | |
9 "----------------------------------------------------------------------------- | |
10 " Normally, this file will reside in the plugins directory and be | |
11 " automatically sourced. If not, you must manually source this file | |
12 " using :source explorer.vim | |
13 " | |
14 " To use it, just edit a directory (vi dirname) or type :Explore to | |
15 " launch the file explorer in the current window, or :Sexplore to split | |
16 " the current window and launch explorer there. | |
17 " | |
18 " If the current buffer is modified, the window is always split. | |
19 " | |
20 " It is also possible to delete files and rename files within explorer. | |
21 " See :help file-explorer for more details | |
22 " | |
23 "----------------------------------------------------------------------------- | |
24 " Update history removed, it's not very interesting. | |
25 " Contributors were: Doug Potts, Bram Moolenaar, Thomas Köhler | |
26 "============================================================================= | |
27 | |
28 " Has this already been loaded? | |
29 if exists("loaded_explorer") | |
30 finish | |
31 endif | |
32 let loaded_explorer=1 | |
33 | |
34 " Line continuation used here | |
35 let s:cpo_save = &cpo | |
36 set cpo&vim | |
37 | |
38 "--- | |
39 " Default settings for global configuration variables | |
40 | |
41 " Split vertically instead of horizontally? | |
42 if !exists("g:explVertical") | |
43 let g:explVertical=0 | |
44 endif | |
45 | |
46 " How big to make the window? Set to "" to avoid resizing | |
47 if !exists("g:explWinSize") | |
48 let g:explWinSize=15 | |
49 endif | |
50 | |
51 " When opening a new file/directory, split below current window (or | |
52 " above)? 1 = below, 0 = to above | |
53 if !exists("g:explSplitBelow") | |
54 let g:explSplitBelow = &splitbelow | |
55 endif | |
56 | |
57 " Split to right of current window (or to left)? | |
58 " 1 = to right, 0 = to left | |
59 if !exists("g:explSplitRight") | |
60 let g:explSplitRight = &splitright | |
61 endif | |
62 | |
63 " Start the first explorer window... | |
64 " Defaults to be the same as explSplitBelow | |
65 if !exists("g:explStartBelow") | |
66 let g:explStartBelow = g:explSplitBelow | |
67 endif | |
68 | |
69 " Start the first explorer window... | |
70 " Defaults to be the same as explSplitRight | |
71 if !exists("g:explStartRight") | |
72 let g:explStartRight = g:explSplitRight | |
73 endif | |
74 | |
75 " Show detailed help? | |
76 if !exists("g:explDetailedHelp") | |
77 let g:explDetailedHelp=0 | |
78 endif | |
79 | |
80 " Show file size and dates? | |
81 if !exists("g:explDetailedList") | |
82 let g:explDetailedList=0 | |
83 endif | |
84 | |
85 " Format for the date | |
86 if !exists("g:explDateFormat") | |
87 let g:explDateFormat="%d %b %Y %H:%M" | |
88 endif | |
89 | |
90 " Files to hide | |
91 if !exists("g:explHideFiles") | |
92 let g:explHideFiles='' | |
93 endif | |
94 | |
95 " Field to sort by | |
96 if !exists("g:explSortBy") | |
97 let g:explSortBy='name' | |
98 endif | |
99 | |
100 " Segregate directories? 1, 0, or -1 | |
101 if !exists("g:explDirsFirst") | |
102 let g:explDirsFirst=1 | |
103 endif | |
104 | |
105 " Segregate items in suffixes option? 1, 0, or -1 | |
106 if !exists("g:explSuffixesLast") | |
107 let g:explSuffixesLast=1 | |
108 endif | |
109 | |
110 " Include separator lines between directories, files, and suffixes? | |
111 if !exists("g:explUseSeparators") | |
112 let g:explUseSeparators=0 | |
113 endif | |
114 | |
115 " Execute file handler | |
116 if !exists("g:explFileHandler") | |
117 if has("win32") | |
118 " for Win32 use rundll32 | |
119 function! s:explFileHandlerWin32(fn) | |
120 exec 'silent !start rundll32 url.dll,FileProtocolHandler "' | |
121 \ . escape(a:fn, '%#') . '"' | |
122 endfunction | |
123 let g:explFileHandler = "<SID>explFileHandlerWin32" | |
124 | |
125 elseif has("unix") | |
126 " for KDE use kfmclient, for GNUME use gnome-open | |
127 if executable("kfmclient") | |
128 let g:explFileHandlerCmd = "kfmclient exec" | |
129 elseif executable("gnome-open") | |
130 let g:explFileHandlerCmd = "gnome-open" | |
131 else | |
132 let g:explFileHandlerCmd = "" | |
133 endif | |
134 if g:explFileHandlerCmd != "" | |
135 function! s:explFileHandlerUnix(fn) | |
136 if &shellredir =~ "%s" | |
137 let redir = substitute(&shellredir, "%s", "/dev/null", "") | |
138 else | |
139 let redir = &shellredir . "/dev/null" | |
140 endif | |
141 " Need to escape % and # but not spaces. | |
142 exec "silent !" . g:explFileHandlerCmd . " '" . escape(a:fn, '%#') . "'" . redir | |
143 endfunction | |
144 let g:explFileHandler = "<SID>explFileHandlerUnix" | |
145 endif | |
146 endif | |
147 endif | |
148 | |
149 "--- | |
150 " script variables - these are the same across all | |
151 " explorer windows | |
152 | |
153 " characters that must be escaped for a regular expression | |
154 let s:escregexp = '/*^$.~\' | |
155 | |
156 " characters that must be escaped for filenames | |
157 if has("dos16") || has("dos32") || has("win16") || has("win32") || has("os2") | |
158 let s:escfilename = ' %#' | |
159 else | |
160 let s:escfilename = ' \%#[]' | |
161 endif | |
162 | |
163 | |
164 " A line to use for separating sections | |
165 let s:separator='"---------------------------------------------------' | |
166 | |
167 "--- | |
168 " Create commands | |
169 | |
170 if !exists(':Explore') | |
171 command -n=? -complete=dir Explore :call s:StartExplorer(0, '<a>') | |
172 endif | |
173 if !exists(':Sexplore') | |
174 command -n=? -complete=dir Sexplore :call s:StartExplorer(1, '<a>') | |
175 endif | |
176 | |
177 "--- | |
178 " Start the explorer using the preferences from the global variables | |
179 " | |
180 function! s:StartExplorer(split, start_dir) | |
181 let startcmd = "edit" | |
182 if a:start_dir != "" | |
183 let fname=a:start_dir | |
184 else | |
185 let fname = expand("%:p:h") | |
186 endif | |
187 if fname == "" | |
188 let fname = getcwd() | |
189 endif | |
190 | |
191 " Create a variable to use if splitting vertically | |
192 let splitMode = "" | |
193 if g:explVertical == 1 | |
194 let splitMode = "vertical" | |
195 endif | |
196 | |
197 " Save the user's settings for splitbelow and splitright | |
198 let savesplitbelow = &splitbelow | |
199 let savesplitright = &splitright | |
200 | |
201 if a:split || &modified | |
202 let startcmd = splitMode . " " . g:explWinSize . "new " . fname | |
203 let &splitbelow = g:explStartBelow | |
204 let &splitright = g:explStartRight | |
205 else | |
206 let startcmd = "edit " . fname | |
207 endif | |
208 silent execute startcmd | |
209 let &splitbelow = savesplitbelow | |
210 let &splitright = savesplitright | |
211 endfunction | |
212 | |
213 "--- | |
214 " This is the main entry for 'editing' a directory | |
215 " | |
216 function! s:EditDir() | |
217 " Get out of here right away if this isn't a directory! | |
218 let name = expand("%") | |
219 if name == "" | |
220 let name = expand("%:p") | |
221 endif | |
222 if !isdirectory(name) | |
223 return | |
224 endif | |
225 | |
226 " Turn off the swapfile, set the buffer type so that it won't get | |
227 " written, and so that it will get deleted when it gets hidden. | |
228 setlocal noreadonly modifiable | |
229 setlocal noswapfile | |
230 setlocal buftype=nowrite | |
231 setlocal bufhidden=delete | |
232 " Don't wrap around long lines | |
233 setlocal nowrap | |
234 | |
235 " No need for any insertmode abbreviations, since we don't allow | |
236 " insertions anyway! | |
237 iabc <buffer> | |
238 | |
239 " Long or short listing? Use the global variable the first time | |
240 " explorer is called, after that use the script variable as set by | |
241 " the interactive user. | |
242 if exists("s:longlist") | |
243 let w:longlist = s:longlist | |
244 else | |
245 let w:longlist = g:explDetailedList | |
246 endif | |
247 | |
248 " Show keyboard shortcuts? | |
249 if exists("s:longhelp") | |
250 let w:longhelp = s:longhelp | |
251 else | |
252 let w:longhelp = g:explDetailedHelp | |
253 endif | |
254 | |
255 " Set the sort based on the global variables the first time. If you | |
256 " later change the sort order, it will be retained in the s:sortby | |
257 " variable for the next time you open explorer | |
258 let w:sortdirection=1 | |
259 let w:sortdirlabel = "" | |
260 let w:sorttype = "" | |
261 if exists("s:sortby") | |
262 let sortby=s:sortby | |
263 else | |
264 let sortby=g:explSortBy | |
265 endif | |
266 if sortby =~ "reverse" | |
267 let w:sortdirection=-1 | |
268 let w:sortdirlabel = "reverse " | |
269 endif | |
270 if sortby =~ "date" | |
271 let w:sorttype = "date" | |
272 elseif sortby =~ "size" | |
273 let w:sorttype = "size" | |
274 else | |
275 let w:sorttype = "name" | |
276 endif | |
277 call s:SetSuffixesLast() | |
278 | |
279 " If directory is already loaded, don't open it again! | |
280 if line('$') > 1 | |
281 setlocal readonly nomodifiable | |
282 return | |
283 endif | |
284 | |
285 " Get the complete path to the directory to look at with a slash at | |
286 " the end. This also removes "/../" and "/./" things. | |
287 let b:completePath = s:Path(expand("%:p")) | |
288 | |
289 " Add a slash at the end | |
290 if b:completePath !~ '/$' | |
291 let b:completePath = b:completePath . '/' | |
292 endif | |
293 | |
294 " escape special characters for exec commands | |
295 let b:completePathEsc = escape(b:completePath, s:escfilename) | |
296 let b:parentDirEsc = substitute(b:completePathEsc, '/[^/]*/$', '/', 'g') | |
297 | |
298 " Set up syntax highlighting | |
299 " Something wrong with the evaluation of the conditional though... | |
300 if has("syntax") && exists("g:syntax_on") && !has("syntax_items") | |
301 syn match browseSynopsis "^\"[ -].*" | |
302 syn match browseDirectory "[^\"].*/ " | |
303 syn match browseDirectory "[^\"].*/$" | |
304 syn match browseCurDir "^\"= .*$" | |
305 syn match browseSortBy "^\" Sorted by .*$" contains=browseSuffixInfo | |
306 syn match browseSuffixInfo "(.*)$" contained | |
307 syn match browseFilter "^\" Not Showing:.*$" | |
308 syn match browseFiletime "««\d\+$" | |
309 exec('syn match browseSuffixes "' . b:suffixesHighlight . '"') | |
310 | |
311 "hi def link browseSynopsis PreProc | |
312 hi def link browseSynopsis Special | |
313 hi def link browseDirectory Directory | |
314 hi def link browseCurDir Statement | |
315 hi def link browseSortBy String | |
316 hi def link browseSuffixInfo Type | |
317 hi def link browseFilter String | |
318 hi def link browseFiletime Ignore | |
319 hi def link browseSuffixes Type | |
320 endif | |
321 | |
322 " Set filter for hiding files | |
323 let b:filterFormula=substitute(g:explHideFiles, '\([^\\]\),', '\1\\|', 'g') | |
324 if b:filterFormula != '' | |
325 let b:filtering="\nNot showing: " . b:filterFormula | |
326 else | |
327 let b:filtering="" | |
328 endif | |
329 | |
330 " Show the files | |
331 call s:ShowDirectory() | |
332 | |
333 " Set up mappings for this buffer | |
334 let cpo_save = &cpo | |
335 set cpo&vim | |
336 nnoremap <buffer> <cr> :call <SID>EditEntry("","edit")<cr> | |
337 nnoremap <buffer> - :exec ("silent e " . b:parentDirEsc)<cr> | |
338 if exists("g:explFileHandler") | |
339 nnoremap <buffer> x :call <SID>ExecuteEntry()<cr> | |
340 endif | |
341 nnoremap <buffer> o :call <SID>OpenEntry()<cr> | |
342 nnoremap <buffer> O :call <SID>OpenEntryPrevWindow()<cr> | |
343 nnoremap <buffer> p :call <SID>EditEntry("","pedit")<cr> | |
344 nnoremap <buffer> ? :call <SID>ToggleHelp()<cr> | |
345 nnoremap <buffer> a :call <SID>ShowAllFiles()<cr> | |
346 nnoremap <buffer> R :call <SID>RenameFile()<cr> | |
347 nnoremap <buffer> D :. call <SID>DeleteFile()<cr> | |
348 vnoremap <buffer> D :call <SID>DeleteFile()<cr> | |
349 nnoremap <buffer> i :call <SID>ToggleLongList()<cr> | |
350 nnoremap <buffer> s :call <SID>SortSelect()<cr> | |
351 nnoremap <buffer> r :call <SID>SortReverse()<cr> | |
352 nnoremap <buffer> c :exec "cd ".b:completePathEsc<cr> | |
353 nnoremap <buffer> <2-leftmouse> :call <SID>DoubleClick()<cr> | |
354 if exists("*ExplorerCustomMap") | |
355 call ExplorerCustomMap() | |
356 endif | |
357 let &cpo = cpo_save | |
358 | |
359 " prevent the buffer from being modified | |
360 setlocal readonly nomodifiable | |
361 endfunction | |
362 | |
363 "--- | |
364 " Determine the number of windows open to this buffer number. | |
365 " Care of Yegappan Lakshman. Thanks! | |
366 fun! s:BufInWindows(bnum) | |
367 let cnt = 0 | |
368 let winnum = 1 | |
369 while 1 | |
370 let bufnum = winbufnr(winnum) | |
371 if bufnum < 0 | |
372 break | |
373 endif | |
374 if bufnum == a:bnum | |
375 let cnt = cnt + 1 | |
376 endif | |
377 let winnum = winnum + 1 | |
378 endwhile | |
379 | |
380 return cnt | |
381 endfunction | |
382 | |
383 " If this is the only window, open file in a new window | |
384 " Otherwise, open file in the most recently visited window | |
385 " | |
386 function! s:OpenEntryPrevWindow() | |
387 " Figure out if there are any other windows | |
388 let n = winnr() | |
389 wincmd p | |
390 " No other window? Then open a new one | |
391 if n == winnr() | |
392 call s:OpenEntry() | |
393 " Other windows exist | |
394 else | |
395 " Check if the previous buffer is modified - ask if they want to save! | |
396 " Was it modified, and is it the only window open to this file | |
397 if &modified && s:BufInWindows(winbufnr(winnr())) < 2 | |
398 let bufname = bufname(winbufnr(winnr())) | |
399 | |
400 let action=confirm("Save Changes in " . bufname . "?","&Yes\n&No\n&Cancel") | |
401 " Yes - try to save - if there is an error, cancel | |
402 if action == 1 | |
403 let v:errmsg = "" | |
404 silent w | |
405 if v:errmsg != "" | |
406 echoerr "Unable to write buffer!" | |
407 wincmd p | |
408 return | |
409 endif | |
410 " No, abandon changes | |
411 elseif action == 2 | |
412 set nomodified | |
413 echomsg "Warning, abandoning changes in " . bufname | |
414 " Cancel (or any other result), don't do the open | |
415 else | |
416 wincmd p | |
417 return | |
418 endif | |
419 endif | |
420 wincmd p | |
421 call s:EditEntry("wincmd p","edit") | |
422 endif | |
423 endfunction | |
424 | |
425 | |
426 "--- | |
427 " Open a file or directory in a new window. | |
428 " Use g:explSplitBelow and g:explSplitRight to decide where to put the | |
429 " split window, and resize the original explorer window if it is | |
430 " larger than g:explWinSize | |
431 " | |
432 function! s:OpenEntry() | |
433 " Are we on a line with a file name? | |
434 let l = getline(".") | |
435 if l =~ '^"' | |
436 return | |
437 endif | |
438 | |
439 " Copy window settings to script settings | |
440 let s:sortby=w:sortdirlabel . w:sorttype | |
441 let s:longhelp = w:longhelp | |
442 let s:longlist = w:longlist | |
443 | |
444 " Get the window number of the explorer window | |
445 let n = winnr() | |
446 | |
447 " Save the user's settings for splitbelow and splitright | |
448 let savesplitbelow=&splitbelow | |
449 let savesplitright=&splitright | |
450 | |
451 " Figure out how to do the split based on the user's preferences. | |
452 " We want to split to the (left,right,top,bottom) of the explorer | |
453 " window, but we want to extract the screen real-estate from the | |
454 " window next to the explorer if possible. | |
455 " | |
456 " 'there' will be set to a command to move from the split window | |
457 " back to the explorer window | |
458 " | |
459 " 'back' will be set to a command to move from the explorer window | |
460 " back to the newly split window | |
461 " | |
462 " 'right' and 'below' will be set to the settings needed for | |
463 " splitbelow and splitright IF the explorer is the only window. | |
464 " | |
465 if g:explVertical | |
466 if g:explSplitRight | |
467 let there="wincmd h" | |
468 let back ="wincmd l" | |
469 let right=1 | |
470 let below=0 | |
471 else | |
472 let there="wincmd l" | |
473 let back ="wincmd h" | |
474 let right=0 | |
475 let below=0 | |
476 endif | |
477 else | |
478 if g:explSplitBelow | |
479 let there="wincmd k" | |
480 let back ="wincmd j" | |
481 let right=0 | |
482 let below=1 | |
483 else | |
484 let there="wincmd j" | |
485 let back ="wincmd k" | |
486 let right=0 | |
487 let below=0 | |
488 endif | |
489 endif | |
490 | |
491 " Get the file name | |
492 let fn=s:GetFullFileName() | |
493 | |
494 " Attempt to go to adjacent window | |
495 exec(back) | |
496 " If no adjacent window, set splitright and splitbelow appropriately | |
497 if n == winnr() | |
498 let &splitright=right | |
499 let &splitbelow=below | |
500 else | |
501 " found adjacent window - invert split direction | |
502 let &splitright=!right | |
503 let &splitbelow=!below | |
504 endif | |
505 | |
506 " Create a variable to use if splitting vertically | |
507 let splitMode = "" | |
508 if g:explVertical == 1 | |
509 let splitMode = "vertical" | |
510 endif | |
511 | |
512 " Is it a directory? If so, get a real path to it instead of | |
513 " relative path. This also removes "/../" and "/./" things. | |
514 if isdirectory(fn) | |
515 let fn = fnamemodify(fn, ":p") | |
516 endif | |
517 | |
518 " Open the new window | |
519 exec("silent " . splitMode." sp " . escape(fn,s:escfilename)) | |
520 | |
521 " resize the explorer window if it is larger than the requested size | |
522 exec(there) | |
523 if g:explWinSize =~ '[0-9]\+' && winheight("") > g:explWinSize | |
524 exec("silent ".splitMode." resize ".g:explWinSize) | |
525 endif | |
526 exec(back) | |
527 | |
528 " Restore splitmode settings | |
529 let &splitbelow=savesplitbelow | |
530 let &splitright=savesplitright | |
531 | |
532 endfunction | |
533 | |
534 function! s:ExecuteEntry() | |
535 " Are we on a line with a file name? | |
536 let l = getline(".") | |
537 if l =~ '^"' | |
538 return | |
539 endif | |
540 | |
541 " Get the file name | |
542 let fn = s:GetFullFileName() | |
543 if has("win32") && fn =~ '^//' | |
544 let fn = substitute(fn, '/', '\\', 'g') | |
545 endif | |
546 exec "call " . g:explFileHandler . "(fn)" | |
547 endfunction | |
548 | |
549 "--- | |
550 " Double click with the mouse | |
551 " | |
552 function s:DoubleClick() | |
553 if expand("<cfile>") =~ '[\\/]$' | |
554 call s:EditEntry("","edit") " directory: open in this window | |
555 else | |
556 call s:OpenEntryPrevWindow() " file: open in another window | |
557 endif | |
558 endfun | |
559 | |
560 "--- | |
561 " Open file or directory in the same window as the explorer is | |
562 " currently in | |
563 " | |
564 function! s:EditEntry(movefirst,editcmd) | |
565 " Are we on a line with a file name? | |
566 let l = getline(".") | |
567 if l =~ '^"' | |
568 return | |
569 endif | |
570 | |
571 " Copy window settings to script settings | |
572 let s:sortby=w:sortdirlabel . w:sorttype | |
573 let s:longhelp = w:longhelp | |
574 let s:longlist = w:longlist | |
575 | |
576 " Get the file name | |
577 let fn = s:GetFullFileName() | |
578 if isdirectory(fn) | |
579 " This removes "/../" and "/./" things. | |
580 let fn = fnamemodify(fn, ":p") | |
581 endif | |
582 | |
583 " Move to desired window if needed | |
584 exec(a:movefirst) | |
585 " Edit the file/dir | |
586 exec(a:editcmd . " " . escape(fn,s:escfilename)) | |
587 endfunction | |
588 | |
589 | |
590 "--- | |
591 " Create a regular expression out of the suffixes option for sorting | |
592 " and set a string to indicate whether we are sorting with the | |
593 " suffixes at the end (or the beginning) | |
594 " | |
595 function! s:SetSuffixesLast() | |
596 let b:suffixesRegexp = '\(' . substitute(escape(&suffixes,s:escregexp),',','\\|','g') . '\)$' | |
597 let b:suffixesHighlight = '^[^"].*\(' . substitute(escape(&suffixes,s:escregexp),',','\\|','g') . '\)\( \|$\)' | |
598 if has("fname_case") | |
599 let b:suffixesRegexp = '\C' . b:suffixesRegexp | |
600 let b:suffixesHighlight = '\C' . b:suffixesHighlight | |
601 else | |
602 let b:suffixesRegexp = '\c' . b:suffixesRegexp | |
603 let b:suffixesHighlight = '\c' . b:suffixesHighlight | |
604 endif | |
605 if g:explSuffixesLast > 0 && &suffixes != "" | |
606 let b:suffixeslast=" (" . &suffixes . " at end of list)" | |
607 elseif g:explSuffixesLast < 0 && &suffixes != "" | |
608 let b:suffixeslast=" (" . &suffixes . " at start of list)" | |
609 else | |
610 let b:suffixeslast=" ('suffixes' mixed with files)" | |
611 endif | |
612 endfunction | |
613 | |
614 "--- | |
615 " Show the header and contents of the directory | |
616 " | |
617 function! s:ShowDirectory() | |
618 "Delete all lines | |
619 1,$d _ | |
620 " Prevent a report of our actions from showing up | |
621 let oldRep=&report | |
622 let save_sc = &sc | |
623 set report=10000 nosc | |
624 | |
625 " Add the header | |
626 call s:AddHeader() | |
627 $d _ | |
628 | |
629 " Display the files | |
630 | |
631 " Get a list of all the files | |
632 let files = s:Path(glob(b:completePathEsc . "*")) | |
633 if files != "" && files !~ "\n$" | |
634 let files = files . "\n" | |
635 endif | |
636 | |
637 " Add the dot files now, making sure "." is not included! | |
638 let files = files . substitute(s:Path(glob(b:completePathEsc . ".*")), "[^\n]*/./\\=\n", '' , '') | |
639 if files != "" && files !~ "\n$" | |
640 let files = files . "\n" | |
641 endif | |
642 | |
643 " Are there any files left after filtering? | |
644 if files != "" | |
645 normal! mt | |
646 put =files | |
647 let b:maxFileLen = 0 | |
648 0 | |
649 /^"=/+1,$g/^/call s:MarkDirs() | |
650 normal! `t | |
651 call s:AddFileInfo() | |
652 endif | |
653 | |
654 normal! zz | |
655 | |
656 " Move to first directory in the listing | |
657 0 | |
658 /^"=/+1 | |
659 | |
660 " Do the sort | |
661 call s:SortListing("Loaded contents of ".b:completePath.". ") | |
662 | |
663 " Move to first directory in the listing | |
664 0 | |
665 /^"=/+1 | |
666 | |
667 let &report=oldRep | |
668 let &sc = save_sc | |
669 | |
670 endfunction | |
671 | |
672 "--- | |
673 " Mark which items are directories - called once for each file name | |
674 " must be used only when size/date is not displayed | |
675 " | |
676 function! s:MarkDirs() | |
677 let oldRep=&report | |
678 set report=1000 | |
679 "Remove slashes if added | |
680 s;/$;;e | |
681 "Removes all the leading slashes and adds slashes at the end of directories | |
682 s;^.*\\\([^\\]*\)$;\1;e | |
683 s;^.*/\([^/]*\)$;\1;e | |
684 "normal! ^ | |
685 let currLine=getline(".") | |
686 if isdirectory(b:completePath . currLine) | |
687 s;$;/; | |
688 let fileLen=strlen(currLine)+1 | |
689 else | |
690 let fileLen=strlen(currLine) | |
691 if (b:filterFormula!="") && (currLine =~ b:filterFormula) | |
692 " Don't show the file if it is to be filtered. | |
693 d _ | |
694 endif | |
695 endif | |
696 if fileLen > b:maxFileLen | |
697 let b:maxFileLen=fileLen | |
698 endif | |
699 let &report=oldRep | |
700 endfunction | |
701 | |
702 "--- | |
703 " Make sure a path has proper form | |
704 " | |
705 function! s:Path(p) | |
706 if has("dos16") || has("dos32") || has("win16") || has("win32") || has("os2") | |
707 return substitute(a:p,'\\','/','g') | |
708 else | |
709 return a:p | |
710 endif | |
711 endfunction | |
712 | |
713 "--- | |
714 " Extract the file name from a line in several different forms | |
715 " | |
716 function! s:GetFullFileNameEsc() | |
717 return s:EscapeFilename(s:GetFullFileName()) | |
718 endfunction | |
719 | |
720 function! s:GetFileNameEsc() | |
721 return s:EscapeFilename(s:GetFileName()) | |
722 endfunction | |
723 | |
724 function! s:EscapeFilename(name) | |
725 return escape(a:name,s:escfilename) | |
726 endfunction | |
727 | |
728 | |
729 function! s:GetFullFileName() | |
730 return s:ExtractFullFileName(getline(".")) | |
731 endfunction | |
732 | |
733 function! s:GetFileName() | |
734 return s:ExtractFileName(getline(".")) | |
735 endfunction | |
736 | |
737 function! s:ExtractFullFileName(line) | |
738 let fn=s:ExtractFileName(a:line) | |
739 if fn == '/' | |
740 return b:completePath | |
741 else | |
742 return b:completePath . s:ExtractFileName(a:line) | |
743 endif | |
744 endfunction | |
745 | |
746 function! s:ExtractFileName(line) | |
747 return substitute(strpart(a:line,0,b:maxFileLen),'\s\+$','','') | |
748 endfunction | |
749 | |
750 "--- | |
751 " Get the size of the file | |
752 function! s:ExtractFileSize(line) | |
753 if (w:longlist==0) | |
754 return getfsize(s:ExtractFileName(a:line)) | |
755 else | |
756 return strpart(a:line,b:maxFileLen+2,b:maxFileSizeLen) | |
757 endif | |
758 endfunction | |
759 | |
760 "--- | |
761 " Get the date of the file as a number | |
762 function! s:ExtractFileDate(line) | |
763 if w:longlist==0 | |
764 return getftime(s:ExtractFileName(a:line)) | |
765 else | |
766 return strpart(matchstr(strpart(a:line,b:maxFileLen+b:maxFileSizeLen+4),"««.*"),2) + 0 | |
767 endif | |
768 endfunction | |
769 | |
770 | |
771 "--- | |
772 " Add the header with help information | |
773 " | |
774 function! s:AddHeader() | |
775 let save_f=@f | |
776 1 | |
777 if w:longhelp==1 | |
778 let @f="\" <enter> : open file or directory\n" | |
779 \."\" o : open new window for file/directory\n" | |
780 \."\" O : open file in previously visited window\n" | |
781 \."\" p : preview the file\n" | |
782 if exists("g:explFileHandler") | |
783 let @f=@f."\" x : execute file or directory\n" | |
784 endif | |
785 let @f=@f | |
786 \."\" i : toggle size/date listing\n" | |
787 \."\" s : select sort field r : reverse sort\n" | |
788 \."\" - : go up one level c : cd to this dir\n" | |
789 \."\" R : rename file D : delete file\n" | |
790 \."\" :help file-explorer for detailed help\n" | |
791 else | |
792 let @f="\" Press ? for keyboard shortcuts\n" | |
793 endif | |
794 let @f=@f."\" Sorted by ".w:sortdirlabel.w:sorttype.b:suffixeslast.b:filtering."\n" | |
795 let @f=@f."\"= ".b:completePath."\n" | |
796 put! f | |
797 let @f=save_f | |
798 endfunction | |
799 | |
800 | |
801 "--- | |
802 " Show the size and date for each file | |
803 " | |
804 function! s:AddFileInfo() | |
805 let save_sc = &sc | |
806 set nosc | |
807 | |
808 " Mark our starting point | |
809 normal! mt | |
810 | |
811 call s:RemoveSeparators() | |
812 | |
813 " Remove all info | |
814 0 | |
815 /^"=/+1,$g/^/call setline(line("."),s:GetFileName()) | |
816 | |
817 " Add info if requested | |
818 if w:longlist==1 | |
819 " Add file size and calculate maximum length of file size field | |
820 let b:maxFileSizeLen = 0 | |
821 0 | |
822 /^"=/+1,$g/^/let fn=s:GetFullFileName() | | |
823 \let fileSize=getfsize(fn) | | |
824 \let fileSizeLen=strlen(fileSize) | | |
825 \if fileSizeLen > b:maxFileSizeLen | | |
826 \ let b:maxFileSizeLen = fileSizeLen | | |
827 \endif | | |
828 \exec "normal! ".(b:maxFileLen-strlen(getline("."))+2)."A \<esc>" | | |
829 \exec 's/$/'.fileSize.'/' | |
830 | |
831 " Right justify the file sizes and | |
832 " add file modification date | |
833 0 | |
834 /^"=/+1,$g/^/let fn=s:GetFullFileName() | | |
835 \exec "normal! A \<esc>$b".(b:maxFileLen+b:maxFileSizeLen-strlen(getline("."))+3)."i \<esc>\"_x" | | |
836 \exec 's/$/ '.escape(s:FileModDate(fn), '/').'/' | |
837 setlocal nomodified | |
838 endif | |
839 | |
840 call s:AddSeparators() | |
841 | |
842 " return to start | |
843 normal! `t | |
844 | |
845 let &sc = save_sc | |
846 endfunction | |
847 | |
848 | |
849 "---- | |
850 " Get the modification time for a file | |
851 " | |
852 function! s:FileModDate(name) | |
853 let filetime=getftime(a:name) | |
854 if filetime > 0 | |
855 return strftime(g:explDateFormat,filetime) . " ««" . filetime | |
856 else | |
857 return "" | |
858 endif | |
859 endfunction | |
860 | |
861 "--- | |
862 " Delete a file or files | |
863 " | |
864 function! s:DeleteFile() range | |
865 let oldRep = &report | |
866 let &report = 1000 | |
867 | |
868 let filesDeleted = 0 | |
869 let stopDel = 0 | |
870 let delAll = 0 | |
871 let currLine = a:firstline | |
872 let lastLine = a:lastline | |
873 setlocal noreadonly modifiable | |
874 | |
875 while ((currLine <= lastLine) && (stopDel==0)) | |
876 exec(currLine) | |
877 let fileName=s:GetFullFileName() | |
878 if isdirectory(fileName) | |
879 echo fileName." : Directory deletion not supported yet" | |
880 let currLine = currLine + 1 | |
881 else | |
882 if delAll == 0 | |
883 let sure=input("Delete ".fileName." (y/n/a/q)? ") | |
884 if sure=="a" | |
885 let delAll = 1 | |
886 endif | |
887 endif | |
888 if (sure=="y") || (sure=="a") | |
889 let success=delete(fileName) | |
890 if success!=0 | |
891 exec (" ") | |
892 echo "\nCannot delete ".fileName | |
893 let currLine = currLine + 1 | |
894 else | |
895 d _ | |
896 let filesDeleted = filesDeleted + 1 | |
897 let lastLine = lastLine - 1 | |
898 endif | |
899 elseif sure=="q" | |
900 let stopDel = 1 | |
901 elseif sure=="n" | |
902 let currLine = currLine + 1 | |
903 endif | |
904 endif | |
905 endwhile | |
906 echo "\n".filesDeleted." files deleted" | |
907 let &report = oldRep | |
908 setlocal nomodified | |
909 setlocal readonly nomodifiable | |
910 endfunction | |
911 | |
912 "--- | |
913 " Rename a file | |
914 " | |
915 function! s:RenameFile() | |
916 let fileName=s:GetFullFileName() | |
917 setlocal noreadonly modifiable | |
918 if isdirectory(fileName) | |
919 echo "Directory renaming not supported yet" | |
920 elseif filereadable(fileName) | |
921 let altName=input("Rename ".fileName." to : ") | |
922 echo " " | |
923 if altName=="" | |
924 setlocal readonly nomodifiable | |
925 return | |
926 endif | |
927 let success=rename(fileName, b:completePath.altName) | |
928 if success!=0 | |
929 echo "Cannot rename ".fileName. " to ".altName | |
930 else | |
931 echo "Renamed ".fileName." to ".altName | |
932 let oldRep=&report | |
933 set report=1000 | |
934 e! | |
935 let &report=oldRep | |
936 endif | |
937 endif | |
938 setlocal nomodified | |
939 setlocal readonly nomodifiable | |
940 endfunction | |
941 | |
942 "--- | |
943 " Toggle between short and long help | |
944 " | |
945 function! s:ToggleHelp() | |
946 if exists("w:longhelp") && w:longhelp==0 | |
947 let w:longhelp=1 | |
948 let s:longhelp=1 | |
949 else | |
950 let w:longhelp=0 | |
951 let s:longhelp=0 | |
952 endif | |
953 " Allow modification | |
954 setlocal noreadonly modifiable | |
955 call s:UpdateHeader() | |
956 " Disallow modification | |
957 setlocal readonly nomodifiable | |
958 endfunction | |
959 | |
960 "--- | |
961 " Update the header | |
962 " | |
963 function! s:UpdateHeader() | |
964 let oldRep=&report | |
965 set report=10000 | |
966 " Save position | |
967 normal! mt | |
968 " Remove old header | |
969 0 | |
970 1,/^"=/ d _ | |
971 " Add new header | |
972 call s:AddHeader() | |
973 " Go back where we came from if possible | |
974 0 | |
975 if line("'t") != 0 | |
976 normal! `t | |
977 endif | |
978 | |
979 let &report=oldRep | |
980 setlocal nomodified | |
981 endfunction | |
982 | |
983 "--- | |
984 " Toggle long vs. short listing | |
985 " | |
986 function! s:ToggleLongList() | |
987 setlocal noreadonly modifiable | |
988 if exists("w:longlist") && w:longlist==1 | |
989 let w:longlist=0 | |
990 let s:longlist=0 | |
991 else | |
992 let w:longlist=1 | |
993 let s:longlist=1 | |
994 endif | |
995 call s:AddFileInfo() | |
996 setlocal readonly nomodifiable | |
997 endfunction | |
998 | |
999 "--- | |
1000 " Show all files - remove filtering | |
1001 " | |
1002 function! s:ShowAllFiles() | |
1003 setlocal noreadonly modifiable | |
1004 let b:filterFormula="" | |
1005 let b:filtering="" | |
1006 call s:ShowDirectory() | |
1007 setlocal readonly nomodifiable | |
1008 endfunction | |
1009 | |
1010 "--- | |
1011 " Figure out what section we are in | |
1012 " | |
1013 function! s:GetSection() | |
1014 let fn=s:GetFileName() | |
1015 let section="file" | |
1016 if fn =~ '/$' | |
1017 let section="directory" | |
1018 elseif fn =~ b:suffixesRegexp | |
1019 let section="suffixes" | |
1020 endif | |
1021 return section | |
1022 endfunction | |
1023 | |
1024 "--- | |
1025 " Remove section separators | |
1026 " | |
1027 function! s:RemoveSeparators() | |
1028 if !g:explUseSeparators | |
1029 return | |
1030 endif | |
1031 0 | |
1032 silent! exec '/^"=/+1,$g/^' . s:separator . "/d _" | |
1033 endfunction | |
1034 | |
1035 "--- | |
1036 " Add section separators | |
1037 " between directories and files if they are separated | |
1038 " between files and 'suffixes' files if they are separated | |
1039 function! s:AddSeparators() | |
1040 if !g:explUseSeparators | |
1041 return | |
1042 endif | |
1043 0 | |
1044 /^"=/+1 | |
1045 let lastsec=s:GetSection() | |
1046 +1 | |
1047 .,$g/^/let sec=s:GetSection() | | |
1048 \if g:explDirsFirst != 0 && sec != lastsec && | |
1049 \ (lastsec == "directory" || sec == "directory") | | |
1050 \ exec "normal! I" . s:separator . "\n\<esc>" | | |
1051 \elseif g:explSuffixesLast != 0 && sec != lastsec && | |
1052 \ (lastsec == "suffixes" || sec == "suffixes") | | |
1053 \ exec "normal! I" . s:separator . "\n\<esc>" | | |
1054 \endif | | |
1055 \let lastsec=sec | |
1056 endfunction | |
1057 | |
1058 "--- | |
1059 " General string comparison function | |
1060 " | |
1061 function! s:StrCmp(line1, line2, direction) | |
1062 if a:line1 < a:line2 | |
1063 return -a:direction | |
1064 elseif a:line1 > a:line2 | |
1065 return a:direction | |
1066 else | |
1067 return 0 | |
1068 endif | |
1069 endfunction | |
1070 | |
1071 "--- | |
1072 " Function for use with Sort(), to compare the file names | |
1073 " Default sort is to put in alphabetical order, but with all directory | |
1074 " names before all file names | |
1075 " | |
1076 function! s:FileNameCmp(line1, line2, direction) | |
1077 let f1=s:ExtractFileName(a:line1) | |
1078 let f2=s:ExtractFileName(a:line2) | |
1079 | |
1080 " Put directory names before file names | |
1081 if (g:explDirsFirst != 0) && (f1 =~ '\/$') && (f2 !~ '\/$') | |
1082 return -g:explDirsFirst | |
1083 elseif (g:explDirsFirst != 0) && (f1 !~ '\/$') && (f2 =~ '\/$') | |
1084 return g:explDirsFirst | |
1085 elseif (g:explSuffixesLast != 0) && (f1 =~ b:suffixesRegexp) && (f2 !~ b:suffixesRegexp) | |
1086 return g:explSuffixesLast | |
1087 elseif (g:explSuffixesLast != 0) && (f1 !~ b:suffixesRegexp) && (f2 =~ b:suffixesRegexp) | |
1088 return -g:explSuffixesLast | |
1089 else | |
1090 return s:StrCmp(substitute(f1, "/$", "", ""), substitute(f2, "/$", "", ""), a:direction) | |
1091 endif | |
1092 | |
1093 endfunction | |
1094 | |
1095 "--- | |
1096 " Function for use with Sort(), to compare the file modification dates | |
1097 " Default sort is to put NEWEST files first. Reverse will put oldest | |
1098 " files first | |
1099 " | |
1100 function! s:FileDateCmp(line1, line2, direction) | |
1101 let f1=s:ExtractFileName(a:line1) | |
1102 let f2=s:ExtractFileName(a:line2) | |
1103 let t1=s:ExtractFileDate(a:line1) | |
1104 let t2=s:ExtractFileDate(a:line2) | |
1105 | |
1106 " Put directory names before file names | |
1107 if (g:explDirsFirst != 0) && (f1 =~ '\/$') && (f2 !~ '\/$') | |
1108 return -g:explDirsFirst | |
1109 elseif (g:explDirsFirst != 0) && (f1 !~ '\/$') && (f2 =~ '\/$') | |
1110 return g:explDirsFirst | |
1111 elseif (g:explSuffixesLast != 0) && (f1 =~ b:suffixesRegexp) && (f2 !~ b:suffixesRegexp) | |
1112 return g:explSuffixesLast | |
1113 elseif (g:explSuffixesLast != 0) && (f1 !~ b:suffixesRegexp) && (f2 =~ b:suffixesRegexp) | |
1114 return -g:explSuffixesLast | |
1115 elseif t1 > t2 | |
1116 return -a:direction | |
1117 elseif t1 < t2 | |
1118 return a:direction | |
1119 else | |
1120 return s:StrCmp(substitute(f1, "/$", "", ""), substitute(f2, "/$", "", ""), 1) | |
1121 endif | |
1122 endfunction | |
1123 | |
1124 "--- | |
1125 " Function for use with Sort(), to compare the file sizes | |
1126 " Default sort is to put largest files first. Reverse will put | |
1127 " smallest files first | |
1128 " | |
1129 function! s:FileSizeCmp(line1, line2, direction) | |
1130 let f1=s:ExtractFileName(a:line1) | |
1131 let f2=s:ExtractFileName(a:line2) | |
1132 let s1=s:ExtractFileSize(a:line1) | |
1133 let s2=s:ExtractFileSize(a:line2) | |
1134 | |
1135 if (g:explDirsFirst != 0) && (f1 =~ '\/$') && (f2 !~ '\/$') | |
1136 return -g:explDirsFirst | |
1137 elseif (g:explDirsFirst != 0) && (f1 !~ '\/$') && (f2 =~ '\/$') | |
1138 return g:explDirsFirst | |
1139 elseif (g:explSuffixesLast != 0) && (f1 =~ b:suffixesRegexp) && (f2 !~ b:suffixesRegexp) | |
1140 return g:explSuffixesLast | |
1141 elseif (g:explSuffixesLast != 0) && (f1 !~ b:suffixesRegexp) && (f2 =~ b:suffixesRegexp) | |
1142 return -g:explSuffixesLast | |
1143 elseif s1 > s2 | |
1144 return -a:direction | |
1145 elseif s1 < s2 | |
1146 return a:direction | |
1147 else | |
1148 return s:StrCmp(substitute(f1, "/$", "", ""), substitute(f2, "/$", "", ""), 1) | |
1149 endif | |
1150 endfunction | |
1151 | |
1152 "--- | |
1153 " Sort lines. SortR() is called recursively. | |
1154 " | |
1155 function! s:SortR(start, end, cmp, direction) | |
1156 | |
1157 " Bottom of the recursion if start reaches end | |
1158 if a:start >= a:end | |
1159 return | |
1160 endif | |
1161 " | |
1162 let partition = a:start - 1 | |
1163 let middle = partition | |
1164 let partStr = getline((a:start + a:end) / 2) | |
1165 let i = a:start | |
1166 while (i <= a:end) | |
1167 let str = getline(i) | |
1168 exec "let result = " . a:cmp . "(str, partStr, " . a:direction . ")" | |
1169 if result <= 0 | |
1170 " Need to put it before the partition. Swap lines i and partition. | |
1171 let partition = partition + 1 | |
1172 if result == 0 | |
1173 let middle = partition | |
1174 endif | |
1175 if i != partition | |
1176 let str2 = getline(partition) | |
1177 call setline(i, str2) | |
1178 call setline(partition, str) | |
1179 endif | |
1180 endif | |
1181 let i = i + 1 | |
1182 endwhile | |
1183 | |
1184 " Now we have a pointer to the "middle" element, as far as partitioning | |
1185 " goes, which could be anywhere before the partition. Make sure it is at | |
1186 " the end of the partition. | |
1187 if middle != partition | |
1188 let str = getline(middle) | |
1189 let str2 = getline(partition) | |
1190 call setline(middle, str2) | |
1191 call setline(partition, str) | |
1192 endif | |
1193 call s:SortR(a:start, partition - 1, a:cmp,a:direction) | |
1194 call s:SortR(partition + 1, a:end, a:cmp,a:direction) | |
1195 endfunction | |
1196 | |
1197 "--- | |
1198 " To Sort a range of lines, pass the range to Sort() along with the name of a | |
1199 " function that will compare two lines. | |
1200 " | |
1201 function! s:Sort(cmp,direction) range | |
1202 call s:SortR(a:firstline, a:lastline, a:cmp, a:direction) | |
1203 endfunction | |
1204 | |
1205 "--- | |
1206 " Reverse the current sort order | |
1207 " | |
1208 function! s:SortReverse() | |
1209 if exists("w:sortdirection") && w:sortdirection == -1 | |
1210 let w:sortdirection = 1 | |
1211 let w:sortdirlabel = "" | |
1212 else | |
1213 let w:sortdirection = -1 | |
1214 let w:sortdirlabel = "reverse " | |
1215 endif | |
1216 let s:sortby=w:sortdirlabel . w:sorttype | |
1217 call s:SortListing("") | |
1218 endfunction | |
1219 | |
1220 "--- | |
1221 " Toggle through the different sort orders | |
1222 " | |
1223 function! s:SortSelect() | |
1224 " Select the next sort option | |
1225 if !exists("w:sorttype") | |
1226 let w:sorttype="name" | |
1227 elseif w:sorttype == "name" | |
1228 let w:sorttype="size" | |
1229 elseif w:sorttype == "size" | |
1230 let w:sorttype="date" | |
1231 else | |
1232 let w:sorttype="name" | |
1233 endif | |
1234 let s:sortby=w:sortdirlabel . w:sorttype | |
1235 call s:SortListing("") | |
1236 endfunction | |
1237 | |
1238 "--- | |
1239 " Sort the file listing | |
1240 " | |
1241 function! s:SortListing(msg) | |
1242 " Save the line we start on so we can go back there when done | |
1243 " sorting | |
1244 let startline = getline(".") | |
1245 let col=col(".") | |
1246 let lin=line(".") | |
1247 | |
1248 " Allow modification | |
1249 setlocal noreadonly modifiable | |
1250 | |
1251 " Send a message about what we're doing | |
1252 " Don't really need this - it can cause hit return prompts | |
1253 " echo a:msg . "Sorting by" . w:sortdirlabel . w:sorttype | |
1254 | |
1255 " Create a regular expression out of the suffixes option in case | |
1256 " we need it. | |
1257 call s:SetSuffixesLast() | |
1258 | |
1259 " Remove section separators | |
1260 call s:RemoveSeparators() | |
1261 | |
1262 " Do the sort | |
1263 0 | |
1264 if w:sorttype == "size" | |
1265 /^"=/+1,$call s:Sort("s:FileSizeCmp",w:sortdirection) | |
1266 elseif w:sorttype == "date" | |
1267 /^"=/+1,$call s:Sort("s:FileDateCmp",w:sortdirection) | |
1268 else | |
1269 /^"=/+1,$call s:Sort("s:FileNameCmp",w:sortdirection) | |
1270 endif | |
1271 | |
1272 " Replace the header with updated information | |
1273 call s:UpdateHeader() | |
1274 | |
1275 " Restore section separators | |
1276 call s:AddSeparators() | |
1277 | |
1278 " Return to the position we started on | |
1279 0 | |
1280 if search('\m^'.escape(startline,s:escregexp),'W') <= 0 | |
1281 execute lin | |
1282 endif | |
1283 execute "normal!" col . "|" | |
1284 | |
1285 " Disallow modification | |
1286 setlocal nomodified | |
1287 setlocal readonly nomodifiable | |
1288 | |
1289 endfunction | |
1290 | |
1291 "--- | |
1292 " Setup for editing directories after starting up by going to each window. | |
1293 " Required for "vim -o filename dirname" | |
1294 " | |
1295 function! s:EditAll() | |
1296 if winbufnr(2) == -1 | |
1297 return | |
1298 endif | |
1299 let cmd = winrestcmd() | |
1300 let curwin = winnr() | |
1301 while 1 | |
1302 wincmd w | |
1303 if winnr() == curwin | |
1304 break | |
1305 endif | |
1306 call s:EditDir() | |
1307 endwhile | |
1308 exe cmd | |
1309 endfunction | |
1310 | |
1311 "--- | |
1312 " Set up the autocommand to allow directories to be edited | |
1313 " | |
1314 augroup fileExplorer | |
1315 au! | |
1316 " Fill the window when entering the buffer; ":edit dir". | |
1317 au BufEnter * call s:EditDir() | |
1318 " Set the window variables after a split; ":split". | |
1319 au WinEnter * if !exists("w:sortdirection") | call s:EditDir() | endif | |
1320 " Fill the windows after Vim has started up. | |
1321 au VimEnter * call s:EditAll() | |
1322 augroup end | |
1323 | |
1324 " restore 'cpo' | |
1325 let &cpo = s:cpo_save | |
1326 unlet s:cpo_save |