1 /*
2  * Copyright (C) the libgit2 contributors. All rights reserved.
3  *
4  * This file is part of libgit2, distributed under the GNU GPL v2 with
5  * a Linking Exception. For full terms see the included COPYING file.
6  */
7 /**
8  * License: GPL-2.0(Linking Exception)
9  */
10 module libgit2.blame;
11 
12 
13 private static import libgit2.oid;
14 private static import libgit2.types;
15 private import libgit2.common: GIT_EXTERN;
16 
17 /*
18  * @file git2/blame.h
19  * @brief Git blame routines
20  * @defgroup git_blame Git blame routines
21  * @ingroup Git
22  * @{
23  */
24 extern (C):
25 nothrow @nogc:
26 public:
27 
28 /**
29  * Flags for indicating option behavior for git_blame APIs.
30  */
31 enum git_blame_flag_t
32 {
33 	/**
34 	 * Normal blame, the default
35 	 */
36 	GIT_BLAME_NORMAL = 0,
37 
38 	/**
39 	 * Track lines that have moved within a file (like `git blame -M`).
40 	 *
41 	 * This is not yet implemented and reserved for future use.
42 	 */
43 	GIT_BLAME_TRACK_COPIES_SAME_FILE = 1 << 0,
44 
45 	/**
46 	 * Track lines that have moved across files in the same commit
47 	 * (like `git blame -C`).
48 	 *
49 	 * This is not yet implemented and reserved for future use.
50 	 */
51 	GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES = 1 << 1,
52 
53 	/**
54 	 * Track lines that have been copied from another file that exists
55 	 * in the same commit (like `git blame -CC`).  Implies SAME_FILE.
56 	 *
57 	 * This is not yet implemented and reserved for future use.
58 	 */
59 	GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES = 1 << 2,
60 
61 	/**
62 	 * Track lines that have been copied from another file that exists in
63 	 * *any* commit (like `git blame -CCC`).  Implies SAME_COMMIT_COPIES.
64 	 *
65 	 * This is not yet implemented and reserved for future use.
66 	 */
67 	GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES = 1 << 3,
68 
69 	/**
70 	 * Restrict the search of commits to those reachable following only
71 	 * the first parents.
72 	 */
73 	GIT_BLAME_FIRST_PARENT = 1 << 4,
74 
75 	/**
76 	 * Use mailmap file to map author and committer names and email
77 	 * addresses to canonical real names and email addresses. The
78 	 * mailmap will be read from the working directory, or HEAD in a
79 	 * bare repository.
80 	 */
81 	GIT_BLAME_USE_MAILMAP = 1 << 5,
82 
83 	/**
84 	 * Ignore whitespace differences
85 	 */
86 	GIT_BLAME_IGNORE_WHITESPACE = 1 << 6,
87 }
88 
89 //Declaration name in C language
90 enum
91 {
92 	GIT_BLAME_NORMAL = .git_blame_flag_t.GIT_BLAME_NORMAL,
93 	GIT_BLAME_TRACK_COPIES_SAME_FILE = .git_blame_flag_t.GIT_BLAME_TRACK_COPIES_SAME_FILE,
94 	GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES = .git_blame_flag_t.GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES,
95 	GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES = .git_blame_flag_t.GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES,
96 	GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES = .git_blame_flag_t.GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES,
97 	GIT_BLAME_FIRST_PARENT = .git_blame_flag_t.GIT_BLAME_FIRST_PARENT,
98 	GIT_BLAME_USE_MAILMAP = .git_blame_flag_t.GIT_BLAME_USE_MAILMAP,
99 	GIT_BLAME_IGNORE_WHITESPACE = .git_blame_flag_t.GIT_BLAME_IGNORE_WHITESPACE,
100 }
101 
102 /**
103  * Blame options structure
104  *
105  * Initialize with `GIT_BLAME_OPTIONS_INIT`. Alternatively, you can
106  * use `git_blame_options_init`.
107  */
108 struct git_blame_options
109 {
110 	uint version_;
111 
112 	/**
113 	 * A combination of `git_blame_flag_t`
114 	 */
115 	uint flags;
116 
117 	/**
118 	 * The lower bound on the number of alphanumeric characters that
119 	 * must be detected as moving/copying within a file for it to
120 	 * associate those lines with the parent commit. The default value
121 	 * is 20.
122 	 *
123 	 * This value only takes effect if any of the `GIT_BLAME_TRACK_COPIES_*`
124 	 * flags are specified.
125 	 */
126 	ushort min_match_characters;
127 
128 	/**
129 	 * The id of the newest commit to consider. The default is HEAD.
130 	 */
131 	libgit2.oid.git_oid newest_commit;
132 
133 	/**
134 	 * The id of the oldest commit to consider.
135 	 * The default is the first commit encountered with a null parent.
136 	 */
137 	libgit2.oid.git_oid oldest_commit;
138 
139 	/**
140 	 * The first line in the file to blame.
141 	 * The default is 1 (line numbers start with 1).
142 	 */
143 	size_t min_line;
144 
145 	/**
146 	 * The last line in the file to blame.
147 	 * The default is the last line of the file.
148 	 */
149 	size_t max_line;
150 }
151 
152 enum GIT_BLAME_OPTIONS_VERSION = 1;
153 
154 pragma(inline, true)
155 pure nothrow @safe @nogc @live
156 .git_blame_options GIT_BLAME_OPTIONS_INIT()
157 
158 	do
159 	{
160 		.git_blame_options OUTPUT =
161 		{
162 			version_: .GIT_BLAME_OPTIONS_VERSION,
163 		};
164 
165 		return OUTPUT;
166 	}
167 
168 /**
169  * Initialize git_blame_options structure
170  *
171  * Initializes a `git_blame_options` with default values. Equivalent to creating
172  * an instance with GIT_BLAME_OPTIONS_INIT.
173  *
174  * Params:
175  *      opts = The `git_blame_options` struct to initialize.
176  *      version_ = The struct version; pass `GIT_BLAME_OPTIONS_VERSION`.
177  *
178  * Returns: Zero on success; -1 on failure.
179  */
180 @GIT_EXTERN
181 int git_blame_options_init(.git_blame_options* opts, uint version_);
182 
183 /**
184  * Structure that represents a blame hunk.
185  */
186 struct git_blame_hunk
187 {
188 	/**
189 	 * The number of lines in this hunk.
190 	 */
191 	size_t lines_in_hunk;
192 
193 	/**
194 	 * The OID of the commit where this line was last changed.
195 	 */
196 	libgit2.oid.git_oid final_commit_id;
197 
198 	/**
199 	 * The 1-based line number where this hunk begins, in the final version
200 	 * of the file.
201 	 */
202 	size_t final_start_line_number;
203 
204 	/**
205 	 * The author of `final_commit_id`. If `GIT_BLAME_USE_MAILMAP` has been
206 	 * specified, it will contain the canonical real name and email address.
207 	 */
208 	libgit2.types.git_signature* final_signature;
209 
210 	/**
211 	 * The OID of the commit where this hunk was found.
212 	 * This will usually be the same as `final_commit_id`, except when
213 	 * `GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES` has been specified.
214 	 */
215 	libgit2.oid.git_oid orig_commit_id;
216 
217 	/**
218 	 * The path to the file where this hunk originated, as of the commit
219 	 * specified by `orig_commit_id`.
220 	 */
221 	const (char)* orig_path;
222 
223 	/**
224 	 * The 1-based line number where this hunk begins in the file named by
225 	 * `orig_path` in the commit specified by `orig_commit_id`.
226 	 */
227 	size_t orig_start_line_number;
228 
229 	/**
230 	 * The author of `orig_commit_id`. If `GIT_BLAME_USE_MAILMAP` has been
231 	 * specified, it will contain the canonical real name and email address.
232 	 */
233 	libgit2.types.git_signature* orig_signature;
234 
235 	/**
236 	 * The 1 iff the hunk has been tracked to a boundary commit (the root,
237 	 * or the commit specified in git_blame_options.oldest_commit)
238 	 */
239 	char boundary = '\0';
240 }
241 
242 /**
243  * Opaque structure to hold blame results
244  */
245 struct git_blame;
246 
247 /**
248  * Gets the number of hunks that exist in the blame structure.
249  *
250  * Params:
251  *      blame = The blame structure to query.
252  *
253  * Returns: The number of hunks.
254  */
255 @GIT_EXTERN
256 uint git_blame_get_hunk_count(.git_blame* blame);
257 
258 /**
259  * Gets the blame hunk at the given index.
260  *
261  * Params:
262  *      blame = the blame structure to query
263  *      index = index of the hunk to retrieve
264  *
265  * Returns: the hunk at the given index, or null on error
266  */
267 @GIT_EXTERN
268 const (.git_blame_hunk)* git_blame_get_hunk_byindex(.git_blame* blame, uint index);
269 
270 /**
271  * Gets the hunk that relates to the given line number in the newest commit.
272  *
273  * Params:
274  *      blame = the blame structure to query
275  *      lineno = the (1-based) line number to find a hunk for
276  *
277  * Returns: the hunk that contains the given line, or null on error
278  */
279 @GIT_EXTERN
280 const (.git_blame_hunk)* git_blame_get_hunk_byline(.git_blame* blame, size_t lineno);
281 
282 /**
283  * Get the blame for a single file.
284  *
285  * Params:
286  *      out_ = pointer that will receive the blame object
287  *      repo = repository whose history is to be walked
288  *      path = path to file to consider
289  *      options = options for the blame operation.  If null, this is treated as though GIT_BLAME_OPTIONS_INIT were passed.
290  *
291  * Returns: 0 on success, or an error code. (use git_error_last for information about the error.)
292  */
293 @GIT_EXTERN
294 int git_blame_file(.git_blame** out_, libgit2.types.git_repository* repo, const (char)* path, .git_blame_options* options);
295 
296 /**
297  * Get blame data for a file that has been modified in memory. The `reference`
298  * parameter is a pre-calculated blame for the in-odb history of the file. This
299  * means that once a file blame is completed (which can be expensive), updating
300  * the buffer blame is very fast.
301  *
302  * Lines that differ between the buffer and the committed version are marked as
303  * having a zero OID for their final_commit_id.
304  *
305  * Params:
306  *      out_ = pointer that will receive the resulting blame data
307  *      reference = cached blame from the history of the file (usually the output from git_blame_file)
308  *      buffer = the (possibly) modified contents of the file
309  *      buffer_len = number of valid bytes in the buffer
310  *
311  * Returns: 0 on success, or an error code. (use git_error_last for information about the error)
312  */
313 @GIT_EXTERN
314 int git_blame_buffer(.git_blame** out_, .git_blame* reference, const (char)* buffer, size_t buffer_len);
315 
316 /**
317  * Free memory allocated by git_blame_file or git_blame_buffer.
318  *
319  * Params:
320  *      blame = the blame structure to free
321  */
322 @GIT_EXTERN
323 void git_blame_free(.git_blame* blame);
324 
325 /* @} */