Skip to content

Commit e7157d5

Browse files
committed
Improve quoting in execute_with_dll() (xolox/vim-easytags#51)
I'm not yet 100% convinced this will work in all cases & environments, because the rule* seems so crazy and arbitrary (coming from a UNIX background). However I did test this quite a bit and it seems to work reliably... Depending on how you read the documentation it could also make sense :-) For further discussion, see: xolox/vim-easytags#51 * "The rule": If your command line is properly quoted, just wrap it in another set of double quotes without escaping any of the double quotes inside and it will Just Work... Who comes up with this stuff?!
1 parent 84c2fda commit e7157d5

File tree

2 files changed

+110
-100
lines changed

2 files changed

+110
-100
lines changed

autoload/xolox/shell.vim

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
" Vim auto-load script
22
" Author: Peter Odding <peter@peterodding.com>
3-
" Last Change: May 28, 2013
3+
" Last Change: June 3, 2013
44
" URL: http://peterodding.com/code/vim/shell/
55

6-
let g:xolox#shell#version = '0.12.9'
6+
let g:xolox#shell#version = '0.12.10'
77

88
if !exists('s:fullscreen_enabled')
99
let s:enoimpl = "%s() hasn't been implemented on your platform! %s"
@@ -121,7 +121,19 @@ endfunction
121121
function! xolox#shell#execute_with_dll(cmd, async) " {{{1
122122
" Execute external commands on Windows using the compiled DLL.
123123
let fn = 'execute_' . (a:async ? 'a' : '') . 'synchronous'
124-
let cmd = &shell . ' ' . &shellcmdflag . ' ' . a:cmd
124+
" Command line parsing on Windows is batshit insane. I intended to define
125+
" exactly how it happens here, but the Microsoft documentation can't even
126+
" explain it properly, so I won't bother either. Suffice to say that the
127+
" outer double quotes with unescaped double quotes in between are
128+
" intentional... Here's a small excerpt from "help cmd":
129+
"
130+
" Otherwise, old behavior is to see if the first character is a quote
131+
" character and if so, strip the leading character and remove the last
132+
" quote character on the command line, preserving any text after the last
133+
" quote character.
134+
"
135+
let cmd = printf('cmd.exe /c "%s"', a:cmd)
136+
call xolox#misc#msg#debug("shell.vim %s: Executing external command: %s", g:xolox#shell#version, cmd)
125137
let result = s:library_call(fn, cmd)
126138
if result =~ '^exit_code=\d\+$'
127139
return matchstr(result, '^exit_code=\zs\d\+$') + 0

doc/shell.txt

Lines changed: 95 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
*shell.txt* Improved integration between Vim and its environment
1+
*shell.txt* Improved integration between Vim and its environment
22

33
===============================================================================
4-
*shell-contents*
54
Contents ~
65

7-
1. Introduction |shell-introduction|
8-
2. Installation |shell-installation|
9-
3. Usage (commands & functions) |shell-usage-(commands-functions)|
6+
1. Introduction |shell-introduction|
7+
2. Installation |shell-installation|
8+
3. Usage (commands & functions) |shell-usage|
109
1. The |:Maximize| command
1110
2. The |:Fullscreen| command
1211
3. The |:Open| command
@@ -18,48 +17,49 @@ Contents ~
1817
9. The |g:shell_fullscreen_always_on_top| option
1918
10. The |g:shell_mappings_enabled| option
2019
11. The |g:shell_verify_urls| option
21-
4. Background |shell-background|
22-
5. Other full-screen implementations |shell-other-full-screen-implementations|
23-
6. Contact |shell-contact|
24-
7. License |shell-license|
20+
4. Background |shell-background|
21+
5. Other full-screen implementations |shell-other-full-screen-implementations|
22+
6. Contact |shell-contact|
23+
7. License |shell-license|
24+
8. References |shell-references|
2525

2626
===============================================================================
27-
*shell-introduction*
27+
*shell-introduction*
2828
Introduction ~
2929

3030
This plug-in aims to improve the integration between Vim and its environment
3131
(your operating system) by providing the following functionality:
3232

33-
- The |:Fullscreen| command and '<F11>' mapping toggle Vim between normal and
34-
full-screen mode (see the screenshots [1]). To invoke this functionality
35-
without using the |:Fullscreen| command see the 'xolox#shell#fullscreen()'
36-
and 'xolox#shell#is_fullscreen()' functions.
33+
- The |:Fullscreen| command and '<F11>' mapping toggle Vim between normal and
34+
full-screen mode (see the screenshots [1]). To invoke this functionality
35+
without using the |:Fullscreen| command see the |xolox#shell#fullscreen()|
36+
and |xolox#shell#is_fullscreen()| functions.
3737

38-
- The |:Maximize| command and '<Control-F11>' mapping toggle Vim between
39-
normal and maximized state: They show/hide Vim's menu bar, tool bar and/or
40-
tab line without hiding the operating system task bar.
38+
- The |:Maximize| command and '<Control-F11>' mapping toggle Vim between
39+
normal and maximized state: They show/hide Vim's menu bar, tool bar and/or
40+
tab line without hiding the operating system task bar.
4141

42-
- The |:Open| command and '<F6>' mapping know how to open file and directory
43-
names, URLs and e-mail addresses in your favorite programs (file manager,
44-
web browser, e-mail client, etc).
42+
- The |:Open| command and '<F6>' mapping know how to open file and directory
43+
names, URLs and e-mail addresses in your favorite programs (file manager,
44+
web browser, e-mail client, etc).
4545

46-
- The 'xolox#misc#os#exec()' function enables other Vim plug-ins (like my
47-
easytags.vim [2] plug-in) to execute external commands in the background
48-
(i.e. asynchronously) without opening a command prompt window on Windows.
46+
- The |xolox#misc#os#exec()| function enables other Vim plug-ins (like my
47+
easytags.vim [2] plug-in) to execute external commands in the background
48+
(i.e. asynchronously) _without opening a command prompt window on Windows_.
4949

