|
1 | 1 | " Vim auto-load script
|
2 | 2 | " Author: Peter Odding <peter@peterodding.com>
|
3 |
| -" Last Change: November 24, 2011 |
| 3 | +" Last Change: May 13, 2013 |
4 | 4 | " URL: http://peterodding.com/code/vim/misc/
|
5 | 5 |
|
6 |
| -let g:xolox#misc#os#version = '0.1' |
| 6 | +let g:xolox#misc#os#version = '0.2' |
7 | 7 |
|
8 |
| -" Check whether Vim is running on Microsoft Windows. |
9 |
| - |
10 |
| -function! xolox#misc#os#is_win() |
| 8 | +function! xolox#misc#os#is_win() " {{{1 |
| 9 | + " Check whether Vim is running on Microsoft Windows. |
11 | 10 | return has('win16') || has('win32') || has('win64')
|
12 | 11 | endfunction
|
13 | 12 |
|
14 |
| -" Execute an external command (hiding the console on Windows when possible). |
15 |
| - |
16 |
| -function! xolox#misc#os#exec(cmdline, ...) |
| 13 | +function! xolox#misc#os#exec(options) " {{{1 |
| 14 | + " Execute an external command (hiding the console on Windows when possible). |
| 15 | + " NB: Everything below is wrapped in a try/finally block to guarantee |
| 16 | + " cleanup of temporary files. |
17 | 17 | try
|
18 |
| - " Try using my shell.vim plug-in. |
19 |
| - return call('xolox#shell#execute', [a:cmdline, 1] + a:000) |
20 |
| - catch /^Vim\%((\a\+)\)\=:E117/ |
21 |
| - " Fall back to system() when we get an "unknown function" error. |
22 |
| - let output = call('system', [a:cmdline] + a:000) |
23 |
| - if v:shell_error |
24 |
| - throw printf("os.vim %s: Command %s failed: %s", g:xolox#misc#os#version, a:cmdline, xolox#misc#str#trim(output)) |
| 18 | + |
| 19 | + " Unpack the options. |
| 20 | + let cmd = a:options['command'] |
| 21 | + let async = get(a:options, 'async', 0) |
| 22 | + |
| 23 | + " Write the input for the external command to a temporary file? |
| 24 | + if has_key(a:options, 'stdin') |
| 25 | + let tempin = tempname() |
| 26 | + if type(a:options['stdin']) == type([]) |
| 27 | + let lines = a:options['stdin'] |
| 28 | + else |
| 29 | + let lines = split(a:options['stdin'], "\n") |
| 30 | + endif |
| 31 | + call writefile(lines, tempin) |
| 32 | + let cmd .= ' < ' . xolox#misc#escape#shell(tempin) |
| 33 | + endif |
| 34 | + |
| 35 | + " Redirect the standard output and standard error streams of the external |
| 36 | + " process to temporary files? (only in synchronous mode, which is the |
| 37 | + " default). |
| 38 | + if !async |
| 39 | + let tempout = tempname() |
| 40 | + let temperr = tempname() |
| 41 | + let cmd = printf('(%s) 1>%s 2>%s', cmd, |
| 42 | + \ xolox#misc#escape#shell(tempout), |
| 43 | + \ xolox#misc#escape#shell(temperr)) |
| 44 | + endif |
| 45 | + |
| 46 | + " If A) we're on Windows, B) the vim-shell plug-in is installed and C) the |
| 47 | + " compiled DLL works, we'll use that because it's the most user friendly |
| 48 | + " method. If the plug-in is not installed Vim will raise the exception |
| 49 | + " "E117: Unknown function" which is caught and handled below. |
| 50 | + try |
| 51 | + if xolox#shell#can_use_dll() |
| 52 | + " Let the user know what's happening (in case they're interested). |
| 53 | + call xolox#misc#msg#debug("os.vim %s: Executing external command using compiled DLL: %s", g:xolox#misc#os#version, cmd) |
| 54 | + let exit_code = xolox#shell#execute_with_dll(cmd, async) |
| 55 | + endif |
| 56 | + catch /^Vim\%((\a\+)\)\=:E117/ |
| 57 | + call xolox#misc#msg#debug("os.vim %s: The vim-shell plug-in is not installed, falling back to system() function.", g:xolox#misc#os#version) |
| 58 | + endtry |
| 59 | + |
| 60 | + " If we cannot use the DLL, we fall back to the default and generic |
| 61 | + " implementation using Vim's system() function. |
| 62 | + if !exists('exit_code') |
| 63 | + |
| 64 | + " Enable asynchronous mode (very platform specific). |
| 65 | + if async |
| 66 | + if xolox#misc#os#is_win() |
| 67 | + let cmd = 'start /b ' . cmd |
| 68 | + elseif has('unix') |
| 69 | + let cmd = '(' . cmd . ') &' |
| 70 | + else |
| 71 | + call xolox#misc#msg#warn("os.vim %s: I don't know how to run commands asynchronously on your platform! Falling back to synchronous mode.", g:xolox#misc#os#version) |
| 72 | + endif |
| 73 | + endif |
| 74 | + |
| 75 | + " Let the user know what's happening (in case they're interested). |
| 76 | + call xolox#misc#msg#debug("os.vim %s: Executing external command using system() function: %s", g:xolox#misc#os#version, cmd) |
| 77 | + call system(cmd) |
| 78 | + let exit_code = v:shell_error |
| 79 | + |
25 | 80 | endif
|
26 |
| - return split(output, "\n") |
| 81 | + |
| 82 | + let result = {} |
| 83 | + if !async |
| 84 | + " If we just executed a synchronous command and the caller didn't |
| 85 | + " specifically ask us *not* to check the exit code of the external |
| 86 | + " command, we'll do so now. |
| 87 | + if get(a:options, 'check', 1) && exit_code != 0 |
| 88 | + let msg = "os.vim %s: External command failed with exit code %d: %s" |
| 89 | + throw printf(msg, g:xolox#misc#os#version, result['exit_code'], result['command']) |
| 90 | + endif |
| 91 | + " Return the results as a dictionary with three key/value pairs. |
| 92 | + let result['exit_code'] = exit_code |
| 93 | + let result['stdout'] = s:readfile(tempout) |
| 94 | + let result['stderr'] = s:readfile(temperr) |
| 95 | + endif |
| 96 | + return result |
| 97 | + |
| 98 | + finally |
| 99 | + " Cleanup any temporary files we created. |
| 100 | + for name in ['tempin', 'tempout', 'temperr'] |
| 101 | + if exists(name) |
| 102 | + call delete({name}) |
| 103 | + endif |
| 104 | + endfor |
| 105 | + endtry |
| 106 | + |
| 107 | +endfunction |
| 108 | + |
| 109 | +function! s:readfile(fname) " {{{1 |
| 110 | + " readfile() that swallows errors. |
| 111 | + try |
| 112 | + return readfile(a:fname) |
| 113 | + catch |
| 114 | + return [] |
27 | 115 | endtry
|
28 | 116 | endfunction
|
29 | 117 |
|
|
0 commit comments