README.txt: add a link to the wiki page
[git-cheetah.git] / explorer / columns.c
blob7d28629e79eb984318250cd6196b39ad133dc637
2 #include "../common/cache.h"
3 #include "../common/exec.h"
5 #include <shlobj.h>
6 #include "../common/menuengine.h"
7 #include "ext.h"
8 #include "columns.h"
10 #ifndef _MSC_VER
12 * this flag, not defined in mingw's ShlObj.h, is a hint that the file
13 * has changed since the last call to GetItemData
15 #define SHCDF_UPDATEITEM 0x00000001
17 #ifndef _WIN64
18 /* convenience macro, not defined in mingw's OleAuto.h */
19 #define V_I1REF(X) V_UNION(X, pcVal)
20 #endif /* _WIN64 */
21 #endif
23 #define CHEETAH_COLUMN_FLAGS (SHCOLSTATE_TYPE_STR)
26 * If a non-standard FMT is specified, the column will be accessible
27 * only in repo folders. But if FMTID_SummaryInformation is used,
28 * the column's info will be "merged" into CHEETAH_PID_* and may
29 * be visible in the Details on folder's task pane
31 #define CHEETAH_FMTID IID_git_columns
34 * column's id, that can be matched to one of standard FMTs
35 * for example, if FMTID is FMTID_SummaryInformation than
36 * PID can be PIDSI_AUTHOR, so the status is provided in the
37 * Author column and visible in the Details
39 #define CHEETAH_STATUS_PID 0
41 /* names and descriptions MUST be wchar * */
42 #define CHEETAH_STATUS_NAME L"Git Status"
43 #define CHEETAH_STATUS_DESC L"Status of the file in a Git repository"
45 STDMETHODIMP initialize_columns(void *p, LPCSHCOLUMNINIT psci)
47 struct git_data *this_ = ((struct git_columns *)p)->git_data;
48 int status;
50 wcstombs(this_->name, psci->wszFolder, MAX_PATH);
53 * don't try to do anything about cache here, because
54 * we're called even if get_item_data will not be called
56 status = exec_program(this_->name, NULL, NULL, WAITMODE,
57 "git", "rev-parse", "--show-prefix", NULL);
60 * if something went terribly wrong or not a repo,
61 * return E_FAIL to prevent calls to get_column_info
63 return status ? E_FAIL : S_OK;
66 STDMETHODIMP get_column_info(void *p, DWORD dwIndex, SHCOLUMNINFO *psci)
68 struct git_data *this_ = ((struct git_columns *)p)->git_data;
70 /* do NOT FORGET to increase this when adding more columns */
71 if (0 < dwIndex)
72 return S_FALSE;
74 psci->scid.fmtid = CHEETAH_FMTID;
75 psci->scid.pid = CHEETAH_STATUS_PID;
76 psci->vt = VT_LPSTR;
77 psci->fmt = LVCFMT_LEFT;
78 psci->cChars = 15;
79 psci->csFlags = CHEETAH_COLUMN_FLAGS;
81 lstrcpynW(psci->wszTitle,
82 CHEETAH_STATUS_NAME, MAX_COLUMN_NAME_LEN);
83 lstrcpynW(psci->wszDescription,
84 CHEETAH_STATUS_DESC, MAX_COLUMN_DESC_LEN);
86 return S_OK;
89 static int cache_others(char *wd, struct strbuf *cache)
91 int status;
93 if (cache->alloc)
94 return 0;
96 strbuf_init(cache, 0);
97 status = exec_program(wd, cache, NULL, WAITMODE,
98 "git", "ls-files", "-z", "--others", "--exclude-standard",
99 NULL);
101 /* something went terribly wrong or not a repo */
102 if (status)
103 strbuf_release(cache);
104 return status;
108 * cache files' status, and return non-zero on the first failure
109 * because if something goes wrong, there is no need to try other statuses
111 static int cache(struct git_data *this_)
113 int status;
114 if (status = cache_others(this_->name, &this_->other_files))
115 return status;
117 /* if everything succeeded, return success */
118 return 0;
121 static char *parse_others(struct strbuf *cache, char *file)
123 char *start = cache->buf;
124 while (*start) {
125 if (!stricmp(file, start))
126 return "other";
128 start += strlen(start) + 1;
131 return 0;
134 static char *parse_status(struct git_data *this_, char *file)
136 char *result = NULL;
138 if (result = parse_others(&this_->other_files, file))
139 return result;
141 /* if no status was found, return NULL string */
142 return NULL;
146 STDMETHODIMP get_item_data(void *p,
147 LPCSHCOLUMNID pscid,
148 LPCSHCOLUMNDATA pscd,
149 VARIANT *pvarData)
151 struct git_data *this_ = ((struct git_columns *)p)->git_data;
152 char file_path[MAX_PATH], *file = file_path;
153 char *result;
155 /* directories don't have status */
156 if (pscd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
157 return S_FALSE;
159 /* update cache and bail out on failure */
160 if (cache(this_))
161 return S_FALSE;
163 if (pscd->dwFlags & SHCDF_UPDATEITEM) {
165 * we can add the file to the usual ls-files
166 * or we can refresh the whole cache
170 wcstombs(file, pscd->wszFile, MAX_PATH);
171 file += strlen(this_->name) + 1;
173 /* get the status from cache and return if any */
174 if (result = parse_status(this_, file)) {
175 V_VT(pvarData) = VT_LPSTR;
176 V_I1REF(pvarData) = result;
177 return S_OK;
180 return S_FALSE;
183 DEFINE_STANDARD_METHODS(git_columns)
185 struct git_columns_virtual_table git_columns_virtual_table = {
186 query_interface_git_columns,
187 add_ref_git_columns,
188 release_git_columns,
189 initialize_columns,
190 get_column_info,
191 get_item_data