Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Better DLL detection, synchronous command execution

 * Added a libversion() function to the DLL which is used by the Vim
   script to verify that the DLL exists & can be loaded and that there
   isn't a version mismatch between the Vim script and the DLL.

 * Added the option of waiting for the external command to finish
   by removing execute() from the DLL and adding execute_synchronous()
   as well as execute_asynchronous(). The Vim script still contains the
   single function xolox#shell#execute() however it used to take
   printf()-style variable arguments and now always requires two
   arguments: the command to execute and whether to wait for the command
   to finish, where 1 = yes and 0 = no.

 * Because the Vim script already contained code to build command-lines
   but that functionality was removed from the xolox#shell#execute()
   function I've decided to make the function used to build
   command-lines public. This way there's no loss in functionality, only
   ease of use.
  • Loading branch information...
commit 82f6cb0f013480f994438d44b6cf98ae136569c0 1 parent 5045306
@xolox authored
Showing with 86 additions and 40 deletions.
  1. +42 −22 autoload.vim
  2. +44 −18 dll/shell.c
View
64 autoload.vim
@@ -1,6 +1,6 @@
" Vim autoload plug-in
" Maintainer: Peter Odding <peter@peterodding.com>
-" Last Change: June 13, 2010
+" Last Change: June 14, 2010
" URL: http://peterodding.com/code/vim/shell
" This Vim script enables tighter integration between Vim and its environment
@@ -52,16 +52,17 @@ function! xolox#shell#openurl(url) " {{{1
throw printf(s:enoimpl, s:script, 'openurl', s:contact)
endfunction
-function! xolox#shell#execute(cmd, ...) " {{{1
- let cmd = s:make_cmdline(a:cmd, a:000)
+function! xolox#shell#execute(command, synchronous) " {{{1
if s:is_windows() && s:has_dll()
- let error = s:library_call('execute', cmd)
+ let fn = 'execute_' . (a:synchronous ? '' : 'a') . 'synchronous'
+ let error = s:library_call(fn, a:command)
if error != ''
- let msg = '%s: execute(%s) failed! (error: %s)'
- throw printf(msg, s:script, strtrans(cmd), strtrans(error))
+ let msg = '%s: %s(%s) failed! (error: %s)'
+ throw printf(msg, s:script, fn, strtrans(a:command), strtrans(error))
endif
else
- if has('unix')
+ let cmd = a:command
+ if has('unix') && !a:synchronous
let cmd = '(' . cmd . ') &'
endif
let output = system(cmd)
@@ -109,6 +110,16 @@ function! xolox#shell#fullscreen() " {{{1
return 0
endfunction
+function! xolox#shell#buildcmd(cmd, args) " {{{1
+ if a:args == []
+ return a:cmd
+ else
+ let args = map(copy(a:args), 'shellescape(v:val)')
+ call insert(args, a:cmd, 0)
+ return call('printf', args)
+ endif
+endfunction
+
" Supporting functions. {{{1
function! s:is_windows() " {{{2
@@ -119,28 +130,37 @@ if s:is_windows()
let s:library = expand('<sfile>:p:h') . '\shell.dll'
- function! s:has_dll() " {{{2
- return filereadable(s:library)
- endfunction
-
function! s:library_call(fn, arg) " {{{2
return libcall(s:library, a:fn, a:arg)
endfunction
-endif
+ function! s:find_dll_version() " {{{2
+ try
+ return s:library_call('libversion', '')
+ catch
+ let msg = "%s: Failed to load %s DLL!"
+ let lib = fnamemodify(s:library, ':~')
+ echohl warningmsg
+ echomsg printf(msg, s:script, lib)
+ echohl none
+ endtry
+ return '?'
+ endfunction
-function! s:make_cmdline(cmd, args) " {{{2
- if a:args == []
- return a:cmd
- else
- let args = map(copy(a:args), 'shellescape(v:val)')
- call insert(args, a:cmd, 0)
- return call('printf', args)
- endif
-endfunction
+ function! s:has_dll() " {{{2
+ " Check that the DLL is available using libversion() before calling any of
+ " the other functions. This is only done the first time this plug-in needs
+ " to call the DLL and also makes sure the right version is loaded.
+ if !exists('s:library_version')
+ let s:library_version = s:find_dll_version()
+ endif
+ return s:library_version == '0.2'
+ endfunction
+
+endif
function! s:execute(cmd, args) " {{{2
- let cmd = s:make_cmdline(a:cmd, a:args)
+ let cmd = xolox#shell#buildcmd(a:cmd, a:args)
let output = system(cmd)
call s:handle_error(cmd, output)
return output
View
62 dll/shell.c
@@ -1,9 +1,10 @@
/* This is a dynamic link library for Vim on Windows that makes the following
* features available to Vim:
*
- * - Open the user's preferred web browser with a given URL;
- * - Execute external programs *without* showing a command prompt;
- * - Toggle Vim's full-screen state using a bit of Windows API magic.
+ * - Open the user's preferred web browser with a given URL;
+ * - Execute external commands *without* showing a command prompt,
+ * optionally waiting for the command to finish;
+ * - Toggle Vim's full-screen state using a bit of Windows API magic.
*
* If you want to compile this library yourself you need to have the Microsoft
* Windows SDK installed, you can find a download link on the following web
@@ -14,14 +15,14 @@
*
* Open the Windows SDK command prompt and run the following command:
*
- * CL /LD shell.c shell32.lib user32.lib
+ * CL /LD shell.c shell32.lib user32.lib
*
* This should create the dynamic link library "shell.dll" which you can call
* from Vim using for example :call libcall('c:/shell.dll', 'fullscreen', 1).
*
* Happy vimming!
*
- * - Peter Odding <peter@peterodding.com>
+ * - Peter Odding <peter@peterodding.com>
*/
#define _WIN32_WINNT 0x0500 /* GetConsoleWindow() */
@@ -35,7 +36,7 @@ static char buffer[1024 * 10];
#undef MessageBox
#define MessageBox(message) MessageBoxA(NULL, message, "Vim Library", 0)
-static char *GetError(void)
+static char *GetError(void) /* {{{1 */
{
int i;
@@ -49,20 +50,19 @@ static char *GetError(void)
return buffer;
}
-static char *Success(char *result)
+static char *Success(char *result) /* {{{1 */
{
/* printf("OK\n"); */
return result;
}
-static char *Failure(char *result)
+static char *Failure(char *result) /* {{{1 */
{
/* if (result && strlen(result)) MessageBox(result); */
return result;
}
-__declspec(dllexport)
-char *execute(char *command)
+static char *execute(char *command, int wait) /* {{{1 */
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
@@ -70,6 +70,13 @@ char *execute(char *command)
ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si);
if (CreateProcess(0, command, 0, 0, 0, CREATE_NO_WINDOW, 0, 0, &si, &pi)) {
+ if (wait) {
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ /* long exit_code; */
+ /* TODO: GetExitCodeProcess( pi.hProcess, &exit_code); */
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ }
return Success(NULL);
} else {
return Failure(GetError());
@@ -77,14 +84,33 @@ char *execute(char *command)
}
__declspec(dllexport)
-char *openurl(char *path)
+char *execute_synchronous(char *command) /* {{{1 */
+{
+ return execute(command, 1);
+}
+
+__declspec(dllexport)
+char *execute_asynchronous(char *command) /* {{{1 */
+{
+ return execute(command, 0);
+}
+
+__declspec(dllexport)
+char *libversion(char *ignored) /* {{{1 */
+{
+ (void)ignored;
+ return Success("0.2");
+}
+
+__declspec(dllexport)
+char *openurl(char *path) /* {{{1 */
{
ShellExecute(NULL, "open", path, NULL, NULL, SW_SHOWNORMAL);
return Success(NULL);
}
__declspec(dllexport)
-char *fullscreen(long enable)
+char *fullscreen(long enable) /* {{{1 */
{
HWND window;
LONG styles;
@@ -98,7 +124,7 @@ char *fullscreen(long enable)
return Failure("Could not query window styles!");
if (enable) styles ^= WS_CAPTION | WS_THICKFRAME;
- else styles |= WS_CAPTION | WS_THICKFRAME;
+ else styles |= WS_CAPTION | WS_THICKFRAME;
if (!SetWindowLong(window, GWL_STYLE, styles))
return Failure("Could not apply window styles!");
@@ -122,13 +148,13 @@ char *fullscreen(long enable)
return Success(NULL);
}
-/* TODO: The quest to embedding a command prompt in Vim :)
- * This doesn't quite work and I'm afraid it never will.
- */
-
__declspec(dllexport)
-char *console(char *command)
+char *console(char *command) /* {{{1 */
{
+ /* TODO: The quest to embedding a command prompt in Vim :)
+ * This doesn't quite work and I'm afraid it never will.
+ */
+
HWND gvim, console;
LONG styles;
Please sign in to comment.
Something went wrong with that request. Please try again.