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

Reply via email to