@@ -658,50 +658,62 @@ static void render_diff_header(struct add_p_state *s,
658
658
659
659
/* Coalesce hunks again that were split */
660
660
static int merge_hunks (struct add_p_state * s , struct file_diff * file_diff ,
661
- size_t * hunk_index , int use_all , struct hunk * temp )
661
+ size_t * hunk_index , int use_all , struct hunk * merged )
662
662
{
663
663
size_t i = * hunk_index , delta ;
664
664
struct hunk * hunk = file_diff -> hunk + i ;
665
- struct hunk_header * header = & temp -> header , * next ;
665
+ /* `header` corresponds to the merged hunk */
666
+ struct hunk_header * header = & merged -> header , * next ;
666
667
667
668
if (!use_all && hunk -> use != USE_HUNK )
668
669
return 0 ;
669
670
670
- memcpy ( temp , hunk , sizeof ( * temp )) ;
671
+ * merged = * hunk ;
671
672
/* We simply skip the colored part (if any) when merging hunks */
672
- temp -> colored_start = temp -> colored_end = 0 ;
673
+ merged -> colored_start = merged -> colored_end = 0 ;
673
674
674
675
for (; i + 1 < file_diff -> hunk_nr ; i ++ ) {
675
676
hunk ++ ;
676
677
next = & hunk -> header ;
677
678
679
+ /*
680
+ * Stop merging hunks when:
681
+ *
682
+ * - the hunk is not selected for use, or
683
+ * - the hunk does not overlap with the already-merged hunk(s)
684
+ */
678
685
if ((!use_all && hunk -> use != USE_HUNK ) ||
679
- header -> new_offset >= next -> new_offset + temp -> delta ||
686
+ header -> new_offset >= next -> new_offset + merged -> delta ||
680
687
header -> new_offset + header -> new_count
681
- < next -> new_offset + temp -> delta )
688
+ < next -> new_offset + merged -> delta )
682
689
break ;
683
690
684
- if (temp -> start < hunk -> start && temp -> end > hunk -> start ) {
685
- temp -> end = hunk -> end ;
686
- temp -> colored_end = hunk -> colored_end ;
691
+ /*
692
+ * If the hunks were not edited, and overlap, we can simply
693
+ * extend the line range.
694
+ */
695
+ if (merged -> start < hunk -> start && merged -> end > hunk -> start ) {
696
+ merged -> end = hunk -> end ;
697
+ merged -> colored_end = hunk -> colored_end ;
687
698
delta = 0 ;
688
699
} else {
689
700
const char * plain = s -> plain .buf ;
690
701
size_t overlapping_line_count = header -> new_offset
691
- + header -> new_count - temp -> delta
702
+ + header -> new_count - merged -> delta
692
703
- next -> new_offset ;
693
704
size_t overlap_end = hunk -> start ;
694
705
size_t overlap_start = overlap_end ;
695
- size_t overlap_next , len , i ;
706
+ size_t overlap_next , len , j ;
696
707
697
708
/*
698
- * One of the hunks was edited; let's ensure that at
699
- * least the last context line of the first hunk
700
- * overlaps with the corresponding line of the second
701
- * hunk, and then merge.
709
+ * One of the hunks was edited: the modified hunk was
710
+ * appended to the strbuf `s->plain`.
711
+ *
712
+ * Let's ensure that at least the last context line of
713
+ * the first hunk overlaps with the corresponding line
714
+ * of the second hunk, and then merge.
702
715
*/
703
-
704
- for (i = 0 ; i < overlapping_line_count ; i ++ ) {
716
+ for (j = 0 ; j < overlapping_line_count ; j ++ ) {
705
717
overlap_next = find_next_line (& s -> plain ,
706
718
overlap_end );
707
719
@@ -715,7 +727,7 @@ static int merge_hunks(struct add_p_state *s, struct file_diff *file_diff,
715
727
if (plain [overlap_end ] != ' ' )
716
728
return error (_ ("expected context line "
717
729
"#%d in\n%.*s" ),
718
- (int )(i + 1 ),
730
+ (int )(j + 1 ),
719
731
(int )(hunk -> end
720
732
- hunk -> start ),
721
733
plain + hunk -> start );
@@ -725,13 +737,13 @@ static int merge_hunks(struct add_p_state *s, struct file_diff *file_diff,
725
737
}
726
738
len = overlap_end - overlap_start ;
727
739
728
- if (len > temp -> end - temp -> start ||
729
- memcmp (plain + temp -> end - len ,
740
+ if (len > merged -> end - merged -> start ||
741
+ memcmp (plain + merged -> end - len ,
730
742
plain + overlap_start , len ))
731
743
return error (_ ("hunks do not overlap:\n%.*s\n"
732
744
"\tdoes not end with:\n%.*s" ),
733
- (int )(temp -> end - temp -> start ),
734
- plain + temp -> start ,
745
+ (int )(merged -> end - merged -> start ),
746
+ plain + merged -> start ,
735
747
(int )len , plain + overlap_start );
736
748
737
749
/*
@@ -740,23 +752,23 @@ static int merge_hunks(struct add_p_state *s, struct file_diff *file_diff,
740
752
* address that, we temporarily append the union of the
741
753
* lines to the `plain` strbuf.
742
754
*/
743
- if (temp -> end != s -> plain .len ) {
755
+ if (merged -> end != s -> plain .len ) {
744
756
size_t start = s -> plain .len ;
745
757
746
- strbuf_add (& s -> plain , plain + temp -> start ,
747
- temp -> end - temp -> start );
758
+ strbuf_add (& s -> plain , plain + merged -> start ,
759
+ merged -> end - merged -> start );
748
760
plain = s -> plain .buf ;
749
- temp -> start = start ;
750
- temp -> end = s -> plain .len ;
761
+ merged -> start = start ;
762
+ merged -> end = s -> plain .len ;
751
763
}
752
764
753
765
strbuf_add (& s -> plain ,
754
766
plain + overlap_end ,
755
767
hunk -> end - overlap_end );
756
- temp -> end = s -> plain .len ;
757
- temp -> splittable_into += hunk -> splittable_into ;
758
- delta = temp -> delta ;
759
- temp -> delta += hunk -> delta ;
768
+ merged -> end = s -> plain .len ;
769
+ merged -> splittable_into += hunk -> splittable_into ;
770
+ delta = merged -> delta ;
771
+ merged -> delta += hunk -> delta ;
760
772
}
761
773
762
774
header -> old_count = next -> old_offset + next -> old_count
@@ -783,16 +795,16 @@ static void reassemble_patch(struct add_p_state *s,
783
795
render_diff_header (s , file_diff , 0 , out );
784
796
785
797
for (i = file_diff -> mode_change ; i < file_diff -> hunk_nr ; i ++ ) {
786
- struct hunk temp = { 0 };
798
+ struct hunk merged = { 0 };
787
799
788
800
hunk = file_diff -> hunk + i ;
789
801
if (!use_all && hunk -> use != USE_HUNK )
790
802
delta += hunk -> header .old_count
791
803
- hunk -> header .new_count ;
792
804
else {
793
805
/* merge overlapping hunks into a temporary hunk */
794
- if (merge_hunks (s , file_diff , & i , use_all , & temp ))
795
- hunk = & temp ;
806
+ if (merge_hunks (s , file_diff , & i , use_all , & merged ))
807
+ hunk = & merged ;
796
808
797
809
render_hunk (s , hunk , delta , 0 , out );
798
810
@@ -829,7 +841,7 @@ static int split_hunk(struct add_p_state *s, struct file_diff *file_diff,
829
841
end = hunk -> end ;
830
842
colored_end = hunk -> colored_end ;
831
843
832
- memcpy ( & remaining , & hunk -> header , sizeof ( remaining )) ;
844
+ remaining = hunk -> header ;
833
845
834
846
file_diff -> hunk_nr += splittable_into - 1 ;
835
847
ALLOC_GROW (file_diff -> hunk , file_diff -> hunk_nr , file_diff -> hunk_alloc );
@@ -997,21 +1009,13 @@ static void recolor_hunk(struct add_p_state *s, struct hunk *hunk)
997
1009
998
1010
static int edit_hunk_manually (struct add_p_state * s , struct hunk * hunk )
999
1011
{
1000
- char * path = xstrdup (git_path ("addp-hunk-edit.diff" ));
1001
- int fd = xopen (path , O_WRONLY | O_CREAT | O_TRUNC , 0666 );
1002
- struct strbuf buf = STRBUF_INIT ;
1003
- size_t i , j ;
1004
- int res , copy ;
1005
-
1006
- if (fd < 0 ) {
1007
- res = error_errno (_ ("could not open '%s' for writing" ), path );
1008
- goto edit_hunk_manually_finish ;
1009
- }
1012
+ size_t i ;
1010
1013
1011
- strbuf_commented_addf (& buf , _ ("Manual hunk edit mode -- see bottom for "
1014
+ strbuf_reset (& s -> buf );
1015
+ strbuf_commented_addf (& s -> buf , _ ("Manual hunk edit mode -- see bottom for "
1012
1016
"a quick guide.\n" ));
1013
- render_hunk (s , hunk , 0 , 0 , & buf );
1014
- strbuf_commented_addf (& buf ,
1017
+ render_hunk (s , hunk , 0 , 0 , & s -> buf );
1018
+ strbuf_commented_addf (& s -> buf ,
1015
1019
_ ("---\n"
1016
1020
"To remove '%c' lines, make them ' ' lines "
1017
1021
"(context).\n"
@@ -1020,63 +1024,51 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
1020
1024
s -> mode -> is_reverse ? '+' : '-' ,
1021
1025
s -> mode -> is_reverse ? '-' : '+' ,
1022
1026
comment_line_char );
1023
- strbuf_commented_addf (& buf , "%s" , _ (s -> mode -> edit_hunk_hint ));
1027
+ strbuf_commented_addf (& s -> buf , "%s" , _ (s -> mode -> edit_hunk_hint ));
1024
1028
/*
1025
1029
* TRANSLATORS: 'it' refers to the patch mentioned in the previous
1026
1030
* messages.
1027
1031
*/
1028
- strbuf_commented_addf (& buf ,
1032
+ strbuf_commented_addf (& s -> buf ,
1029
1033
_ ("If it does not apply cleanly, you will be "
1030
1034
"given an opportunity to\n"
1031
1035
"edit again. If all lines of the hunk are "
1032
1036
"removed, then the edit is\n"
1033
1037
"aborted and the hunk is left unchanged.\n" ));
1034
- if (write_in_full (fd , buf .buf , buf .len ) < 0 ) {
1035
- res = error_errno (_ ("could not write to '%s'" ), path );
1036
- goto edit_hunk_manually_finish ;
1037
- }
1038
-
1039
- res = close (fd );
1040
- fd = -1 ;
1041
- if (res < 0 )
1042
- goto edit_hunk_manually_finish ;
1043
1038
1044
- hunk -> start = s -> plain .len ;
1045
- if (launch_editor (path , & s -> plain , NULL ) < 0 ) {
1046
- res = error_errno (_ ("could not edit '%s'" ), path );
1047
- goto edit_hunk_manually_finish ;
1048
- }
1049
- unlink (path );
1039
+ if (strbuf_edit_interactively (& s -> buf , "addp-hunk-edit.diff" , NULL ) < 0 )
1040
+ return -1 ;
1050
1041
1051
1042
/* strip out commented lines */
1052
- copy = s -> plain .buf [hunk -> start ] != comment_line_char ;
1053
- for (i = j = hunk -> start ; i < s -> plain .len ; ) {
1054
- if (copy )
1055
- s -> plain .buf [j ++ ] = s -> plain .buf [i ];
1056
- if (s -> plain .buf [i ++ ] == '\n' )
1057
- copy = s -> plain .buf [i ] != comment_line_char ;
1043
+ hunk -> start = s -> plain .len ;
1044
+ for (i = 0 ; i < s -> buf .len ; ) {
1045
+ const char * bol = s -> buf .buf + i ;
1046
+ size_t rest = s -> buf .len - i ;
1047
+ const char * eol = memchr (bol , '\n' , rest );
1048
+ size_t len = eol ? eol + 1 - bol : rest ;
1049
+
1050
+ if (* bol != comment_line_char )
1051
+ strbuf_add (& s -> plain , bol , len );
1052
+ i += len ;
1058
1053
}
1059
1054
1060
- if (j == hunk -> start )
1061
- /* User aborted by deleting everything */
1062
- goto edit_hunk_manually_finish ;
1055
+ hunk -> end = s -> plain .len ;
1056
+ if (hunk -> end == hunk -> start )
1057
+ /* The user aborted editing by deleting everything */
1058
+ return 0 ;
1063
1059
1064
- res = 1 ;
1065
- strbuf_setlen (& s -> plain , j );
1066
- hunk -> end = j ;
1067
1060
recolor_hunk (s , hunk );
1061
+
1062
+ /*
1063
+ * If the hunk header is intact, parse it, otherwise simply use the
1064
+ * hunk header prior to editing (which will adjust `hunk->start` to
1065
+ * skip the hunk header).
1066
+ */
1068
1067
if (s -> plain .buf [hunk -> start ] == '@' &&
1069
- /* If the hunk header was deleted, simply use the original one. */
1070
1068
parse_hunk_header (s , hunk ) < 0 )
1071
- res = -1 ;
1069
+ return error ( _ ( "could not parse hunk header" )) ;
1072
1070
1073
- edit_hunk_manually_finish :
1074
- if (fd >= 0 )
1075
- close (fd );
1076
- free (path );
1077
- strbuf_release (& buf );
1078
-
1079
- return res ;
1071
+ return 1 ;
1080
1072
}
1081
1073
1082
1074
static ssize_t recount_edited_hunk (struct add_p_state * s , struct hunk * hunk ,
@@ -1158,13 +1150,13 @@ static int edit_hunk_loop(struct add_p_state *s,
1158
1150
size_t plain_len = s -> plain .len , colored_len = s -> colored .len ;
1159
1151
struct hunk backup ;
1160
1152
1161
- memcpy ( & backup , hunk , sizeof ( backup )) ;
1153
+ backup = * hunk ;
1162
1154
1163
1155
for (;;) {
1164
1156
int res = edit_hunk_manually (s , hunk );
1165
1157
if (res == 0 ) {
1166
1158
/* abandonded */
1167
- memcpy ( hunk , & backup , sizeof ( backup )) ;
1159
+ * hunk = backup ;
1168
1160
return -1 ;
1169
1161
}
1170
1162
@@ -1180,7 +1172,7 @@ static int edit_hunk_loop(struct add_p_state *s,
1180
1172
/* Drop edits (they were appended to s->plain) */
1181
1173
strbuf_setlen (& s -> plain , plain_len );
1182
1174
strbuf_setlen (& s -> colored , colored_len );
1183
- memcpy ( hunk , & backup , sizeof ( backup )) ;
1175
+ * hunk = backup ;
1184
1176
1185
1177
/*
1186
1178
* TRANSLATORS: do not translate [y/n]
0 commit comments