Refactor windows into array and add /move

Oof.
master
C. McEnroe 2020-02-13 05:05:53 -05:00
parent ff518a8eb9
commit 92ccabaafd
4 changed files with 129 additions and 101 deletions

View File

@ -1,4 +1,4 @@
.Dd February 12, 2020 .Dd February 13, 2020
.Dt CATGIRL 1 .Dt CATGIRL 1
.Os .Os
. .
@ -286,6 +286,8 @@ Type
.Ic q .Ic q
to return to to return to
.Nm . .Nm .
.It Ic /move Oo Ar name Oc Ar num
Move named window to number.
.It Ic /open Op Ar count .It Ic /open Op Ar count
Open each of Open each of
.Ar count .Ar count

1
chat.h
View File

@ -169,6 +169,7 @@ void uiHide(void);
void uiDraw(void); void uiDraw(void);
void uiShowID(size_t id); void uiShowID(size_t id);
void uiShowNum(size_t num); void uiShowNum(size_t num);
void uiMoveID(size_t id, size_t num);
void uiCloseID(size_t id); void uiCloseID(size_t id);
void uiCloseNum(size_t id); void uiCloseNum(size_t id);
void uiRead(void); void uiRead(void);

View File

@ -159,6 +159,17 @@ static void commandWindow(size_t id, char *params) {
} }
} }
static void commandMove(size_t id, char *params) {
if (!params) return;
char *name = strsep(&params, " ");
if (params) {
id = idFind(name);
if (id) uiMoveID(id, strtoul(params, NULL, 10));
} else {
uiMoveID(id, strtoul(name, NULL, 10));
}
}
static void commandClose(size_t id, char *params) { static void commandClose(size_t id, char *params) {
if (!params) { if (!params) {
uiCloseID(id); uiCloseID(id);
@ -213,6 +224,7 @@ static const struct Handler {
{ "/join", .fn = commandJoin, .restricted = true }, { "/join", .fn = commandJoin, .restricted = true },
{ "/list", .fn = commandList }, { "/list", .fn = commandList },
{ "/me", .fn = commandMe }, { "/me", .fn = commandMe },
{ "/move", .fn = commandMove },
{ "/msg", .fn = commandMsg, .restricted = true }, { "/msg", .fn = commandMsg, .restricted = true },
{ "/names", .fn = commandNames }, { "/names", .fn = commandNames },
{ "/nick", .fn = commandNick }, { "/nick", .fn = commandNick },

213
ui.c
View File

@ -86,38 +86,52 @@ struct Window {
enum Heat heat; enum Heat heat;
int unreadCount; int unreadCount;
int unreadLines; int unreadLines;
struct Window *prev;
struct Window *next;
}; };
static struct { static struct {
struct Window *active; size_t show;
struct Window *other; size_t swap;
struct Window *head; struct Window *ptrs[IDCap];
struct Window *tail; size_t len;
} windows; } windows;
static void windowAdd(struct Window *window) { static size_t windowPush(struct Window *window) {
if (windows.tail) windows.tail->next = window; assert(windows.len < IDCap);
window->prev = windows.tail; windows.ptrs[windows.len] = window;
window->next = NULL; return windows.len++;
windows.tail = window;
if (!windows.head) windows.head = window;
} }
static void windowRemove(struct Window *window) { static size_t windowInsert(size_t num, struct Window *window) {
if (window->prev) window->prev->next = window->next; assert(windows.len < IDCap);
if (window->next) window->next->prev = window->prev; assert(num <= windows.len);
if (windows.head == window) windows.head = window->next; memmove(
if (windows.tail == window) windows.tail = window->prev; &windows.ptrs[num + 1],
&windows.ptrs[num],
sizeof(*windows.ptrs) * (windows.len - num)
);
windows.ptrs[num] = window;
windows.len++;
return num;
} }
static struct Window *windowFor(size_t id) { static struct Window *windowRemove(size_t num) {
struct Window *window; assert(num < windows.len);
for (window = windows.head; window; window = window->next) { struct Window *window = windows.ptrs[num];
if (window->id == id) return window; windows.len--;
memmove(
&windows.ptrs[num],
&windows.ptrs[num + 1],
sizeof(*windows.ptrs) * (windows.len - num)
);
return window;
}
static size_t windowFor(size_t id) {
for (size_t num = 0; num < windows.len; ++num) {
if (windows.ptrs[num]->id == id) return num;
} }
window = calloc(1, sizeof(*window));
struct Window *window = calloc(1, sizeof(*window));
if (!window) err(EX_OSERR, "malloc"); if (!window) err(EX_OSERR, "malloc");
window->id = id; window->id = id;
@ -127,8 +141,15 @@ static struct Window *windowFor(size_t id) {
wmove(window->pad, WindowLines - 1, 0); wmove(window->pad, WindowLines - 1, 0);
window->mark = true; window->mark = true;
windowAdd(window); return windowPush(window);
return window; }
static void windowFree(struct Window *window) {
for (size_t i = 0; i < BufferCap; ++i) {
free(window->buffer.lines[i]);
}
delwin(window->pad);
free(window);
} }
static short colorPairs; static short colorPairs;
@ -256,7 +277,7 @@ void uiInit(void) {
keypad(input, true); keypad(input, true);
nodelay(input, true); nodelay(input, true);
windows.active = windowFor(Network); windowFor(Network);
uiShow(); uiShow();
} }
@ -269,7 +290,7 @@ static char prevTitle[sizeof(title)];
void uiDraw(void) { void uiDraw(void) {
if (hidden) return; if (hidden) return;
wnoutrefresh(status); wnoutrefresh(status);
struct Window *window = windows.active; const struct Window *window = windows.ptrs[windows.show];
pnoutrefresh( pnoutrefresh(
window->pad, window->pad,
WindowLines - window->scroll - PAGE_LINES + !!window->scroll, 0, WindowLines - window->scroll - PAGE_LINES + !!window->scroll, 0,
@ -381,19 +402,18 @@ static void statusUpdate(void) {
enum Heat otherHeat = Cold; enum Heat otherHeat = Cold;
wmove(status, 0, 0); wmove(status, 0, 0);
int num; for (size_t num = 0; num < windows.len; ++num) {
const struct Window *window; const struct Window *window = windows.ptrs[num];
for (num = 0, window = windows.head; window; ++num, window = window->next) { if (!window->heat && num != windows.show) continue;
if (!window->heat && window != windows.active) continue; if (num != windows.show) {
if (window != windows.active) {
otherUnread += window->unreadCount; otherUnread += window->unreadCount;
if (window->heat > otherHeat) otherHeat = window->heat; if (window->heat > otherHeat) otherHeat = window->heat;
} }
int trunc; int trunc;
char buf[256]; char buf[256];
snprintf( snprintf(
buf, sizeof(buf), "\3%d%s %d %s %n(\3%02d%d\3%d) ", buf, sizeof(buf), "\3%d%s %zu %s %n(\3%02d%d\3%d) ",
idColors[window->id], (window == windows.active ? "\26" : ""), idColors[window->id], (num == windows.show ? "\26" : ""),
num, idNames[window->id], num, idNames[window->id],
&trunc, (window->heat > Warm ? White : idColors[window->id]), &trunc, (window->heat > Warm ? White : idColors[window->id]),
window->unreadCount, window->unreadCount,
@ -404,7 +424,7 @@ static void statusUpdate(void) {
} }
wclrtoeol(status); wclrtoeol(status);
window = windows.active; const struct Window *window = windows.ptrs[windows.show];
snprintf(title, sizeof(title), "%s %s", self.network, idNames[window->id]); snprintf(title, sizeof(title), "%s %s", self.network, idNames[window->id]);
if (window->mark && window->unreadCount) { if (window->mark && window->unreadCount) {
snprintf( snprintf(
@ -441,11 +461,11 @@ void uiShow(void) {
putp(EnterPasteMode); putp(EnterPasteMode);
fflush(stdout); fflush(stdout);
hidden = false; hidden = false;
unmark(windows.active); unmark(windows.ptrs[windows.show]);
} }
void uiHide(void) { void uiHide(void) {
mark(windows.active); mark(windows.ptrs[windows.show]);
hidden = true; hidden = true;
putp(ExitFocusMode); putp(ExitFocusMode);
putp(ExitPasteMode); putp(ExitPasteMode);
@ -560,7 +580,7 @@ static void notify(size_t id, const char *str) {
} }
void uiWrite(size_t id, enum Heat heat, const time_t *src, const char *str) { void uiWrite(size_t id, enum Heat heat, const time_t *src, const char *str) {
struct Window *window = windowFor(id); struct Window *window = windows.ptrs[windowFor(id)];
time_t clock = (src ? *src : time(NULL)); time_t clock = (src ? *src : time(NULL));
bufferPush(&window->buffer, clock, str); bufferPush(&window->buffer, clock, str);
@ -614,11 +634,11 @@ static void reflow(struct Window *window) {
static void resize(void) { static void resize(void) {
mvwin(marker, LINES - 2, 0); mvwin(marker, LINES - 2, 0);
int height, width; int height, width;
getmaxyx(windows.active->pad, height, width); getmaxyx(windows.ptrs[0]->pad, height, width);
if (width == COLS) return; if (width == COLS) return;
for (struct Window *window = windows.head; window; window = window->next) { for (size_t num = 0; num < windows.len; ++num) {
wresize(window->pad, BufferCap, COLS); wresize(windows.ptrs[num]->pad, BufferCap, COLS);
reflow(window); reflow(windows.ptrs[num]);
} }
(void)height; (void)height;
statusUpdate(); statusUpdate();
@ -690,7 +710,7 @@ static void inputAdd(struct Style *style, const char *str) {
} }
static void inputUpdate(void) { static void inputUpdate(void) {
size_t id = windows.active->id; size_t id = windows.ptrs[windows.show]->id;
size_t pos; size_t pos;
char *buf = editBuffer(&pos); char *buf = editBuffer(&pos);
@ -743,13 +763,12 @@ static void inputUpdate(void) {
wmove(input, y, x); wmove(input, y, x);
} }
static void windowShow(struct Window *window) { static void windowShow(size_t num) {
if (!window) return; touchwin(windows.ptrs[num]->pad);
touchwin(window->pad); windows.swap = windows.show;
windows.other = windows.active; windows.show = num;
windows.active = window; mark(windows.ptrs[windows.swap]);
mark(windows.other); unmark(windows.ptrs[windows.show]);
unmark(windows.active);
inputUpdate(); inputUpdate();
} }
@ -758,31 +777,29 @@ void uiShowID(size_t id) {
} }
void uiShowNum(size_t num) { void uiShowNum(size_t num) {
struct Window *window = windows.head; if (num < windows.len) windowShow(num);
for (size_t i = 0; i < num; ++i) {
window = window->next;
if (!window) return;
}
windowShow(window);
} }
static void windowClose(struct Window *window) { void uiMoveID(size_t id, size_t num) {
if (window->id == Network) return; struct Window *window = windowRemove(windowFor(id));
if (num < windows.len) {
windowShow(windowInsert(num, window));
} else {
windowShow(windowPush(window));
}
}
static void windowClose(size_t num) {
if (windows.ptrs[num]->id == Network) return;
struct Window *window = windowRemove(num);
completeClear(window->id); completeClear(window->id);
if (windows.active == window) { windowFree(window);
if (windows.other && windows.other != window) { if (windows.swap >= num) windows.swap--;
windowShow(windows.other); if (windows.show == num) {
} else { windowShow(windows.swap);
windowShow(window->prev ? window->prev : window->next); } else if (windows.show > num) {
} windows.show--;
} }
if (windows.other == window) windows.other = NULL;
windowRemove(window);
for (size_t i = 0; i < BufferCap; ++i) {
free(window->buffer.lines[i]);
}
delwin(window->pad);
free(window);
statusUpdate(); statusUpdate();
} }
@ -791,36 +808,31 @@ void uiCloseID(size_t id) {
} }
void uiCloseNum(size_t num) { void uiCloseNum(size_t num) {
struct Window *window = windows.head; if (num < windows.len) windowClose(num);
for (size_t i = 0; i < num; ++i) {
window = window->next;
if (!window) return;
}
windowClose(window);
} }
static void showAuto(void) { static void showAuto(void) {
static struct Window *other; static size_t swap;
if (windows.other != other) { if (windows.swap != swap) {
other = windows.active; swap = windows.show;
} }
for (struct Window *window = windows.head; window; window = window->next) { for (size_t num = 0; num < windows.len; ++num) {
if (window->heat < Hot) continue; if (windows.ptrs[num]->heat < Hot) continue;
windowShow(window); windowShow(num);
windows.other = other; windows.swap = swap;
return; return;
} }
for (struct Window *window = windows.head; window; window = window->next) { for (size_t num = 0; num < windows.len; ++num) {
if (window->heat < Warm) continue; if (windows.ptrs[num]->heat < Warm) continue;
windowShow(window); windowShow(num);
windows.other = other; windows.swap = swap;
return; return;
} }
windowShow(windows.other); windowShow(windows.swap);
} }
static void keyCode(int code) { static void keyCode(int code) {
struct Window *window = windows.active; struct Window *window = windows.ptrs[windows.show];
size_t id = window->id; size_t id = window->id;
switch (code) { switch (code) {
break; case KEY_RESIZE: resize(); break; case KEY_RESIZE: resize();
@ -829,7 +841,7 @@ static void keyCode(int code) {
break; case KeyPasteOn:; // TODO break; case KeyPasteOn:; // TODO
break; case KeyPasteOff:; // TODO break; case KeyPasteOff:; // TODO
break; case KeyMetaSlash: windowShow(windows.other); break; case KeyMetaSlash: windowShow(windows.swap);
break; case KeyMetaA: showAuto(); break; case KeyMetaA: showAuto();
break; case KeyMetaB: edit(id, EditPrevWord, 0); break; case KeyMetaB: edit(id, EditPrevWord, 0);
@ -861,7 +873,8 @@ static void keyCode(int code) {
} }
static void keyCtrl(wchar_t ch) { static void keyCtrl(wchar_t ch) {
size_t id = windows.active->id; struct Window *window = windows.ptrs[windows.show];
size_t id = window->id;
switch (ch ^ L'@') { switch (ch ^ L'@') {
break; case L'?': edit(id, EditDeletePrev, 0); break; case L'?': edit(id, EditDeletePrev, 0);
break; case L'A': edit(id, EditHead, 0); break; case L'A': edit(id, EditHead, 0);
@ -875,19 +888,19 @@ static void keyCtrl(wchar_t ch) {
break; case L'J': edit(id, EditEnter, 0); break; case L'J': edit(id, EditEnter, 0);
break; case L'K': edit(id, EditDeleteTail, 0); break; case L'K': edit(id, EditDeleteTail, 0);
break; case L'L': clearok(curscr, true); break; case L'L': clearok(curscr, true);
break; case L'N': windowShow(windows.active->next); break; case L'N': uiShowNum(windows.show + 1);
break; case L'O': windowShow(windows.other); break; case L'O': windowShow(windows.swap);
break; case L'P': windowShow(windows.active->prev); break; case L'P': uiShowNum(windows.show - 1);
break; case L'T': edit(id, EditTranspose, 0); break; case L'T': edit(id, EditTranspose, 0);
break; case L'U': edit(id, EditDeleteHead, 0); break; case L'U': edit(id, EditDeleteHead, 0);
break; case L'V': windowScroll(windows.active, -(PAGE_LINES - 2)); break; case L'V': windowScroll(window, -(PAGE_LINES - 2));
break; case L'W': edit(id, EditDeletePrevWord, 0); break; case L'W': edit(id, EditDeletePrevWord, 0);
break; case L'Y': edit(id, EditPaste, 0); break; case L'Y': edit(id, EditPaste, 0);
} }
} }
static void keyStyle(wchar_t ch) { static void keyStyle(wchar_t ch) {
size_t id = windows.active->id; size_t id = windows.ptrs[windows.show]->id;
switch (iswcntrl(ch) ? ch ^ L'@' : (wchar_t)towupper(ch)) { switch (iswcntrl(ch) ? ch ^ L'@' : (wchar_t)towupper(ch)) {
break; case L'B': edit(id, EditInsert, B); break; case L'B': edit(id, EditInsert, B);
break; case L'C': edit(id, EditInsert, C); break; case L'C': edit(id, EditInsert, C);
@ -923,7 +936,7 @@ void uiRead(void) {
} else if (iswcntrl(ch)) { } else if (iswcntrl(ch)) {
keyCtrl(ch); keyCtrl(ch);
} else { } else {
edit(windows.active->id, EditInsert, ch); edit(windows.ptrs[windows.show]->id, EditInsert, ch);
} }
style = false; style = false;
} }
@ -953,8 +966,8 @@ int uiSave(const char *name) {
if (!file) return -1; if (!file) return -1;
if (writeTime(file, Signatures[0])) return -1; if (writeTime(file, Signatures[0])) return -1;
const struct Window *window; for (size_t num = 0; num < windows.len; ++num) {
for (window = windows.head; window; window = window->next) { const struct Window *window = windows.ptrs[num];
if (writeString(file, idNames[window->id])) return -1; if (writeString(file, idNames[window->id])) return -1;
for (size_t i = 0; i < BufferCap; ++i) { for (size_t i = 0; i < BufferCap; ++i) {
time_t time = bufferTime(&window->buffer, i); time_t time = bufferTime(&window->buffer, i);
@ -1003,7 +1016,7 @@ void uiLoad(const char *name) {
char *buf = NULL; char *buf = NULL;
size_t cap = 0; size_t cap = 0;
while (0 < readString(file, &buf, &cap)) { while (0 < readString(file, &buf, &cap)) {
struct Window *window = windowFor(idFor(buf)); struct Window *window = windows.ptrs[windowFor(idFor(buf))];
for (;;) { for (;;) {
time_t time = readTime(file); time_t time = readTime(file);
if (!time) break; if (!time) break;