5050
Two Windows DLL files [3] are included to perform these functions on Windows,
5151
while on UNIX external commands are used.
5252

5353
===============================================================================
54-
*shell-installation*
54+
*shell-installation*
5555
Installation ~
5656

57-
Please note that the vim-shell plug-in requires my vim-misc plug-in which is
58-
separately distributed.
57+
_Please note that the vim-shell plug-in requires my vim-misc plug-in which is
58+
separately distributed._
5959

60-
Unzip the most recent ZIP archives of the vim-shell [4] and vim-misc [5]
61-
plug-ins inside your Vim profile directory (usually this is '~/.vim' on UNIX
62-
and '%USERPROFILE%\vimfiles' on Windows), restart Vim and execute the command
60+
Unzip the most recent ZIP archives of the vim-shell [4] and vim-misc [5] plug-
61+
ins inside your Vim profile directory (usually this is '~/.vim' on UNIX and
62+
'%USERPROFILE%\vimfiles' on Windows), restart Vim and execute the command
6363
':helptags ~/.vim/doc' (use ':helptags ~\vimfiles\doc' instead on Windows).
6464

6565
If you prefer you can also use Pathogen [6], Vundle [7] or a similar tool to
@@ -70,7 +70,7 @@ After you've installed the plug-in and restarted Vim, the following commands
7070
will be available to you:
7171

7272
===============================================================================
73-
*shell-usage-(commands-functions)*
73+
*shell-usage*
7474
Usage (commands & functions) ~
7575

