jcs
/amend
/amendments
/15
browser+committer: Enable TETab on all TextEdits
Fix some logic errors in UpdateScrollbarForTE
jcs made amendment 15 over 3 years ago
--- browser.c Mon Oct 18 13:09:06 2021
+++ browser.c Thu Oct 21 17:37:32 2021
@@ -23,6 +23,7 @@
#include "committer.h"
#include "diff.h"
#include "repo.h"
+#include "tetab.h"
#include "util.h"
void browser_add_files(struct browser *browser);
@@ -144,12 +145,11 @@ browser_init(struct repo *repo)
bounds.left = padding;
bounds.right = browser->win->portRect.right - SCROLLBAR_WIDTH - padding;
bounds.bottom = browser->win->portRect.bottom - padding;
- TextFont(monaco);
- TextSize(9);
te_bounds = bounds;
InsetRect(&te_bounds, 2, 2);
- browser->diff_te = TENew(&te_bounds, &bounds);
+ browser->diff_te = TEStylNew(&te_bounds, &bounds);
TEAutoView(true, browser->diff_te);
+ TETabEnable(browser->diff_te);
/* scrollbar for diff text */
bounds.right = browser->win->portRect.right - padding;
@@ -325,7 +325,6 @@ browser_show_commit(struct browser *browser, struct re
SetCursor(&arrow);
}
- InvalRect(&(*(browser->diff_te))->viewRect);
UpdateScrollbarForTE(browser->diff_scroller, browser->diff_te, true);
}
@@ -404,7 +403,6 @@ browser_update(struct browser *browser, EventRecord *e
case updateEvt:
FillRect(&browser->win->portRect, fill_pattern);
- TextFont(monaco);
r = (*(browser->diff_te))->viewRect;
FillRect(&r, white);
TEUpdate(&r, browser->diff_te);
@@ -563,7 +561,7 @@ browser_mouse_down(struct browser *browser, EventRecor
if (adj != 0) {
val -= adj;
if (control == browser->diff_scroller)
- TEScroll(0, adj * (*(browser->diff_te))->lineHeight,
+ TEScroll(0, adj * TEGetHeight(0, 0, browser->diff_te),
browser->diff_te);
SetCtlValue(control, val);
}
--- committer.c Mon Oct 18 16:47:01 2021
+++ committer.c Fri Oct 22 10:23:36 2021
@@ -23,6 +23,7 @@
#include "committer.h"
#include "diff.h"
#include "repo.h"
+#include "tetab.h"
#include "util.h"
/* needed by diffreg */
@@ -30,10 +31,14 @@ struct stat stb1, stb2;
long diff_format, diff_context, status = 0;
char *ifdefname, *diffargs, *label[2], *ignore_pats;
-#define DIFF_LINE_SIZE 1024
+#define DIFF_LINE_SIZE 512
Handle diff_line = NULL;
size_t diff_line_pos = 0;
+#define DIFF_CHUNK_SIZE (1024 * 4)
+Handle diff_chunk = NULL;
+size_t diff_chunk_pos = 0;
+
static short padding = 10;
static short diff_too_big = 0;
@@ -46,7 +51,8 @@ void committer_generate_diff(struct committer *committ
void committer_update_menu(struct committer *committer);
void committer_status(char *format, ...);
void committer_commit(struct committer *committer);
-void diff_append_line(char *str, size_t len);
+void diff_append_line(char *str, size_t len, bool flush);
+void diff_chunk_write(void);
void diff_finish(void);
void
@@ -55,6 +61,7 @@ committer_init(struct browser *browser)
char title[256] = { 0 };
struct committer *committer;
Rect bounds = { 0 }, te_bounds = { 0 };
+ TextStyle style;
short fh;
committer = xmalloczero(sizeof(struct committer));
@@ -82,15 +89,19 @@ committer_init(struct browser *browser)
bounds.top = padding;
bounds.left = 50;
fh = FontHeight(monaco, 9);
- bounds.bottom = bounds.top + 2 + (fh * 5) + 2;
+ bounds.bottom = bounds.top + (fh * 5) + 2;
bounds.right = committer->win->portRect.right - SCROLLBAR_WIDTH -
padding;
- TextFont(monaco);
- TextSize(9);
te_bounds = bounds;
InsetRect(&te_bounds, 2, 2);
- committer->log_te = TENew(&te_bounds, &bounds);
+ TextFont(monaco);
+ TextSize(9);
+ committer->log_te = TEStylNew(&te_bounds, &bounds);
+ style.tsFont = monaco;
+ style.tsSize = 9;
+ TESetStyle(doFont | doSize, &style, false, committer->log_te);
TEAutoView(true, committer->log_te);
+ TETabEnable(committer->log_te);
/* scrollbar for log message */
bounds.left = bounds.right;
@@ -107,12 +118,11 @@ committer_init(struct browser *browser)
padding;
bounds.right = committer->win->portRect.right - SCROLLBAR_WIDTH -
padding;
- TextFont(monaco);
- TextSize(9);
te_bounds = bounds;
InsetRect(&te_bounds, 2, 2);
- committer->diff_te = TENew(&te_bounds, &bounds);
+ committer->diff_te = TEStylNew(&te_bounds, &bounds);
TEAutoView(true, committer->diff_te);
+ TETabEnable(committer->diff_te);
/* scrollbar for diff */
bounds.left = bounds.right;
@@ -153,10 +163,13 @@ committer_close(struct committer *committer)
DisposeWindow(committer->win);
TEDispose(committer->log_te);
DisposHandle(committer->log_scroller);
- TEDispose(committer->diff_te);
DisposHandle(committer->diff_scroller);
DisposHandle(committer->commit_button);
+ /* in case the hText got committed as a resource */
+ ReleaseResource((*(committer->log_te))->hText);
+ TEDispose(committer->diff_te);
+
free(committer);
}
@@ -179,14 +192,12 @@ committer_update(struct committer *committer, EventRec
switch (what) {
case -1:
case updateEvt:
+ r = (*(committer->log_te))->viewRect;
+ MoveTo(r.top, r.top + FontHeight(applFont, 11) - 2);
TextFont(applFont);
TextSize(11);
-
- r = (*(committer->log_te))->viewRect;
- MoveTo(r.top, r.top + FontHeight(applFont, 10) - 2);
DrawText("Log:", 0, 4);
- TextFont(monaco);
r = (*(committer->log_te))->viewRect;
TEUpdate(&r, committer->log_te);
InsetRect(&r, -1, -1);
@@ -228,7 +239,8 @@ committer_key_down(struct committer *committer, EventR
k = (event->message & charCodeMask);
TEKey(k, committer->log_te);
- UpdateScrollbarForTE(committer->log_scroller, committer->log_te, false);
+ UpdateScrollbarForTE(committer->log_scroller, committer->log_te,
+ false);
committer_update_menu(committer);
}
@@ -287,10 +299,10 @@ committer_mouse_down(struct committer *committer, Even
if (adj != 0) {
val -= adj;
if (control == committer->diff_scroller)
- TEScroll(0, adj * (*(committer->diff_te))->lineHeight,
+ TEScroll(0, adj * TEGetHeight(0, 0, committer->diff_te),
committer->diff_te);
else if (control == committer->log_scroller)
- TEScroll(0, adj * (*(committer->log_te))->lineHeight,
+ TEScroll(0, adj * TEGetHeight(0, 0, committer->log_te),
committer->log_te);
SetCtlValue(control, val);
}
@@ -335,6 +347,7 @@ committer_generate_diff(struct committer *committer)
short i;
short *selected_files = NULL;
short nselected_files = 0;
+ TextStyle style;
SetCursor(*(GetCursor(watchCursor)));
@@ -355,6 +368,10 @@ committer_generate_diff(struct committer *committer)
HLock(committer->diff_te);
+ style.tsFont = monaco;
+ style.tsSize = 9;
+ TESetStyle(doFont | doSize, &style, false, cur_committer->diff_te);
+
for (i = 0; i < nselected_files; i++) {
file = repo_file_with_id(committer->browser->repo,
selected_files[i]);
@@ -369,7 +386,8 @@ committer_generate_diff(struct committer *committer)
HUnlock(committer->diff_te);
InvalRect(&committer->win->portRect);
- UpdateScrollbarForTE(committer->diff_scroller, committer->diff_te, true);
+ UpdateScrollbarForTE(committer->diff_scroller, committer->diff_te,
+ true);
cur_committer = NULL;
committer_status(NULL);
@@ -476,7 +494,8 @@ diff_output(const char *format, ...)
for (i = last_pos; i < diff_line_pos; i++) {
if (((char *)*diff_line)[i] == '\n') {
((char *)*diff_line)[i] = '\r';
- diff_append_line(*diff_line + last_line, i - last_line + 1);
+ diff_append_line(*diff_line + last_line, i - last_line + 1,
+ false);
last_line = i + 1;
}
}
@@ -493,37 +512,56 @@ diff_output(const char *format, ...)
}
void
-diff_append_line(char *str, size_t len)
+diff_append_line(char *str, size_t len, bool flush)
{
- unsigned long cur_htext_size;
short tabsize;
- cur_htext_size = GetHandleSize((*(cur_committer->diff_te))->hText);
- if (cur_committer->diff_te_len + len >= cur_htext_size) {
- SetHandleSize((*(cur_committer->diff_te))->hText,
- cur_htext_size + (1024 * 4));
- if (MemError())
- err(1, "Out of memory! Can't expand diff TE beyond %lu bytes.",
- cur_htext_size);
+ if (diff_chunk == NULL) {
+ diff_chunk = xNewHandle(DIFF_CHUNK_SIZE);
+ diff_chunk_pos = 0;
}
+ if (str[0] == '-' && str[1] != '-')
+ cur_committer->diff_subs++;
+ else if (str[0] == '+' && str[1] != '+')
+ cur_committer->diff_adds++;
+
+ if (diff_chunk_pos + len >= DIFF_CHUNK_SIZE)
+ diff_chunk_write();
+
+ HLock(diff_chunk);
+ memcpy(*diff_chunk + diff_chunk_pos, str, len);
+ HUnlock(diff_chunk);
+ diff_chunk_pos += len;
+
+ if (flush)
+ diff_chunk_write();
+}
+
+void
+diff_chunk_write(void)
+{
+ HLock(diff_chunk);
+
+ if (cur_committer->diff_te_len + diff_chunk_pos > MAX_TEXTEDIT_SIZE) {
+ HUnlock((*(cur_committer->diff_te))->hText);
+ SetHandleSize((*(cur_committer->diff_te))->hText,
+ cur_committer->diff_te_len + diff_chunk_pos);
+ if (MemError())
+ err(1, "Out of memory! Can't expand diff TE by %lu bytes.",
+ diff_chunk_pos);
HLock((*(cur_committer->diff_te))->hText);
memcpy(*(*(cur_committer->diff_te))->hText +
- cur_committer->diff_te_len, str, len);
+ cur_committer->diff_te_len, *diff_chunk, diff_chunk_pos);
HUnlock((*(cur_committer->diff_te))->hText);
-
- cur_committer->diff_te_len += len;
-
- if (!diff_too_big && TECanAddLine(cur_committer->diff_te, len)) {
- (*(cur_committer->diff_te))->teLength = cur_committer->diff_te_len;
} else {
- diff_too_big = 1;
+ TEStylInsert(*diff_chunk, diff_chunk_pos, 0,
+ cur_committer->diff_te);
}
+ HUnlock(diff_chunk);
- if (str[0] == '-' && str[1] != '-')
- cur_committer->diff_subs++;
- else if (str[0] == '+' && str[1] != '+')
- cur_committer->diff_adds++;
+ cur_committer->diff_te_len += diff_chunk_pos;
+ diff_chunk_pos = 0;
}
void
@@ -531,26 +569,20 @@ diff_finish(void)
{
if (diff_line != NULL) {
if (diff_line_pos)
- diff_append_line(*diff_line, diff_line_pos);
+ diff_append_line(*diff_line, diff_line_pos, true);
DisposHandle(diff_line);
diff_line = NULL;
}
-#if 0
if (diff_chunk != NULL) {
- if (diff_chunk_pos) {
- TESetSelect(1024 * 32, 1024 * 32, cur_committer->diff_te);
- TEInsert((*diff_chunk), diff_chunk_pos,
- cur_committer->diff_te);
- }
-
- diff_chunk_pos = 0;
+ if (diff_chunk_pos)
+ diff_chunk_write();
DisposHandle(diff_chunk);
diff_chunk = NULL;
}
-#endif
+ HUnlock((*(cur_committer->diff_te))->hText);
SetHandleSize((*(cur_committer->diff_te))->hText,
cur_committer->diff_te_len);
TECalText(cur_committer->diff_te);
--- repo.c Mon Oct 18 17:12:17 2021
+++ repo.c Fri Oct 22 13:10:20 2021
@@ -331,23 +331,33 @@ repo_file_with_id(struct repo *repo, short id)
void
repo_show_diff_text(struct repo_commit *commit, TEHandle te)
{
- char buf[512];
- Handle diffh;
+ Handle diffh, allh;
+ TextStyle style;
struct tm *ttm = NULL;
- unsigned long diff_len;
- short header_len, i, blen;
+ char *buf;
+ char truncbuf[64];
+ unsigned long diff_len, all_len;
+ short header_len, i, blen, height, trunc = 0;
+ unsigned short warn_off;
diffh = Get1Resource(REPO_DIFF_RTYPE, commit->id);
if (diffh == NULL)
err(1, "failed finding DIFF %d", commit->id);
- HLock(diffh);
- HLock(commit->log);
-
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)
- LoadResource(diffh);
+ err(1, "diff still zero bytes");
+ }
+ buf = xmalloc(512);
ttm = localtime(&commit->date);
header_len = sprintf(buf,
"Author: %s\r"
@@ -357,32 +367,63 @@ repo_show_diff_text(struct repo_commit *commit, TEHand
ttm->tm_year + 1900, ttm->tm_mon + 1, ttm->tm_mday,
ttm->tm_hour, ttm->tm_min, ttm->tm_sec);
+ /* copy log, indenting each line */
+ HLock(commit->log);
for (i = 0; i < commit->log_len; i++) {
- buf[header_len++] = (*(commit->log))[i];
+ *(buf + header_len++) = (*(commit->log))[i];
if ((*(commit->log))[i] == '\r' && i < commit->log_len - 1) {
- buf[header_len++] = ' ';
- buf[header_len++] = ' ';
+ *(buf + header_len++) = ' ';
+ *(buf + header_len++) = ' ';
}
}
- buf[header_len++] = '\r';
- buf[header_len++] = '\r';
+ HUnlock(commit->log);
+ *(buf + header_len++) = '\r';
+ *(buf + header_len++) = '\r';
- TESetText("", 0, te);
- TEAppendFast(buf, header_len, te);
+ all_len = header_len + diff_len;
+ if (all_len >= MAX_TEXTEDIT_SIZE) {
+ all_len = MAX_TEXTEDIT_SIZE;
+ trunc = 1;
+ }
+ allh = xNewHandle(all_len);
- if (diff_len + header_len > 32767L) {
- diff_len = 32767L - header_len - strlen(REPO_DIFF_TOO_BIG) - 20;
- blen = sprintf(buf, REPO_DIFF_TOO_BIG,
- GetHandleSize(diffh) - diff_len);
- TEAppendFast(*diffh, diff_len, te);
- TEAppendFast(buf, blen, te);
- } else
- TEAppendFast(*diffh, diff_len, te);
+ /*
+ * A more memory-efficient method would be:
+ *
+ * DetachResource(diffh);
+ * SetHandleSize(diffh, all_len);
+ * memmove(*diffh, *diffh + header_len, all_len - header_len);
+ * memcpy(*diffh, buf, header_len);
+ *
+ * But memmove doesn't support overlapping buffers :/
+ */
+ HLock(allh);
+ memcpy(*allh, buf, header_len);
+ free(buf);
+
+ HLock(diffh);
+ memcpy(*allh + header_len, *diffh, all_len - header_len);
ReleaseResource(diffh);
- TECalText(te);
+ if (trunc) {
+ warn_off = MAX_TEXTEDIT_SIZE - header_len -
+ strlen(REPO_DIFF_TOO_BIG);
+ blen = sprintf(truncbuf, REPO_DIFF_TOO_BIG,
+ diff_len - warn_off);
+ memcpy(*allh + MAX_TEXTEDIT_SIZE - blen, truncbuf, blen);
+ }
+
+ TESetText("", 0, te);
+ /* manually reset scroll without TESetSelect(0, 0, te) which redraws */
+ height = (*te)->destRect.bottom - (*te)->destRect.top;
+ (*te)->destRect.top = (*te)->viewRect.top;
+ (*te)->destRect.bottom = (*te)->viewRect.top + height;
+ style.tsFont = monaco;
+ style.tsSize = 9;
+ TESetStyle(doFont | doSize, &style, false, te);
+ TEStylInsert(*allh, all_len, 0, te);
}
struct repo_file *
--- util.c Mon Oct 18 13:14:58 2021
+++ util.c Fri Oct 22 13:02:18 2021
@@ -460,32 +460,42 @@ DrawGrowIconOnly(WindowPtr win)
void
UpdateScrollbarForTE(ControlHandle scroller, TEHandle te, bool reset)
{
- size_t vlines;
+ size_t vlines, telines;
TERec *ter;
- short vtop;
+ short vtop, lheight;
+ short max, val;
HLock(te);
ter = *te;
- vlines = (ter->viewRect.bottom - ter->viewRect.top) / ter->lineHeight;
- if (vlines >= ter->nLines)
- vlines = ter->nLines;
- SetCtlMax(scroller, ter->nLines - vlines + 1);
+#define ceildiv(a,b) ((a / b) + (!!(a % b)))
- if (reset) {
- SetCtlValue(scroller, 1);
+ lheight = TEGetHeight(0, 0, te);
+ vlines = (ter->viewRect.bottom - ter->viewRect.top) / lheight;
+ telines = ter->nLines;
+ /* telines is inaccurate if the last line doesn't have any chars */
+ if (telines >= vlines)
+ telines++;
+ max = telines - vlines;
+ if (max < 1)
+ max = 1;
- /*
- * TESetSelect will redraw if TEAutoView is enabled, but only if
- * the control was scrolled already
- */
+ if (reset) {
+ val = 1;
vtop = (*te)->viewRect.top;
TESetSelect(0, 0, te);
- if (vtop == (*te)->viewRect.top)
- TEUpdate(&ter->viewRect, te);
- ValidRect(&ter->viewRect);
- } else if (GetCtlValue(scroller) > GetCtlMax(scroller))
- SetCtlValue(scroller, GetCtlMax(scroller));
+ } else {
+ val = (ter->viewRect.top - ter->destRect.top);
+ if (val < 0)
+ val = 1;
+ else {
+ val = ceildiv(val, lheight) + 1;
+ if (val > max)
+ max = val;
+ }
+ }
+ SetCtlMax(scroller, max);
+ SetCtlValue(scroller, val);
HUnlock(te);
}
@@ -499,15 +509,16 @@ SetTrackControlTE(TEHandle te)
pascal void
TrackMouseDownInControl(ControlHandle control, short part)
{
- short page, val, adj;
+ short page, val, adj, lheight;
if (track_control_te == NULL)
err(1, "TrackMouseDownInControl without SetTrackControlTE");
+ lheight = TEGetHeight(0, 0, track_control_te);
+
/* keep 1 line of context between pages */
page = (((*track_control_te)->viewRect.bottom -
- (*track_control_te)->viewRect.top) /
- (*track_control_te)->lineHeight) - 1;
+ (*track_control_te)->viewRect.top) / lheight) - 1;
adj = 0;
switch (part) {
@@ -533,7 +544,7 @@ TrackMouseDownInControl(ControlHandle control, short p
if (adj == 0)
return;
- TEScroll(0, -adj * (*track_control_te)->lineHeight, track_control_te);
+ TEScroll(0, -adj * lheight, track_control_te);
SetCtlValue(control, val + adj);
}
--- util.h Mon Oct 18 13:09:59 2021
+++ util.h Thu Oct 21 21:20:25 2021
@@ -27,6 +27,8 @@
#define SCROLLBAR_WIDTH 16
+#define MAX_TEXTEDIT_SIZE 32767L
+
#define nitems(what) (sizeof((what)) / sizeof((what)[0]))
#ifndef bool