AmendHub

Download

jcs

/

amend

/

committer.c

 

(View History)

jcs   committer: Add Command+W shortcut to cancel commit Latest amendment: 103 on 2022-09-12

1 /*
2 * Copyright (c) 2021 joshua stein <jcs@jcs.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <stdarg.h>
18 #include <stdio.h>
19 #include <string.h>
20
21 #include "amend.h"
22 #include "browser.h"
23 #include "committer.h"
24 #include "diff.h"
25 #include "focusable.h"
26 #include "repo.h"
27 #include "settings.h"
28 #include "tetab.h"
29 #include "util.h"
30
31 #define LABEL_FONT geneva
32 #define LABEL_FONT_SIZE 10
33
34 #define PADDING 10
35
36 /* needed by diffreg */
37 struct stat stb1, stb2;
38 long diff_format, diff_context, status = 0;
39 char *ifdefname, *diffargs, *label[2], *ignore_pats;
40
41 struct committer *committer_diffing = NULL;
42
43 bool committer_close(struct focusable *focusable);
44 void committer_idle(struct focusable *focusable, EventRecord *event);
45 void committer_update(struct focusable *focusable, EventRecord *event);
46 void committer_suspend(struct focusable *focusable);
47 void committer_resume(struct focusable *focusable);
48 void committer_key_down(struct focusable *focusable, EventRecord *event);
49 void committer_mouse_down(struct focusable *focusable, EventRecord *event);
50 bool committer_handle_menu(struct focusable *focusable, short menu,
51 short item);
52
53 void committer_generate_diff(struct committer *committer);
54 void committer_update_menu(struct committer *committer);
55 void committer_commit(struct committer *committer);
56 void diff_append_line(char *str, size_t len, bool flush);
57 void diff_chunk_write(void);
58 void diff_finish(void);
59
60 void
61 committer_init(struct browser *browser)
62 {
63 Str255 title, filename;
64 struct committer *committer;
65 struct focusable *focusable;
66 Rect bounds = { 0 }, te_bounds = { 0 };
67 TextStyle style;
68 short fh;
69
70 committer = xmalloczero(sizeof(struct committer), "committer_init");
71 committer->browser = browser;
72 browser->committer = committer;
73
74 /* main window, centered in its browser */
75 bounds = (*(((WindowPeek)browser->win)->strucRgn))->rgnBBox;
76 bounds.left += (PADDING / 2);
77 bounds.top += ((PADDING / 2) + MBarHeight);
78 bounds.right -= (PADDING / 2);
79 bounds.bottom -= (PADDING / 2);
80
81 memcpy(filename, browser->repo->bile->filename, sizeof(filename));
82 PtoCstr(filename);
83 snprintf((char *)&title, sizeof(title), "%s: %s: diff",
84 PROGRAM_NAME, (browser->repo ? (char *)filename : "No repo open"));
85
86 committer->win = NewWindow(0L, &bounds, CtoPstr(title), false,
87 noGrowDocProc, (WindowPtr)-1L, true, 0);
88 if (!committer)
89 err(1, "Can't create committer window");
90 SetPort(committer->win);
91
92 /* log message */
93 bounds.top = PADDING;
94 bounds.left = 50;
95 fh = FontHeight(monaco, 9);
96 bounds.bottom = bounds.top + (fh * 5) + 2;
97 bounds.right = committer->win->portRect.right - SCROLLBAR_WIDTH -
98 PADDING;
99 te_bounds = bounds;
100 InsetRect(&te_bounds, 2, 2);
101 TextFont(monaco);
102 TextSize(9);
103 committer->log_te = TEStylNew(&te_bounds, &bounds);
104 style.tsFont = monaco;
105 style.tsSize = 9;
106 TESetStyle(doFont | doSize, &style, false, committer->log_te);
107 TEAutoView(true, committer->log_te);
108 TETabEnable(committer->log_te);
109 TEActivate(committer->log_te);
110
111 /* scrollbar for log message */
112 bounds.left = bounds.right;
113 bounds.right += SCROLLBAR_WIDTH;
114 bounds.bottom++;
115 bounds.top--;
116 committer->log_scroller = NewControl(committer->win, &bounds, "\p",
117 true, 1, 1, 1, scrollBarProc, 0L);
118
119 /* diff */
120 bounds.top = bounds.bottom + PADDING;
121 bounds.left = PADDING;
122 bounds.bottom = committer->win->portRect.bottom - 20 - PADDING -
123 PADDING;
124 bounds.right = committer->win->portRect.right - SCROLLBAR_WIDTH -
125 PADDING;
126 te_bounds = bounds;
127 InsetRect(&te_bounds, 2, 2);
128 committer->diff_te = TEStylNew(&te_bounds, &bounds);
129 TEAutoView(true, committer->diff_te);
130 TETabEnable(committer->diff_te);
131 (*(committer->diff_te))->caretHook = NullCaretHook;
132 TEActivate(committer->diff_te);
133
134 /* scrollbar for diff */
135 bounds.left = bounds.right;
136 bounds.right += SCROLLBAR_WIDTH;
137 bounds.bottom++;
138 bounds.top--;
139 committer->diff_scroller = NewControl(committer->win, &bounds, "\p",
140 true, 1, 1, 1, scrollBarProc, 0L);
141
142 /* commit button */
143 bounds.left = committer->win->portRect.right - PADDING - 100;
144 bounds.right = bounds.left + 100;
145 bounds.bottom = committer->win->portRect.bottom - PADDING;
146 bounds.top = bounds.bottom - 20;
147 committer->commit_button = NewControl(committer->win, &bounds,
148 "\pCommit", true, 1, 1, 1, pushButProc, 0L);
149
150 committer->last_te = committer->log_te;
151
152 focusable = xmalloczero(sizeof(struct focusable), "committer focusable");
153 focusable->cookie = committer;
154 focusable->win = committer->win;
155 focusable->modal = true;
156 focusable->idle = committer_idle;
157 focusable->update = committer_update;
158 focusable->mouse_down = committer_mouse_down;
159 focusable->key_down = committer_key_down;
160 focusable->menu = committer_handle_menu;
161 focusable->close = committer_close;
162 focusable_add(focusable);
163
164 committer->state = COMMITTER_STATE_DO_DIFF;
165 }
166
167 bool
168 committer_close(struct focusable *focusable)
169 {
170 struct committer *committer = (struct committer *)focusable->cookie;
171
172 committer->browser->committer = NULL;
173
174 if (committer->diff_line != NULL) {
175 DisposHandle(committer->diff_line);
176 committer->diff_line = NULL;
177 }
178
179 if (committer->diffed_files != NULL)
180 xfree(&committer->diffed_files);
181
182 TEDispose(committer->log_te);
183 TEDispose(committer->diff_te);
184 DisposeWindow(committer->win);
185
186 xfree(&committer);
187
188 return true;
189 }
190
191 void
192 committer_idle(struct focusable *focusable, EventRecord *event)
193 {
194 struct committer *committer = (struct committer *)focusable->cookie;
195
196 switch (committer->state) {
197 case COMMITTER_STATE_IDLE:
198 if (committer->last_te == committer->log_te)
199 TEIdle(committer->log_te);
200 break;
201 case COMMITTER_STATE_DO_DIFF:
202 committer_generate_diff(committer);
203 committer->state = COMMITTER_STATE_IDLE;
204 break;
205 case COMMITTER_STATE_DO_COMMIT:
206 break;
207 }
208 }
209
210 void
211 committer_update(struct focusable *focusable, EventRecord *event)
212 {
213 Str255 buf;
214 Rect r;
215 short what = -1, len;
216 struct committer *committer = (struct committer *)focusable->cookie;
217
218 if (event != NULL)
219 what = event->what;
220
221 switch (what) {
222 case -1:
223 case updateEvt:
224 r = (*(committer->log_te))->viewRect;
225 MoveTo(r.top, r.top + FontHeight(LABEL_FONT, LABEL_FONT_SIZE) - 2);
226 TextFont(LABEL_FONT);
227 TextSize(LABEL_FONT_SIZE);
228 DrawText("Log:", 0, 4);
229
230 r = (*(committer->log_te))->viewRect;
231 TEUpdate(&r, committer->log_te);
232 InsetRect(&r, -1, -1);
233 FrameRect(&r);
234
235 r = (*(committer->diff_te))->viewRect;
236 TEUpdate(&r, committer->diff_te);
237 InsetRect(&r, -1, -1);
238 FrameRect(&r);
239
240 if ((*(committer->diff_te))->nLines > 0) {
241 r = (*(committer->diff_te))->viewRect;
242 MoveTo(r.left, r.bottom + FontHeight(monaco, 9) + PADDING);
243 TextFont(monaco);
244 TextSize(9);
245 len = snprintf((char *)buf, sizeof(buf), "%d (+), %d (-)",
246 committer->diff_adds, committer->diff_subs);
247 DrawText(buf, 0, len);
248 }
249
250 committer_update_menu(committer);
251 UpdtControl(committer->win, committer->win->visRgn);
252
253 break;
254 case activateEvt:
255 if (event->modifiers & activeFlag) {
256 TEActivate(committer->log_te);
257 TEActivate(committer->diff_te);
258 } else {
259 TEDeactivate(committer->log_te);
260 TEDeactivate(committer->diff_te);
261 }
262 break;
263 }
264 }
265
266 void
267 committer_suspend(struct focusable *focusable)
268 {
269 struct committer *committer = (struct committer *)focusable->cookie;
270
271 TEDeactivate(committer->log_te);
272 TEDeactivate(committer->diff_te);
273 }
274
275 void
276 committer_resume(struct focusable *focusable)
277 {
278 struct committer *committer = (struct committer *)focusable->cookie;
279
280 TEActivate(committer->log_te);
281 TEActivate(committer->diff_te);
282 }
283
284 void
285 committer_key_down(struct focusable *focusable, EventRecord *event)
286 {
287 struct committer *committer = (struct committer *)focusable->cookie;
288 char k;
289
290 k = event->message & charCodeMask;
291 if ((event->modifiers & cmdKey) != 0) {
292 if (k == 'w')
293 focusable_close(focusable);
294 return;
295 }
296
297 TEKey(k, committer->log_te);
298 UpdateScrollbarForTE(committer->win, committer->log_scroller,
299 committer->log_te, false);
300 committer_update_menu(committer);
301 }
302
303 void
304 committer_mouse_down(struct focusable *focusable, EventRecord *event)
305 {
306 struct committer *committer = (struct committer *)focusable->cookie;
307 Point p;
308 ControlHandle control;
309 Rect r;
310 short val, adj, page, was_selected, part, i;
311
312 p = event->where;
313 GlobalToLocal(&p);
314
315 r = (*(committer->diff_te))->viewRect;
316 if (PtInRect(p, &r)) {
317 TEClick(p, ((event->modifiers & shiftKey) != 0),
318 committer->diff_te);
319 committer->last_te = committer->diff_te;
320 committer_update_menu(committer);
321 return;
322 }
323
324 r = (*(committer->log_te))->viewRect;
325 if (PtInRect(p, &r)) {
326 TEClick(p, ((event->modifiers & shiftKey) != 0), committer->log_te);
327 committer->last_te = committer->log_te;
328 committer_update_menu(committer);
329 return;
330 }
331
332 switch (part = FindControl(p, committer->win, &control)) {
333 case inButton:
334 if (TrackControl(control, p, 0L) &&
335 control == committer->commit_button)
336 committer_commit(committer);
337 break;
338 case inUpButton:
339 case inDownButton:
340 case inPageUp:
341 case inPageDown:
342 if (control == committer->diff_scroller)
343 SetTrackControlTE(committer->diff_te);
344 else if (control == committer->log_scroller)
345 SetTrackControlTE(committer->log_te);
346 else
347 break;
348 TrackControl(control, p, TrackMouseDownInControl);
349 break;
350 case inThumb:
351 val = GetCtlValue(control);
352 if (TrackControl(control, p, 0L) == 0)
353 break;
354 adj = val - GetCtlValue(control);
355 if (adj != 0) {
356 val -= adj;
357 if (control == committer->diff_scroller)
358 TEScroll(0, adj * TEGetHeight(0, 0, committer->diff_te),
359 committer->diff_te);
360 else if (control == committer->log_scroller)
361 TEScroll(0, adj * TEGetHeight(0, 0, committer->log_te),
362 committer->log_te);
363 SetCtlValue(control, val);
364 }
365 break;
366 }
367 }
368
369 void
370 committer_update_menu(struct committer *committer)
371 {
372 HLock(committer->diff_te);
373 HLock(committer->log_te);
374
375 if (committer->last_te == committer->diff_te) {
376 DisableItem(edit_menu, EDIT_MENU_CUT_ID);
377 if ((*(committer->diff_te))->selStart ==
378 (*(committer->diff_te))->selEnd)
379 DisableItem(edit_menu, EDIT_MENU_COPY_ID);
380 else
381 EnableItem(edit_menu, EDIT_MENU_COPY_ID);
382 if ((*(committer->diff_te))->nLines > 0)
383 EnableItem(edit_menu, EDIT_MENU_SELECT_ALL_ID);
384 else
385 DisableItem(edit_menu, EDIT_MENU_SELECT_ALL_ID);
386 DisableItem(edit_menu, EDIT_MENU_PASTE_ID);
387 } else if (committer->last_te == committer->log_te) {
388 if ((*(committer->log_te))->selStart ==
389 (*(committer->log_te))->selEnd) {
390 DisableItem(edit_menu, EDIT_MENU_CUT_ID);
391 DisableItem(edit_menu, EDIT_MENU_COPY_ID);
392 } else {
393 EnableItem(edit_menu, EDIT_MENU_CUT_ID);
394 EnableItem(edit_menu, EDIT_MENU_COPY_ID);
395 }
396 if ((*(committer->log_te))->nLines > 0)
397 EnableItem(edit_menu, EDIT_MENU_SELECT_ALL_ID);
398 else
399 DisableItem(edit_menu, EDIT_MENU_SELECT_ALL_ID);
400 EnableItem(edit_menu, EDIT_MENU_PASTE_ID);
401 }
402
403 DisableItem(repo_menu, REPO_MENU_ADD_FILE_ID);
404 DisableItem(repo_menu, REPO_MENU_DISCARD_CHANGES_ID);
405 DisableItem(repo_menu, REPO_MENU_APPLY_PATCH_ID);
406
407 DisableItem(amendment_menu, AMENDMENT_MENU_EDIT_ID);
408 DisableItem(amendment_menu, AMENDMENT_MENU_EXPORT_ID);
409
410 HUnlock(committer->log_te);
411 HUnlock(committer->diff_te);
412
413 EnableItem(repo_menu, 0);
414
415 if ((*(committer->log_te))->nLines > 0 && committer->allow_commit)
416 HiliteControl(committer->commit_button, 0);
417 else
418 HiliteControl(committer->commit_button, 255);
419 }
420
421 void
422 committer_generate_diff(struct committer *committer)
423 {
424 struct repo_file *file;
425 short i, all_files;
426 short *selected_files = NULL;
427 short nselected_files = 0;
428 short diff_text = 0;
429 TextStyle style;
430
431 SetCursor(*(GetCursor(watchCursor)));
432
433 nselected_files = browser_selected_file_ids(committer->browser,
434 &selected_files);
435
436 /* default to unified diffs (should this be a setting?) */
437 diff_format = D_UNIFIED;
438 diff_context = 3;
439
440 committer->diff_adds = 0;
441 committer->diff_subs = 0;
442 committer->ndiffed_files = 0;
443 committer->allow_commit = false;
444 committer->diffed_files = xcalloc(sizeof(struct diffed_file),
445 nselected_files, "committer diffed_files");
446 committer->diff_too_big = false;
447
448 HLock(committer->diff_te);
449
450 style.tsFont = monaco;
451 style.tsSize = 9;
452 TESetStyle(doFont | doSize, &style, false, committer->diff_te);
453
454 all_files = browser_is_all_files_selected(committer->browser);
455
456 committer_diffing = committer;
457
458 for (i = 0; i < nselected_files; i++) {
459 file = repo_file_with_id(committer->browser->repo,
460 selected_files[i]);
461 if (file == NULL)
462 err(1, "Failed to find file in repo with id %d",
463 selected_files[i]);
464
465 if (all_files && !repo_file_changed(committer->browser->repo,
466 file)) {
467 progress("Skipping unchanged %s...", file->filename);
468 continue;
469 }
470
471 committer->diffed_files[committer->ndiffed_files].file = file;
472 committer->diffed_files[committer->ndiffed_files].flags =
473 DIFFED_FILE_METADATA;
474
475 progress("Diffing %s...", file->filename);
476 if (repo_diff_file(committer->browser->repo, file)) {
477 committer->diffed_files[committer->ndiffed_files].flags |=
478 DIFFED_FILE_TEXT;
479 committer->allow_commit = true;
480 }
481
482 diff_finish();
483 committer->ndiffed_files++;
484 }
485
486 committer_diffing = NULL;
487
488 HUnlock(committer->diff_te);
489 InvalRect(&committer->win->portRect);
490 UpdateScrollbarForTE(committer->win, committer->diff_scroller,
491 committer->diff_te, true);
492
493 progress(NULL);
494
495 done_diffing:
496 if (selected_files != NULL)
497 xfree(&selected_files);
498 SetCursor(&arrow);
499
500 if (!committer->allow_commit) {
501 warnx("No changes detected");
502 browser_close_committer(committer->browser);
503 }
504 }
505
506 void
507 committer_commit(struct committer *committer)
508 {
509 struct browser *browser;
510 short loglen;
511
512 HLock(committer->log_te);
513 HLock(committer->diff_te);
514
515 loglen = (*(committer->log_te))->teLength;
516
517 SetCursor(*(GetCursor(watchCursor)));
518
519 progress("Committing changes...");
520
521 repo_amend(committer->browser->repo, committer->diffed_files,
522 committer->ndiffed_files, committer->diff_adds, committer->diff_subs,
523 settings.author, (*(committer->log_te))->hText, loglen,
524 (*(committer->diff_te))->hText, committer->diff_te_len);
525
526 HUnlock(committer->diff_te);
527 HUnlock(committer->log_te);
528
529 progress(NULL);
530 SetCursor(&arrow);
531
532 browser = committer->browser;
533 browser_close_committer(committer->browser);
534 browser->state = BROWSER_STATE_UPDATE_AMENDMENT_LIST;
535 }
536
537 bool
538 committer_handle_menu(struct focusable *focusable, short menu, short item)
539 {
540 struct committer *committer = (struct committer *)focusable->cookie;
541
542 switch (menu) {
543 case EDIT_MENU_ID:
544 switch (item) {
545 case EDIT_MENU_CUT_ID:
546 if (committer->last_te == committer->log_te) {
547 TECut(committer->log_te);
548 committer_update_menu(committer);
549 }
550 return true;
551 case EDIT_MENU_COPY_ID:
552 if (committer->last_te)
553 TECopy(committer->last_te);
554 committer_update_menu(committer);
555 return true;
556 case EDIT_MENU_PASTE_ID:
557 if (committer->last_te == committer->log_te) {
558 TEPaste(committer->log_te);
559 committer_update_menu(committer);
560 }
561 return true;
562 case EDIT_MENU_SELECT_ALL_ID:
563 if (committer->last_te)
564 TESetSelect(0, 1024 * 32, committer->last_te);
565 committer_update_menu(committer);
566 return true;
567 }
568 break;
569 }
570
571 return false;
572 }
573
574 size_t
575 diff_output(const char *format, ...)
576 {
577 va_list argptr;
578 size_t len, last_pos, last_line, i;
579
580 if (committer_diffing == NULL)
581 panic("diff_output without committer_diffing");
582
583 if (committer_diffing->diff_line == NULL) {
584 committer_diffing->diff_line = xNewHandle(DIFF_LINE_SIZE);
585 committer_diffing->diff_line_pos = 0;
586 HLock(committer_diffing->diff_line);
587 }
588
589 last_pos = committer_diffing->diff_line_pos;
590 last_line = 0;
591
592 va_start(argptr, format);
593
594 if (format[0] == '%' && format[1] == 'c' && format[2] == '\0') {
595 /* avoid having to vsprintf just to append 1 character */
596 (*(committer_diffing->diff_line))[last_pos] = va_arg(argptr, int);
597 len = 1;
598 } else
599 len = vsprintf(*(committer_diffing->diff_line) + last_pos, format,
600 argptr);
601
602 va_end(argptr);
603
604 committer_diffing->diff_line_pos += len;
605 if (committer_diffing->diff_line_pos >= DIFF_LINE_SIZE)
606 err(1, "diff line overflow!");
607
608 if (len == 1 && (*(committer_diffing->diff_line))[last_pos] != '\r')
609 return 1;
610
611 for (i = last_pos; i < committer_diffing->diff_line_pos; i++) {
612 if (((char *)*(committer_diffing->diff_line))[i] == '\r') {
613 diff_append_line(*(committer_diffing->diff_line) + last_line,
614 i - last_line + 1, false);
615 last_line = i + 1;
616 }
617 }
618
619 if (last_line == committer_diffing->diff_line_pos) {
620 committer_diffing->diff_line_pos = 0;
621 } else if (last_line > 0) {
622 memmove(*(committer_diffing->diff_line),
623 *(committer_diffing->diff_line) + last_line,
624 committer_diffing->diff_line_pos - last_line);
625 committer_diffing->diff_line_pos -= last_line;
626 }
627
628 return len;
629 }
630
631 void
632 diff_append_line(char *str, size_t len, bool flush)
633 {
634 short tabsize;
635
636 if (committer_diffing == NULL)
637 panic("diff_append_line without committer_diffing");
638
639 if (committer_diffing->diff_chunk == NULL) {
640 committer_diffing->diff_chunk = xNewHandle(DIFF_CHUNK_SIZE);
641 committer_diffing->diff_chunk_pos = 0;
642 }
643
644 if (str[0] == '-' && str[1] != '-')
645 committer_diffing->diff_subs++;
646 else if (str[0] == '+' && str[1] != '+')
647 committer_diffing->diff_adds++;
648
649 if (committer_diffing->diff_chunk_pos + len >= DIFF_CHUNK_SIZE)
650 diff_chunk_write();
651
652 HLock(committer_diffing->diff_chunk);
653 memcpy(*(committer_diffing->diff_chunk) +
654 committer_diffing->diff_chunk_pos, str, len);
655 HUnlock(committer_diffing->diff_chunk);
656 committer_diffing->diff_chunk_pos += len;
657
658 if (flush)
659 diff_chunk_write();
660 }
661
662 void
663 diff_chunk_write(void)
664 {
665 if (committer_diffing == NULL)
666 panic("diff_chunk_write without committer_diffing");
667
668 HLock(committer_diffing->diff_chunk);
669
670 if (committer_diffing->diff_te_len +
671 committer_diffing->diff_chunk_pos > MAX_TEXTEDIT_SIZE) {
672 HUnlock((*(committer_diffing->diff_te))->hText);
673 SetHandleSize((*(committer_diffing->diff_te))->hText,
674 committer_diffing->diff_te_len +
675 committer_diffing->diff_chunk_pos);
676 if (MemError())
677 err(1, "Out of memory! Can't expand diff TE by %lu bytes.",
678 committer_diffing->diff_chunk_pos);
679 HLock((*(committer_diffing->diff_te))->hText);
680 memcpy(*(*(committer_diffing->diff_te))->hText +
681 committer_diffing->diff_te_len, *(committer_diffing->diff_chunk),
682 committer_diffing->diff_chunk_pos);
683 HUnlock((*(committer_diffing->diff_te))->hText);
684 } else {
685 TEStylInsert(*(committer_diffing->diff_chunk),
686 committer_diffing->diff_chunk_pos, 0,
687 committer_diffing->diff_te);
688 }
689 HUnlock(committer_diffing->diff_chunk);
690
691 committer_diffing->diff_te_len += committer_diffing->diff_chunk_pos;
692 committer_diffing->diff_chunk_pos = 0;
693 }
694
695 void
696 diff_finish(void)
697 {
698 if (committer_diffing == NULL)
699 panic("diff_finish without committer_diffing");
700
701 if (committer_diffing->diff_line != NULL) {
702 if (committer_diffing->diff_line_pos)
703 diff_append_line(*(committer_diffing->diff_line),
704 committer_diffing->diff_line_pos, true);
705
706 DisposHandle(committer_diffing->diff_line);
707 committer_diffing->diff_line = NULL;
708 }
709
710 if (committer_diffing->diff_chunk != NULL) {
711 if (committer_diffing->diff_chunk_pos)
712 diff_chunk_write();
713 DisposHandle(committer_diffing->diff_chunk);
714 committer_diffing->diff_chunk = NULL;
715 }
716
717 HUnlock((*(committer_diffing->diff_te))->hText);
718 SetHandleSize((*(committer_diffing->diff_te))->hText,
719 committer_diffing->diff_te_len);
720 TECalText(committer_diffing->diff_te);
721 }