-
-
Notifications
You must be signed in to change notification settings - Fork 6k
Expand file tree
/
Copy pathzip.vim
More file actions
584 lines (521 loc) · 19.4 KB
/
zip.vim
File metadata and controls
584 lines (521 loc) · 19.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
" zip.vim: Handles browsing zipfiles
" AUTOLOAD PORTION
" Date: 2024 Aug 21
" Version: 34
" Maintainer: This runtime file is looking for a new maintainer.
" Former Maintainer: Charles E Campbell
" Last Change:
" 2024 Jun 16 by Vim Project: handle whitespace on Windows properly (#14998)
" 2024 Jul 23 by Vim Project: fix 'x' command
" 2024 Jul 24 by Vim Project: use delete() function
" 2024 Jul 30 by Vim Project: fix opening remote zipfile
" 2024 Aug 04 by Vim Project: escape '[' in name of file to be extracted
" 2024 Aug 05 by Vim Project: workaround for the FreeBSD's unzip
" 2024 Aug 05 by Vim Project: clean-up and make it work with shellslash on Windows
" 2024 Aug 18 by Vim Project: correctly handle special globbing chars
" 2024 Aug 21 by Vim Project: simplify condition to detect MS-Windows
" 2025 Mar 11 by Vim Project: handle filenames with leading '-' correctly
" 2025 Jul 12 by Vim Project: drop ../ on write to prevent path traversal attacks
" 2025 Sep 22 by Vim Project: support PowerShell Core
" 2025 Dec 20 by Vim Project: use :lcd instead of :cd
" 2026 Feb 08 by Vim Project: use system() instead of :!
" 2026 Mar 08 by Vim Project: Make ZipUpdatePS() check for powershell
" License: Vim License (see vim's :help license)
" Copyright: Copyright (C) 2005-2019 Charles E. Campbell {{{1
" Permission is hereby granted to use and distribute this code,
" with or without modifications, provided that this copyright
" notice is copied with it. Like anything else that's free,
" zip.vim and zipPlugin.vim are provided *as is* and comes with
" no warranty of any kind, either expressed or implied. By using
" this plugin, you agree that in no event will the copyright
" holder be liable for any damages resulting from the use
" of this software.
" ---------------------------------------------------------------------
" Load Once: {{{1
if &cp || exists("g:loaded_zip")
finish
endif
let g:loaded_zip= "v34"
let s:keepcpo= &cpo
set cpo&vim
let s:zipfile_escape = ' ?&;\'
let s:ERROR = 2
let s:WARNING = 1
let s:NOTE = 0
" ---------------------------------------------------------------------
" Global Values: {{{1
if !exists("g:zip_shq")
if &shq != ""
let g:zip_shq= &shq
elseif has("unix")
let g:zip_shq= "'"
else
let g:zip_shq= '"'
endif
endif
if !exists("g:zip_zipcmd")
let g:zip_zipcmd= "zip"
endif
if !exists("g:zip_unzipcmd")
let g:zip_unzipcmd= "unzip"
endif
if !exists("g:zip_extractcmd")
let g:zip_extractcmd= g:zip_unzipcmd
endif
" ---------------------------------------------------------------------
" required early
" s:Mess: {{{2
fun! s:Mess(group, msg)
redraw!
exe "echohl " . a:group
echomsg a:msg
echohl Normal
endfun
if v:version < 901
" required for defer
call s:Mess('WarningMsg', "***warning*** this version of zip needs vim 9.1 or later")
finish
endif
" sanity checks
if !executable(g:zip_unzipcmd) && &shell !~ 'pwsh'
call s:Mess('Error', "***error*** (zip#Browse) unzip not available on your system")
finish
endif
if !dist#vim#IsSafeExecutable('zip', g:zip_unzipcmd) && &shell !~ 'pwsh'
call s:Mess('Error', "Warning: NOT executing " .. g:zip_unzipcmd .. " from current directory!")
finish
endif
" ----------------
" PowerShell: {{{1
" ----------------
function! s:TryExecGnuFallBackToPs(executable, gnu_func_call, ...)
" Check that a gnu executable is available, run the gnu_func_call if so. If
" the gnu executable is not available or if gnu_func_call fails, try
" ps_func_call if &shell =~ 'pwsh'. If all attempts fail, print errors.
" a:executable - one of (g:zip_zipcmd, g:zip_unzipcmd, g:zip_extractcmd)
" a:gnu_func_call - (string) a gnu function call to execute
" a:1 - (optional string) a PowerShell function call to execute.
let failures = []
if executable(substitute(a:executable,'\s\+.*$','',''))
try
exe a:gnu_func_call
return
catch
call add(failures, 'Failed to execute '.a:gnu_func_call)
endtry
else
call add(failures, a:executable.' not available on your system')
endif
if &shell =~ 'pwsh' && a:0 == 1
try
exe a:1
return
catch
call add(failures, 'Fallback to PowerShell attempted but failed')
endtry
endif
for msg in failures
call s:Mess('Error', msg)
endfor
endfunction
function! s:ZipBrowsePS(zipfile)
" Browse the contents of a zip file using PowerShell's
" Equivalent `unzip -Z1 -- zipfile`
let cmds = [
\ '$zip = [System.IO.Compression.ZipFile]::OpenRead(' . s:Escape(a:zipfile, 1) . ');',
\ '$zip.Entries | ForEach-Object { $_.FullName };',
\ '$zip.Dispose()'
\ ]
return 'pwsh -NoProfile -Command ' . s:Escape(join(cmds, ' '), 1)
endfunction
function! s:ZipReadPS(zipfile, fname, tempfile)
" Read a filename within a zipped file to a temporary file.
" Equivalent to `unzip -p -- zipfile fname > tempfile`
if &shell =~ 'pwsh'
call s:Mess('WarningMsg', "***warning*** PowerShell can display, but cannot update, files in archive subfolders")
endif
let cmds = [
\ '$zip = [System.IO.Compression.ZipFile]::OpenRead(' . s:Escape(a:zipfile, 1) . ');',
\ '$fileEntry = $zip.Entries | Where-Object { $_.FullName -eq ' . s:Escape(a:fname, 1) . ' };',
\ '$stream = $fileEntry.Open();',
\ '$fileStream = [System.IO.File]::Create(' . s:Escape(a:tempfile, 1) . ');',
\ '$stream.CopyTo($fileStream);',
\ '$fileStream.Close();',
\ '$stream.Close();',
\ '$zip.Dispose()'
\ ]
return 'pwsh -NoProfile -Command ' . s:Escape(join(cmds, ' '), 1)
endfunction
function! s:ZipUpdatePS(zipfile, fname)
" Update a filename within a zipped file
" Equivalent to `zip -u zipfile fname`
if &shell =~ 'pwsh' && a:fname =~ '/'
call s:Mess('Error', "***error*** PowerShell cannot update files in archive subfolders")
return ':'
endif
return 'Compress-Archive -Path ' . a:fname . ' -Update -DestinationPath ' . a:zipfile
endfunction
function! s:ZipExtractFilePS(zipfile, fname)
" Extract a single file from an archive
" Equivalent to `unzip -o zipfile fname`
if a:fname =~ '/'
call s:Mess('Error', "***error*** PowerShell cannot extract files in archive subfolders")
return ':'
endif
let cmds = [
\ '$zip = [System.IO.Compression.ZipFile]::OpenRead(' . s:Escape(a:zipfile, 1) . ');',
\ '$fileEntry = $zip.Entries | Where-Object { $_.FullName -eq ' . a:fname . ' };',
\ '$stream = $fileEntry.Open();',
\ '$fileStream = [System.IO.File]::Create(' . a:fname . ');',
\ '$stream.CopyTo($fileStream);',
\ '$fileStream.Close();',
\ '$stream.Close();',
\ '$zip.Dispose()'
\ ]
return 'pwsh -NoProfile -Command ' . s:Escape(join(cmds, ' '), 1)
endfunction
function! s:ZipDeleteFilePS(zipfile, fname)
" Delete a single file from an archive
" Equivalent to `zip -d zipfile fname`
let cmds = [
\ 'Add-Type -AssemblyName System.IO.Compression.FileSystem;',
\ '$zip = [System.IO.Compression.ZipFile]::Open(' . s:Escape(a:zipfile, 1) . ', ''Update'');',
\ '$entry = $zip.Entries | Where-Object { $_.Name -eq ' . s:Escape(a:fname, 1) . ' };',
\ 'if ($entry) { $entry.Delete(); $zip.Dispose() }',
\ 'else { $zip.Dispose() }'
\ ]
return 'pwsh -NoProfile -Command ' . s:Escape(join(cmds, ' '), 1)
endfunction
" ----------------
" Functions: {{{1
" ----------------
" ---------------------------------------------------------------------
" zip#Browse: {{{2
fun! zip#Browse(zipfile)
" sanity check: ensure that the zipfile has "PK" as its first two letters
" (zip files have a leading PK as a "magic cookie")
if filereadable(a:zipfile) && readblob(a:zipfile, 0, 2) != 0z50.4B
exe "noswapfile noautocmd e " .. fnameescape(a:zipfile)
return
endif
let dict = s:SetSaneOpts()
defer s:RestoreOpts(dict)
" sanity checks
if !executable(g:zip_unzipcmd) && &shell !~ 'pwsh'
call s:Mess('Error', "***error*** (zip#Browse) unzip not available on your system")
return
endif
if !filereadable(a:zipfile)
if a:zipfile !~# '^\a\+://'
" if it's an url, don't complain, let url-handlers such as vim do its thing
call s:Mess('Error', "***error*** (zip#Browse) File not readable <".a:zipfile.">")
endif
return
endif
if &ma != 1
set ma
endif
let b:zipfile= a:zipfile
setlocal noswapfile
setlocal buftype=nofile
setlocal bufhidden=hide
setlocal nobuflisted
setlocal nowrap
" Oct 12, 2021: need to re-use Bram's syntax/tar.vim.
" Setting the filetype to zip doesn't do anything (currently),
" but it is perhaps less confusing to curious perusers who do
" a :echo &ft
setf zip
run! syntax/tar.vim
" give header
call append(0, ['" zip.vim version '.g:loaded_zip,
\ '" Browsing zipfile '.a:zipfile,
\ '" Select a file with cursor and press ENTER'])
keepj $
let gnu_cmd = "keepj sil r! " . g:zip_unzipcmd . " -Z1 -- " . s:Escape(a:zipfile, 1)
let ps_cmd = 'keepj sil r! ' . s:ZipBrowsePS(a:zipfile)
call s:TryExecGnuFallBackToPs(g:zip_unzipcmd, gnu_cmd, ps_cmd)
if v:shell_error != 0
call s:Mess('WarningMsg', "***warning*** (zip#Browse) ".fnameescape(a:zipfile)." is not a zip file")
keepj sil! %d
let eikeep= &ei
set ei=BufReadCmd,FileReadCmd
exe "keepj r ".fnameescape(a:zipfile)
let &ei= eikeep
keepj 1d
return
endif
" Maps associated with zip plugin
setlocal noma nomod ro
noremap <silent> <buffer> <cr> :call <SID>ZipBrowseSelect()<cr>
noremap <silent> <buffer> x :call zip#Extract()<cr>
if &mouse != ""
noremap <silent> <buffer> <leftmouse> <leftmouse>:call <SID>ZipBrowseSelect()<cr>
endif
endfun
" ---------------------------------------------------------------------
" ZipBrowseSelect: {{{2
fun! s:ZipBrowseSelect()
let dict = s:SetSaneOpts()
defer s:RestoreOpts(dict)
let fname= getline(".")
if !exists("b:zipfile")
return
endif
" sanity check
if fname =~ '^"'
return
endif
if fname =~ '/$'
call s:Mess('Error', "***error*** (zip#Browse) Please specify a file, not a directory")
return
endif
" get zipfile to the new-window
let zipfile = b:zipfile
let curfile = expand("%")
noswapfile new
if !exists("g:zip_nomax") || g:zip_nomax == 0
wincmd _
endif
let s:zipfile_{winnr()}= curfile
exe "noswapfile e ".fnameescape("zipfile://".zipfile.'::'.fname)
filetype detect
endfun
" ---------------------------------------------------------------------
" zip#Read: {{{2
fun! zip#Read(fname,mode)
let dict = s:SetSaneOpts()
defer s:RestoreOpts(dict)
if has("unix")
let zipfile = substitute(a:fname,'zipfile://\(.\{-}\)::[^\\].*$','\1','')
let fname = substitute(a:fname,'zipfile://.\{-}::\([^\\].*\)$','\1','')
else
let zipfile = substitute(a:fname,'^.\{-}zipfile://\(.\{-}\)::[^\\].*$','\1','')
let fname = substitute(a:fname,'^.\{-}zipfile://.\{-}::\([^\\].*\)$','\1','')
endif
let fname = fname->substitute('[', '[[]', 'g')->escape('?*\\')
" sanity check
if !executable(substitute(g:zip_unzipcmd,'\s\+.*$','','')) && &shell !~ 'pwsh'
call s:Mess('Error', "***error*** (zip#Read) sorry, your system doesn't appear to have the ".g:zip_unzipcmd." program")
return
endif
" the following code does much the same thing as
" exe "keepj sil! r! ".g:zip_unzipcmd." -p -- ".s:Escape(zipfile,1)." ".s:Escape(fname,1)
" but allows zipfile://... entries in quickfix lists
let temp = tempname()
let fn = expand('%:p')
let gnu_cmd = g:zip_unzipcmd . ' -p -- ' . s:Escape(zipfile, 0) . ' ' . s:Escape(fname, 0) . ' > ' . s:Escape(temp, 0)
let gnu_cmd = 'call system(''' . substitute(gnu_cmd, "'", "''", 'g') . ''')'
let ps_cmd = 'sil !' . s:ZipReadPS(zipfile, fname, temp)
call s:TryExecGnuFallBackToPs(g:zip_unzipcmd, gnu_cmd, ps_cmd)
sil exe 'keepalt file '.temp
sil keepj e!
sil exe 'keepalt file '.fnameescape(fn)
call delete(temp)
filetype detect
" cleanup
set nomod
endfun
" ---------------------------------------------------------------------
" zip#Write: {{{2
fun! zip#Write(fname)
let dict = s:SetSaneOpts()
let need_rename = 0
defer s:RestoreOpts(dict)
" sanity checks
if !executable(substitute(g:zip_zipcmd,'\s\+.*$','','')) && &shell !~ 'pwsh'
call s:Mess('Error', "***error*** (zip#Write) sorry, your system doesn't appear to have the ".g:zip_zipcmd." program")
return
endif
let curdir= getcwd()
let tmpdir= tempname()
if tmpdir =~ '\.'
let tmpdir= substitute(tmpdir,'\.[^.]*$','','e')
endif
call mkdir(tmpdir,"p")
" attempt to change to the indicated directory
if s:ChgDir(tmpdir,s:ERROR,"(zip#Write) cannot lcd to temporary directory")
return
endif
" place temporary files under .../_ZIPVIM_/
if isdirectory("_ZIPVIM_")
call delete("_ZIPVIM_", "rf")
endif
call mkdir("_ZIPVIM_")
lcd _ZIPVIM_
if has("unix")
let zipfile = substitute(a:fname,'zipfile://\(.\{-}\)::[^\\].*$','\1','')
let fname = substitute(a:fname,'zipfile://.\{-}::\([^\\].*\)$','\1','')
else
let zipfile = substitute(a:fname,'^.\{-}zipfile://\(.\{-}\)::[^\\].*$','\1','')
let fname = substitute(a:fname,'^.\{-}zipfile://.\{-}::\([^\\].*\)$','\1','')
endif
if fname =~ '^[.]\{1,2}/'
let gnu_cmd = g:zip_zipcmd . ' -d ' . s:Escape(fnamemodify(zipfile,":p"),0) . ' ' . s:Escape(fname,0)
let gnu_cmd = 'call system(''' . substitute(gnu_cmd, "'", "''", 'g') . ''')'
let ps_cmd = $"call system({s:Escape(s:ZipDeleteFilePS(zipfile, fname), 1)})"
call s:TryExecGnuFallBackToPs(g:zip_zipcmd, gnu_cmd, ps_cmd)
let fname = fname->substitute('^\([.]\{1,2}/\)\+', '', 'g')
let need_rename = 1
endif
if fname =~ '/'
let dirpath = substitute(fname,'/[^/]\+$','','e')
if has("win32unix") && executable("cygpath")
let dirpath = substitute(system("cygpath ".s:Escape(dirpath,0)),'\n','','e')
endif
call mkdir(dirpath,"p")
endif
if zipfile !~ '/'
let zipfile= curdir.'/'.zipfile
endif
" don't overwrite files forcefully
exe "w ".fnameescape(fname)
if has("win32unix") && executable("cygpath")
let zipfile = substitute(system("cygpath ".s:Escape(zipfile,0)),'\n','','e')
endif
if (has("win32") || has("win95") || has("win64") || has("win16")) && &shell !~? 'sh$'
let fname = substitute(fname, '[', '[[]', 'g')
endif
let gnu_cmd = g:zip_zipcmd . ' -u '. s:Escape(fnamemodify(zipfile,":p"),0) . ' ' . s:Escape(fname,0)
let gnu_cmd = 'call system(''' . substitute(gnu_cmd, "'", "''", 'g') . ''')'
let ps_cmd = s:ZipUpdatePS(s:Escape(fnamemodify(zipfile, ':p'), 0), s:Escape(fname, 0))
let ps_cmd = 'call system(''' . substitute(ps_cmd, "'", "''", 'g') . ''')'
call s:TryExecGnuFallBackToPs(g:zip_zipcmd, gnu_cmd, ps_cmd)
if &shell =~ 'pwsh'
" Vim flashes 'creation in progress ...' from what I believe is the
" ProgressAction stream of PowerShell. Unfortunately, this cannot be
" suppressed (as of 250824) due to an open PowerShell issue.
" https://github.com/PowerShell/PowerShell/issues/21074
" This necessitates a redraw of the buffer.
redraw!
endif
if v:shell_error != 0
call s:Mess('Error', "***error*** (zip#Write) sorry, unable to update ".zipfile." with ".fname)
elseif s:zipfile_{winnr()} =~ '^\a\+://'
" support writing zipfiles across a network
let netzipfile= s:zipfile_{winnr()}
1split|enew
let binkeep= &binary
let eikeep = &ei
set binary ei=all
exe "noswapfile e! ".fnameescape(zipfile)
call netrw#NetWrite(netzipfile)
let &ei = eikeep
let &binary = binkeep
q!
unlet s:zipfile_{winnr()}
elseif need_rename
exe $"sil keepalt file {fnameescape($"zipfile://{zipfile}::{fname}")}"
call s:Mess('Warning', "***error*** (zip#Browse) Path Traversal Attack detected, dropping relative path")
endif
" cleanup and restore current directory
lcd ..
call delete("_ZIPVIM_", "rf")
call s:ChgDir(curdir,s:WARNING,"(zip#Write) unable to return to ".curdir."!")
call delete(tmpdir, "rf")
setlocal nomod
endfun
" ---------------------------------------------------------------------
" zip#Extract: extract a file from a zip archive {{{2
fun! zip#Extract()
let dict = s:SetSaneOpts()
defer s:RestoreOpts(dict)
let fname= getline(".")
" sanity check
if fname =~ '^"'
return
endif
if fname =~ '/$'
call s:Mess('Error', "***error*** (zip#Extract) Please specify a file, not a directory")
return
elseif fname =~ '^[.]\?[.]/'
call s:Mess('Error', "***error*** (zip#Browse) Path Traversal Attack detected, not extracting!")
return
endif
if filereadable(fname)
call s:Mess('Error', "***error*** (zip#Extract) <" .. fname .."> already exists in directory, not overwriting!")
return
endif
let target = fname->substitute('\[', '[[]', 'g')
" unzip 6.0 does not support -- to denote end-of-arguments
" unzip 6.1 (2010) apparently supports, it, but hasn't been released
" so the workaround is to use glob '[-]' so that it won't be considered an argument
" else, it would be possible to use 'unzip -o <file.zip> '-d/tmp' to extract the whole archive
let target = target->substitute('^-', '[&]', '')
if &shell =~ 'cmd' && has("win32")
let target = target
\ ->substitute('[?*]', '[&]', 'g')
\ ->substitute('[\\]', '?', 'g')
\ ->shellescape()
" there cannot be a file name with '\' in its name, unzip replaces it by _
let fname = fname->substitute('[\\?*]', '_', 'g')
else
let target = target->escape('*?\\')->shellescape()
endif
" extract the file mentioned under the cursor
let gnu_cmd = g:zip_extractcmd . ' -o '. shellescape(b:zipfile) . ' ' . target
let gnu_cmd = 'call system(''' . substitute(gnu_cmd, "'", "''", 'g') . ''')'
let ps_cmd = $"call system({s:Escape(s:ZipExtractFilePS(b:zipfile, target), 1)})"
call s:TryExecGnuFallBackToPs(g:zip_extractcmd, gnu_cmd, ps_cmd)
if v:shell_error != 0
call s:Mess('Error', "***error*** ".g:zip_extractcmd." ".b:zipfile." ".fname.": failed!")
elseif !filereadable(fname) && &shell !~ 'pwsh'
call s:Mess('Error', "***error*** attempted to extract ".fname." but it doesn't appear to be present!")
else
echomsg "***note*** successfully extracted ".fname
endif
endfun
" ---------------------------------------------------------------------
" s:Escape: {{{2
fun! s:Escape(fname,isfilt)
if exists("*shellescape")
if a:isfilt
let qnameq= shellescape(a:fname,1)
else
let qnameq= shellescape(a:fname)
endif
else
let qnameq= g:zip_shq.escape(a:fname,g:zip_shq).g:zip_shq
endif
return qnameq
endfun
" ---------------------------------------------------------------------
" s:ChgDir: {{{2
fun! s:ChgDir(newdir,errlvl,errmsg)
try
exe "lcd ".fnameescape(a:newdir)
catch /^Vim\%((\a\+)\)\=:E344/
redraw!
if a:errlvl == s:NOTE
echomsg "***note*** ".a:errmsg
elseif a:errlvl == s:WARNING
call s:Mess("WarningMsg", "***warning*** ".a:errmsg)
elseif a:errlvl == s:ERROR
call s:Mess("Error", "***error*** ".a:errmsg)
endif
return 1
endtry
return 0
endfun
" ---------------------------------------------------------------------
" s:SetSaneOpts: {{{2
fun! s:SetSaneOpts()
let dict = {}
let dict.report = &report
let dict.shellslash = &shellslash
let &report = 10
let &shellslash = 0
return dict
endfun
" ---------------------------------------------------------------------
" s:RestoreOpts: {{{2
fun! s:RestoreOpts(dict)
for [key, val] in items(a:dict)
exe $"let &{key} = {val}"
endfor
endfun
" ------------------------------------------------------------------------
" Modelines And Restoration: {{{1
let &cpo= s:keepcpo
unlet s:keepcpo
" vim:ts=8 fdm=marker