AmendHub

jcs

/

amend

/

amendments

/

88

editor: Add amendment metadata editor

This allows changing an amendment's author, date/time, and log.
Also continue on changing commit to amendment.

jcs made amendment 88 about 1 month ago
--- amend.h Tue Aug 16 10:54:26 2022 +++ amend.h Tue Aug 16 16:38:21 2022 @@ -38,11 +38,11 @@ #define REPO_MENU_DISCARD_CHANGES_ID 2 #define REPO_MENU_APPLY_PATCH_ID 3 -#define COMMIT_MENU_ID 132 -#define COMMIT_MENU_EDIT_ID 1 -#define COMMIT_MENU_EXPORT_ID 2 +#define AMENDMENT_MENU_ID 132 +#define AMENDMENT_MENU_EDIT_ID 1 +#define AMENDMENT_MENU_EXPORT_ID 2 -#define COMMIT_LDEF_ID 128 +#define AMENDMENT_LDEF_ID 128 #define SETTINGS_DLOG_ID 130 #define SETTINGS_SAVE_ID 1 @@ -53,6 +53,6 @@ #define STR_AUTHOR_ID 128 #define STR_TABWIDTH_ID 129 -extern MenuHandle file_menu, edit_menu, repo_menu, commit_menu; +extern MenuHandle file_menu, edit_menu, repo_menu, amendment_menu; void menu_defaults(void); --- browser.c Tue Aug 16 14:34:48 2022 +++ browser.c Wed Aug 17 14:24:15 2022 @@ -22,6 +22,7 @@ #include "browser.h" #include "committer.h" #include "diff.h" +#include "editor.h" #include "focusable.h" #include "patch.h" #include "repo.h" @@ -33,16 +34,17 @@ bool browser_close(struct focusable *focusable); void browser_idle(struct focusable *focusable, EventRecord *event); void browser_update_menu(struct browser *browser); void browser_update(struct focusable *focusable, EventRecord *event); -void browser_show_commit(struct browser *browser, - struct repo_commit *commit); +void browser_show_amendment(struct browser *browser, + struct repo_amendment *amendment); void browser_key_down(struct focusable *focusable, EventRecord *event); void browser_mouse_down(struct focusable *focusable, EventRecord *event); bool browser_handle_menu(struct focusable *focusable, short menu, short item); void browser_add_files(struct browser *browser); -void browser_filter_commits(struct browser *browser); +void browser_filter_amendments(struct browser *browser); void browser_discard_changes(struct browser *browser); +void browser_edit_amendment(struct browser *browser); Pattern fill_pattern; @@ -53,6 +55,10 @@ browser_idle(struct focusable *focusable, EventRecord switch (browser->state) { case BROWSER_STATE_IDLE: + if (browser->need_refresh) { + browser->need_refresh = false; + browser->state = BROWSER_STATE_UPDATE_AMENDMENT_LIST; + } break; case BROWSER_STATE_ADD_FILE: if (repo_add_file(browser->repo) == NULL) @@ -64,8 +70,8 @@ browser_idle(struct focusable *focusable, EventRecord browser_add_files(browser); browser->state = BROWSER_STATE_IDLE; break; - case BROWSER_STATE_UPDATE_COMMIT_LIST: - browser_filter_commits(browser); + case BROWSER_STATE_UPDATE_AMENDMENT_LIST: + browser_filter_amendments(browser); browser->state = BROWSER_STATE_IDLE; break; case BROWSER_STATE_OPEN_COMMITTER: @@ -86,6 +92,10 @@ browser_idle(struct focusable *focusable, EventRecord browser_apply_patch(browser); browser->state = BROWSER_STATE_IDLE; break; + case BROWSER_STATE_EDIT_AMENDMENT: + browser_edit_amendment(browser); + browser->state = BROWSER_STATE_IDLE; + break; } } @@ -153,21 +163,21 @@ browser_init(struct repo *repo) browser->diff_button = NewControl(browser->win, &bounds, "\pGenerate Diff", true, 1, 1, 1, pushButProc | useWFont, 0L); - /* commit list */ + /* amendment list */ bounds.top = bounds.left = padding; bounds.left = bounds.right + padding; bounds.right = browser->win->portRect.right - SCROLLBAR_WIDTH - padding; cell_size.v = (FontHeight(applFont, 9) * 2) + 2; - browser->commit_list = LNew(&bounds, &data_bounds, cell_size, - COMMIT_LDEF_ID, browser->win, true, true, false, true); - if (!browser->commit_list) - err(1, "Can't create commit list"); - LAddColumn(1, 0, browser->commit_list); - (*(browser->commit_list))->selFlags = lOnlyOne; + browser->amendment_list = LNew(&bounds, &data_bounds, cell_size, + AMENDMENT_LDEF_ID, browser->win, true, true, false, true); + if (!browser->amendment_list) + err(1, "Can't create amendment list"); + LAddColumn(1, 0, browser->amendment_list); + (*(browser->amendment_list))->selFlags = lOnlyOne; /* diff text */ - bounds.top = (*browser->commit_list)->rView.bottom + padding; + bounds.top = (*browser->amendment_list)->rView.bottom + padding; bounds.left = padding; bounds.right = browser->win->portRect.right - SCROLLBAR_WIDTH - padding; bounds.bottom = browser->win->portRect.bottom - padding; @@ -248,7 +258,7 @@ browser_add_files(struct browser *browser) LDoDraw(false, browser->file_list); LDelRow(0, 0, browser->file_list); - browser_show_commit(browser, NULL); + browser_show_amendment(browser, NULL); TextFont(applFont); TextSize(10); @@ -272,7 +282,7 @@ browser_add_files(struct browser *browser) LDoDraw(true, browser->file_list); - browser_filter_commits(browser); + browser_filter_amendments(browser); InvalRect(&browser->win->portRect); } @@ -326,28 +336,28 @@ browser_selected_file_ids(struct browser *browser, sho } void -browser_filter_commits(struct browser *browser) +browser_filter_amendments(struct browser *browser) { Cell cell = { 0 }; - struct repo_commit *commit; + struct repo_amendment *amendment; short i, j, k, add = 0, file_id; short *selected_files = NULL; short nselected_files = 0; - LDoDraw(false, browser->commit_list); - LDelRow(0, 0, browser->commit_list); - browser_show_commit(browser, NULL); + LDoDraw(false, browser->amendment_list); + LDelRow(0, 0, browser->amendment_list); + browser_show_amendment(browser, NULL); - /* fill in commits for selected files */ + /* fill in amendments for selected files */ nselected_files = browser_selected_file_ids(browser, &selected_files); cell.v = 0; - for (i = 0; i < browser->repo->ncommits; i++) { + for (i = 0; i < browser->repo->namendments; i++) { add = 0; - commit = browser->repo->commits[i]; - for (j = 0; j < commit->nfiles; j++) { - file_id = commit->file_ids[j]; + amendment = browser->repo->amendments[i]; + for (j = 0; j < amendment->nfiles; j++) { + file_id = amendment->file_ids[j]; for (k = 0; k < nselected_files; k++) { - if (selected_files[k] == commit->file_ids[j]) { + if (selected_files[k] == amendment->file_ids[j]) { add = 1; break; } @@ -359,32 +369,33 @@ browser_filter_commits(struct browser *browser) if (!add) continue; - LAddRow(1, cell.v, browser->commit_list); - LSetCell(&(browser->repo->commits[i]), sizeof(Ptr), cell, - browser->commit_list); + LAddRow(1, cell.v, browser->amendment_list); + LSetCell(&(browser->repo->amendments[i]), sizeof(Ptr), cell, + browser->amendment_list); cell.v++; } - LDoDraw(true, browser->commit_list); - InvalRect(&(*(browser->commit_list))->rView); + LDoDraw(true, browser->amendment_list); + InvalRect(&(*(browser->amendment_list))->rView); if (selected_files) free(selected_files); } void -browser_show_commit(struct browser *browser, struct repo_commit *commit) +browser_show_amendment(struct browser *browser, + struct repo_amendment *amendment) { struct repo_diff *diff; - if (commit == NULL) { + if (amendment == NULL) { TESetText("", 0, browser->diff_te); HLock(browser->diff_te); InvalRect(&(*(browser->diff_te))->viewRect); HUnlock(browser->diff_te); } else { SetCursor(*(GetCursor(watchCursor))); - repo_show_diff_text(browser->repo, commit, browser->diff_te); + repo_show_diff_text(browser->repo, amendment, browser->diff_te); SetCursor(&arrow); } @@ -428,21 +439,21 @@ browser_export_patch(struct browser *browser) { Point pt = { 75, 100 }; Cell selected = { 0 }; - struct repo_commit *commit; + struct repo_amendment *amendment; short error, len; SFReply reply; - if (LGetSelect(true, &selected, browser->commit_list) == false) + if (LGetSelect(true, &selected, browser->amendment_list) == false) return; len = sizeof(Ptr); - LGetCell(&commit, &len, selected, browser->commit_list); + LGetCell(&amendment, &len, selected, browser->amendment_list); SFPutFile(pt, "\pSave patch as:", NULL, NULL, &reply); if (!reply.good) return; - repo_export_patch(browser->repo, commit, reply.vRefNum, reply.fName); + repo_export_patch(browser->repo, amendment, reply.vRefNum, reply.fName); } void @@ -459,6 +470,24 @@ browser_apply_patch(struct browser *browser) } void +browser_edit_amendment(struct browser *browser) +{ + Point pt = { 75, 100 }; + Cell selected = { 0 }; + struct repo_amendment *amendment; + short error, len; + SFReply reply; + + if (LGetSelect(true, &selected, browser->amendment_list) == false) + return; + + len = sizeof(Ptr); + LGetCell(&amendment, &len, selected, browser->amendment_list); + + editor_init(browser, amendment); +} + +void browser_update_menu(struct browser *browser) { size_t vlines; @@ -498,10 +527,12 @@ browser_update_menu(struct browser *browser) EnableItem(repo_menu, REPO_MENU_APPLY_PATCH_ID); } - if (LGetSelect(true, &cell, browser->commit_list)) { - EnableItem(commit_menu, COMMIT_MENU_EXPORT_ID); + if (LGetSelect(true, &cell, browser->amendment_list)) { + EnableItem(amendment_menu, AMENDMENT_MENU_EDIT_ID); + EnableItem(amendment_menu, AMENDMENT_MENU_EXPORT_ID); } else { - DisableItem(commit_menu, COMMIT_MENU_EXPORT_ID); + DisableItem(amendment_menu, AMENDMENT_MENU_EDIT_ID); + DisableItem(amendment_menu, AMENDMENT_MENU_EXPORT_ID); } } @@ -535,11 +566,11 @@ browser_update(struct focusable *focusable, EventRecor TextSize(10); LUpdate(browser->win->visRgn, browser->file_list); - r = (*(browser->commit_list))->rView; + r = (*(browser->amendment_list))->rView; InsetRect(&r, -1, -1); FillRect(&r, white); FrameRect(&r); - LUpdate(browser->win->visRgn, browser->commit_list); + LUpdate(browser->win->visRgn, browser->amendment_list); TextFont(applFont); TextSize(11); @@ -559,7 +590,7 @@ browser_mouse_down(struct focusable *focusable, EventR ControlHandle control; Rect r; struct browser *browser = (struct browser *)focusable->cookie; - struct repo_commit *commit = NULL; + struct repo_amendment *amendment = NULL; short *selected_files = NULL, *now_selected_files = NULL; short nselected = 0, nnow_selected = 0; short val, adj, page, was_selected, part, i, data_len; @@ -598,13 +629,13 @@ browser_mouse_down(struct focusable *focusable, EventR selected.v = 0; LSetSelect(true, selected, browser->file_list); if (nselected != browser->repo->nfiles) - browser_filter_commits(browser); + browser_filter_amendments(browser); } else if (nselected != nnow_selected) { - browser_filter_commits(browser); + browser_filter_amendments(browser); } else { for (i = 0; i < nselected; i++) { if (selected_files[i] != now_selected_files[i]) { - browser_filter_commits(browser); + browser_filter_amendments(browser); break; } } @@ -618,31 +649,31 @@ browser_mouse_down(struct focusable *focusable, EventR return; } - /* is it in commit list? */ - r = (*(browser->commit_list))->rView; + /* is it in amendment list? */ + r = (*(browser->amendment_list))->rView; r.right += SCROLLBAR_WIDTH; if (PtInRect(p, &r)) { if (browser->repo == NULL) return; /* store what is selected now */ - was_selected = LGetSelect(true, &selected, browser->commit_list); + was_selected = LGetSelect(true, &selected, browser->amendment_list); /* possibly highlight a new cell */ - LClick(p, event->modifiers, browser->commit_list); + LClick(p, event->modifiers, browser->amendment_list); - if (LGetSelect(true, &now, browser->commit_list) == false) { + if (LGetSelect(true, &now, browser->amendment_list) == false) { if (was_selected) - browser_show_commit(browser, NULL); + browser_show_amendment(browser, NULL); } else if (!was_selected || selected.v != now.v) { if (was_selected) - LSetSelect(false, selected, browser->commit_list); - LSetSelect(true, now, browser->commit_list); + LSetSelect(false, selected, browser->amendment_list); + LSetSelect(true, now, browser->amendment_list); - /* in a filtered list, commits[now.v] won't be accurate */ + /* in a filtered list, amendments[now.v] won't be accurate */ data_len = sizeof(Ptr); - LGetCell(&commit, &data_len, now, browser->commit_list); - browser_show_commit(browser, commit); + LGetCell(&amendment, &data_len, now, browser->amendment_list); + browser_show_amendment(browser, amendment); } return; @@ -711,9 +742,12 @@ browser_handle_menu(struct focusable *focusable, short return true; } break; - case COMMIT_MENU_ID: + case AMENDMENT_MENU_ID: switch (item) { - case COMMIT_MENU_EXPORT_ID: + case AMENDMENT_MENU_EDIT_ID: + browser->state = BROWSER_STATE_EDIT_AMENDMENT; + return true; + case AMENDMENT_MENU_EXPORT_ID: browser->state = BROWSER_STATE_EXPORT_PATCH; return true; } --- browser.h Tue Aug 16 13:20:59 2022 +++ browser.h Wed Aug 17 14:23:45 2022 @@ -26,13 +26,14 @@ enum { BROWSER_STATE_IDLE, BROWSER_STATE_ADD_FILE, BROWSER_STATE_UPDATE_FILE_LIST, - BROWSER_STATE_UPDATE_COMMIT_LIST, + BROWSER_STATE_UPDATE_AMENDMENT_LIST, BROWSER_STATE_OPEN_COMMITTER, BROWSER_STATE_WAITING_FOR_COMMITTER, BROWSER_STATE_REMOVE_FILE, BROWSER_STATE_DISCARD_CHANGES, BROWSER_STATE_EXPORT_PATCH, - BROWSER_STATE_APPLY_PATCH + BROWSER_STATE_APPLY_PATCH, + BROWSER_STATE_EDIT_AMENDMENT }; struct browser { @@ -40,17 +41,18 @@ struct browser { WindowPtr win; struct repo *repo; ListHandle file_list; - ListHandle commit_list; + ListHandle amendment_list; TEHandle diff_te; ControlHandle diff_scroller; ControlHandle diff_button; struct committer *committer; + bool need_refresh; }; struct browser *browser_init(struct repo *repo); void browser_update_titlebar(struct browser *browser); -void browser_show_commit(struct browser *browser, - struct repo_commit *commit); +void browser_show_amendment(struct browser *browser, + struct repo_amendment *amendment); void browser_close_committer(struct browser *browser); void browser_export_patch(struct browser *browser); short browser_is_all_files_selected(struct browser *browser); @@ -58,7 +60,7 @@ short browser_selected_file_ids(struct browser *browse short **selected_files); void browser_apply_patch(struct browser *browser); -pascal void commit_list_ldef(short message, Boolean selected, +pascal void amendment_list_ldef(short message, Boolean selected, Rect *cellRect, Cell theCell, short dataOffset, short dataLen, ListHandle theList); --- committer.c Tue Aug 16 13:40:20 2022 +++ committer.c Tue Aug 16 16:56:14 2022 @@ -67,12 +67,12 @@ committer_init(struct browser *browser) committer->browser = browser; browser->committer = committer; - /* main window */ - bounds.left = (padding / 2); - bounds.top = screenBits.bounds.top + (GetMBarHeight() * 2) - 1 + - (padding / 2); - bounds.right = screenBits.bounds.right - 1 - (padding / 2); - bounds.bottom = screenBits.bounds.bottom - 1 - (padding / 2); + /* main window, centered in its browser */ + bounds = (*(((WindowPeek)browser->win)->strucRgn))->rgnBBox; + bounds.left += (padding / 2); + bounds.top += ((padding / 2) + MBarHeight); + bounds.right -= (padding / 2); + bounds.bottom -= (padding / 2); memcpy(filename, browser->repo->bile->filename, sizeof(filename)); PtoCstr(filename); @@ -401,8 +401,8 @@ committer_update_menu(struct committer *committer) DisableItem(repo_menu, REPO_MENU_DISCARD_CHANGES_ID); DisableItem(repo_menu, REPO_MENU_APPLY_PATCH_ID); - DisableItem(commit_menu, COMMIT_MENU_EDIT_ID); - DisableItem(commit_menu, COMMIT_MENU_EXPORT_ID); + DisableItem(amendment_menu, AMENDMENT_MENU_EDIT_ID); + DisableItem(amendment_menu, AMENDMENT_MENU_EXPORT_ID); HUnlock(committer->log_te); HUnlock(committer->diff_te); @@ -510,7 +510,7 @@ committer_commit(struct committer *committer) progress("Committing changes..."); - repo_commit(committer->browser->repo, committer->diffed_files, + repo_amend(committer->browser->repo, committer->diffed_files, committer->ndiffed_files, committer->diff_adds, committer->diff_subs, settings.author, (*(committer->log_te))->hText, loglen, (*(committer->diff_te))->hText, committer->diff_te_len); @@ -523,7 +523,7 @@ committer_commit(struct committer *committer) browser = committer->browser; browser_close_committer(committer->browser); - browser->state = BROWSER_STATE_UPDATE_COMMIT_LIST; + browser->state = BROWSER_STATE_UPDATE_AMENDMENT_LIST; } bool --- editor.c Wed Aug 17 14:25:10 2022 +++ editor.c Wed Aug 17 14:25:10 2022 @@ -0,0 +1,495 @@ +/* + * Copyright (c) 2022 joshua stein <jcs@jcs.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#include <time.h> +#include "amend.h" +#include "browser.h" +#include "editor.h" +#include "focusable.h" +#include "repo.h" +#include "tetab.h" +#include "util.h" + +static short padding = 10; + +bool editor_close(struct focusable *focusable); +void editor_idle(struct focusable *focusable, EventRecord *event); +void editor_update(struct focusable *focusable, EventRecord *event); +void editor_suspend(struct focusable *focusable); +void editor_resume(struct focusable *focusable); +void editor_key_down(struct focusable *focusable, EventRecord *event); +void editor_mouse_down(struct focusable *focusable, EventRecord *event); +bool editor_handle_menu(struct focusable *focusable, short menu, + short item); + +void editor_update_menu(struct editor *editor); +void editor_save(struct editor *editor); + +void +editor_init(struct browser *browser, struct repo_amendment *amendment) +{ + Str255 title, filename; + struct editor *editor; + struct focusable *focusable; + char date[32]; + Rect bounds = { 0 }, te_bounds = { 0 }; + TextStyle style; + short fh, off; + struct tm *ttm = NULL; + + editor = xmalloczero(sizeof(struct editor)); + editor->browser = browser; + editor->amendment = amendment; + + /* main window, centered in its browser */ + window_rect(browser->win, &bounds); + bounds.top += MBarHeight; + InsetRect(&bounds, 2, 2); + off = (bounds.bottom - bounds.top) / 5; + bounds.top += off; + bounds.bottom -= off; + + memcpy(filename, browser->repo->bile->filename, sizeof(filename)); + PtoCstr(filename); + snprintf((char *)&title, sizeof(title), "%s: %s: Edit Amendment", + PROGRAM_NAME, (browser->repo ? (char *)filename : "No repo open")); + + editor->win = NewWindow(0L, &bounds, CtoPstr(title), false, + noGrowDocProc, (WindowPtr)-1L, true, 0); + if (!editor) + err(1, "Can't create editor window"); + SetPort(editor->win); + + /* author */ + bounds.top = padding; + bounds.left = 60; + fh = FontHeight(applFont, 10); + bounds.bottom = bounds.top + fh + 4; + bounds.right = 140; + te_bounds = bounds; + InsetRect(&te_bounds, 2, 2); + TextFont(applFont); + TextSize(10); + editor->author_te = TENew(&te_bounds, &bounds); + TEAutoView(true, editor->author_te); + TEActivate(editor->author_te); + TEInsert(amendment->author, strlen(amendment->author), + editor->author_te); + + /* date */ + bounds.top = bounds.bottom + padding; + bounds.bottom = bounds.top + fh + 2; + bounds.right = 200; + te_bounds = bounds; + InsetRect(&te_bounds, 2, 2); + TextFont(applFont); + TextSize(10); + editor->date_te = TENew(&te_bounds, &bounds); + TEAutoView(true, editor->date_te); + + ttm = localtime(&amendment->date); + snprintf(date, sizeof(date), "%04d-%02d-%02d %02d:%02d:%02d", + ttm->tm_year + 1900, ttm->tm_mon + 1, ttm->tm_mday, + ttm->tm_hour, ttm->tm_min, ttm->tm_sec); + TEInsert(date, strlen(date), editor->date_te); + + /* log message */ + bounds.top = bounds.bottom + padding; + fh = FontHeight(monaco, 9); + bounds.bottom = editor->win->portRect.bottom - 20 - (padding * 2); + bounds.right = editor->win->portRect.right - SCROLLBAR_WIDTH - + padding; + te_bounds = bounds; + InsetRect(&te_bounds, 2, 2); + TextFont(monaco); + TextSize(9); + editor->log_te = TEStylNew(&te_bounds, &bounds); + style.tsFont = monaco; + style.tsSize = 9; + TESetStyle(doFont | doSize, &style, false, editor->log_te); + TEAutoView(true, editor->log_te); + TETabEnable(editor->log_te); + HLock(amendment->log); + TEInsert(*(amendment->log), amendment->log_len, editor->log_te); + HUnlock(amendment->log); + + /* scrollbar for log message */ + bounds.left = bounds.right; + bounds.right += SCROLLBAR_WIDTH; + bounds.bottom++; + bounds.top--; + editor->log_scroller = NewControl(editor->win, &bounds, "\p", + true, 1, 1, 1, scrollBarProc, 0L); + + /* save button */ + TextFont(applFont); + TextSize(11); + bounds.left = editor->win->portRect.right - padding - 100; + bounds.right = bounds.left + 100; + bounds.bottom = editor->win->portRect.bottom - padding; + bounds.top = bounds.bottom - 20; + editor->save_button = NewControl(editor->win, &bounds, "\pSave", + true, 1, 1, 1, pushButProc, 0L); + + editor->last_te = editor->author_te; + + focusable = xmalloczero(sizeof(struct focusable)); + focusable->cookie = editor; + focusable->win = editor->win; + focusable->modal = true; + focusable->idle = editor_idle; + focusable->update = editor_update; + focusable->mouse_down = editor_mouse_down; + focusable->key_down = editor_key_down; + focusable->menu = editor_handle_menu; + focusable->close = editor_close; + focusable_add(focusable); +} + +bool +editor_close(struct focusable *focusable) +{ + struct editor *editor = (struct editor *)focusable->cookie; + + TEDispose(editor->author_te); + TEDispose(editor->date_te); + TEDispose(editor->log_te); + DisposeWindow(editor->win); + + free(editor); + + return true; +} + +void +editor_idle(struct focusable *focusable, EventRecord *event) +{ + struct editor *editor = (struct editor *)focusable->cookie; + + TEIdle(editor->last_te); +} + +void +editor_update(struct focusable *focusable, EventRecord *event) +{ + Str255 buf; + Rect r; + short what = -1, len; + struct editor *editor = (struct editor *)focusable->cookie; + + if (event != NULL) + what = event->what; + + switch (what) { + case -1: + case updateEvt: + r = (*(editor->author_te))->viewRect; + MoveTo(padding, r.top + FontHeight(applFont, 11) - 2); + TextFont(applFont); + TextSize(11); + DrawText("Author:", 0, 7); + InsetRect(&r, -1, -1); + FrameRect(&r); + TEUpdate(&r, editor->author_te); + + r = (*(editor->date_te))->viewRect; + MoveTo(padding, r.top + FontHeight(applFont, 11) - 2); + TextFont(applFont); + TextSize(11); + DrawText("Date:", 0, 5); + InsetRect(&r, -1, -1); + FrameRect(&r); + TEUpdate(&r, editor->date_te); + + r = (*(editor->log_te))->viewRect; + MoveTo(padding, r.top + FontHeight(applFont, 11) - 2); + TextFont(applFont); + TextSize(11); + DrawText("Log:", 0, 4); + InsetRect(&r, -1, -1); + FrameRect(&r); + TEUpdate(&r, editor->log_te); + + editor_update_menu(editor); + UpdtControl(editor->win, editor->win->visRgn); + + break; + } +} + +void +editor_suspend(struct focusable *focusable) +{ + struct editor *editor = (struct editor *)focusable->cookie; + + TEDeactivate(editor->author_te); + TEDeactivate(editor->date_te); + TEDeactivate(editor->log_te); +} + +void +editor_resume(struct focusable *focusable) +{ + struct editor *editor = (struct editor *)focusable->cookie; + + TEActivate(editor->author_te); + TEActivate(editor->date_te); + TEActivate(editor->log_te); +} + +void +editor_key_down(struct focusable *focusable, EventRecord *event) +{ + struct editor *editor = (struct editor *)focusable->cookie; + char k; + + k = (event->message & charCodeMask); + + if (k == '\r' && (editor->last_te == editor->author_te || + editor->last_te == editor->date_te)) + return; + + TEKey(k, editor->last_te); + if (editor->last_te == editor->log_te) + UpdateScrollbarForTE(editor->log_scroller, editor->last_te, false); + editor_update_menu(editor); +} + +void +editor_mouse_down(struct focusable *focusable, EventRecord *event) +{ + struct editor *editor = (struct editor *)focusable->cookie; + Point p; + ControlHandle control; + Rect r; + short val, adj, page, was_selected, part, i; + + p = event->where; + GlobalToLocal(&p); + + r = (*(editor->author_te))->viewRect; + if (PtInRect(p, &r)) { + if (editor->last_te != editor->author_te) { + editor->last_te = editor->author_te; + TEDeactivate(editor->date_te); + TEDeactivate(editor->log_te); + TEActivate(editor->author_te); + } + TEClick(p, ((event->modifiers & shiftKey) != 0), editor->author_te); + editor_update_menu(editor); + return; + } + + + r = (*(editor->date_te))->viewRect; + if (PtInRect(p, &r)) { + if (editor->last_te != editor->date_te) { + editor->last_te = editor->date_te; + TEDeactivate(editor->author_te); + TEDeactivate(editor->log_te); + TEActivate(editor->date_te); + } + TEClick(p, ((event->modifiers & shiftKey) != 0), editor->date_te); + editor_update_menu(editor); + return; + } + + r = (*(editor->log_te))->viewRect; + if (PtInRect(p, &r)) { + if (editor->last_te != editor->log_te) { + editor->last_te = editor->log_te; + TEDeactivate(editor->author_te); + TEDeactivate(editor->date_te); + TEActivate(editor->log_te); + } + TEClick(p, ((event->modifiers & shiftKey) != 0), editor->log_te); + editor_update_menu(editor); + return; + } + + switch (part = FindControl(p, editor->win, &control)) { + case inButton: + TextFont(applFont); + TextSize(11); + if (TrackControl(control, p, 0L) && + control == editor->save_button) + editor_save(editor); + break; + case inUpButton: + case inDownButton: + case inPageUp: + case inPageDown: + if (control == editor->log_scroller) + SetTrackControlTE(editor->log_te); + else + break; + TrackControl(control, p, TrackMouseDownInControl); + break; + case inThumb: + val = GetCtlValue(control); + if (TrackControl(control, p, 0L) == 0) + break; + adj = val - GetCtlValue(control); + if (adj != 0) { + val -= adj; + if (control == editor->log_scroller) + TEScroll(0, adj * TEGetHeight(0, 0, editor->log_te), + editor->log_te); + SetCtlValue(control, val); + } + break; + } +} + +void +editor_update_menu(struct editor *editor) +{ + if ((*(editor->last_te))->selStart == (*(editor->last_te))->selEnd) { + DisableItem(edit_menu, EDIT_MENU_CUT_ID); + DisableItem(edit_menu, EDIT_MENU_COPY_ID); + } else { + EnableItem(edit_menu, EDIT_MENU_CUT_ID); + EnableItem(edit_menu, EDIT_MENU_COPY_ID); + } + if ((*(editor->last_te))->nLines > 0) + EnableItem(edit_menu, EDIT_MENU_SELECT_ALL_ID); + else + DisableItem(edit_menu, EDIT_MENU_SELECT_ALL_ID); + EnableItem(edit_menu, EDIT_MENU_PASTE_ID); + + DisableItem(repo_menu, REPO_MENU_ADD_FILE_ID); + DisableItem(repo_menu, REPO_MENU_DISCARD_CHANGES_ID); + DisableItem(repo_menu, REPO_MENU_APPLY_PATCH_ID); + + DisableItem(amendment_menu, AMENDMENT_MENU_EDIT_ID); + DisableItem(amendment_menu, AMENDMENT_MENU_EXPORT_ID); + + EnableItem(repo_menu, 0); +} + +bool +editor_handle_menu(struct focusable *focusable, short menu, short item) +{ + struct editor *editor = (struct editor *)focusable->cookie; + + switch (menu) { + case EDIT_MENU_ID: + switch (item) { + case EDIT_MENU_CUT_ID: + TECut(editor->last_te); + editor_update_menu(editor); + return true; + case EDIT_MENU_COPY_ID: + TECopy(editor->last_te); + editor_update_menu(editor); + return true; + case EDIT_MENU_PASTE_ID: + TEPaste(editor->last_te); + editor_update_menu(editor); + return true; + case EDIT_MENU_SELECT_ALL_ID: + TESetSelect(0, 1024 * 32, editor->last_te); + editor_update_menu(editor); + return true; + } + break; + } + + return false; +} + +void +editor_save(struct editor *editor) +{ + struct tm ttm; + size_t len, size; + time_t ts; + short ret, yy, mm, dd, hh, min, ss, count = 0; + char *date, *author, *log, *data; + + if ((*(editor->author_te))->teLength == 0) { + warn("Author field cannot be blank"); + return; + } + + len = (*(editor->date_te))->teLength; + if (len == 0) { + warn("Date field cannot be blank"); + return; + } + + date = xmalloc(len + 1); + memcpy(date, *(*(editor->date_te))->hText, len); + date[len] = '\0'; + + ret = sscanf(date, "%d-%d-%d %d:%d:%d%n", &yy, &mm, &dd, &hh, &min, + &ss, &count); + free(date); + if (ret != 6 || count < 11) { + warn("Date must be in YYYY-MM-DD HH:MM:SS format"); + return; + } + + ttm.tm_year = yy - 1900; + ttm.tm_mon = mm - 1; + ttm.tm_mday = dd; + ttm.tm_hour = hh; + ttm.tm_min = min; + ttm.tm_sec = ss; + ts = mktime(&ttm); + + len = (*(editor->log_te))->teLength; + if (len == 0) { + warn("Log cannot be blank"); + return; + } + + editor->amendment->date = ts; + + len = sizeof(editor->amendment->author) - 1; + if ((*(editor->author_te))->teLength < len) + len = (*(editor->author_te))->teLength; + memcpy(editor->amendment->author, *(*(editor->author_te))->hText, + len); + editor->amendment->author[len] = '\0'; + + editor->amendment->log_len = (*(editor->log_te))->teLength; + if (editor->amendment->log) + DisposHandle(editor->amendment->log); + + editor->amendment->log = xNewHandle(editor->amendment->log_len); + memcpy(*(editor->amendment->log), *(*(editor->log_te))->hText, + editor->amendment->log_len); + + progress("Storing updated amendment metadata..."); + + repo_marshall_amendment(editor->amendment, &data, &len); + + size = bile_write(editor->browser->repo->bile, REPO_AMENDMENT_RTYPE, + editor->amendment->id, data, len); + if (size != len) + panic("Failed storing amendment in repo file: %d", + bile_error(editor->browser->repo->bile)); + free(data); + + editor->browser->need_refresh = true; + focusable_close(focusable_find(editor->win)); + progress(NULL); +} --- editor.h Tue Aug 16 22:12:41 2022 +++ editor.h Tue Aug 16 22:12:41 2022 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022 joshua stein <jcs@jcs.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __EDITOR_H__ +#define __EDITOR_H__ + +#include "browser.h" +#include "repo.h" +#include "util.h" + +struct editor { + struct browser *browser; + WindowPtr win; + short state; + TEHandle log_te; + ControlHandle log_scroller; + TEHandle date_te; + TEHandle author_te; + ControlHandle save_button; + TEHandle last_te; + struct repo_amendment *amendment; +}; + +void editor_init(struct browser *browser, struct repo_amendment *amendment); + +#endif --- main.c Tue Aug 16 13:32:45 2022 +++ main.c Tue Aug 16 16:44:27 2022 @@ -25,8 +25,8 @@ #include "settings.h" #include "util.h" -MenuHandle file_menu, edit_menu, repo_menu, commit_menu; -Handle commit_list_ldef_h; +MenuHandle file_menu, edit_menu, repo_menu, amendment_menu; +Handle amendment_list_ldef_h; bool quitting = false; void handle_menu(long menu_id); @@ -65,16 +65,16 @@ main(void) file_menu = GetMHandle(FILE_MENU_ID); edit_menu = GetMHandle(EDIT_MENU_ID); repo_menu = GetMHandle(REPO_MENU_ID); - commit_menu = GetMHandle(COMMIT_MENU_ID); + amendment_menu = GetMHandle(AMENDMENT_MENU_ID); menu_defaults(); DrawMenuBar(); /* dynamically patch list LDEF to point to our *_list_ldef funcs */ - commit_list_ldef_h = GetResource('LDEF', COMMIT_LDEF_ID); - if (!commit_list_ldef_h) - err(1, "Can't find commit list LDEF %d", COMMIT_LDEF_ID); - HLock(commit_list_ldef_h); - ((tCodeStub *)*commit_list_ldef_h)->addr = &commit_list_ldef; + amendment_list_ldef_h = GetResource('LDEF', AMENDMENT_LDEF_ID); + if (!amendment_list_ldef_h) + err(1, "Can't find amendment list LDEF %d", AMENDMENT_LDEF_ID); + HLock(amendment_list_ldef_h); + ((tCodeStub *)*amendment_list_ldef_h)->addr = &amendment_list_ldef; /* see if we were started by double-clicking a .repo file */ CountAppFiles(&finder_action, &finder_count); @@ -272,6 +272,6 @@ menu_defaults(void) DisableItem(repo_menu, REPO_MENU_DISCARD_CHANGES_ID); DisableItem(repo_menu, REPO_MENU_APPLY_PATCH_ID); - DisableItem(commit_menu, COMMIT_MENU_EDIT_ID); - DisableItem(commit_menu, COMMIT_MENU_EXPORT_ID); + DisableItem(amendment_menu, AMENDMENT_MENU_EDIT_ID); + DisableItem(amendment_menu, AMENDMENT_MENU_EXPORT_ID); }