AmendHub

Download

jcs

/

amend

/

committer.c

 

(View History)

jcs   committer+editor: Update log scrollbar after cut or paste Latest amendment: 114 on 2023-04-17

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;
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 (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_DIFF_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 TextStyle style;
429
430 SetCursor(*(GetCursor(watchCursor)));
431
432 nselected_files = browser_selected_file_ids(committer->browser,
433 &selected_files);
434
435 /* default to unified diffs (should this be a setting?) */
436 diff_format = D_UNIFIED;
437 diff_context = 3;
438
439 committer->diff_adds = 0;
440 committer->diff_subs = 0;
441 committer->ndiffed_files = 0;
442 committer->allow_commit = false;
443 committer->diffed_files = xcalloc(sizeof(struct diffed_file),
444 nselected_files, "committer diffed_files");
445 committer->diff_too_big = false;
446
447 HLock(committer->diff_te);
448
449 style.tsFont = monaco;
450 style.tsSize = 9;
451 TESetStyle(doFont | doSize, &style, false, committer->diff_te);
452
453 all_files = browser_is_all_files_selected(committer->browser);
454
455 committer_diffing = committer;
456
457 for (i = 0; i < nselected_files; i++) {
458 file = repo_file_with_id(committer->browser->repo,
459 selected_files[i]);
460 if (file == NULL)
461 err(1, "Failed to find file in repo with id %d",
462 selected_files[i]);
463
464 if (all_files && !repo_file_changed(committer->browser->repo,
465 file)) {
466 progress("Skipping unchanged %s...", file->filename);
467 continue;
468 }
469
470 committer->diffed_files[committer->ndiffed_files].file = file;
471 committer->diffed_files[committer->ndiffed_files].flags =
472 DIFFED_FILE_METADATA;
473
474 progress("Diffing %s...", file->filename);
475 if (repo_diff_file(committer->browser->repo, file)) {
476 committer->diffed_files[committer->ndiffed_files].flags |=
477 DIFFED_FILE_TEXT;
478 committer->allow_commit = true;
479 }
480
481 diff_finish();
482 committer->ndiffed_files++;
483 }
484
485 committer_diffing = NULL;
486
487 HUnlock(committer->diff_te);
488 InvalRect(&committer->win->portRect);
489 UpdateScrollbarForTE(committer->win, committer->diff_scroller,
490 committer->diff_te, true);
491
492 progress(NULL);
493
494 done_diffing:
495 if (selected_files != NULL)
496 xfree(&selected_files);
497 SetCursor(&arrow);
498
499 if (!committer->allow_commit) {
500 warnx("No changes detected");
501 browser_close_committer(committer->browser);
502 }
503 }
504
505 void
506 committer_commit(struct committer *committer)
507 {
508 struct browser *browser;
509 short loglen;
510
511 HLock(committer->log_te);
512 HLock(committer->diff_te);
513
514 loglen = (*(committer->log_te))->teLength;
515
516 SetCursor(*(GetCursor(watchCursor)));
517
518 progress("Committing changes...");
519
520 repo_amend(committer->browser->repo, committer->diffed_files,
521 committer->ndiffed_files, committer->diff_adds, committer->diff_subs,
522 settings.author, (*(committer->log_te))->hText, loglen,
523 (*(committer->diff_te))->hText, committer->diff_te_len);
524
525 HUnlock(committer->diff_te);
526 HUnlock(committer->log_te);
527
528 progress(NULL);
529 SetCursor(&arrow);
530
531 browser = committer->browser;
532 browser_close_committer(committer->browser);
533 browser->state = BROWSER_STATE_UPDATE_AMENDMENT_LIST;
534 }
535
536 bool
537 committer_handle_menu(struct focusable *focusable, short menu, short item)
538 {
539 struct committer *committer = (struct committer *)focusable->cookie;
540
541 switch (menu) {
542 case EDIT_MENU_ID:
543 switch (item) {
544 case EDIT_MENU_CUT_ID:
545 if (committer->last_te == committer->log_te) {
546 TECut(committer->log_te);
547 UpdateScrollbarForTE(committer->win,
548 committer->log_scroller, committer->log_te, false);
549 committer_update_menu(committer);
550 }
551 return true;
552 case EDIT_MENU_COPY_ID:
553 if (committer->last_te)
554 TECopy(committer->last_te);
555 committer_update_menu(committer);
556 return true;
557 case EDIT_MENU_PASTE_ID:
558 if (committer->last_te == committer->log_te) {
559 TEPaste(committer->log_te);
560 UpdateScrollbarForTE(committer->win,
561 committer->log_scroller, committer->log_te, false);
562 committer_update_menu(committer);
563 }
564 return true;
565 case EDIT_MENU_SELECT_ALL_ID:
566 if (committer->last_te)
567 TESetSelect(0, 1024 * 32, committer->last_te);
568 committer_update_menu(committer);
569 return true;
570 }
571 break;
572 }
573
574 return false;
575 }
576
577 size_t
578 diff_output(const char *format, ...)
579 {
580 va_list argptr;
581 size_t len, last_pos, last_line, i;
582
583 if (committer_diffing == NULL)
584 panic("diff_output without committer_diffing");
585
586 if (committer_diffing->diff_line == NULL) {
587 committer_diffing->diff_line = xNewHandle(DIFF_LINE_SIZE);
588 committer_diffing->diff_line_pos = 0;
589 HLock(committer_diffing->diff_line);
590 }
591
592 last_pos = committer_diffing->diff_line_pos;
593 last_line = 0;
594
595 va_start(argptr, format);
596
597 if (format[0] == '%' && format[1] == 'c' && format[2] == '\0') {
598 /* avoid having to vsprintf just to append 1 character */
599 (*(committer_diffing->diff_line))[last_pos] = va_arg(argptr, int);
600 len = 1;
601 } else
602 len = vsprintf(*(committer_diffing->diff_line) + last_pos, format,
603 argptr);
604
605 va_end(argptr);
606
607 committer_diffing->diff_line_pos += len;
608 if (committer_diffing->diff_line_pos >= DIFF_LINE_SIZE)
609 err(1, "diff line overflow!");
610
611 if (len == 1 && (*(committer_diffing->diff_line))[last_pos] != '\r')
612 return 1;
613
614 for (i = last_pos; i < committer_diffing->diff_line_pos; i++) {
615 if (((char *)*(committer_diffing->diff_line))[i] == '\r') {
616 diff_append_line(*(committer_diffing->diff_line) + last_line,
617 i - last_line + 1, false);
618 last_line = i + 1;
619 }
620 }
621
622 if (last_line == committer_diffing->diff_line_pos) {
623 committer_diffing->diff_line_pos = 0;
624 } else if (last_line > 0) {
625 memmove(*(committer_diffing->diff_line),
626 *(committer_diffing->diff_line) + last_line,
627 committer_diffing->diff_line_pos - last_line);
628 committer_diffing->diff_line_pos -= last_line;
629 }
630
631 return len;
632 }
633
634 void
635 diff_append_line(char *str, size_t len, bool flush)
636 {
637 if (committer_diffing == NULL)
638 panic("diff_append_line without committer_diffing");
639
640 if (committer_diffing->diff_chunk == NULL) {
641 committer_diffing->diff_chunk = xNewHandle(DIFF_CHUNK_SIZE);
642 committer_diffing->diff_chunk_pos = 0;
643 }
644
645 if (str[0] == '-' && str[1] != '-')
646 committer_diffing->diff_subs++;
647 else if (str[0] == '+' && str[1] != '+')
648 committer_diffing->diff_adds++;
649
650 if (committer_diffing->diff_chunk_pos + len >= DIFF_CHUNK_SIZE)
651 diff_chunk_write();
652
653 HLock(committer_diffing->diff_chunk);
654 memcpy(*(committer_diffing->diff_chunk) +
655 committer_diffing->diff_chunk_pos, str, len);
656 HUnlock(committer_diffing->diff_chunk);
657 committer_diffing->diff_chunk_pos += len;
658
659 if (flush)
660 diff_chunk_write();
661 }
662
663 void
664 diff_chunk_write(void)
665 {
666 if (committer_diffing == NULL)
667 panic("diff_chunk_write without committer_diffing");
668
669 HLock(committer_diffing->diff_chunk);
670
671 if (committer_diffing->diff_te_len +
672 committer_diffing->diff_chunk_pos > MAX_TEXTEDIT_SIZE) {
673 HUnlock((*(committer_diffing->diff_te))->hText);
674 SetHandleSize((*(committer_diffing->diff_te))->hText,
675 committer_diffing->diff_te_len +
676 committer_diffing->diff_chunk_pos);
677 if (MemError())
678 err(1, "Out of memory! Can't expand diff TE by %lu bytes.",
679 committer_diffing->diff_chunk_pos);
680 HLock((*(committer_diffing->diff_te))->hText);
681 memcpy(*(*(committer_diffing->diff_te))->hText +
682 committer_diffing->diff_te_len, *(committer_diffing->diff_chunk),
683 committer_diffing->diff_chunk_pos);
684 HUnlock((*(committer_diffing->diff_te))->hText);
685 } else {
686 TEStylInsert(*(committer_diffing->diff_chunk),
687 committer_diffing->diff_chunk_pos, 0,
688 committer_diffing->diff_te);
689 }
690 HUnlock(committer_diffing->diff_chunk);
691
692 committer_diffing->diff_te_len += committer_diffing->diff_chunk_pos;
693 committer_diffing->diff_chunk_pos = 0;
694 }
695
696 void
697 diff_finish(void)
698 {
699 if (committer_diffing == NULL)
700 panic("diff_finish without committer_diffing");
701
702 if (committer_diffing->diff_line != NULL) {
703 if (committer_diffing->diff_line_pos)
704 diff_append_line(*(committer_diffing->diff_line),
705 committer_diffing->diff_line_pos, true);
706
707 DisposHandle(committer_diffing->diff_line);
708 committer_diffing->diff_line = NULL;
709 }
710
711 if (committer_diffing->diff_chunk != NULL) {
712 if (committer_diffing->diff_chunk_pos)
713 diff_chunk_write();
714 DisposHandle(committer_diffing->diff_chunk);
715 committer_diffing->diff_chunk = NULL;
716 }
717
718 HUnlock((*(committer_diffing->diff_te))->hText);
719 SetHandleSize((*(committer_diffing->diff_te))->hText,
720 committer_diffing->diff_te_len);
721 TECalText(committer_diffing->diff_te);
722 }