1 #include <string.h>
2
3 #include "git2.h"
4
5 #include "egit.h"
6 #include "egit-util.h"
7 #include "interface.h"
8 #include "egit-pathspec.h"
9
10 EGIT_DOC(pathspec_new, "PATHSPECS",
11 "Compile a pathspec object from a PATHSPECS list of strings.");
egit_pathspec_new(emacs_env * env,emacs_value _pathspecs)12 emacs_value egit_pathspec_new(emacs_env *env, emacs_value _pathspecs)
13 {
14 git_strarray pathspecs;
15 if (!egit_strarray_from_list(&pathspecs, env, _pathspecs)) {
16 return esym_nil;
17 }
18
19 git_pathspec* spec = NULL;
20 int retval = git_pathspec_new(&spec, &pathspecs);
21 egit_strarray_dispose(&pathspecs);
22 EGIT_CHECK_ERROR(retval);
23
24 return egit_wrap(env, EGIT_PATHSPEC, spec, NULL);
25 }
26
extract_flags(int32_t * out,emacs_env * env,emacs_value _flags)27 static emacs_value extract_flags(int32_t *out, emacs_env* env, emacs_value _flags) {
28 {
29 EM_DOLIST(_flag, _flags, flags_label);
30 git_pathspec_flag_t flag = 0;
31 em_findsym_pathspec_flag(&flag, env, _flag, true);
32 *out |= flag;
33 EM_DOLIST_END(flags_label);
34 }
35 return esym_t;
36 }
37
38 EGIT_DOC(pathspec_matches_path, "PATHSPEC FLAGS PATH",
39 "Try to match a PATH against a PATHSPEC.\n"
40 "\n"
41 "FLAGS should be nil or a list with the following symbols:\n"
42 " - ignore-case: forces match to ignore case\n"
43 " - use-case: forces case sensitive match\n"
44 " - no-glob: disables glob patterns and just uses simple string "
45 "comparison for matching\n"
46 "\n"
47 "Unlike most of the other pathspec matching functions, this will not "
48 "fall back on the native case-sensitivity for your platform. "
49 "You must explicitly pass flags to control case sensitivity or else "
50 "this will fall back on being case sensitive.");
egit_pathspec_matches_path(emacs_env * env,emacs_value _pathspec,emacs_value _flags,emacs_value _path)51 emacs_value egit_pathspec_matches_path(emacs_env *env, emacs_value _pathspec,
52 emacs_value _flags, emacs_value _path)
53 {
54 EGIT_ASSERT_PATHSPEC(_pathspec);
55 EM_ASSERT_STRING(_path);
56
57 git_pathspec *pathspec = EGIT_EXTRACT(_pathspec);
58 int32_t flags = 0;
59 extract_flags(&flags, env, _flags);
60 char *path = EM_EXTRACT_STRING(_path);
61
62 bool retval = git_pathspec_matches_path(pathspec, flags, path);
63 free(path);
64 return retval ? esym_t : esym_nil;
65 }
66
67 EGIT_DOC(pathspec_match_list_entrycount, "PATHSPEC-MATCH-LIST",
68 "Get the number of items in a match list.");
egit_pathspec_match_list_entrycount(emacs_env * env,emacs_value _match_list)69 emacs_value egit_pathspec_match_list_entrycount(emacs_env *env,
70 emacs_value _match_list) {
71 EGIT_ASSERT_PATHSPEC_MATCH_LIST(_match_list);
72 git_pathspec_match_list *match_list = EGIT_EXTRACT(_match_list);
73 return EM_INTEGER(git_pathspec_match_list_entrycount(match_list));
74 }
75
76 EGIT_DOC(pathspec_match_list_entry, "PATHSPEC-MATCH-LIST POSITION",
77 "Get a matching filename by position.\n"
78 "\n"
79 "This routine cannot be used if the match list was generated by "
80 "`libgit-pathspec-match-diff'. If so, it will always return nil.");
egit_pathspec_match_list_entry(emacs_env * env,emacs_value _match_list,emacs_value _pos)81 emacs_value egit_pathspec_match_list_entry(emacs_env *env,
82 emacs_value _match_list,
83 emacs_value _pos) {
84 EGIT_ASSERT_PATHSPEC_MATCH_LIST(_match_list);
85 EM_ASSERT_INTEGER(_pos);
86 git_pathspec_match_list *match_list = EGIT_EXTRACT(_match_list);
87 size_t pos = EM_EXTRACT_INTEGER(_pos);
88 const char *filename = git_pathspec_match_list_entry(match_list, pos);
89 if (!filename) {
90 return esym_nil;
91 }
92 return EM_STRING(filename);
93 }
94
95 EGIT_DOC(pathspec_match_list_diff_entry, "PATHSPEC-MATCH-LIST POSITION",
96 "Get a matching diff delta by position.\n"
97 "\n"
98 "This routine can only be used if the match list was generated by "
99 "`libgit-pathspec-match-diff'. Otherwise it will always return nil.");
egit_pathspec_match_list_diff_entry(emacs_env * env,emacs_value _match_list,emacs_value _pos)100 emacs_value egit_pathspec_match_list_diff_entry(emacs_env *env,
101 emacs_value _match_list,
102 emacs_value _pos) {
103 EGIT_ASSERT_PATHSPEC_MATCH_LIST(_match_list);
104 EM_ASSERT_INTEGER(_pos);
105 git_pathspec_match_list *match_list = EGIT_EXTRACT(_match_list);
106 size_t pos = EM_EXTRACT_INTEGER(_pos);
107 const git_diff_delta *delta = git_pathspec_match_list_diff_entry(match_list, pos);
108 if (!delta) {
109 return esym_nil;
110 }
111 return egit_wrap(env, EGIT_DIFF_DELTA, delta, NULL);
112 }
113
114 EGIT_DOC(pathspec_match_list_failed_entrycount, "PATHSPEC-MATCH-LIST",
115 "Get the number of pathspec items that did not match.\n"
116 "\n"
117 "This will be zero unless you passed `find-failures' when "
118 "generating the pathspec match list.");
egit_pathspec_match_list_failed_entrycount(emacs_env * env,emacs_value _match_list)119 emacs_value egit_pathspec_match_list_failed_entrycount(emacs_env *env,
120 emacs_value _match_list) {
121 EGIT_ASSERT_PATHSPEC_MATCH_LIST(_match_list);
122 git_pathspec_match_list *match_list = EGIT_EXTRACT(_match_list);
123 return EM_INTEGER(git_pathspec_match_list_failed_entrycount(match_list));
124 }
125
126 EGIT_DOC(pathspec_match_list_failed_entry, "PATHSPEC-MATCH-LIST POSITION",
127 "Get an original pathspec string that had no matches.\n"
128 "\n"
129 "This will be return nil for positions out of range.");
egit_pathspec_match_list_failed_entry(emacs_env * env,emacs_value _match_list,emacs_value _pos)130 emacs_value egit_pathspec_match_list_failed_entry(emacs_env *env,
131 emacs_value _match_list,
132 emacs_value _pos) {
133 EGIT_ASSERT_PATHSPEC_MATCH_LIST(_match_list);
134 EM_ASSERT_INTEGER(_pos);
135 git_pathspec_match_list *match_list = EGIT_EXTRACT(_match_list);
136 size_t pos = EM_EXTRACT_INTEGER(_pos);
137 const char *filename = git_pathspec_match_list_failed_entry(match_list, pos);
138 if (!filename) {
139 return esym_nil;
140 }
141 return EM_STRING(filename);
142 }
143
144 EGIT_DOC(pathspec_match_workdir, "REPO FLAGS PATHSPEC",
145 "Match a PATHSPEC against the working directory of a REPO repository.\n"
146 "\n"
147 "This matches the pathspec against the current files in the working "
148 "directory of the repository. It is an error to invoke this on a bare"
149 "repo. This handles git ignores (i.e. ignored files will not be"
150 "considered to match the PATHSPEC unless the file is tracked in the "
151 "index).\n"
152 "\n"
153 "FLAGS should be nil or a list with the following symbols:\n"
154 " - ignore-case: forces match to ignore case\n"
155 " - use-case: forces case sensitive match\n"
156 " - no-glob: disables glob patterns and just uses simple string "
157 "comparison for matching\n"
158 " - no-match-error: signal an error if no matches are found; "
159 "otherwise no matches is still success, but "
160 "`libgit-pathspec-match-list-entrycount' will indicate 0 matches.\n"
161 " - find-failures: means that the `libgit-pathspec-match-list' object "
162 "should track which patterns matched which files so that at the end of "
163 "the match we can identify patterns that did not match any files.\n"
164 " - failures-only: means that the `libgit-pathspec-match-list' object "
165 "does not need to keep the actual matching filenames. Use this to "
166 "just test if there were any matches at all or in combination with "
167 "`find-failures' to validate a pathspec.");
egit_pathspec_match_workdir(emacs_env * env,emacs_value _repo,emacs_value _flags,emacs_value _pathspec)168 emacs_value egit_pathspec_match_workdir(emacs_env *env,
169 emacs_value _repo,
170 emacs_value _flags,
171 emacs_value _pathspec)
172 {
173 EGIT_ASSERT_REPOSITORY(_repo);
174 EGIT_ASSERT_PATHSPEC(_pathspec);
175
176 git_repository *repo = EGIT_EXTRACT(_repo);
177 git_pathspec *pathspec = EGIT_EXTRACT(_pathspec);
178 int32_t flags = 0;
179 extract_flags(&flags, env, _flags);
180
181 git_pathspec_match_list *match_list;
182 int retval = git_pathspec_match_workdir(&match_list, repo, flags,
183 pathspec);
184 EGIT_CHECK_ERROR(retval);
185
186 return egit_wrap(env, EGIT_PATHSPEC_MATCH_LIST, match_list, NULL);
187 }
188
189 EGIT_DOC(pathspec_match_index, "INDEX FLAGS PATHSPEC",
190 "Match a PATHSPEC against an INDEX.\n"
191 "\n"
192 "FLAGS should be nil or a list with the following symbols:\n"
193 " - ignore-case: forces match to ignore case\n"
194 " - use-case: forces case sensitive match\n"
195 " - no-glob: disables glob patterns and just uses simple string "
196 "comparison for matching\n"
197 " - no-match-error: signal an error if no matches are found; "
198 "otherwise no matches is still success, but "
199 "`libgit-pathspec-match-list-entrycount' will indicate 0 matches.\n"
200 " - find-failures: means that the `libgit-pathspec-match-list' object "
201 "should track which patterns matched which files so that at the end of "
202 "the match we can identify patterns that did not match any files.\n"
203 " - failures-only: means that the `libgit-pathspec-match-list' object "
204 "does not need to keep the actual matching filenames. Use this to "
205 "just test if there were any matches at all or in combination with "
206 "`find-failures' to validate a pathspec.");
egit_pathspec_match_index(emacs_env * env,emacs_value _index,emacs_value _flags,emacs_value _pathspec)207 emacs_value egit_pathspec_match_index(emacs_env *env,
208 emacs_value _index,
209 emacs_value _flags,
210 emacs_value _pathspec)
211 {
212 EGIT_ASSERT_INDEX(_index);
213 EGIT_ASSERT_PATHSPEC(_pathspec);
214
215 git_index *index = EGIT_EXTRACT(_index);
216 git_pathspec *pathspec = EGIT_EXTRACT(_pathspec);
217 int32_t flags = 0;
218 extract_flags(&flags, env, _flags);
219
220 git_pathspec_match_list *match_list;
221 int retval = git_pathspec_match_index(&match_list, index, flags,
222 pathspec);
223 EGIT_CHECK_ERROR(retval);
224
225 return egit_wrap(env, EGIT_PATHSPEC_MATCH_LIST, match_list, NULL);
226 }
227
228 EGIT_DOC(pathspec_match_tree, "TREE FLAGS PATHSPEC",
229 "Match a PATHSPEC against a TREE.\n"
230 "\n"
231 "FLAGS should be nil or a list with the following symbols:\n"
232 " - ignore-case: forces match to ignore case\n"
233 " - use-case: forces case sensitive match\n"
234 " - no-glob: disables glob patterns and just uses simple string "
235 "comparison for matching\n"
236 " - no-match-error: signal an error if no matches are found; "
237 "otherwise no matches is still success, but "
238 "`libgit-pathspec-match-list-entrycount' will indicate 0 matches.\n"
239 " - find-failures: means that the `libgit-pathspec-match-list' object "
240 "should track which patterns matched which files so that at the end of "
241 "the match we can identify patterns that did not match any files.\n"
242 " - failures-only: means that the `libgit-pathspec-match-list' object "
243 "does not need to keep the actual matching filenames. Use this to "
244 "just test if there were any matches at all or in combination with "
245 "`find-failures' to validate a pathspec.");
egit_pathspec_match_tree(emacs_env * env,emacs_value _tree,emacs_value _flags,emacs_value _pathspec)246 emacs_value egit_pathspec_match_tree(emacs_env *env,
247 emacs_value _tree,
248 emacs_value _flags,
249 emacs_value _pathspec)
250 {
251 EGIT_ASSERT_TREE(_tree);
252 EGIT_ASSERT_PATHSPEC(_pathspec);
253
254 git_tree *tree = EGIT_EXTRACT(_tree);
255 git_pathspec *pathspec = EGIT_EXTRACT(_pathspec);
256 int32_t flags = 0;
257 extract_flags(&flags, env, _flags);
258
259 git_pathspec_match_list *match_list;
260 int retval = git_pathspec_match_tree(&match_list, tree, flags,
261 pathspec);
262 EGIT_CHECK_ERROR(retval);
263
264 return egit_wrap(env, EGIT_PATHSPEC_MATCH_LIST, match_list, NULL);
265 }
266
267 EGIT_DOC(pathspec_match_diff, "DIFF FLAGS PATHSPEC",
268 "Match a PATHSPEC against a DIFF.\n"
269 "\n"
270 "FLAGS should be nil or a list with the following symbols:\n"
271 " - ignore-case: forces match to ignore case\n"
272 " - use-case: forces case sensitive match\n"
273 " - no-glob: disables glob patterns and just uses simple string "
274 "comparison for matching\n"
275 " - no-match-error: signal an error if no matches are found; "
276 "otherwise no matches is still success, but "
277 "`libgit-pathspec-match-list-entrycount' will indicate 0 matches.\n"
278 " - find-failures: means that the `libgit-pathspec-match-list' object "
279 "should track which patterns matched which files so that at the end of "
280 "the match we can identify patterns that did not match any files.\n"
281 " - failures-only: means that the `libgit-pathspec-match-list' object "
282 "does not need to keep the actual matching filenames. Use this to "
283 "just test if there were any matches at all or in combination with "
284 "`find-failures' to validate a pathspec.");
egit_pathspec_match_diff(emacs_env * env,emacs_value _diff,emacs_value _flags,emacs_value _pathspec)285 emacs_value egit_pathspec_match_diff(emacs_env *env,
286 emacs_value _diff,
287 emacs_value _flags,
288 emacs_value _pathspec)
289 {
290 EGIT_ASSERT_DIFF(_diff);
291 EGIT_ASSERT_PATHSPEC(_pathspec);
292
293 git_diff *diff = EGIT_EXTRACT(_diff);
294 git_pathspec *pathspec = EGIT_EXTRACT(_pathspec);
295 int32_t flags = 0;
296 extract_flags(&flags, env, _flags);
297
298 git_pathspec_match_list *match_list;
299 int retval = git_pathspec_match_diff(&match_list, diff, flags,
300 pathspec);
301 EGIT_CHECK_ERROR(retval);
302
303 return egit_wrap(env, EGIT_PATHSPEC_MATCH_LIST, match_list, NULL);
304 }
305