1- use libc:: c_uint;
1+ use libc:: { c_uint, c_ushort} ;
2+ use std:: ffi:: CString ;
23use std:: marker;
34use std:: mem;
5+ use std:: ptr;
46use std:: str;
57
68use crate :: call:: Convert ;
79use crate :: util:: Binding ;
810use crate :: { raw, Commit , FileFavor , Oid } ;
11+ use crate :: IntoCString ;
912
1013/// A structure to represent an annotated commit, the input to merge and rebase.
1114///
@@ -22,6 +25,20 @@ pub struct MergeOptions {
2225 raw : raw:: git_merge_options ,
2326}
2427
28+ /// Options for merging a file.
29+ pub struct MergeFileOptions {
30+ ancestor_label : Option < CString > ,
31+ our_label : Option < CString > ,
32+ their_label : Option < CString > ,
33+ raw : raw:: git_merge_file_options ,
34+ }
35+
36+ /// Information about file-level merging.
37+ pub struct MergeFileResult < ' repo > {
38+ raw : raw:: git_merge_file_result ,
39+ _marker : marker:: PhantomData < & ' repo str > ,
40+ }
41+
2542impl < ' repo > AnnotatedCommit < ' repo > {
2643 /// Gets the commit ID that the given git_annotated_commit refers to
2744 pub fn id ( & self ) -> Oid {
@@ -192,3 +209,208 @@ impl<'repo> Drop for AnnotatedCommit<'repo> {
192209 unsafe { raw:: git_annotated_commit_free ( self . raw ) }
193210 }
194211}
212+
213+ impl Default for MergeFileOptions {
214+ fn default ( ) -> Self {
215+ Self :: new ( )
216+ }
217+ }
218+
219+ impl MergeFileOptions {
220+ /// Creates a default set of merge file options.
221+ pub fn new ( ) -> MergeFileOptions {
222+ let mut opts = MergeFileOptions {
223+ ancestor_label : None ,
224+ our_label : None ,
225+ their_label : None ,
226+ raw : unsafe { mem:: zeroed ( ) } ,
227+ } ;
228+ assert_eq ! ( unsafe { raw:: git_merge_file_options_init( & mut opts. raw, 1 ) } , 0 ) ;
229+ opts
230+ }
231+
232+ /// Label for the ancestor file side of the conflict which will be prepended
233+ /// to labels in diff3-format merge files.
234+ pub fn ancestor_label < T : IntoCString > ( & mut self , t : T ) -> & mut MergeFileOptions {
235+ self . ancestor_label = Some ( t. into_c_string ( ) . unwrap ( ) ) ;
236+
237+ self . raw . ancestor_label = self
238+ . ancestor_label
239+ . as_ref ( )
240+ . map ( |s| s. as_ptr ( ) )
241+ . unwrap_or ( ptr:: null ( ) ) ;
242+
243+ self
244+ }
245+
246+ /// Label for our file side of the conflict which will be prepended to labels
247+ /// in merge files.
248+ pub fn our_label < T : IntoCString > ( & mut self , t : T ) -> & mut MergeFileOptions {
249+ self . our_label = Some ( t. into_c_string ( ) . unwrap ( ) ) ;
250+
251+ self . raw . our_label = self
252+ . our_label
253+ . as_ref ( )
254+ . map ( |s| s. as_ptr ( ) )
255+ . unwrap_or ( ptr:: null ( ) ) ;
256+
257+ self
258+ }
259+
260+ /// Label for their file side of the conflict which will be prepended to labels
261+ /// in merge files.
262+ pub fn their_label < T : IntoCString > ( & mut self , t : T ) -> & mut MergeFileOptions {
263+ self . their_label = Some ( t. into_c_string ( ) . unwrap ( ) ) ;
264+
265+ self . raw . their_label = self
266+ . their_label
267+ . as_ref ( )
268+ . map ( |s| s. as_ptr ( ) )
269+ . unwrap_or ( ptr:: null ( ) ) ;
270+
271+ self
272+ }
273+
274+ /// Specify a side to favor for resolving conflicts
275+ pub fn favor ( & mut self , favor : FileFavor ) -> & mut MergeFileOptions {
276+ self . raw . favor = favor. convert ( ) ;
277+ self
278+ }
279+
280+ fn flag ( & mut self , opt : u32 , val : bool ) -> & mut MergeFileOptions {
281+ if val {
282+ self . raw . flags |= opt;
283+ } else {
284+ self . raw . flags &= !opt;
285+ }
286+ self
287+ }
288+
289+ /// Create standard conflicted merge files
290+ pub fn style_standard ( & mut self , standard : bool ) -> & mut MergeFileOptions {
291+ self . flag ( raw:: GIT_MERGE_FILE_STYLE_MERGE as u32 , standard)
292+ }
293+
294+ /// Create diff3-style file
295+ pub fn style_diff3 ( & mut self , diff3 : bool ) -> & mut MergeFileOptions {
296+ self . flag ( raw:: GIT_MERGE_FILE_STYLE_DIFF3 as u32 , diff3)
297+ }
298+
299+ /// Condense non-alphanumeric regions for simplified diff file
300+ pub fn simplify_alnum ( & mut self , simplify : bool ) -> & mut MergeFileOptions {
301+ self . flag ( raw:: GIT_MERGE_FILE_SIMPLIFY_ALNUM as u32 , simplify)
302+ }
303+
304+ /// Ignore all whitespace
305+ pub fn ignore_whitespace ( & mut self , ignore : bool ) -> & mut MergeFileOptions {
306+ self . flag ( raw:: GIT_MERGE_FILE_IGNORE_WHITESPACE as u32 , ignore)
307+ }
308+
309+ /// Ignore changes in amount of whitespace
310+ pub fn ignore_whitespace_change ( & mut self , ignore : bool ) -> & mut MergeFileOptions {
311+ self . flag ( raw:: GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE as u32 , ignore)
312+ }
313+
314+ /// Ignore whitespace at end of line
315+ pub fn ignore_whitespace_eol ( & mut self , ignore : bool ) -> & mut MergeFileOptions {
316+ self . flag ( raw:: GIT_MERGE_FILE_IGNORE_WHITESPACE_EOL as u32 , ignore)
317+ }
318+
319+ /// Use the "patience diff" algorithm
320+ pub fn patience ( & mut self , patience : bool ) -> & mut MergeFileOptions {
321+ self . flag ( raw:: GIT_MERGE_FILE_DIFF_PATIENCE as u32 , patience)
322+ }
323+
324+ /// Take extra time to find minimal diff
325+ pub fn minimal ( & mut self , minimal : bool ) -> & mut MergeFileOptions {
326+ self . flag ( raw:: GIT_MERGE_FILE_DIFF_MINIMAL as u32 , minimal)
327+ }
328+
329+ /// Create zdiff3 ("zealous diff3")-style files
330+ pub fn style_zdiff3 ( & mut self , zdiff3 : bool ) -> & mut MergeFileOptions {
331+ self . flag ( raw:: GIT_MERGE_FILE_STYLE_ZDIFF3 as u32 , zdiff3)
332+ }
333+
334+ /// Do not produce file conflicts when common regions have changed
335+ pub fn accept_conflicts ( & mut self , accept : bool ) -> & mut MergeFileOptions {
336+ self . flag ( raw:: GIT_MERGE_FILE_ACCEPT_CONFLICTS as u32 , accept)
337+ }
338+
339+ /// The size of conflict markers (eg, "<<<<<<<"). Default is 7.
340+ pub fn marker_size ( & mut self , size : u16 ) -> & mut MergeFileOptions {
341+ self . raw . marker_size = size as c_ushort ;
342+ self
343+ }
344+
345+ /// Acquire a pointer to the underlying raw options.
346+ pub unsafe fn raw ( & mut self ) -> * const raw:: git_merge_file_options {
347+ & self . raw as * const _
348+ }
349+ }
350+
351+ impl < ' repo > MergeFileResult < ' repo > {
352+ /// True if the output was automerged, false if the output contains
353+ /// conflict markers.
354+ pub fn is_automergeable ( & self ) -> bool {
355+ self . raw . automergeable > 0
356+ }
357+
358+ /// The path that the resultant merge file should use.
359+ ///
360+ /// returns `None` if a filename conflict would occur,
361+ /// or if the path is not valid utf-8
362+ pub fn path ( & self ) -> Option < & str > {
363+ self . path_bytes ( ) . and_then ( |bytes| str:: from_utf8 ( bytes) . ok ( ) )
364+ }
365+
366+ /// Gets the path as a byte slice.
367+ pub fn path_bytes ( & self ) -> Option < & [ u8 ] > {
368+ unsafe { crate :: opt_bytes ( self , self . raw . path ) }
369+ }
370+
371+ /// The mode that the resultant merge file should use.
372+ pub fn mode ( & self ) -> u32 {
373+ self . raw . mode as u32
374+ }
375+
376+ /// The contents of the merge.
377+ pub fn content ( & self ) -> & ' repo [ u8 ] {
378+ unsafe {
379+ std:: slice:: from_raw_parts (
380+ self . raw . ptr as * const u8 ,
381+ self . raw . len as usize ,
382+ )
383+ }
384+ }
385+ }
386+
387+ impl < ' repo > Binding for MergeFileResult < ' repo > {
388+ type Raw = raw:: git_merge_file_result ;
389+ unsafe fn from_raw ( raw : raw:: git_merge_file_result ) -> MergeFileResult < ' repo > {
390+ MergeFileResult {
391+ raw,
392+ _marker : marker:: PhantomData ,
393+ }
394+ }
395+ fn raw ( & self ) -> raw:: git_merge_file_result {
396+ self . raw
397+ }
398+ }
399+
400+ impl < ' repo > Drop for MergeFileResult < ' repo > {
401+ fn drop ( & mut self ) {
402+ unsafe { raw:: git_merge_file_result_free ( & mut self . raw ) }
403+ }
404+ }
405+
406+ impl < ' repo > std:: fmt:: Display for MergeFileResult < ' repo > {
407+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
408+ let mut ds = f. debug_struct ( "MergeFileResult" ) ;
409+ if let Some ( path) = & self . path ( ) {
410+ ds. field ( "path" , path) ;
411+ }
412+ ds. field ( "automergeable" , & self . is_automergeable ( ) ) ;
413+ ds. field ( "mode" , & self . mode ( ) ) ;
414+ ds. finish ( )
415+ }
416+ }
0 commit comments