As Johannes Schindelin suggested, it verifies that the selected item is
a valid Git repository and add different menu items accordingly.
This version is for preview purposes only. It implements the suggestion
in a way that the text of the item is context-sensitive, but the action
is always the same.
TODO: think about making LONGEST_MENU_ITEM and MAX_PROCESSING_TIME
dynamic/configurable.
TODO: decide on a structure and actions of added menu items.
---
exec.c | 49 +++++++++++++++++++++++++++++-------
exec.h | 7 +++-
ext.c | 4 +++
menu.c | 86 ++++++++++++++++++++++++++++++++++++++++++---------------------
4 files changed, 105 insertions(+), 41 deletions(-)
diff --git a/exec.c b/exec.c
index 4d519cc..950a527 100644
--- a/exec.c
+++ b/exec.c
@@ -1,9 +1,12 @@
#include <windows.h>
#include <stdio.h>
+#include <process.h>
#include "debug.h"
#include "systeminfo.h"
#include "exec.h"
+#define MAX_PROCESSING_TIME (60 * 1000)
+
char *env_for_git()
{
static char *environment;
@@ -51,26 +54,52 @@ char *env_for_git()
return environment;
}
-void exec_gui(char *command, const char *wd)
+int exec_git(int mode, char *command, const char *wd)
{
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
+ DWORD status = -1;
+ char cmd[1024];
+
+ if (!msys_path()) {
+ debug_git("[ERROR] Could not find msysPath");
+ return -1;
+ }
+
+ sprintf(cmd, "\"%s\\bin\\git.exe\" %s", msys_path(), command);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
- debug_git("Trying to spawn '%s' in working directory '%s'\n",
+ debug_git("Trying to spawn 'git %s' in working directory '%s'\n",
command, wd);
- if (CreateProcess(NULL, command, NULL, NULL, FALSE, 0,
- env_for_git(), wd, &si, &pi))
- {
- CloseHandle(pi.hProcess);
- CloseHandle(pi.hThread);
- }
- else
- debug_git("[ERROR] Could not create process (%d)"
+ if (! CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0,
+ env_for_git(), wd, &si, &pi)) {
+ debug_git("[ERROR] Could not create process (%d); "
"wd: %s; cmd: %s",
GetLastError(), wd, command);
+ return -1;
+ }
+
+ if (P_WAIT == mode) {
+ if (WAIT_OBJECT_0 == WaitForSingleObject(pi.hProcess,
+ MAX_PROCESSING_TIME)) {
+
+ if (! GetExitCodeProcess(pi.hProcess, &status))
+ debug_git("[ERROR] GetExitCode failed (%d); "
+ "wd: %s; cmd: %s",
+ GetLastError(), wd, command);
+
+ } else
+ debug_git("[ERROR] process timed out; "
+ "wd: %s; cmd: %s",
+ wd, command);
+ }
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+
+ return status;
}
diff --git a/exec.h b/exec.h
index cebb56b..146f501 100644
--- a/exec.h
+++ b/exec.h
@@ -5,7 +5,10 @@
char *env_for_git();
/*
- * Executes a console application hidden as in "git gui" to hide git
+ * Native, simplified implementation of spawn with a working directory
+ *
+ * Executes git.exe
+ * Supports only P_WAIT and P_NOWAIT modes.
*/
-void exec_gui(char *cmd, const char *wd);
+int exec_git(int mode, char *cmd, const char *wd);
diff --git a/ext.c b/ext.c
index 593d4e4..cf85ae8 100644
--- a/ext.c
+++ b/ext.c
@@ -57,6 +57,10 @@ inline STDMETHODIMP initialize_git_data(struct
git_data *this_,
UINT count;
HRESULT result = S_OK;
+ /* store the folder, if provided */
+ if (folder)
+ SHGetPathFromIDList(folder, this_->name);
+
if (!data)
return S_OK;
diff --git a/menu.c b/menu.c
index 97811fa..55f17d4 100644
--- a/menu.c
+++ b/menu.c
@@ -1,13 +1,15 @@
#include <shlobj.h>
-#include <stdarg.h>
#include <tchar.h>
#include <stdio.h>
+#include <process.h>
#include "menu.h"
#include "ext.h"
#include "debug.h"
#include "systeminfo.h"
#include "exec.h"
+#define LONGEST_MENU_ITEM 40
+
/*
* These are the functions for handling the context menu.
*/
@@ -18,16 +20,55 @@ static STDMETHODIMP query_context_menu(void *p, HMENU menu,
{
struct git_menu *this_menu = p;
struct git_data *this_ = this_menu->git_data;
+ char *wd;
+ BOOL bDirSelected = TRUE;
+
+ UINT original_first = first_command;
+ char menu_item[LONGEST_MENU_ITEM];
+
+ int status;
if (flags & CMF_DEFAULTONLY)
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
+ /* figure out the directory */
+ wd = strdup(this_->name);
+ if (!(FILE_ATTRIBUTE_DIRECTORY & GetFileAttributes(wd))) {
+ char *c = strrchr(wd, '\\');
+ *c = 0;
+ bDirSelected = FALSE;
+ }
+
+ status = exec_git(P_WAIT, "rev-parse --show-cdup", wd);
+ free (wd);
+
+ if (-1 == status)
+ return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
+
+ /*
+ * TODO: the following big, ugly code needs to be something like
+ * build_menu_items()
+ * It's left as is to signify the preview nature of the patch
+ */
+ if (0 != status) { /* this is not a repository */
+ if (bDirSelected)
+ strcpy(menu_item, "&Git Clone Here");
+ else
+ strcpy(menu_item, "&Git Init Here");
+ } else
+ strcpy(menu_item, "&Git");
+
InsertMenu(menu, index, MF_SEPARATOR | MF_BYPOSITION,
- first_command, "");
+ first_command++, "");
InsertMenu(menu, index+1, MF_STRING | MF_BYPOSITION,
- first_command+1, _T("&Git Gui"));
+ first_command++, menu_item);
- return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 2);
+ /*
+ * TODO: when the above block is fixed, we'll just have
+ * return MAKE_RESULT(..., build_menu_items());
+ */
+ return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL,
+ first_command - original_first);
}
/*
@@ -95,32 +136,19 @@ static STDMETHODIMP invoke_command(void *p,
if (command == 1)
{
- TCHAR * msysPath = msys_path();
+ const char *wd;
+ DWORD dwAttr, fa;
- if (msysPath)
- {
- TCHAR command[1024];
- const char *wd;
- DWORD dwAttr, fa;
-
- wsprintf(command, TEXT("\"%s\\bin\\git.exe\" gui"),
- msysPath);
-
-
- wd = this_->name;
- if (wd == NULL || strlen(wd) == 0)
- wd = info->lpDirectory;
-
- dwAttr = FILE_ATTRIBUTE_DIRECTORY;
- fa = GetFileAttributes(wd);
- if (! (fa & dwAttr))
- wd = info->lpDirectory;
-
- exec_gui(command, wd);
- }
- else
- debug_git("[ERROR] %s/%s:%d Could not find msysPath",
- __FILE__, __FUNCTION__, __LINE__);
+ wd = this_->name;
+ if (wd == NULL || strlen(wd) == 0)
+ wd = info->lpDirectory;
+
+ dwAttr = FILE_ATTRIBUTE_DIRECTORY;
+ fa = GetFileAttributes(wd);
+ if (!(fa & dwAttr))
+ wd = info->lpDirectory;
+
+ exec_git(P_NOWAIT, "gui", wd);
return S_OK;
}
--
1.5.4.rc0.929.g50e2