jcs
/amend
/amendments
/20
browser+repo: Add diff exporting
Refactor diff header generation into a function to also use here.
When disabling menus, only disable their items. This avoids having
to call DrawMenuBar() which flashes annoyingly.
jcs made amendment 20 over 3 years ago
--- amend.h Mon Oct 18 13:09:14 2021
+++ amend.h Wed Oct 27 09:39:20 2021
@@ -35,8 +35,11 @@
#define REPO_MENU_REVERT_FILE_ID 2
#define REPO_MENU_APPLY_DIFF_ID 3
+#define COMMIT_MENU_ID 132
+#define COMMIT_MENU_EXPORT_ID 1
+
#define COMMIT_LDEF_ID 128
#define TABWIDTH_ID 130
-extern MenuHandle file_menu, edit_menu, repo_menu;
+extern MenuHandle file_menu, edit_menu, repo_menu, commit_menu;
--- browser.c Mon Oct 18 13:09:06 2021
+++ browser.c Wed Oct 27 13:43:28 2021
@@ -67,6 +67,11 @@ browser_idle(struct browser *browser)
case BROWSER_STATE_REVERT_FILE:
browser_revert_file(browser);
browser->state = BROWSER_STATE_IDLE;
+ break;
+ case BROWSER_STATE_EXPORT_DIFF:
+ browser_export_diff(browser);
+ browser->state = BROWSER_STATE_IDLE;
+ break;
}
}
@@ -160,7 +165,6 @@ browser_init(struct repo *repo)
1, 1, 1, scrollBarProc, 0L);
browser_update_menu(browser);
- DrawMenuBar();
browser_add_files(browser);
UpdateScrollbarForTE(browser->diff_scroller, browser->diff_te, true);
ShowWindow(browser->win);
@@ -317,15 +321,19 @@ browser_show_commit(struct browser *browser, struct re
{
struct repo_diff *diff;
- if (commit == NULL)
+ if (commit == NULL) {
TESetText("", 0, browser->diff_te);
- else {
+ HLock(browser->diff_te);
+ InvalRect(&(*(browser->diff_te))->viewRect);
+ HUnlock(browser->diff_te);
+ } else {
SetCursor(*(GetCursor(watchCursor)));
- repo_show_diff_text(commit, browser->diff_te);
+ repo_show_diff_text(browser->repo, commit, browser->diff_te);
SetCursor(&arrow);
}
UpdateScrollbarForTE(browser->diff_scroller, browser->diff_te, true);
+ browser_update_menu(browser);
}
void
@@ -360,10 +368,33 @@ browser_revert_file(struct browser *browser)
}
void
+browser_export_diff(struct browser *browser)
+{
+ Point pt = { 75, 100 };
+ Cell selected = { 0 };
+ struct repo_commit *commit;
+ short error, len;
+ SFReply reply;
+
+ if (LGetSelect(true, &selected, browser->commit_list) == false)
+ return;
+
+ len = sizeof(Ptr);
+ LGetCell(&commit, &len, selected, browser->commit_list);
+
+ SFPutFile(pt, "\pSave diff as:", NULL, NULL, &reply);
+ if (!reply.good)
+ return;
+
+ repo_export_diff(browser->repo, commit, reply.vRefNum, reply.fName);
+}
+
+void
browser_update_menu(struct browser *browser)
{
size_t vlines;
TERec *diff;
+ Cell cell = { 0, 0 };
HLock(browser->diff_te);
diff = *(browser->diff_te);
@@ -378,14 +409,21 @@ browser_update_menu(struct browser *browser)
else
EnableItem(edit_menu, EDIT_MENU_COPY_ID);
+ HUnlock(browser->diff_te);
+
if (browser->repo->nfiles == 0)
HiliteControl(browser->diff_button, 255);
else
HiliteControl(browser->diff_button, 0);
- HUnlock(browser->diff_te);
+ EnableItem(repo_menu, REPO_MENU_ADD_FILE_ID);
+ EnableItem(repo_menu, REPO_MENU_REVERT_FILE_ID);
+ EnableItem(repo_menu, REPO_MENU_APPLY_DIFF_ID);
- EnableItem(repo_menu, 0);
+ if (LGetSelect(true, &cell, browser->commit_list))
+ EnableItem(commit_menu, COMMIT_MENU_EXPORT_ID);
+ else
+ DisableItem(commit_menu, COMMIT_MENU_EXPORT_ID);
}
void
--- browser.h Mon Oct 18 13:09:23 2021
+++ browser.h Wed Oct 27 13:05:39 2021
@@ -30,7 +30,8 @@ enum {
BROWSER_STATE_OPEN_COMMITTER,
BROWSER_STATE_COMMITTER_DO_DIFF,
BROWSER_STATE_WAITING_FOR_COMMITTER,
- BROWSER_STATE_REVERT_FILE
+ BROWSER_STATE_REVERT_FILE,
+ BROWSER_STATE_EXPORT_DIFF
};
struct browser {
@@ -55,6 +56,7 @@ void browser_update_menu(struct browser *browser);
void browser_update(struct browser *browser, EventRecord *event);
void browser_show_commit(struct browser *browser,
struct repo_commit *commit);
+void browser_export_diff(struct browser *browser);
short browser_selected_file_ids(struct browser *browser,
short **selected_files);
void browser_mouse_down(struct browser *browser, EventRecord *event);
--- main.c Mon Oct 18 09:22:19 2021
+++ main.c Wed Oct 27 12:58:00 2021
@@ -23,7 +23,7 @@
#include "repo.h"
#include "util.h"
-MenuHandle file_menu, edit_menu, repo_menu;
+MenuHandle file_menu, edit_menu, repo_menu, commit_menu;
Handle commit_list_ldef_h;
short quitting = 0;
struct browser *cur_browser = NULL;
@@ -64,7 +64,9 @@ 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);
update_menu();
+ DrawMenuBar();
/* dynamically patch list LDEF to point to our *_list_ldef funcs */
commit_list_ldef_h = GetResource('LDEF', COMMIT_LDEF_ID);
@@ -259,7 +261,15 @@ handle_menu(long menu_id)
break;
}
break;
+ case COMMIT_MENU_ID:
+ switch (LoWord(menu_id)) {
+ case COMMIT_MENU_EXPORT_ID:
+ if (cur_browser)
+ cur_browser->state = BROWSER_STATE_EXPORT_DIFF;
+ break;
}
+ break;
+ }
HiliteMenu(0);
}
@@ -274,6 +284,10 @@ update_menu(void)
DisableItem(edit_menu, EDIT_MENU_SELECT_ALL_ID);
DisableItem(edit_menu, EDIT_MENU_COPY_ID);
- DisableItem(repo_menu, 0);
- DrawMenuBar();
+
+ DisableItem(repo_menu, REPO_MENU_ADD_FILE_ID);
+ DisableItem(repo_menu, REPO_MENU_REVERT_FILE_ID);
+ DisableItem(repo_menu, REPO_MENU_APPLY_DIFF_ID);
+
+ DisableItem(commit_menu, COMMIT_MENU_EXPORT_ID);
}
--- repo.c Mon Oct 18 17:12:17 2021
+++ repo.c Wed Oct 27 13:42:15 2021
@@ -29,6 +29,8 @@ void repo_sort_commits(struct repo *repo);
short repo_get_file_attrs(struct repo *repo, Str255 filename,
struct repo_file_attrs *attrs);
short repo_file_update(struct repo *repo, struct repo_file *file);
+unsigned short repo_diff_header(struct repo *repo,
+ struct repo_commit *commit, char **ret);
struct repo *
repo_open(AppFile *file)
@@ -86,7 +88,7 @@ repo_create(void)
DetachResource(tmpls[i].h);
}
- error = Create(reply.fName, reply.vRefNum, REPO_CREATOR, REPO_TYPE);
+ error = Create(reply.fName, reply.vRefNum, AMEND_CREATOR, REPO_TYPE);
if (error != 0)
err(1, "Failed to create %s: %d", PtoCstr(reply.fName), error);
@@ -328,38 +330,17 @@ repo_file_with_id(struct repo *repo, short id)
return NULL;
}
-void
-repo_show_diff_text(struct repo_commit *commit, TEHandle te)
+unsigned short
+repo_diff_header(struct repo *repo, struct repo_commit *commit,
+ char **ret)
{
- Handle diffh;
- TextStyle style;
struct tm *ttm = NULL;
- char *buf;
- char truncbuf[64];
- unsigned long diff_len, all_len;
- short header_len, i, blen, height, trunc = 0;
- unsigned short warn_off;
+ unsigned short header_len;
+ short i;
- diffh = Get1Resource(REPO_DIFF_RTYPE, commit->id);
- if (diffh == NULL)
- err(1, "failed finding DIFF %d", commit->id);
-
- diff_len = GetHandleSize(diffh);
- if (diff_len == 0) {
- /*
- * Not sure why this happens when viewing the diff that was just
- * committed.
- */
- ReleaseResource(diffh);
- diffh = Get1Resource(REPO_DIFF_RTYPE, commit->id);
- diff_len = GetHandleSize(diffh);
- if (diff_len == 0)
- err(1, "diff still zero bytes");
- }
-
- buf = xmalloc(512);
+ *ret = xmalloc(128 + commit->log_len);
ttm = localtime(&commit->date);
- header_len = sprintf(buf,
+ header_len = sprintf(*ret,
"Author: %s\r"
"Date: %04d-%02d-%02d %02d:%02d:%02d\r"
"\r ",
@@ -370,17 +351,42 @@ repo_show_diff_text(struct repo_commit *commit, TEHand
/* copy log, indenting each line */
HLock(commit->log);
for (i = 0; i < commit->log_len; i++) {
- *(buf + header_len++) = (*(commit->log))[i];
+ *(*ret + header_len++) = (*(commit->log))[i];
if ((*(commit->log))[i] == '\r' && i < commit->log_len - 1) {
- *(buf + header_len++) = ' ';
- *(buf + header_len++) = ' ';
+ *(*ret + header_len++) = ' ';
+ *(*ret + header_len++) = ' ';
}
}
HUnlock(commit->log);
- *(buf + header_len++) = '\r';
- *(buf + header_len++) = '\r';
+ *(*ret + header_len++) = '\r';
+ *(*ret + header_len++) = '\r';
+ return header_len;
+}
+
+void
+repo_show_diff_text(struct repo *repo, struct repo_commit *commit,
+ TEHandle te)
+{
+ Handle diffh;
+ TextStyle style;
+ char *buf = NULL;
+ char truncbuf[64];
+ unsigned long diff_len, all_len;
+ short header_len, i, blen, height, trunc = 0;
+ unsigned short warn_off;
+
+ header_len = repo_diff_header(repo, commit, &buf);
+
+ diffh = Get1Resource(REPO_DIFF_RTYPE, commit->id);
+ if (diffh == NULL)
+ err(1, "failed finding DIFF %d", commit->id);
+
+ diff_len = GetHandleSize(diffh);
+ if (diff_len == 0)
+ err(1, "diff zero bytes");
+
all_len = header_len + diff_len;
if (all_len >= MAX_TEXTEDIT_SIZE) {
all_len = MAX_TEXTEDIT_SIZE;
@@ -738,6 +744,56 @@ repo_diff_file(struct repo *repo, struct repo_file *fi
}
void
+repo_export_diff(struct repo *repo, struct repo_commit *commit,
+ short vrefnum, Str255 filename)
+{
+ Handle diffh;
+ size_t len;
+ char *buf = NULL;
+ short error, frefnum, header_len;
+
+ diffh = Get1Resource(REPO_DIFF_RTYPE, commit->id);
+ if (diffh == NULL)
+ err(1, "failed finding DIFF %d", commit->id);
+
+ /*
+ * Don't use our creator here because we don't want finder opening us
+ * to view diffs, they are plain text
+ */
+ error = Create(filename, vrefnum, DIFF_FILE_TYPE, DIFF_FILE_TYPE);
+ if (error && error != dupFNErr) {
+ warn("Failed to create file %s: %d", PtoCstr(filename),
+ error);
+ return;
+ }
+
+ error = FSOpen(filename, vrefnum, &frefnum);
+ if (error)
+ err(1, "Failed to open file %s: %d", PtoCstr(filename), error);
+
+ error = SetEOF(frefnum, 0);
+ if (error)
+ err(1, "Failed to truncate file %s: %d", PtoCstr(filename),
+ error);
+
+ len = repo_diff_header(repo, commit, &buf);
+ error = FSWrite(frefnum, &len, buf);
+ if (error)
+ err(1, "Failed to write diff header to %s: %d", PtoCstr(filename),
+ error);
+ free(buf);
+
+ len = GetHandleSize(diffh);
+ HLock(diffh);
+ error = FSWrite(frefnum, &len, *diffh);
+ if (error)
+ err(1, "Failed to write diff to %s: %d", PtoCstr(filename), error);
+ ReleaseResource(diffh);
+
+ FSClose(frefnum);
+}
+
+void
repo_commit(struct repo *repo, short *files, short nfiles, short adds,
short subs, Handle log, short loglen, Handle diff, unsigned long difflen)
{
@@ -811,6 +867,7 @@ repo_commit(struct repo *repo, short *files, short nfi
if (ResError())
err(1, "Failed storing diff in repo file (%d)", ResError());
WriteResource(diff);
+ ReleaseResource(diff);
/* store commit */
AddResource(commith, REPO_COMMIT_RTYPE, commit_id, NULL);
--- repo.h Mon Oct 18 15:08:25 2021
+++ repo.h Wed Oct 27 13:42:51 2021
@@ -19,7 +19,8 @@
#include <time.h>
-#define REPO_CREATOR 'AMND'
+#define AMEND_CREATOR 'AMND'
+
#define REPO_TYPE 'AMRP'
#define REPO_FILE_RTYPE 'AFIL'
@@ -27,6 +28,8 @@
#define REPO_DIFF_RTYPE 'DIFF'
#define REPO_TEXT_RTYPE 'TEXT'
+#define DIFF_FILE_TYPE 'TEXT'
+
#define REPO_DIFF_TOO_BIG "\r[ Diff too large to view, %lu bytes not shown ]"
struct repo_file {
@@ -76,10 +79,13 @@ void repo_close(struct repo *repo);
struct repo_commit *repo_parse_commit(Handle hcommit);
struct repo_file *repo_parse_file(Handle hfile);
struct repo_file *repo_file_with_id(struct repo *repo, short id);
-void repo_show_diff_text(struct repo_commit *commit, TEHandle te);
+void repo_show_diff_text(struct repo *repo, struct repo_commit *commit,
+ TEHandle te);
struct repo_file *repo_add_file(struct repo *repo);
short repo_diff_file(struct repo *repo, struct repo_file *file);
short repo_checkout_file(struct repo *repo, struct repo_file *file,
+ short vrefnum, Str255 filename);
+void repo_export_diff(struct repo *repo, struct repo_commit *commit,
short vrefnum, Str255 filename);
void repo_commit(struct repo *repo, short *files, short nfiles, short adds,
short subs, Handle log, short loglen, Handle diff, unsigned long difflen);