AmendHub

Download

jcs

/

amend

/

committer.c

 

(View History)

jcs   committer: Clear browser's associated committer on close, SetPort too Latest amendment: 73 on 2022-06-15

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 "repo.h"
26 #include "settings.h"
27 #include "tetab.h"
28 #include "util.h"
29
30 /* needed by diffreg */
31 struct stat stb1, stb2;
32 long diff_format, diff_context, status = 0;
33 char *ifdefname, *diffargs, *label[2], *ignore_pats;
34
35 static short padding = 10;
36
37 static DialogPtr committer_dialog = NULL;
38
39 /* so diff_* know what they're operating on */
40 struct committer *cur_committer = NULL;
41
42 /* the last-accessed TE to do cut/copy/paste/select operations on */
43 static TEHandle committer_last_te = NULL;
44
45 void committer_generate_diff(struct committer *committer);
46 void committer_update_menu(struct committer *committer);
47 void committer_commit(struct committer *committer);
48 void diff_append_line(char *str, size_t len, bool flush);
49 void diff_chunk_write(void);
50 void diff_finish(void);
51
52 void
53 committer_init(struct browser *browser)
54 {
55 Str255 title, filename;
56 struct committer *committer;
57 Rect bounds = { 0 }, te_bounds = { 0 };
58 TextStyle style;
59 short fh;
60
61 committer = xmalloczero(sizeof(struct committer));
62 committer->browser = browser;
63 browser->committer = committer;
64
65 /* main window */
66 bounds.left = (padding / 2);
67 bounds.top = screenBits.bounds.top + (GetMBarHeight() * 2) - 1 +
68 (padding / 2);
69 bounds.right = screenBits.bounds.right - 1 - (padding / 2);
70 bounds.bottom = screenBits.bounds.bottom - 1 - (padding / 2);
71
72 memcpy(filename, browser->repo->bile->filename, sizeof(filename));
73 PtoCstr(filename);
74 snprintf((char *)&title, sizeof(title), "%s: %s: diff",
75 PROGRAM_NAME, (browser->repo ? (char *)filename : "No repo open"));
76
77 committer->win = NewWindow(0L, &bounds, CtoPstr(title), false,
78 noGrowDocProc, (WindowPtr)-1L, true, 0);
79 if (!committer)
80 err(1, "Can't create committer window");
81 SetPort(committer->win);
82
83 /* log message */
84 bounds.top = padding;
85 bounds.left = 50;
86 fh = FontHeight(monaco, 9);
87 bounds.bottom = bounds.top + (fh * 5) + 2;
88 bounds.right = committer->win->portRect.right - SCROLLBAR_WIDTH -
89 padding;
90 te_bounds = bounds;
91 InsetRect(&te_bounds, 2, 2);
92 TextFont(monaco);
93 TextSize(9);
94 committer->log_te = TEStylNew(&te_bounds, &bounds);
95 style.tsFont = monaco;
96 style.tsSize = 9;
97 TESetStyle(doFont | doSize, &style, false, committer->log_te);
98 TEAutoView(true, committer->log_te);
99 TETabEnable(committer->log_te);
100 TEActivate(committer->log_te);
101
102 /* scrollbar for log message */
103 bounds.left = bounds.right;
104 bounds.right += SCROLLBAR_WIDTH;
105 bounds.bottom++;
106 bounds.top--;
107 committer->log_scroller = NewControl(committer->win, &bounds, "\p",
108 true, 1, 1, 1, scrollBarProc, 0L);
109
110 /* diff */
111 bounds.top = bounds.bottom + padding;
112 bounds.left = padding;
113 bounds.bottom = committer->win->portRect.bottom - 20 - padding -
114 padding;
115 bounds.right = committer->win->portRect.right - SCROLLBAR_WIDTH -
116 padding;
117 te_bounds = bounds;
118 InsetRect(&te_bounds, 2, 2);
119 committer->diff_te = TEStylNew(&te_bounds, &bounds);
120 TEAutoView(true, committer->diff_te);
121 TETabEnable(committer->diff_te);
122 (*(committer->diff_te))->caretHook = NullCaretHook;
123 TEActivate(committer->diff_te);
124
125 /* scrollbar for diff */
126 bounds.left = bounds.right;
127 bounds.right += SCROLLBAR_WIDTH;
128 bounds.bottom++;
129 bounds.top--;
130 committer->diff_scroller = NewControl(committer->win, &bounds, "\p",
131 true, 1, 1, 1, scrollBarProc, 0L);
132
133 /* commit button */
134 TextFont(applFont);
135 TextSize(11);
136 bounds.left = committer->win->portRect.right - padding - 100;
137 bounds.right = bounds.left + 100;
138 bounds.bottom = committer->win->portRect.bottom - padding;
139 bounds.top = bounds.bottom - 20;
140 committer->commit_button = NewControl(committer->win, &bounds,
141 "\pCommit", true, 1, 1, 1, pushButProc, 0L);
142
143 ShowWindow(committer->win);
144 committer_last_te = committer->log_te;
145 committer_update(committer, NULL);
146 DrawMenuBar();
147 }
148
149 void
150 committer_close(struct committer *committer)
151 {
152 committer->browser->committer = NULL;
153
154 if (committer->diff_line != NULL) {
155 DisposHandle(committer->diff_line);
156 committer->diff_line = NULL;
157 }
158
159 if (committer->diffed_files != NULL)
160 free(committer->diffed_files);
161
162 TEDispose(committer->log_te);
163 TEDispose(committer->diff_te);
164 DisposeWindow(committer->win);
165 SetPort(committer->browser->win);
166
167 free(committer);
168
169 committer_last_te = NULL;
170 }
171
172 void
173 committer_idle(struct committer *committer)
174 {
175 if (committer_last_te == committer->log_te)
176 TEIdle(committer->log_te);
177 }
178
179 void
180 committer_update(struct committer *committer, EventRecord *event)
181 {
182 Str255 buf;
183 Rect r;
184 short what = -1, len;
185
186 if (event != NULL)
187 what = event->what;
188
189 switch (what) {
190 case -1:
191 case updateEvt:
192 r = (*(committer->log_te))->viewRect;
193 MoveTo(r.top, r.top + FontHeight(applFont, 11) - 2);
194 TextFont(applFont);
195 TextSize(11);
196 DrawText("Log:", 0, 4);
197
198 r = (*(committer->log_te))->viewRect;
199 TEUpdate(&r, committer->log_te);
200 InsetRect(&r, -1, -1);
201 FrameRect(&r);
202
203 r = (*(committer->diff_te))->viewRect;
204 TEUpdate(&r, committer->diff_te);
205 InsetRect(&r, -1, -1);
206 FrameRect(&r);
207
208 if ((*(committer->diff_te))->nLines > 0) {
209 r = (*(committer->diff_te))->viewRect;
210 MoveTo(r.left, r.bottom + FontHeight(applFont, 10) + padding);
211 len = snprintf((char *)buf, sizeof(buf), "%d (+), %d (-)",
212 committer->diff_adds, committer->diff_subs);
213 DrawText(buf, 0, len);
214 }
215
216 committer_update_menu(committer);
217 UpdtControl(committer->win, committer->win->visRgn);
218
219 break;
220 case activateEvt:
221 if (event->modifiers & activeFlag) {
222 TEActivate(committer->log_te);
223 TEActivate(committer->diff_te);
224 } else {
225 TEDeactivate(committer->log_te);
226 TEDeactivate(committer->diff_te);
227 }
228 break;
229 }
230 }
231
232 void
233 committer_suspend(struct committer *committer)
234 {
235 TEDeactivate(committer->log_te);
236 TEDeactivate(committer->diff_te);
237 }
238
239 void
240 committer_resume(struct committer *committer)
241 {
242 TEActivate(committer->log_te);
243 TEActivate(committer->diff_te);
244 }
245
246 void
247 committer_key_down(struct committer *committer, EventRecord *event)
248 {
249 char k;
250
251 k = (event->message & charCodeMask);
252 TEKey(k, committer->log_te);
253 UpdateScrollbarForTE(committer->log_scroller, committer->log_te,
254 false);
255 committer_update_menu(committer);
256 }
257
258 void
259 committer_mouse_down(struct committer *committer, EventRecord *event)
260 {
261 Point p;
262 ControlHandle control;
263 Rect r;
264 short val, adj, page, was_selected, part, i;
265
266 p = event->where;
267 GlobalToLocal(&p);
268
269 r = (*(committer->diff_te))->viewRect;
270 if (PtInRect(p, &r)) {
271 TEClick(p, ((event->modifiers & shiftKey) != 0),
272 committer->diff_te);
273 committer_last_te = committer->diff_te;
274 committer_update_menu(committer);
275 return;
276 }
277
278 r = (*(committer->log_te))->viewRect;
279 if (PtInRect(p, &r)) {
280 TEClick(p, ((event->modifiers & shiftKey) != 0),
281 committer->log_te);
282 committer_last_te = committer->log_te;
283 committer_update_menu(committer);
284 return;
285 }
286
287 switch (part = FindControl(p, committer->win, &control)) {
288 case inButton:
289 TextFont(applFont);
290 TextSize(11);
291 if (TrackControl(control, p, 0L) &&
292 control == committer->commit_button)
293 committer_commit(committer);
294 break;
295 case inUpButton:
296 case inDownButton:
297 case inPageUp:
298 case inPageDown:
299 if (control == committer->diff_scroller)
300 SetTrackControlTE(committer->diff_te);
301 else if (control == committer->log_scroller)
302 SetTrackControlTE(committer->log_te);
303 else
304 break;
305 TrackControl(control, p, TrackMouseDownInControl);
306 break;
307 case inThumb:
308 val = GetCtlValue(control);
309 if (TrackControl(control, p, 0L) == 0)
310 break;
311 adj = val - GetCtlValue(control);
312 if (adj != 0) {
313 val -= adj;
314 if (control == committer->diff_scroller)
315 TEScroll(0, adj * TEGetHeight(0, 0, committer->diff_te),
316 committer->diff_te);
317 else if (control == committer->log_scroller)
318 TEScroll(0, adj * TEGetHeight(0, 0, committer->log_te),
319 committer->log_te);
320 SetCtlValue(control, val);
321 }
322 break;
323 }
324 }
325
326 void
327 committer_update_menu(struct committer *committer)
328 {
329 HLock(committer->diff_te);
330 HLock(committer->log_te);
331
332 if (committer_last_te == committer->diff_te) {
333 DisableItem(edit_menu, EDIT_MENU_CUT_ID);
334 if ((*(committer->diff_te))->selStart ==
335 (*(committer->diff_te))->selEnd)
336 DisableItem(edit_menu, EDIT_MENU_COPY_ID);
337 else
338 EnableItem(edit_menu, EDIT_MENU_COPY_ID);
339 if ((*(committer->diff_te))->nLines > 0)
340 EnableItem(edit_menu, EDIT_MENU_SELECT_ALL_ID);
341 else
342 DisableItem(edit_menu, EDIT_MENU_SELECT_ALL_ID);
343 DisableItem(edit_menu, EDIT_MENU_PASTE_ID);
344 } else if (committer_last_te == committer->log_te) {
345 if ((*(committer->log_te))->selStart ==
346 (*(committer->log_te))->selEnd) {
347 DisableItem(edit_menu, EDIT_MENU_CUT_ID);
348 DisableItem(edit_menu, EDIT_MENU_COPY_ID);
349 } else {
350 EnableItem(edit_menu, EDIT_MENU_CUT_ID);
351 EnableItem(edit_menu, EDIT_MENU_COPY_ID);
352 }
353 if ((*(committer->log_te))->nLines > 0)
354 EnableItem(edit_menu, EDIT_MENU_SELECT_ALL_ID);
355 else
356 DisableItem(edit_menu, EDIT_MENU_SELECT_ALL_ID);
357 EnableItem(edit_menu, EDIT_MENU_PASTE_ID);
358 }
359
360 if ((*(committer->log_te))->nLines > 0 && committer->allow_commit)
361 HiliteControl(committer->commit_button, 0);
362 else
363 HiliteControl(committer->commit_button, 255);
364
365 DisableItem(repo_menu, REPO_MENU_ADD_FILE_ID);
366 DisableItem(repo_menu, REPO_MENU_REVERT_FILE_ID);
367 DisableItem(repo_menu, REPO_MENU_APPLY_PATCH_ID);
368
369 DisableItem(commit_menu, COMMIT_MENU_EXPORT_ID);
370
371 HUnlock(committer->log_te);
372 HUnlock(committer->diff_te);
373
374 EnableItem(repo_menu, 0);
375 }
376
377 void
378 committer_generate_diff(struct committer *committer)
379 {
380 struct repo_file *file;
381 short i, all_files;
382 short *selected_files = NULL;
383 short nselected_files = 0;
384 short diff_text = 0;
385 TextStyle style;
386
387 SetCursor(*(GetCursor(watchCursor)));
388
389 nselected_files = browser_selected_file_ids(committer->browser,
390 &selected_files);
391
392 /* default to unified diffs (should this be a setting?) */
393 diff_format = D_UNIFIED;
394 diff_context = 3;
395
396 committer->diff_adds = 0;
397 committer->diff_subs = 0;
398 committer->ndiffed_files = 0;
399 committer->allow_commit = 0;
400 committer->diffed_files = xmalloc(sizeof(struct diffed_file) *
401 nselected_files);
402
403 cur_committer = committer;
404 committer->diff_too_big = 0;
405
406 HLock(committer->diff_te);
407
408 style.tsFont = monaco;
409 style.tsSize = 9;
410 TESetStyle(doFont | doSize, &style, false, cur_committer->diff_te);
411
412 all_files = browser_is_all_files_selected(committer->browser);
413
414 for (i = 0; i < nselected_files; i++) {
415 file = repo_file_with_id(committer->browser->repo,
416 selected_files[i]);
417 if (file == NULL)
418 err(1, "Failed to find file in repo with id %d",
419 selected_files[i]);
420
421 if (all_files && !repo_file_changed(committer->browser->repo,
422 file)) {
423 progress("Skipping unchanged %s...", file->filename);
424 continue;
425 }
426
427 committer->diffed_files[committer->ndiffed_files].file = file;
428 committer->diffed_files[committer->ndiffed_files].flags =
429 DIFFED_FILE_METADATA;
430
431 progress("Diffing %s...", file->filename);
432 if (repo_diff_file(committer->browser->repo, file)) {
433 committer->diffed_files[committer->ndiffed_files].flags |=
434 DIFFED_FILE_TEXT;
435 committer->allow_commit = 1;
436 }
437
438 diff_finish();
439 committer->ndiffed_files++;
440 }
441
442 HUnlock(committer->diff_te);
443 InvalRect(&committer->win->portRect);
444 UpdateScrollbarForTE(committer->diff_scroller, committer->diff_te,
445 true);
446 cur_committer = NULL;
447
448 progress(NULL);
449
450 done_diffing:
451 if (selected_files != NULL)
452 free(selected_files);
453 SetCursor(&arrow);
454
455 if (committer->allow_commit == 0) {
456 warnx("No changes detected");
457 browser_close_committer(committer->browser);
458 }
459 }
460
461 void
462 committer_commit(struct committer *committer)
463 {
464 struct browser *browser;
465 short loglen;
466
467 HLock(committer->log_te);
468 HLock(committer->diff_te);
469
470 loglen = (*(committer->log_te))->teLength;
471
472 SetCursor(*(GetCursor(watchCursor)));
473
474 progress("Committing changes...");
475
476 repo_commit(committer->browser->repo, committer->diffed_files,
477 committer->ndiffed_files, committer->diff_adds, committer->diff_subs,
478 settings.author, (*(committer->log_te))->hText, loglen,
479 (*(committer->diff_te))->hText, committer->diff_te_len);
480
481 HUnlock(committer->diff_te);
482 HUnlock(committer->log_te);
483
484 progress(NULL);
485 SetCursor(&arrow);
486
487 browser = committer->browser;
488 browser_close_committer(committer->browser);
489 browser->state = BROWSER_STATE_UPDATE_COMMIT_LIST;
490 }
491
492 void
493 committer_handle_menu(struct committer *committer, long menu_id)
494 {
495 switch (HiWord(menu_id)) {
496 case EDIT_MENU_ID:
497 switch (LoWord(menu_id)) {
498 case EDIT_MENU_CUT_ID:
499 if (committer_last_te == committer->log_te) {
500 TECut(committer->log_te);
501 committer_update_menu(committer);
502 }
503 break;
504 case EDIT_MENU_COPY_ID:
505 TECopy(committer_last_te);
506 committer_update_menu(committer);
507 break;
508 case EDIT_MENU_PASTE_ID:
509 if (committer_last_te == committer->log_te) {
510 TEPaste(committer->log_te);
511 committer_update_menu(committer);
512 }
513 break;
514 case EDIT_MENU_SELECT_ALL_ID:
515 TESetSelect(0, 1024 * 32, committer_last_te);
516 committer_update_menu(committer);
517 break;
518 }
519 break;
520 }
521 }
522
523 size_t
524 diff_output(const char *format, ...)
525 {
526 va_list argptr;
527 size_t len, last_pos, last_line, i;
528
529 if (cur_committer->diff_line == NULL) {
530 cur_committer->diff_line = xNewHandle(DIFF_LINE_SIZE);
531 cur_committer->diff_line_pos = 0;
532 HLock(cur_committer->diff_line);
533 }
534
535 last_pos = cur_committer->diff_line_pos;
536 last_line = 0;
537
538 va_start(argptr, format);
539
540 if (format[0] == '%' && format[1] == 'c' && format[2] == '\0') {
541 /* avoid having to vsprintf just to append 1 character */
542 (*(cur_committer->diff_line))[last_pos] = va_arg(argptr, int);
543 len = 1;
544 } else
545 len = vsprintf(*(cur_committer->diff_line) + last_pos, format,
546 argptr);
547
548 va_end(argptr);
549
550 cur_committer->diff_line_pos += len;
551 if (cur_committer->diff_line_pos >= DIFF_LINE_SIZE)
552 err(1, "diff line overflow!");
553
554 if (len == 1 && (*(cur_committer->diff_line))[last_pos] != '\r')
555 return 1;
556
557 for (i = last_pos; i < cur_committer->diff_line_pos; i++) {
558 if (((char *)*(cur_committer->diff_line))[i] == '\r') {
559 diff_append_line(*(cur_committer->diff_line) + last_line,
560 i - last_line + 1, false);
561 last_line = i + 1;
562 }
563 }
564
565 if (last_line == cur_committer->diff_line_pos) {
566 cur_committer->diff_line_pos = 0;
567 } else if (last_line > 0) {
568 memmove(*(cur_committer->diff_line), *(cur_committer->diff_line) +
569 last_line, cur_committer->diff_line_pos - last_line);
570 cur_committer->diff_line_pos -= last_line;
571 }
572
573 return len;
574 }
575
576 void
577 diff_append_line(char *str, size_t len, bool flush)
578 {
579 short tabsize;
580
581 if (cur_committer->diff_chunk == NULL) {
582 cur_committer->diff_chunk = xNewHandle(DIFF_CHUNK_SIZE);
583 cur_committer->diff_chunk_pos = 0;
584 }
585
586 if (str[0] == '-' && str[1] != '-')
587 cur_committer->diff_subs++;
588 else if (str[0] == '+' && str[1] != '+')
589 cur_committer->diff_adds++;
590
591 if (cur_committer->diff_chunk_pos + len >= DIFF_CHUNK_SIZE)
592 diff_chunk_write();
593
594 HLock(cur_committer->diff_chunk);
595 memcpy(*(cur_committer->diff_chunk) + cur_committer->diff_chunk_pos,
596 str, len);
597 HUnlock(cur_committer->diff_chunk);
598 cur_committer->diff_chunk_pos += len;
599
600 if (flush)
601 diff_chunk_write();
602 }
603
604 void
605 diff_chunk_write(void)
606 {
607 HLock(cur_committer->diff_chunk);
608
609 if (cur_committer->diff_te_len + cur_committer->diff_chunk_pos >
610 MAX_TEXTEDIT_SIZE) {
611 HUnlock((*(cur_committer->diff_te))->hText);
612 SetHandleSize((*(cur_committer->diff_te))->hText,
613 cur_committer->diff_te_len + cur_committer->diff_chunk_pos);
614 if (MemError())
615 err(1, "Out of memory! Can't expand diff TE by %lu bytes.",
616 cur_committer->diff_chunk_pos);
617 HLock((*(cur_committer->diff_te))->hText);
618 memcpy(*(*(cur_committer->diff_te))->hText +
619 cur_committer->diff_te_len, *(cur_committer->diff_chunk),
620 cur_committer->diff_chunk_pos);
621 HUnlock((*(cur_committer->diff_te))->hText);
622 } else {
623 TEStylInsert(*(cur_committer->diff_chunk),
624 cur_committer->diff_chunk_pos, 0, cur_committer->diff_te);
625 }
626 HUnlock(cur_committer->diff_chunk);
627
628 cur_committer->diff_te_len += cur_committer->diff_chunk_pos;
629 cur_committer->diff_chunk_pos = 0;
630 }
631
632 void
633 diff_finish(void)
634 {
635 if (cur_committer->diff_line != NULL) {
636 if (cur_committer->diff_line_pos)
637 diff_append_line(*(cur_committer->diff_line),
638 cur_committer->diff_line_pos, true);
639
640 DisposHandle(cur_committer->diff_line);
641 cur_committer->diff_line = NULL;
642 }
643
644 if (cur_committer->diff_chunk != NULL) {
645 if (cur_committer->diff_chunk_pos)
646 diff_chunk_write();
647 DisposHandle(cur_committer->diff_chunk);
648 cur_committer->diff_chunk = NULL;
649 }
650
651 HUnlock((*(cur_committer->diff_te))->hText);
652 SetHandleSize((*(cur_committer->diff_te))->hText,
653 cur_committer->diff_te_len);
654 TECalText(cur_committer->diff_te);
655 }