add-patch.c 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743
  1. #include "cache.h"
  2. #include "add-interactive.h"
  3. #include "strbuf.h"
  4. #include "run-command.h"
  5. #include "strvec.h"
  6. #include "pathspec.h"
  7. #include "color.h"
  8. #include "diff.h"
  9. #include "compat/terminal.h"
  10. #include "prompt.h"
  11. enum prompt_mode_type {
  12. PROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_ADDITION, PROMPT_HUNK,
  13. PROMPT_MODE_MAX, /* must be last */
  14. };
  15. struct patch_mode {
  16. /*
  17. * The magic constant 4 is chosen such that all patch modes
  18. * provide enough space for three command-line arguments followed by a
  19. * trailing `NULL`.
  20. */
  21. const char *diff_cmd[4], *apply_args[4], *apply_check_args[4];
  22. unsigned is_reverse:1, index_only:1, apply_for_checkout:1;
  23. const char *prompt_mode[PROMPT_MODE_MAX];
  24. const char *edit_hunk_hint, *help_patch_text;
  25. };
  26. static struct patch_mode patch_mode_add = {
  27. .diff_cmd = { "diff-files", NULL },
  28. .apply_args = { "--cached", NULL },
  29. .apply_check_args = { "--cached", NULL },
  30. .prompt_mode = {
  31. N_("Stage mode change [y,n,q,a,d%s,?]? "),
  32. N_("Stage deletion [y,n,q,a,d%s,?]? "),
  33. N_("Stage addition [y,n,q,a,d%s,?]? "),
  34. N_("Stage this hunk [y,n,q,a,d%s,?]? ")
  35. },
  36. .edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
  37. "will immediately be marked for staging."),
  38. .help_patch_text =
  39. N_("y - stage this hunk\n"
  40. "n - do not stage this hunk\n"
  41. "q - quit; do not stage this hunk or any of the remaining "
  42. "ones\n"
  43. "a - stage this hunk and all later hunks in the file\n"
  44. "d - do not stage this hunk or any of the later hunks in "
  45. "the file\n")
  46. };
  47. static struct patch_mode patch_mode_stash = {
  48. .diff_cmd = { "diff-index", "HEAD", NULL },
  49. .apply_args = { "--cached", NULL },
  50. .apply_check_args = { "--cached", NULL },
  51. .prompt_mode = {
  52. N_("Stash mode change [y,n,q,a,d%s,?]? "),
  53. N_("Stash deletion [y,n,q,a,d%s,?]? "),
  54. N_("Stash addition [y,n,q,a,d%s,?]? "),
  55. N_("Stash this hunk [y,n,q,a,d%s,?]? "),
  56. },
  57. .edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
  58. "will immediately be marked for stashing."),
  59. .help_patch_text =
  60. N_("y - stash this hunk\n"
  61. "n - do not stash this hunk\n"
  62. "q - quit; do not stash this hunk or any of the remaining "
  63. "ones\n"
  64. "a - stash this hunk and all later hunks in the file\n"
  65. "d - do not stash this hunk or any of the later hunks in "
  66. "the file\n"),
  67. };
  68. static struct patch_mode patch_mode_reset_head = {
  69. .diff_cmd = { "diff-index", "--cached", NULL },
  70. .apply_args = { "-R", "--cached", NULL },
  71. .apply_check_args = { "-R", "--cached", NULL },
  72. .is_reverse = 1,
  73. .index_only = 1,
  74. .prompt_mode = {
  75. N_("Unstage mode change [y,n,q,a,d%s,?]? "),
  76. N_("Unstage deletion [y,n,q,a,d%s,?]? "),
  77. N_("Unstage addition [y,n,q,a,d%s,?]? "),
  78. N_("Unstage this hunk [y,n,q,a,d%s,?]? "),
  79. },
  80. .edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
  81. "will immediately be marked for unstaging."),
  82. .help_patch_text =
  83. N_("y - unstage this hunk\n"
  84. "n - do not unstage this hunk\n"
  85. "q - quit; do not unstage this hunk or any of the remaining "
  86. "ones\n"
  87. "a - unstage this hunk and all later hunks in the file\n"
  88. "d - do not unstage this hunk or any of the later hunks in "
  89. "the file\n"),
  90. };
  91. static struct patch_mode patch_mode_reset_nothead = {
  92. .diff_cmd = { "diff-index", "-R", "--cached", NULL },
  93. .apply_args = { "--cached", NULL },
  94. .apply_check_args = { "--cached", NULL },
  95. .index_only = 1,
  96. .prompt_mode = {
  97. N_("Apply mode change to index [y,n,q,a,d%s,?]? "),
  98. N_("Apply deletion to index [y,n,q,a,d%s,?]? "),
  99. N_("Apply addition to index [y,n,q,a,d%s,?]? "),
  100. N_("Apply this hunk to index [y,n,q,a,d%s,?]? "),
  101. },
  102. .edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
  103. "will immediately be marked for applying."),
  104. .help_patch_text =
  105. N_("y - apply this hunk to index\n"
  106. "n - do not apply this hunk to index\n"
  107. "q - quit; do not apply this hunk or any of the remaining "
  108. "ones\n"
  109. "a - apply this hunk and all later hunks in the file\n"
  110. "d - do not apply this hunk or any of the later hunks in "
  111. "the file\n"),
  112. };
  113. static struct patch_mode patch_mode_checkout_index = {
  114. .diff_cmd = { "diff-files", NULL },
  115. .apply_args = { "-R", NULL },
  116. .apply_check_args = { "-R", NULL },
  117. .is_reverse = 1,
  118. .prompt_mode = {
  119. N_("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
  120. N_("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
  121. N_("Discard addition from worktree [y,n,q,a,d%s,?]? "),
  122. N_("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
  123. },
  124. .edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
  125. "will immediately be marked for discarding."),
  126. .help_patch_text =
  127. N_("y - discard this hunk from worktree\n"
  128. "n - do not discard this hunk from worktree\n"
  129. "q - quit; do not discard this hunk or any of the remaining "
  130. "ones\n"
  131. "a - discard this hunk and all later hunks in the file\n"
  132. "d - do not discard this hunk or any of the later hunks in "
  133. "the file\n"),
  134. };
  135. static struct patch_mode patch_mode_checkout_head = {
  136. .diff_cmd = { "diff-index", NULL },
  137. .apply_for_checkout = 1,
  138. .apply_check_args = { "-R", NULL },
  139. .is_reverse = 1,
  140. .prompt_mode = {
  141. N_("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "),
  142. N_("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "),
  143. N_("Discard addition from index and worktree [y,n,q,a,d%s,?]? "),
  144. N_("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "),
  145. },
  146. .edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
  147. "will immediately be marked for discarding."),
  148. .help_patch_text =
  149. N_("y - discard this hunk from index and worktree\n"
  150. "n - do not discard this hunk from index and worktree\n"
  151. "q - quit; do not discard this hunk or any of the remaining "
  152. "ones\n"
  153. "a - discard this hunk and all later hunks in the file\n"
  154. "d - do not discard this hunk or any of the later hunks in "
  155. "the file\n"),
  156. };
  157. static struct patch_mode patch_mode_checkout_nothead = {
  158. .diff_cmd = { "diff-index", "-R", NULL },
  159. .apply_for_checkout = 1,
  160. .apply_check_args = { NULL },
  161. .prompt_mode = {
  162. N_("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "),
  163. N_("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "),
  164. N_("Apply addition to index and worktree [y,n,q,a,d%s,?]? "),
  165. N_("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "),
  166. },
  167. .edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
  168. "will immediately be marked for applying."),
  169. .help_patch_text =
  170. N_("y - apply this hunk to index and worktree\n"
  171. "n - do not apply this hunk to index and worktree\n"
  172. "q - quit; do not apply this hunk or any of the remaining "
  173. "ones\n"
  174. "a - apply this hunk and all later hunks in the file\n"
  175. "d - do not apply this hunk or any of the later hunks in "
  176. "the file\n"),
  177. };
  178. static struct patch_mode patch_mode_worktree_head = {
  179. .diff_cmd = { "diff-index", NULL },
  180. .apply_args = { "-R", NULL },
  181. .apply_check_args = { "-R", NULL },
  182. .is_reverse = 1,
  183. .prompt_mode = {
  184. N_("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "),
  185. N_("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "),
  186. N_("Discard addition from index and worktree [y,n,q,a,d%s,?]? "),
  187. N_("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "),
  188. },
  189. .edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
  190. "will immediately be marked for discarding."),
  191. .help_patch_text =
  192. N_("y - discard this hunk from worktree\n"
  193. "n - do not discard this hunk from worktree\n"
  194. "q - quit; do not discard this hunk or any of the remaining "
  195. "ones\n"
  196. "a - discard this hunk and all later hunks in the file\n"
  197. "d - do not discard this hunk or any of the later hunks in "
  198. "the file\n"),
  199. };
  200. static struct patch_mode patch_mode_worktree_nothead = {
  201. .diff_cmd = { "diff-index", "-R", NULL },
  202. .apply_args = { NULL },
  203. .apply_check_args = { NULL },
  204. .prompt_mode = {
  205. N_("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "),
  206. N_("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "),
  207. N_("Apply addition to index and worktree [y,n,q,a,d%s,?]? "),
  208. N_("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "),
  209. },
  210. .edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
  211. "will immediately be marked for applying."),
  212. .help_patch_text =
  213. N_("y - apply this hunk to worktree\n"
  214. "n - do not apply this hunk to worktree\n"
  215. "q - quit; do not apply this hunk or any of the remaining "
  216. "ones\n"
  217. "a - apply this hunk and all later hunks in the file\n"
  218. "d - do not apply this hunk or any of the later hunks in "
  219. "the file\n"),
  220. };
  221. struct hunk_header {
  222. unsigned long old_offset, old_count, new_offset, new_count;
  223. /*
  224. * Start/end offsets to the extra text after the second `@@` in the
  225. * hunk header, e.g. the function signature. This is expected to
  226. * include the newline.
  227. */
  228. size_t extra_start, extra_end, colored_extra_start, colored_extra_end;
  229. };
  230. struct hunk {
  231. size_t start, end, colored_start, colored_end, splittable_into;
  232. ssize_t delta;
  233. enum { UNDECIDED_HUNK = 0, SKIP_HUNK, USE_HUNK } use;
  234. struct hunk_header header;
  235. };
  236. struct add_p_state {
  237. struct add_i_state s;
  238. struct strbuf answer, buf;
  239. /* parsed diff */
  240. struct strbuf plain, colored;
  241. struct file_diff {
  242. struct hunk head;
  243. struct hunk *hunk;
  244. size_t hunk_nr, hunk_alloc;
  245. unsigned deleted:1, added:1, mode_change:1,binary:1;
  246. } *file_diff;
  247. size_t file_diff_nr;
  248. /* patch mode */
  249. struct patch_mode *mode;
  250. const char *revision;
  251. };
  252. static void add_p_state_clear(struct add_p_state *s)
  253. {
  254. size_t i;
  255. strbuf_release(&s->answer);
  256. strbuf_release(&s->buf);
  257. strbuf_release(&s->plain);
  258. strbuf_release(&s->colored);
  259. for (i = 0; i < s->file_diff_nr; i++)
  260. free(s->file_diff[i].hunk);
  261. free(s->file_diff);
  262. clear_add_i_state(&s->s);
  263. }
  264. static void err(struct add_p_state *s, const char *fmt, ...)
  265. {
  266. va_list args;
  267. va_start(args, fmt);
  268. fputs(s->s.error_color, stderr);
  269. vfprintf(stderr, fmt, args);
  270. fputs(s->s.reset_color, stderr);
  271. fputc('\n', stderr);
  272. va_end(args);
  273. }
  274. static void setup_child_process(struct add_p_state *s,
  275. struct child_process *cp, ...)
  276. {
  277. va_list ap;
  278. const char *arg;
  279. va_start(ap, cp);
  280. while ((arg = va_arg(ap, const char *)))
  281. strvec_push(&cp->args, arg);
  282. va_end(ap);
  283. cp->git_cmd = 1;
  284. strvec_pushf(&cp->env_array,
  285. INDEX_ENVIRONMENT "=%s", s->s.r->index_file);
  286. }
  287. static int parse_range(const char **p,
  288. unsigned long *offset, unsigned long *count)
  289. {
  290. char *pend;
  291. *offset = strtoul(*p, &pend, 10);
  292. if (pend == *p)
  293. return -1;
  294. if (*pend != ',') {
  295. *count = 1;
  296. *p = pend;
  297. return 0;
  298. }
  299. *count = strtoul(pend + 1, (char **)p, 10);
  300. return *p == pend + 1 ? -1 : 0;
  301. }
  302. static int parse_hunk_header(struct add_p_state *s, struct hunk *hunk)
  303. {
  304. struct hunk_header *header = &hunk->header;
  305. const char *line = s->plain.buf + hunk->start, *p = line;
  306. char *eol = memchr(p, '\n', s->plain.len - hunk->start);
  307. if (!eol)
  308. eol = s->plain.buf + s->plain.len;
  309. if (!skip_prefix(p, "@@ -", &p) ||
  310. parse_range(&p, &header->old_offset, &header->old_count) < 0 ||
  311. !skip_prefix(p, " +", &p) ||
  312. parse_range(&p, &header->new_offset, &header->new_count) < 0 ||
  313. !skip_prefix(p, " @@", &p))
  314. return error(_("could not parse hunk header '%.*s'"),
  315. (int)(eol - line), line);
  316. hunk->start = eol - s->plain.buf + (*eol == '\n');
  317. header->extra_start = p - s->plain.buf;
  318. header->extra_end = hunk->start;
  319. if (!s->colored.len) {
  320. header->colored_extra_start = header->colored_extra_end = 0;
  321. return 0;
  322. }
  323. /* Now find the extra text in the colored diff */
  324. line = s->colored.buf + hunk->colored_start;
  325. eol = memchr(line, '\n', s->colored.len - hunk->colored_start);
  326. if (!eol)
  327. eol = s->colored.buf + s->colored.len;
  328. p = memmem(line, eol - line, "@@ -", 4);
  329. if (!p)
  330. return error(_("could not parse colored hunk header '%.*s'"),
  331. (int)(eol - line), line);
  332. p = memmem(p + 4, eol - p - 4, " @@", 3);
  333. if (!p)
  334. return error(_("could not parse colored hunk header '%.*s'"),
  335. (int)(eol - line), line);
  336. hunk->colored_start = eol - s->colored.buf + (*eol == '\n');
  337. header->colored_extra_start = p + 3 - s->colored.buf;
  338. header->colored_extra_end = hunk->colored_start;
  339. return 0;
  340. }
  341. static int is_octal(const char *p, size_t len)
  342. {
  343. if (!len)
  344. return 0;
  345. while (len--)
  346. if (*p < '0' || *(p++) > '7')
  347. return 0;
  348. return 1;
  349. }
  350. static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
  351. {
  352. struct strvec args = STRVEC_INIT;
  353. const char *diff_algorithm = s->s.interactive_diff_algorithm;
  354. struct strbuf *plain = &s->plain, *colored = NULL;
  355. struct child_process cp = CHILD_PROCESS_INIT;
  356. char *p, *pend, *colored_p = NULL, *colored_pend = NULL, marker = '\0';
  357. size_t file_diff_alloc = 0, i, color_arg_index;
  358. struct file_diff *file_diff = NULL;
  359. struct hunk *hunk = NULL;
  360. int res;
  361. strvec_pushv(&args, s->mode->diff_cmd);
  362. if (diff_algorithm)
  363. strvec_pushf(&args, "--diff-algorithm=%s", diff_algorithm);
  364. if (s->revision) {
  365. struct object_id oid;
  366. strvec_push(&args,
  367. /* could be on an unborn branch */
  368. !strcmp("HEAD", s->revision) &&
  369. get_oid("HEAD", &oid) ?
  370. empty_tree_oid_hex() : s->revision);
  371. }
  372. color_arg_index = args.nr;
  373. /* Use `--no-color` explicitly, just in case `diff.color = always`. */
  374. strvec_pushl(&args, "--no-color", "-p", "--", NULL);
  375. for (i = 0; i < ps->nr; i++)
  376. strvec_push(&args, ps->items[i].original);
  377. setup_child_process(s, &cp, NULL);
  378. cp.argv = args.v;
  379. res = capture_command(&cp, plain, 0);
  380. if (res) {
  381. strvec_clear(&args);
  382. return error(_("could not parse diff"));
  383. }
  384. if (!plain->len) {
  385. strvec_clear(&args);
  386. return 0;
  387. }
  388. strbuf_complete_line(plain);
  389. if (want_color_fd(1, -1)) {
  390. struct child_process colored_cp = CHILD_PROCESS_INIT;
  391. const char *diff_filter = s->s.interactive_diff_filter;
  392. setup_child_process(s, &colored_cp, NULL);
  393. xsnprintf((char *)args.v[color_arg_index], 8, "--color");
  394. colored_cp.argv = args.v;
  395. colored = &s->colored;
  396. res = capture_command(&colored_cp, colored, 0);
  397. strvec_clear(&args);
  398. if (res)
  399. return error(_("could not parse colored diff"));
  400. if (diff_filter) {
  401. struct child_process filter_cp = CHILD_PROCESS_INIT;
  402. setup_child_process(s, &filter_cp,
  403. diff_filter, NULL);
  404. filter_cp.git_cmd = 0;
  405. filter_cp.use_shell = 1;
  406. strbuf_reset(&s->buf);
  407. if (pipe_command(&filter_cp,
  408. colored->buf, colored->len,
  409. &s->buf, colored->len,
  410. NULL, 0) < 0)
  411. return error(_("failed to run '%s'"),
  412. diff_filter);
  413. strbuf_swap(colored, &s->buf);
  414. }
  415. strbuf_complete_line(colored);
  416. colored_p = colored->buf;
  417. colored_pend = colored_p + colored->len;
  418. }
  419. strvec_clear(&args);
  420. /* parse files and hunks */
  421. p = plain->buf;
  422. pend = p + plain->len;
  423. while (p != pend) {
  424. char *eol = memchr(p, '\n', pend - p);
  425. const char *deleted = NULL, *mode_change = NULL;
  426. if (!eol)
  427. eol = pend;
  428. if (starts_with(p, "diff ")) {
  429. ALLOC_GROW_BY(s->file_diff, s->file_diff_nr, 1,
  430. file_diff_alloc);
  431. file_diff = s->file_diff + s->file_diff_nr - 1;
  432. hunk = &file_diff->head;
  433. hunk->start = p - plain->buf;
  434. if (colored_p)
  435. hunk->colored_start = colored_p - colored->buf;
  436. marker = '\0';
  437. } else if (p == plain->buf)
  438. BUG("diff starts with unexpected line:\n"
  439. "%.*s\n", (int)(eol - p), p);
  440. else if (file_diff->deleted)
  441. ; /* keep the rest of the file in a single "hunk" */
  442. else if (starts_with(p, "@@ ") ||
  443. (hunk == &file_diff->head &&
  444. (skip_prefix(p, "deleted file", &deleted)))) {
  445. if (marker == '-' || marker == '+')
  446. /*
  447. * Should not happen; previous hunk did not end
  448. * in a context line? Handle it anyway.
  449. */
  450. hunk->splittable_into++;
  451. ALLOC_GROW_BY(file_diff->hunk, file_diff->hunk_nr, 1,
  452. file_diff->hunk_alloc);
  453. hunk = file_diff->hunk + file_diff->hunk_nr - 1;
  454. hunk->start = p - plain->buf;
  455. if (colored)
  456. hunk->colored_start = colored_p - colored->buf;
  457. if (deleted)
  458. file_diff->deleted = 1;
  459. else if (parse_hunk_header(s, hunk) < 0)
  460. return -1;
  461. /*
  462. * Start counting into how many hunks this one can be
  463. * split
  464. */
  465. marker = *p;
  466. } else if (hunk == &file_diff->head &&
  467. starts_with(p, "new file")) {
  468. file_diff->added = 1;
  469. } else if (hunk == &file_diff->head &&
  470. skip_prefix(p, "old mode ", &mode_change) &&
  471. is_octal(mode_change, eol - mode_change)) {
  472. if (file_diff->mode_change)
  473. BUG("double mode change?\n\n%.*s",
  474. (int)(eol - plain->buf), plain->buf);
  475. if (file_diff->hunk_nr)
  476. BUG("mode change in the middle?\n\n%.*s",
  477. (int)(eol - plain->buf), plain->buf);
  478. /*
  479. * Do *not* change `hunk`: the mode change pseudo-hunk
  480. * is _part of_ the header "hunk".
  481. */
  482. file_diff->mode_change = 1;
  483. ALLOC_GROW_BY(file_diff->hunk, file_diff->hunk_nr, 1,
  484. file_diff->hunk_alloc);
  485. file_diff->hunk->start = p - plain->buf;
  486. if (colored_p)
  487. file_diff->hunk->colored_start =
  488. colored_p - colored->buf;
  489. } else if (hunk == &file_diff->head &&
  490. skip_prefix(p, "new mode ", &mode_change) &&
  491. is_octal(mode_change, eol - mode_change)) {
  492. /*
  493. * Extend the "mode change" pseudo-hunk to include also
  494. * the "new mode" line.
  495. */
  496. if (!file_diff->mode_change)
  497. BUG("'new mode' without 'old mode'?\n\n%.*s",
  498. (int)(eol - plain->buf), plain->buf);
  499. if (file_diff->hunk_nr != 1)
  500. BUG("mode change in the middle?\n\n%.*s",
  501. (int)(eol - plain->buf), plain->buf);
  502. if (p - plain->buf != file_diff->hunk->end)
  503. BUG("'new mode' does not immediately follow "
  504. "'old mode'?\n\n%.*s",
  505. (int)(eol - plain->buf), plain->buf);
  506. } else if (hunk == &file_diff->head &&
  507. starts_with(p, "Binary files "))
  508. file_diff->binary = 1;
  509. if (!!file_diff->deleted + !!file_diff->added +
  510. !!file_diff->mode_change > 1)
  511. BUG("diff can only contain delete *or* add *or* a "
  512. "mode change?!?\n%.*s",
  513. (int)(eol - (plain->buf + file_diff->head.start)),
  514. plain->buf + file_diff->head.start);
  515. if ((marker == '-' || marker == '+') && *p == ' ')
  516. hunk->splittable_into++;
  517. if (marker && *p != '\\')
  518. marker = *p;
  519. p = eol == pend ? pend : eol + 1;
  520. hunk->end = p - plain->buf;
  521. if (colored) {
  522. char *colored_eol = memchr(colored_p, '\n',
  523. colored_pend - colored_p);
  524. if (colored_eol)
  525. colored_p = colored_eol + 1;
  526. else if (p != pend)
  527. /* colored shorter than non-colored? */
  528. goto mismatched_output;
  529. else
  530. colored_p = colored_pend;
  531. hunk->colored_end = colored_p - colored->buf;
  532. }
  533. if (mode_change) {
  534. if (file_diff->hunk_nr != 1)
  535. BUG("mode change in hunk #%d???",
  536. (int)file_diff->hunk_nr);
  537. /* Adjust the end of the "mode change" pseudo-hunk */
  538. file_diff->hunk->end = hunk->end;
  539. if (colored)
  540. file_diff->hunk->colored_end = hunk->colored_end;
  541. }
  542. }
  543. if (marker == '-' || marker == '+')
  544. /*
  545. * Last hunk ended in non-context line (i.e. it appended lines
  546. * to the file, so there are no trailing context lines).
  547. */
  548. hunk->splittable_into++;
  549. /* non-colored shorter than colored? */
  550. if (colored_p != colored_pend) {
  551. mismatched_output:
  552. error(_("mismatched output from interactive.diffFilter"));
  553. advise(_("Your filter must maintain a one-to-one correspondence\n"
  554. "between its input and output lines."));
  555. return -1;
  556. }
  557. return 0;
  558. }
  559. static size_t find_next_line(struct strbuf *sb, size_t offset)
  560. {
  561. char *eol;
  562. if (offset >= sb->len)
  563. BUG("looking for next line beyond buffer (%d >= %d)\n%s",
  564. (int)offset, (int)sb->len, sb->buf);
  565. eol = memchr(sb->buf + offset, '\n', sb->len - offset);
  566. if (!eol)
  567. return sb->len;
  568. return eol - sb->buf + 1;
  569. }
  570. static void render_hunk(struct add_p_state *s, struct hunk *hunk,
  571. ssize_t delta, int colored, struct strbuf *out)
  572. {
  573. struct hunk_header *header = &hunk->header;
  574. if (hunk->header.old_offset != 0 || hunk->header.new_offset != 0) {
  575. /*
  576. * Generate the hunk header dynamically, except for special
  577. * hunks (such as the diff header).
  578. */
  579. const char *p;
  580. size_t len;
  581. unsigned long old_offset = header->old_offset;
  582. unsigned long new_offset = header->new_offset;
  583. if (!colored) {
  584. p = s->plain.buf + header->extra_start;
  585. len = header->extra_end - header->extra_start;
  586. } else {
  587. strbuf_addstr(out, s->s.fraginfo_color);
  588. p = s->colored.buf + header->colored_extra_start;
  589. len = header->colored_extra_end
  590. - header->colored_extra_start;
  591. }
  592. if (s->mode->is_reverse)
  593. old_offset -= delta;
  594. else
  595. new_offset += delta;
  596. strbuf_addf(out, "@@ -%lu,%lu +%lu,%lu @@",
  597. old_offset, header->old_count,
  598. new_offset, header->new_count);
  599. if (len)
  600. strbuf_add(out, p, len);
  601. else if (colored)
  602. strbuf_addf(out, "%s\n", GIT_COLOR_RESET);
  603. else
  604. strbuf_addch(out, '\n');
  605. }
  606. if (colored)
  607. strbuf_add(out, s->colored.buf + hunk->colored_start,
  608. hunk->colored_end - hunk->colored_start);
  609. else
  610. strbuf_add(out, s->plain.buf + hunk->start,
  611. hunk->end - hunk->start);
  612. }
  613. static void render_diff_header(struct add_p_state *s,
  614. struct file_diff *file_diff, int colored,
  615. struct strbuf *out)
  616. {
  617. /*
  618. * If there was a mode change, the first hunk is a pseudo hunk that
  619. * corresponds to the mode line in the header. If the user did not want
  620. * to stage that "hunk", we actually have to cut it out from the header.
  621. */
  622. int skip_mode_change =
  623. file_diff->mode_change && file_diff->hunk->use != USE_HUNK;
  624. struct hunk *head = &file_diff->head, *first = file_diff->hunk;
  625. if (!skip_mode_change) {
  626. render_hunk(s, head, 0, colored, out);
  627. return;
  628. }
  629. if (colored) {
  630. const char *p = s->colored.buf;
  631. strbuf_add(out, p + head->colored_start,
  632. first->colored_start - head->colored_start);
  633. strbuf_add(out, p + first->colored_end,
  634. head->colored_end - first->colored_end);
  635. } else {
  636. const char *p = s->plain.buf;
  637. strbuf_add(out, p + head->start, first->start - head->start);
  638. strbuf_add(out, p + first->end, head->end - first->end);
  639. }
  640. }
  641. /* Coalesce hunks again that were split */
  642. static int merge_hunks(struct add_p_state *s, struct file_diff *file_diff,
  643. size_t *hunk_index, int use_all, struct hunk *merged)
  644. {
  645. size_t i = *hunk_index, delta;
  646. struct hunk *hunk = file_diff->hunk + i;
  647. /* `header` corresponds to the merged hunk */
  648. struct hunk_header *header = &merged->header, *next;
  649. if (!use_all && hunk->use != USE_HUNK)
  650. return 0;
  651. *merged = *hunk;
  652. /* We simply skip the colored part (if any) when merging hunks */
  653. merged->colored_start = merged->colored_end = 0;
  654. for (; i + 1 < file_diff->hunk_nr; i++) {
  655. hunk++;
  656. next = &hunk->header;
  657. /*
  658. * Stop merging hunks when:
  659. *
  660. * - the hunk is not selected for use, or
  661. * - the hunk does not overlap with the already-merged hunk(s)
  662. */
  663. if ((!use_all && hunk->use != USE_HUNK) ||
  664. header->new_offset >= next->new_offset + merged->delta ||
  665. header->new_offset + header->new_count
  666. < next->new_offset + merged->delta)
  667. break;
  668. /*
  669. * If the hunks were not edited, and overlap, we can simply
  670. * extend the line range.
  671. */
  672. if (merged->start < hunk->start && merged->end > hunk->start) {
  673. merged->end = hunk->end;
  674. merged->colored_end = hunk->colored_end;
  675. delta = 0;
  676. } else {
  677. const char *plain = s->plain.buf;
  678. size_t overlapping_line_count = header->new_offset
  679. + header->new_count - merged->delta
  680. - next->new_offset;
  681. size_t overlap_end = hunk->start;
  682. size_t overlap_start = overlap_end;
  683. size_t overlap_next, len, j;
  684. /*
  685. * One of the hunks was edited: the modified hunk was
  686. * appended to the strbuf `s->plain`.
  687. *
  688. * Let's ensure that at least the last context line of
  689. * the first hunk overlaps with the corresponding line
  690. * of the second hunk, and then merge.
  691. */
  692. for (j = 0; j < overlapping_line_count; j++) {
  693. overlap_next = find_next_line(&s->plain,
  694. overlap_end);
  695. if (overlap_next > hunk->end)
  696. BUG("failed to find %d context lines "
  697. "in:\n%.*s",
  698. (int)overlapping_line_count,
  699. (int)(hunk->end - hunk->start),
  700. plain + hunk->start);
  701. if (plain[overlap_end] != ' ')
  702. return error(_("expected context line "
  703. "#%d in\n%.*s"),
  704. (int)(j + 1),
  705. (int)(hunk->end
  706. - hunk->start),
  707. plain + hunk->start);
  708. overlap_start = overlap_end;
  709. overlap_end = overlap_next;
  710. }
  711. len = overlap_end - overlap_start;
  712. if (len > merged->end - merged->start ||
  713. memcmp(plain + merged->end - len,
  714. plain + overlap_start, len))
  715. return error(_("hunks do not overlap:\n%.*s\n"
  716. "\tdoes not end with:\n%.*s"),
  717. (int)(merged->end - merged->start),
  718. plain + merged->start,
  719. (int)len, plain + overlap_start);
  720. /*
  721. * Since the start-end ranges are not adjacent, we
  722. * cannot simply take the union of the ranges. To
  723. * address that, we temporarily append the union of the
  724. * lines to the `plain` strbuf.
  725. */
  726. if (merged->end != s->plain.len) {
  727. size_t start = s->plain.len;
  728. strbuf_add(&s->plain, plain + merged->start,
  729. merged->end - merged->start);
  730. plain = s->plain.buf;
  731. merged->start = start;
  732. merged->end = s->plain.len;
  733. }
  734. strbuf_add(&s->plain,
  735. plain + overlap_end,
  736. hunk->end - overlap_end);
  737. merged->end = s->plain.len;
  738. merged->splittable_into += hunk->splittable_into;
  739. delta = merged->delta;
  740. merged->delta += hunk->delta;
  741. }
  742. header->old_count = next->old_offset + next->old_count
  743. - header->old_offset;
  744. header->new_count = next->new_offset + delta
  745. + next->new_count - header->new_offset;
  746. }
  747. if (i == *hunk_index)
  748. return 0;
  749. *hunk_index = i;
  750. return 1;
  751. }
  752. static void reassemble_patch(struct add_p_state *s,
  753. struct file_diff *file_diff, int use_all,
  754. struct strbuf *out)
  755. {
  756. struct hunk *hunk;
  757. size_t save_len = s->plain.len, i;
  758. ssize_t delta = 0;
  759. render_diff_header(s, file_diff, 0, out);
  760. for (i = file_diff->mode_change; i < file_diff->hunk_nr; i++) {
  761. struct hunk merged = { 0 };
  762. hunk = file_diff->hunk + i;
  763. if (!use_all && hunk->use != USE_HUNK)
  764. delta += hunk->header.old_count
  765. - hunk->header.new_count;
  766. else {
  767. /* merge overlapping hunks into a temporary hunk */
  768. if (merge_hunks(s, file_diff, &i, use_all, &merged))
  769. hunk = &merged;
  770. render_hunk(s, hunk, delta, 0, out);
  771. /*
  772. * In case `merge_hunks()` used `plain` as a scratch
  773. * pad (this happens when an edited hunk had to be
  774. * coalesced with another hunk).
  775. */
  776. strbuf_setlen(&s->plain, save_len);
  777. delta += hunk->delta;
  778. }
  779. }
  780. }
  781. static int split_hunk(struct add_p_state *s, struct file_diff *file_diff,
  782. size_t hunk_index)
  783. {
  784. int colored = !!s->colored.len, first = 1;
  785. struct hunk *hunk = file_diff->hunk + hunk_index;
  786. size_t splittable_into;
  787. size_t end, colored_end, current, colored_current = 0, context_line_count;
  788. struct hunk_header remaining, *header;
  789. char marker, ch;
  790. if (hunk_index >= file_diff->hunk_nr)
  791. BUG("invalid hunk index: %d (must be >= 0 and < %d)",
  792. (int)hunk_index, (int)file_diff->hunk_nr);
  793. if (hunk->splittable_into < 2)
  794. return 0;
  795. splittable_into = hunk->splittable_into;
  796. end = hunk->end;
  797. colored_end = hunk->colored_end;
  798. remaining = hunk->header;
  799. file_diff->hunk_nr += splittable_into - 1;
  800. ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr, file_diff->hunk_alloc);
  801. if (hunk_index + splittable_into < file_diff->hunk_nr)
  802. memmove(file_diff->hunk + hunk_index + splittable_into,
  803. file_diff->hunk + hunk_index + 1,
  804. (file_diff->hunk_nr - hunk_index - splittable_into)
  805. * sizeof(*hunk));
  806. hunk = file_diff->hunk + hunk_index;
  807. hunk->splittable_into = 1;
  808. memset(hunk + 1, 0, (splittable_into - 1) * sizeof(*hunk));
  809. header = &hunk->header;
  810. header->old_count = header->new_count = 0;
  811. current = hunk->start;
  812. if (colored)
  813. colored_current = hunk->colored_start;
  814. marker = '\0';
  815. context_line_count = 0;
  816. while (splittable_into > 1) {
  817. ch = s->plain.buf[current];
  818. if (!ch)
  819. BUG("buffer overrun while splitting hunks");
  820. /*
  821. * Is this the first context line after a chain of +/- lines?
  822. * Then record the start of the next split hunk.
  823. */
  824. if ((marker == '-' || marker == '+') && ch == ' ') {
  825. first = 0;
  826. hunk[1].start = current;
  827. if (colored)
  828. hunk[1].colored_start = colored_current;
  829. context_line_count = 0;
  830. }
  831. /*
  832. * Was the previous line a +/- one? Alternatively, is this the
  833. * first line (and not a +/- one)?
  834. *
  835. * Then just increment the appropriate counter and continue
  836. * with the next line.
  837. */
  838. if (marker != ' ' || (ch != '-' && ch != '+')) {
  839. next_hunk_line:
  840. /* Comment lines are attached to the previous line */
  841. if (ch == '\\')
  842. ch = marker ? marker : ' ';
  843. /* current hunk not done yet */
  844. if (ch == ' ')
  845. context_line_count++;
  846. else if (ch == '-')
  847. header->old_count++;
  848. else if (ch == '+')
  849. header->new_count++;
  850. else
  851. BUG("unhandled diff marker: '%c'", ch);
  852. marker = ch;
  853. current = find_next_line(&s->plain, current);
  854. if (colored)
  855. colored_current =
  856. find_next_line(&s->colored,
  857. colored_current);
  858. continue;
  859. }
  860. /*
  861. * We got us the start of a new hunk!
  862. *
  863. * This is a context line, so it is shared with the previous
  864. * hunk, if any.
  865. */
  866. if (first) {
  867. if (header->old_count || header->new_count)
  868. BUG("counts are off: %d/%d",
  869. (int)header->old_count,
  870. (int)header->new_count);
  871. header->old_count = context_line_count;
  872. header->new_count = context_line_count;
  873. context_line_count = 0;
  874. first = 0;
  875. goto next_hunk_line;
  876. }
  877. remaining.old_offset += header->old_count;
  878. remaining.old_count -= header->old_count;
  879. remaining.new_offset += header->new_count;
  880. remaining.new_count -= header->new_count;
  881. /* initialize next hunk header's offsets */
  882. hunk[1].header.old_offset =
  883. header->old_offset + header->old_count;
  884. hunk[1].header.new_offset =
  885. header->new_offset + header->new_count;
  886. /* add one split hunk */
  887. header->old_count += context_line_count;
  888. header->new_count += context_line_count;
  889. hunk->end = current;
  890. if (colored)
  891. hunk->colored_end = colored_current;
  892. hunk++;
  893. hunk->splittable_into = 1;
  894. hunk->use = hunk[-1].use;
  895. header = &hunk->header;
  896. header->old_count = header->new_count = context_line_count;
  897. context_line_count = 0;
  898. splittable_into--;
  899. marker = ch;
  900. }
  901. /* last hunk simply gets the rest */
  902. if (header->old_offset != remaining.old_offset)
  903. BUG("miscounted old_offset: %lu != %lu",
  904. header->old_offset, remaining.old_offset);
  905. if (header->new_offset != remaining.new_offset)
  906. BUG("miscounted new_offset: %lu != %lu",
  907. header->new_offset, remaining.new_offset);
  908. header->old_count = remaining.old_count;
  909. header->new_count = remaining.new_count;
  910. hunk->end = end;
  911. if (colored)
  912. hunk->colored_end = colored_end;
  913. return 0;
  914. }
  915. static void recolor_hunk(struct add_p_state *s, struct hunk *hunk)
  916. {
  917. const char *plain = s->plain.buf;
  918. size_t current, eol, next;
  919. if (!s->colored.len)
  920. return;
  921. hunk->colored_start = s->colored.len;
  922. for (current = hunk->start; current < hunk->end; ) {
  923. for (eol = current; eol < hunk->end; eol++)
  924. if (plain[eol] == '\n')
  925. break;
  926. next = eol + (eol < hunk->end);
  927. if (eol > current && plain[eol - 1] == '\r')
  928. eol--;
  929. strbuf_addstr(&s->colored,
  930. plain[current] == '-' ?
  931. s->s.file_old_color :
  932. plain[current] == '+' ?
  933. s->s.file_new_color :
  934. s->s.context_color);
  935. strbuf_add(&s->colored, plain + current, eol - current);
  936. strbuf_addstr(&s->colored, GIT_COLOR_RESET);
  937. if (next > eol)
  938. strbuf_add(&s->colored, plain + eol, next - eol);
  939. current = next;
  940. }
  941. hunk->colored_end = s->colored.len;
  942. }
  943. static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
  944. {
  945. size_t i;
  946. strbuf_reset(&s->buf);
  947. strbuf_commented_addf(&s->buf, _("Manual hunk edit mode -- see bottom for "
  948. "a quick guide.\n"));
  949. render_hunk(s, hunk, 0, 0, &s->buf);
  950. strbuf_commented_addf(&s->buf,
  951. _("---\n"
  952. "To remove '%c' lines, make them ' ' lines "
  953. "(context).\n"
  954. "To remove '%c' lines, delete them.\n"
  955. "Lines starting with %c will be removed.\n"),
  956. s->mode->is_reverse ? '+' : '-',
  957. s->mode->is_reverse ? '-' : '+',
  958. comment_line_char);
  959. strbuf_commented_addf(&s->buf, "%s", _(s->mode->edit_hunk_hint));
  960. /*
  961. * TRANSLATORS: 'it' refers to the patch mentioned in the previous
  962. * messages.
  963. */
  964. strbuf_commented_addf(&s->buf,
  965. _("If it does not apply cleanly, you will be "
  966. "given an opportunity to\n"
  967. "edit again. If all lines of the hunk are "
  968. "removed, then the edit is\n"
  969. "aborted and the hunk is left unchanged.\n"));
  970. if (strbuf_edit_interactively(&s->buf, "addp-hunk-edit.diff", NULL) < 0)
  971. return -1;
  972. /* strip out commented lines */
  973. hunk->start = s->plain.len;
  974. for (i = 0; i < s->buf.len; ) {
  975. size_t next = find_next_line(&s->buf, i);
  976. if (s->buf.buf[i] != comment_line_char)
  977. strbuf_add(&s->plain, s->buf.buf + i, next - i);
  978. i = next;
  979. }
  980. hunk->end = s->plain.len;
  981. if (hunk->end == hunk->start)
  982. /* The user aborted editing by deleting everything */
  983. return 0;
  984. recolor_hunk(s, hunk);
  985. /*
  986. * If the hunk header is intact, parse it, otherwise simply use the
  987. * hunk header prior to editing (which will adjust `hunk->start` to
  988. * skip the hunk header).
  989. */
  990. if (s->plain.buf[hunk->start] == '@' &&
  991. parse_hunk_header(s, hunk) < 0)
  992. return error(_("could not parse hunk header"));
  993. return 1;
  994. }
  995. static ssize_t recount_edited_hunk(struct add_p_state *s, struct hunk *hunk,
  996. size_t orig_old_count, size_t orig_new_count)
  997. {
  998. struct hunk_header *header = &hunk->header;
  999. size_t i;
  1000. header->old_count = header->new_count = 0;
  1001. for (i = hunk->start; i < hunk->end; ) {
  1002. switch (s->plain.buf[i]) {
  1003. case '-':
  1004. header->old_count++;
  1005. break;
  1006. case '+':
  1007. header->new_count++;
  1008. break;
  1009. case ' ': case '\r': case '\n':
  1010. header->old_count++;
  1011. header->new_count++;
  1012. break;
  1013. }
  1014. i = find_next_line(&s->plain, i);
  1015. }
  1016. return orig_old_count - orig_new_count
  1017. - header->old_count + header->new_count;
  1018. }
  1019. static int run_apply_check(struct add_p_state *s,
  1020. struct file_diff *file_diff)
  1021. {
  1022. struct child_process cp = CHILD_PROCESS_INIT;
  1023. strbuf_reset(&s->buf);
  1024. reassemble_patch(s, file_diff, 1, &s->buf);
  1025. setup_child_process(s, &cp,
  1026. "apply", "--check", NULL);
  1027. strvec_pushv(&cp.args, s->mode->apply_check_args);
  1028. if (pipe_command(&cp, s->buf.buf, s->buf.len, NULL, 0, NULL, 0))
  1029. return error(_("'git apply --cached' failed"));
  1030. return 0;
  1031. }
  1032. static int read_single_character(struct add_p_state *s)
  1033. {
  1034. if (s->s.use_single_key) {
  1035. int res = read_key_without_echo(&s->answer);
  1036. printf("%s\n", res == EOF ? "" : s->answer.buf);
  1037. return res;
  1038. }
  1039. if (git_read_line_interactively(&s->answer) == EOF)
  1040. return EOF;
  1041. return 0;
  1042. }
  1043. static int prompt_yesno(struct add_p_state *s, const char *prompt)
  1044. {
  1045. for (;;) {
  1046. color_fprintf(stdout, s->s.prompt_color, "%s", _(prompt));
  1047. fflush(stdout);
  1048. if (read_single_character(s) == EOF)
  1049. return -1;
  1050. switch (tolower(s->answer.buf[0])) {
  1051. case 'n': return 0;
  1052. case 'y': return 1;
  1053. }
  1054. }
  1055. }
  1056. static int edit_hunk_loop(struct add_p_state *s,
  1057. struct file_diff *file_diff, struct hunk *hunk)
  1058. {
  1059. size_t plain_len = s->plain.len, colored_len = s->colored.len;
  1060. struct hunk backup;
  1061. backup = *hunk;
  1062. for (;;) {
  1063. int res = edit_hunk_manually(s, hunk);
  1064. if (res == 0) {
  1065. /* abandoned */
  1066. *hunk = backup;
  1067. return -1;
  1068. }
  1069. if (res > 0) {
  1070. hunk->delta +=
  1071. recount_edited_hunk(s, hunk,
  1072. backup.header.old_count,
  1073. backup.header.new_count);
  1074. if (!run_apply_check(s, file_diff))
  1075. return 0;
  1076. }
  1077. /* Drop edits (they were appended to s->plain) */
  1078. strbuf_setlen(&s->plain, plain_len);
  1079. strbuf_setlen(&s->colored, colored_len);
  1080. *hunk = backup;
  1081. /*
  1082. * TRANSLATORS: do not translate [y/n]
  1083. * The program will only accept that input at this point.
  1084. * Consider translating (saying "no" discards!) as
  1085. * (saying "n" for "no" discards!) if the translation
  1086. * of the word "no" does not start with n.
  1087. */
  1088. res = prompt_yesno(s, _("Your edited hunk does not apply. "
  1089. "Edit again (saying \"no\" discards!) "
  1090. "[y/n]? "));
  1091. if (res < 1)
  1092. return -1;
  1093. }
  1094. }
  1095. static int apply_for_checkout(struct add_p_state *s, struct strbuf *diff,
  1096. int is_reverse)
  1097. {
  1098. const char *reverse = is_reverse ? "-R" : NULL;
  1099. struct child_process check_index = CHILD_PROCESS_INIT;
  1100. struct child_process check_worktree = CHILD_PROCESS_INIT;
  1101. struct child_process apply_index = CHILD_PROCESS_INIT;
  1102. struct child_process apply_worktree = CHILD_PROCESS_INIT;
  1103. int applies_index, applies_worktree;
  1104. setup_child_process(s, &check_index,
  1105. "apply", "--cached", "--check", reverse, NULL);
  1106. applies_index = !pipe_command(&check_index, diff->buf, diff->len,
  1107. NULL, 0, NULL, 0);
  1108. setup_child_process(s, &check_worktree,
  1109. "apply", "--check", reverse, NULL);
  1110. applies_worktree = !pipe_command(&check_worktree, diff->buf, diff->len,
  1111. NULL, 0, NULL, 0);
  1112. if (applies_worktree && applies_index) {
  1113. setup_child_process(s, &apply_index,
  1114. "apply", "--cached", reverse, NULL);
  1115. pipe_command(&apply_index, diff->buf, diff->len,
  1116. NULL, 0, NULL, 0);
  1117. setup_child_process(s, &apply_worktree,
  1118. "apply", reverse, NULL);
  1119. pipe_command(&apply_worktree, diff->buf, diff->len,
  1120. NULL, 0, NULL, 0);
  1121. return 1;
  1122. }
  1123. if (!applies_index) {
  1124. err(s, _("The selected hunks do not apply to the index!"));
  1125. if (prompt_yesno(s, _("Apply them to the worktree "
  1126. "anyway? ")) > 0) {
  1127. setup_child_process(s, &apply_worktree,
  1128. "apply", reverse, NULL);
  1129. return pipe_command(&apply_worktree, diff->buf,
  1130. diff->len, NULL, 0, NULL, 0);
  1131. }
  1132. err(s, _("Nothing was applied.\n"));
  1133. } else
  1134. /* As a last resort, show the diff to the user */
  1135. fwrite(diff->buf, diff->len, 1, stderr);
  1136. return 0;
  1137. }
  1138. #define SUMMARY_HEADER_WIDTH 20
  1139. #define SUMMARY_LINE_WIDTH 80
  1140. static void summarize_hunk(struct add_p_state *s, struct hunk *hunk,
  1141. struct strbuf *out)
  1142. {
  1143. struct hunk_header *header = &hunk->header;
  1144. struct strbuf *plain = &s->plain;
  1145. size_t len = out->len, i;
  1146. strbuf_addf(out, " -%lu,%lu +%lu,%lu ",
  1147. header->old_offset, header->old_count,
  1148. header->new_offset, header->new_count);
  1149. if (out->len - len < SUMMARY_HEADER_WIDTH)
  1150. strbuf_addchars(out, ' ',
  1151. SUMMARY_HEADER_WIDTH + len - out->len);
  1152. for (i = hunk->start; i < hunk->end; i = find_next_line(plain, i))
  1153. if (plain->buf[i] != ' ')
  1154. break;
  1155. if (i < hunk->end)
  1156. strbuf_add(out, plain->buf + i, find_next_line(plain, i) - i);
  1157. if (out->len - len > SUMMARY_LINE_WIDTH)
  1158. strbuf_setlen(out, len + SUMMARY_LINE_WIDTH);
  1159. strbuf_complete_line(out);
  1160. }
  1161. #define DISPLAY_HUNKS_LINES 20
  1162. static size_t display_hunks(struct add_p_state *s,
  1163. struct file_diff *file_diff, size_t start_index)
  1164. {
  1165. size_t end_index = start_index + DISPLAY_HUNKS_LINES;
  1166. if (end_index > file_diff->hunk_nr)
  1167. end_index = file_diff->hunk_nr;
  1168. while (start_index < end_index) {
  1169. struct hunk *hunk = file_diff->hunk + start_index++;
  1170. strbuf_reset(&s->buf);
  1171. strbuf_addf(&s->buf, "%c%2d: ", hunk->use == USE_HUNK ? '+'
  1172. : hunk->use == SKIP_HUNK ? '-' : ' ',
  1173. (int)start_index);
  1174. summarize_hunk(s, hunk, &s->buf);
  1175. fputs(s->buf.buf, stdout);
  1176. }
  1177. return end_index;
  1178. }
  1179. static const char help_patch_remainder[] =
  1180. N_("j - leave this hunk undecided, see next undecided hunk\n"
  1181. "J - leave this hunk undecided, see next hunk\n"
  1182. "k - leave this hunk undecided, see previous undecided hunk\n"
  1183. "K - leave this hunk undecided, see previous hunk\n"
  1184. "g - select a hunk to go to\n"
  1185. "/ - search for a hunk matching the given regex\n"
  1186. "s - split the current hunk into smaller hunks\n"
  1187. "e - manually edit the current hunk\n"
  1188. "? - print help\n");
  1189. static int patch_update_file(struct add_p_state *s,
  1190. struct file_diff *file_diff)
  1191. {
  1192. size_t hunk_index = 0;
  1193. ssize_t i, undecided_previous, undecided_next;
  1194. struct hunk *hunk;
  1195. char ch;
  1196. struct child_process cp = CHILD_PROCESS_INIT;
  1197. int colored = !!s->colored.len, quit = 0;
  1198. enum prompt_mode_type prompt_mode_type;
  1199. enum {
  1200. ALLOW_GOTO_PREVIOUS_HUNK = 1 << 0,
  1201. ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK = 1 << 1,
  1202. ALLOW_GOTO_NEXT_HUNK = 1 << 2,
  1203. ALLOW_GOTO_NEXT_UNDECIDED_HUNK = 1 << 3,
  1204. ALLOW_SEARCH_AND_GOTO = 1 << 4,
  1205. ALLOW_SPLIT = 1 << 5,
  1206. ALLOW_EDIT = 1 << 6
  1207. } permitted = 0;
  1208. /* Empty added files have no hunks */
  1209. if (!file_diff->hunk_nr && !file_diff->added)
  1210. return 0;
  1211. strbuf_reset(&s->buf);
  1212. render_diff_header(s, file_diff, colored, &s->buf);
  1213. fputs(s->buf.buf, stdout);
  1214. for (;;) {
  1215. if (hunk_index >= file_diff->hunk_nr)
  1216. hunk_index = 0;
  1217. hunk = file_diff->hunk_nr
  1218. ? file_diff->hunk + hunk_index
  1219. : &file_diff->head;
  1220. undecided_previous = -1;
  1221. undecided_next = -1;
  1222. if (file_diff->hunk_nr) {
  1223. for (i = hunk_index - 1; i >= 0; i--)
  1224. if (file_diff->hunk[i].use == UNDECIDED_HUNK) {
  1225. undecided_previous = i;
  1226. break;
  1227. }
  1228. for (i = hunk_index + 1; i < file_diff->hunk_nr; i++)
  1229. if (file_diff->hunk[i].use == UNDECIDED_HUNK) {
  1230. undecided_next = i;
  1231. break;
  1232. }
  1233. }
  1234. /* Everything decided? */
  1235. if (undecided_previous < 0 && undecided_next < 0 &&
  1236. hunk->use != UNDECIDED_HUNK)
  1237. break;
  1238. strbuf_reset(&s->buf);
  1239. if (file_diff->hunk_nr) {
  1240. render_hunk(s, hunk, 0, colored, &s->buf);
  1241. fputs(s->buf.buf, stdout);
  1242. strbuf_reset(&s->buf);
  1243. if (undecided_previous >= 0) {
  1244. permitted |= ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK;
  1245. strbuf_addstr(&s->buf, ",k");
  1246. }
  1247. if (hunk_index) {
  1248. permitted |= ALLOW_GOTO_PREVIOUS_HUNK;
  1249. strbuf_addstr(&s->buf, ",K");
  1250. }
  1251. if (undecided_next >= 0) {
  1252. permitted |= ALLOW_GOTO_NEXT_UNDECIDED_HUNK;
  1253. strbuf_addstr(&s->buf, ",j");
  1254. }
  1255. if (hunk_index + 1 < file_diff->hunk_nr) {
  1256. permitted |= ALLOW_GOTO_NEXT_HUNK;
  1257. strbuf_addstr(&s->buf, ",J");
  1258. }
  1259. if (file_diff->hunk_nr > 1) {
  1260. permitted |= ALLOW_SEARCH_AND_GOTO;
  1261. strbuf_addstr(&s->buf, ",g,/");
  1262. }
  1263. if (hunk->splittable_into > 1) {
  1264. permitted |= ALLOW_SPLIT;
  1265. strbuf_addstr(&s->buf, ",s");
  1266. }
  1267. if (hunk_index + 1 > file_diff->mode_change &&
  1268. !file_diff->deleted) {
  1269. permitted |= ALLOW_EDIT;
  1270. strbuf_addstr(&s->buf, ",e");
  1271. }
  1272. }
  1273. if (file_diff->deleted)
  1274. prompt_mode_type = PROMPT_DELETION;
  1275. else if (file_diff->added)
  1276. prompt_mode_type = PROMPT_ADDITION;
  1277. else if (file_diff->mode_change && !hunk_index)
  1278. prompt_mode_type = PROMPT_MODE_CHANGE;
  1279. else
  1280. prompt_mode_type = PROMPT_HUNK;
  1281. color_fprintf(stdout, s->s.prompt_color,
  1282. "(%"PRIuMAX"/%"PRIuMAX") ",
  1283. (uintmax_t)hunk_index + 1,
  1284. (uintmax_t)(file_diff->hunk_nr
  1285. ? file_diff->hunk_nr
  1286. : 1));
  1287. color_fprintf(stdout, s->s.prompt_color,
  1288. _(s->mode->prompt_mode[prompt_mode_type]),
  1289. s->buf.buf);
  1290. fflush(stdout);
  1291. if (read_single_character(s) == EOF)
  1292. break;
  1293. if (!s->answer.len)
  1294. continue;
  1295. ch = tolower(s->answer.buf[0]);
  1296. if (ch == 'y') {
  1297. hunk->use = USE_HUNK;
  1298. soft_increment:
  1299. hunk_index = undecided_next < 0 ?
  1300. file_diff->hunk_nr : undecided_next;
  1301. } else if (ch == 'n') {
  1302. hunk->use = SKIP_HUNK;
  1303. goto soft_increment;
  1304. } else if (ch == 'a') {
  1305. if (file_diff->hunk_nr) {
  1306. for (; hunk_index < file_diff->hunk_nr; hunk_index++) {
  1307. hunk = file_diff->hunk + hunk_index;
  1308. if (hunk->use == UNDECIDED_HUNK)
  1309. hunk->use = USE_HUNK;
  1310. }
  1311. } else if (hunk->use == UNDECIDED_HUNK) {
  1312. hunk->use = USE_HUNK;
  1313. }
  1314. } else if (ch == 'd' || ch == 'q') {
  1315. if (file_diff->hunk_nr) {
  1316. for (; hunk_index < file_diff->hunk_nr; hunk_index++) {
  1317. hunk = file_diff->hunk + hunk_index;
  1318. if (hunk->use == UNDECIDED_HUNK)
  1319. hunk->use = SKIP_HUNK;
  1320. }
  1321. } else if (hunk->use == UNDECIDED_HUNK) {
  1322. hunk->use = SKIP_HUNK;
  1323. }
  1324. if (ch == 'q') {
  1325. quit = 1;
  1326. break;
  1327. }
  1328. } else if (s->answer.buf[0] == 'K') {
  1329. if (permitted & ALLOW_GOTO_PREVIOUS_HUNK)
  1330. hunk_index--;
  1331. else
  1332. err(s, _("No previous hunk"));
  1333. } else if (s->answer.buf[0] == 'J') {
  1334. if (permitted & ALLOW_GOTO_NEXT_HUNK)
  1335. hunk_index++;
  1336. else
  1337. err(s, _("No next hunk"));
  1338. } else if (s->answer.buf[0] == 'k') {
  1339. if (permitted & ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK)
  1340. hunk_index = undecided_previous;
  1341. else
  1342. err(s, _("No previous hunk"));
  1343. } else if (s->answer.buf[0] == 'j') {
  1344. if (permitted & ALLOW_GOTO_NEXT_UNDECIDED_HUNK)
  1345. hunk_index = undecided_next;
  1346. else
  1347. err(s, _("No next hunk"));
  1348. } else if (s->answer.buf[0] == 'g') {
  1349. char *pend;
  1350. unsigned long response;
  1351. if (!(permitted & ALLOW_SEARCH_AND_GOTO)) {
  1352. err(s, _("No other hunks to goto"));
  1353. continue;
  1354. }
  1355. strbuf_remove(&s->answer, 0, 1);
  1356. strbuf_trim(&s->answer);
  1357. i = hunk_index - DISPLAY_HUNKS_LINES / 2;
  1358. if (i < file_diff->mode_change)
  1359. i = file_diff->mode_change;
  1360. while (s->answer.len == 0) {
  1361. i = display_hunks(s, file_diff, i);
  1362. printf("%s", i < file_diff->hunk_nr ?
  1363. _("go to which hunk (<ret> to see "
  1364. "more)? ") : _("go to which hunk? "));
  1365. fflush(stdout);
  1366. if (strbuf_getline(&s->answer,
  1367. stdin) == EOF)
  1368. break;
  1369. strbuf_trim_trailing_newline(&s->answer);
  1370. }
  1371. strbuf_trim(&s->answer);
  1372. response = strtoul(s->answer.buf, &pend, 10);
  1373. if (*pend || pend == s->answer.buf)
  1374. err(s, _("Invalid number: '%s'"),
  1375. s->answer.buf);
  1376. else if (0 < response && response <= file_diff->hunk_nr)
  1377. hunk_index = response - 1;
  1378. else
  1379. err(s, Q_("Sorry, only %d hunk available.",
  1380. "Sorry, only %d hunks available.",
  1381. file_diff->hunk_nr),
  1382. (int)file_diff->hunk_nr);
  1383. } else if (s->answer.buf[0] == '/') {
  1384. regex_t regex;
  1385. int ret;
  1386. if (!(permitted & ALLOW_SEARCH_AND_GOTO)) {
  1387. err(s, _("No other hunks to search"));
  1388. continue;
  1389. }
  1390. strbuf_remove(&s->answer, 0, 1);
  1391. strbuf_trim_trailing_newline(&s->answer);
  1392. if (s->answer.len == 0) {
  1393. printf("%s", _("search for regex? "));
  1394. fflush(stdout);
  1395. if (strbuf_getline(&s->answer,
  1396. stdin) == EOF)
  1397. break;
  1398. strbuf_trim_trailing_newline(&s->answer);
  1399. if (s->answer.len == 0)
  1400. continue;
  1401. }
  1402. ret = regcomp(&regex, s->answer.buf,
  1403. REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
  1404. if (ret) {
  1405. char errbuf[1024];
  1406. regerror(ret, &regex, errbuf, sizeof(errbuf));
  1407. err(s, _("Malformed search regexp %s: %s"),
  1408. s->answer.buf, errbuf);
  1409. continue;
  1410. }
  1411. i = hunk_index;
  1412. for (;;) {
  1413. /* render the hunk into a scratch buffer */
  1414. render_hunk(s, file_diff->hunk + i, 0, 0,
  1415. &s->buf);
  1416. if (regexec(&regex, s->buf.buf, 0, NULL, 0)
  1417. != REG_NOMATCH)
  1418. break;
  1419. i++;
  1420. if (i == file_diff->hunk_nr)
  1421. i = 0;
  1422. if (i != hunk_index)
  1423. continue;
  1424. err(s, _("No hunk matches the given pattern"));
  1425. break;
  1426. }
  1427. hunk_index = i;
  1428. } else if (s->answer.buf[0] == 's') {
  1429. size_t splittable_into = hunk->splittable_into;
  1430. if (!(permitted & ALLOW_SPLIT))
  1431. err(s, _("Sorry, cannot split this hunk"));
  1432. else if (!split_hunk(s, file_diff,
  1433. hunk - file_diff->hunk))
  1434. color_fprintf_ln(stdout, s->s.header_color,
  1435. _("Split into %d hunks."),
  1436. (int)splittable_into);
  1437. } else if (s->answer.buf[0] == 'e') {
  1438. if (!(permitted & ALLOW_EDIT))
  1439. err(s, _("Sorry, cannot edit this hunk"));
  1440. else if (edit_hunk_loop(s, file_diff, hunk) >= 0) {
  1441. hunk->use = USE_HUNK;
  1442. goto soft_increment;
  1443. }
  1444. } else {
  1445. const char *p = _(help_patch_remainder), *eol = p;
  1446. color_fprintf(stdout, s->s.help_color, "%s",
  1447. _(s->mode->help_patch_text));
  1448. /*
  1449. * Show only those lines of the remainder that are
  1450. * actually applicable with the current hunk.
  1451. */
  1452. for (; *p; p = eol + (*eol == '\n')) {
  1453. eol = strchrnul(p, '\n');
  1454. /*
  1455. * `s->buf` still contains the part of the
  1456. * commands shown in the prompt that are not
  1457. * always available.
  1458. */
  1459. if (*p != '?' && !strchr(s->buf.buf, *p))
  1460. continue;
  1461. color_fprintf_ln(stdout, s->s.help_color,
  1462. "%.*s", (int)(eol - p), p);
  1463. }
  1464. }
  1465. }
  1466. /* Any hunk to be used? */
  1467. for (i = 0; i < file_diff->hunk_nr; i++)
  1468. if (file_diff->hunk[i].use == USE_HUNK)
  1469. break;
  1470. if (i < file_diff->hunk_nr ||
  1471. (!file_diff->hunk_nr && file_diff->head.use == USE_HUNK)) {
  1472. /* At least one hunk selected: apply */
  1473. strbuf_reset(&s->buf);
  1474. reassemble_patch(s, file_diff, 0, &s->buf);
  1475. discard_index(s->s.r->index);
  1476. if (s->mode->apply_for_checkout)
  1477. apply_for_checkout(s, &s->buf,
  1478. s->mode->is_reverse);
  1479. else {
  1480. setup_child_process(s, &cp, "apply", NULL);
  1481. strvec_pushv(&cp.args, s->mode->apply_args);
  1482. if (pipe_command(&cp, s->buf.buf, s->buf.len,
  1483. NULL, 0, NULL, 0))
  1484. error(_("'git apply' failed"));
  1485. }
  1486. if (repo_read_index(s->s.r) >= 0)
  1487. repo_refresh_and_write_index(s->s.r, REFRESH_QUIET, 0,
  1488. 1, NULL, NULL, NULL);
  1489. }
  1490. putchar('\n');
  1491. return quit;
  1492. }
  1493. int run_add_p(struct repository *r, enum add_p_mode mode,
  1494. const char *revision, const struct pathspec *ps)
  1495. {
  1496. struct add_p_state s = {
  1497. { r }, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
  1498. };
  1499. size_t i, binary_count = 0;
  1500. init_add_i_state(&s.s, r);
  1501. if (mode == ADD_P_STASH)
  1502. s.mode = &patch_mode_stash;
  1503. else if (mode == ADD_P_RESET) {
  1504. if (!revision || !strcmp(revision, "HEAD"))
  1505. s.mode = &patch_mode_reset_head;
  1506. else
  1507. s.mode = &patch_mode_reset_nothead;
  1508. } else if (mode == ADD_P_CHECKOUT) {
  1509. if (!revision)
  1510. s.mode = &patch_mode_checkout_index;
  1511. else if (!strcmp(revision, "HEAD"))
  1512. s.mode = &patch_mode_checkout_head;
  1513. else
  1514. s.mode = &patch_mode_checkout_nothead;
  1515. } else if (mode == ADD_P_WORKTREE) {
  1516. if (!revision)
  1517. s.mode = &patch_mode_checkout_index;
  1518. else if (!strcmp(revision, "HEAD"))
  1519. s.mode = &patch_mode_worktree_head;
  1520. else
  1521. s.mode = &patch_mode_worktree_nothead;
  1522. } else
  1523. s.mode = &patch_mode_add;
  1524. s.revision = revision;
  1525. if (discard_index(r->index) < 0 || repo_read_index(r) < 0 ||
  1526. (!s.mode->index_only &&
  1527. repo_refresh_and_write_index(r, REFRESH_QUIET, 0, 1,
  1528. NULL, NULL, NULL) < 0) ||
  1529. parse_diff(&s, ps) < 0) {
  1530. add_p_state_clear(&s);
  1531. return -1;
  1532. }
  1533. for (i = 0; i < s.file_diff_nr; i++)
  1534. if (s.file_diff[i].binary && !s.file_diff[i].hunk_nr)
  1535. binary_count++;
  1536. else if (patch_update_file(&s, s.file_diff + i))
  1537. break;
  1538. if (s.file_diff_nr == 0)
  1539. fprintf(stderr, _("No changes.\n"));
  1540. else if (binary_count == s.file_diff_nr)
  1541. fprintf(stderr, _("Only binary files changed.\n"));
  1542. add_p_state_clear(&s);
  1543. return 0;
  1544. }