7676
-------------------------------------------------------------------------------
@@ -102,17 +102,16 @@ addresses. It's mapped to '<F6>' by default, see |g:shell_mappings_enabled| if
102102
you don't like this. You can provide a filename, URL or e-mail address as
103103
argument to the command or if there's a filename, URL or e-mail address under
104104
the text cursor that will be used. If both of those fail, the directory
105-
containing the current file will be opened. You can use the command as
106-
follows:
105+
containing the current file will be opened. You can use the command as follows:
107106
>
108-
:Open http://www.vim.org/
109-
107+
:Open http://www.vim.org/
108+
<
110109
This will launch your preferred (or the best available) web browser. Likewise
111110
the following command will open your file manager in the directory of Vim's
112111
runtime files:
113112
>
114-
:Open $VIMRUNTIME
115-
113+
:Open $VIMRUNTIME
114+
<
116115
Note that on UNIX if the environment variable '$DISPLAY' is empty the plug-in
117116
will fall back to a command-line web browser. Because such web browsers are
118117
executed in front of Vim you have to quit the web browser to return to Vim.
@@ -134,15 +133,15 @@ for |v:shell_error|.
134133
The *xolox#misc#os#exec()* function
135134

136135
This function enables other Vim plug-ins to execute external commands in the
137-
background (i.e. asynchronously) without opening a command prompt window on
138-
Windows. For example try to execute the following command on Windows
136+
background (i.e. asynchronously) _without opening a command prompt window on
137+
Windows_. For example try to execute the following command on Windows
139138
(vimrun.exe (see |win32-vimrun|) is only included with Vim for Windows because
140139
it isn't needed on other platforms):
141140
>
142-
:call xolox#misc#os#exec({'command': 'vimrun', 'async': 1})
143-
141+
:call xolox#misc#os#exec({'command': 'vimrun', 'async': 1})
142+
<
144143
Immediately after executing this command Vim will respond to input again
145-
because 'xolox#misc#os#exec()' doesn't wait for the external command to finish
144+
because |xolox#misc#os#exec()| doesn't wait for the external command to finish
146145
when the 'async' argument is true (1). In addition no command prompt window
147146
will be shown which means vimrun.exe (see |win32-vimrun|) is running completely
148147
invisible in the background.
@@ -151,22 +150,23 @@ The function returns a dictionary of return values. In asynchronous mode the
151150
dictionary is empty. In synchronous mode it contains the following key/value
152151
pairs:
153152
>
154-
:echo xolox#misc#os#exec({'command': 'echo "this is stdout" && echo "this is stderr" >&2 && exit 42'})
155-
{'exit_code': 42, 'stdout': ['this is stdout'], 'stderr': ['this is stderr']}
156-
153+
:echo xolox#misc#os#exec({'command': 'echo "this is stdout" && echo "this is stderr" >&2 && exit 42'})
154+
{'exit_code': 42, 'stdout': ['this is stdout'], 'stderr': ['this is stderr']}
155+
<
157156
If you want to verify that this function works as described, execute the
158157
command mentioning 'vimrun' above, open the Windows task manager by pressing
159-
'Control-Shift-Escape' and check that the process 'vimrun.exe' is listed in
160-
the processes tab. If you don't see the problem this is solving, try executing
161-
vimrun.exe (see |win32-vimrun|) using Vim's built-in |system()| function instead:
158+
'Control-Shift-Escape' and check that the process 'vimrun.exe' is listed in the
159+
processes tab. If you don't see the problem this is solving, try executing
160+
vimrun.exe (see |win32-vimrun|) using Vim's built-in |system()| function
161+
instead:
162162
>
163-
:call system('vimrun')
164-
163+
:call system('vimrun')
164+
<
165165
Vim will be completely unresponsive until you "press any key to continue" in
166166
the command prompt window that's running vimrun.exe (see |win32-vimrun|). Of
167-
course the |system()| function should only be used with non-interactive programs
168-
(the documentation says as much) but the point is to simulate an external
169-
command that takes a while to finish and blocks Vim while doing so.
167+
course the |system()| function should only be used with non-interactive
168+
programs (the documentation says as much) but the point is to simulate an
169+
external command that takes a while to finish and blocks Vim while doing so.
170170

171171
Note that on Windows this function uses Vim's |'shell'| and |'shellcmdflag'|
172172
options to compose the command line passed to the DLL.
@@ -189,16 +189,14 @@ The *g:shell_fullscreen_items* option
189189
This variable is a string containing any combination of the following
190190
characters:
191191

192-
- 'm': Hide the main menu (see |'go-m'|) when switching to full-screen;
192+
- 'm': Hide the main menu (see |'go-m'|) when switching to full-screen;
193+
- 'T': Hide the toolbar (see |'go-T'|) when switching to full-screen;
194+
- 'e': Hide the tabline (see |'go-e'|) when switching to full-screen (this
195+
also toggles the showtabline option (see |'showtabline'|)).
193196

194-
- 'T': Hide the toolbar (see |'go-T'|) when switching to full-screen;
195-
196-
- 'e': Hide the tabline (see |'go-e'|) when switching to full-screen (this also
197-
toggles the showtabline option (see |'showtabline'|)).
198-
199-
By default all the above items are hidden in full-screen mode. You can also
200-
set the buffer local variable 'b:shell_fullscreen_items' to change these
201-
settings for specific buffers.
197+
By default all the above items are hidden in full-screen mode. You can also set
198+
the buffer local variable 'b:shell_fullscreen_items' to change these settings
199+
for specific buffers.
202200

203201
-------------------------------------------------------------------------------
204202
The *g:shell_fullscreen_always_on_top* option
@@ -208,45 +206,45 @@ Some people don't like this which is why this option was added. Its default
208206
value is true (1) so to disable the "always on top" feature you would add this
209207
to your |vimrc| script:
210208
>
211-
:let g:shell_fullscreen_always_on_top = 0
212-
209+
:let g:shell_fullscreen_always_on_top = 0
210+
<
213211
-------------------------------------------------------------------------------
214212
The *g:shell_mappings_enabled* option
215213

216214
If you don't like the default mappings for the |:Open| and |:Fullscreen|
217215
commands then add the following to your |vimrc| script:
218216
>
219-
:let g:shell_mappings_enabled = 0
220-
217+
:let g:shell_mappings_enabled = 0
218+
<
221219
Since no mappings will be defined now you can add something like the following
222220
to your |vimrc| script:
223221
>
224-
:inoremap <Leader>fs <C-o>:Fullscreen<CR>
225-
:nnoremap <Leader>fs :Fullscreen<CR>
226-
:inoremap <Leader>op <C-o>:Open<CR>
227-
:nnoremap <Leader>op :Open<CR>
228-
222+
:inoremap <Leader>fs <C-o>:Fullscreen<CR>
223+
:nnoremap <Leader>fs :Fullscreen<CR>
224+
:inoremap <Leader>op <C-o>:Open<CR>
225+
:nnoremap <Leader>op :Open<CR>
226+
<
229227
-------------------------------------------------------------------------------
230228
The *g:shell_verify_urls* option
231229

232230
When you use the |:Open| command or the '<F6>' mapping to open the URL under
233-
the text cursor, the shell plug-in uses a regular expression to guess where
234-
the URL starts and ends. This works 99% percent of the time but it can break,
231+
the text cursor, the shell plug-in uses a regular expression to guess where the
232+
URL starts and ends. This works 99% percent of the time but it can break,
235233
because in this process the shell plug-in will strip trailing punctuation
236234
characters like dots (because they were likely not intended to be included in
237235
the URL).
238236

239237
If you actually deal with URLs that include significant trailing punctuation
240238
and your Vim is compiled with Python support you can enable the option
241239
|g:shell_verify_urls| (by setting it to 1 in your |vimrc| script). When you do
242-
this the plug-in will perform an HTTP HEAD request on the URL without
243-
stripping trailing punctuation. If the request returns an HTTP status code
244-
that indicates some form of success (the status code is at least 200 and less
245-
than 400) the URL including trailing punctuation is opened. If the HEAD
246-
request fails the plug-in will try again without trailing punctuation.
240+
this the plug-in will perform an HTTP HEAD request on the URL without stripping
241+
trailing punctuation. If the request returns an HTTP status code that indicates
242+
some form of success (the status code is at least 200 and less than 400) the
243+
URL including trailing punctuation is opened. If the HEAD request fails the
244+
plug-in will try again without trailing punctuation.
247245

248246
===============================================================================
249-
*shell-background*
247+
*shell-background*
250248
Background ~
251249

252250
Vim has a limited ability to call external libraries using the Vim script
@@ -257,28 +255,28 @@ useful functions, e.g. 'openurl()' to launch the default web browser and
257255
'execute()' which works like Vim's |system()| function but doesn't wait for the
258256
process to finish and doesn't show a command prompt.
259257

260-
Since then I switched to Linux and didn't look back, which meant the DLL sat
261-
in my '~/.vim/etc/' waiting to be revived. Now that I've published my
262-
easytags.vim [2] plug-in and put a lot of effort into making it Windows
263-
compatible, the 'execute()' function from the DLL would be very useful to run
264-
Exuberant Ctags [12] in the background without stealing Vim's focus by opening
265-
a command prompt window. This is why I've decided to release the DLL. Because
266-
I switched to Linux I've also added an autoload script that wraps the DLL on
267-
Windows and calls out to external programs such as 'wmctrl', 'gnome-open',
268-
'kde-open', and others on UNIX.
258+
Since then I switched to Linux and didn't look back, which meant the DLL sat in
259+
my '~/.vim/etc/' waiting to be revived. Now that I've published my easytags.vim
260+
[2] plug-in and put a lot of effort into making it Windows compatible, the
261+
'execute()' function from the DLL would be very useful to run Exuberant Ctags
262+
[12] in the background without stealing Vim's focus by opening a command prompt
263+
window. This is why I've decided to release the DLL. Because I switched to
264+
Linux I've also added an autoload script that wraps the DLL on Windows and
265+
calls out to external programs such as 'wmctrl', 'gnome-open', 'kde-open', and
266+
others on UNIX.
269267

270268
===============================================================================
271-
*shell-other-full-screen-implementations*
269+
*shell-other-full-screen-implementations*
272270
Other full-screen implementations ~
273271

274272
After publishing this plug-in I found that the Vim plug-ins VimTweak [13] and
275-
gvimfullscreen_win32 [14] also implement full-screen on Windows using a
276-
similar approach as my plug-in. I prefer the effect of my plug-in because it
277-
seems to hide window decorations more effectively. Also note that my plug-in
278-
was developed independently of the other two.
273+
gvimfullscreen_win32 [14] also implement full-screen on Windows using a similar
274+
approach as my plug-in. I prefer the effect of my plug-in because it seems to
275+
hide window decorations more effectively. Also note that my plug-in was
276+
developed independently of the other two.
279277

280278
===============================================================================
281-
*shell-contact*
279+
*shell-contact*
282280
Contact ~
283281

284282
If you have questions, bug reports, suggestions, etc. the author can be
@@ -287,14 +285,14 @@ http://peterodding.com/code/vim/shell/ and http://github.com/xolox/vim-shell.
287285
If you like the plug-in please vote for it on Vim Online [15].
288286

289287
===============================================================================
290-
*shell-license*
288+
*shell-license*
291289
License ~
292290

293-
This software is licensed under the MIT license [16]. Copyright 2013 Peter
294-
Odding <peter@peterodding.com>.
291+
This software is licensed under the MIT license [16]. © 2013 Peter Odding
292+
<peter@peterodding.com>.
295293

296294
===============================================================================
297-
*shell-references*
295+
*shell-references*
298296
References ~
299297

300298
[1] http://peterodding.com/code/vim/shell/screenshots/

0 commit comments

Comments
 (0)