Various small cleanup in ui.c

master
C. McEnroe 2020-02-19 01:18:09 -05:00
parent 460207440b
commit 026a8ca979
1 changed files with 105 additions and 92 deletions

197
ui.c
View File

@ -79,14 +79,14 @@ static const char *bufferLine(const struct Buffer *buffer, size_t i) {
enum { WindowLines = BufferCap };
struct Window {
uint id;
struct Buffer buffer;
WINDOW *pad;
int scroll;
bool mark;
enum Heat heat;
uint unreadTotal;
uint unread;
uint unreadWarm;
uint unreadLines;
struct Buffer buffer;
};
static struct {
@ -186,36 +186,6 @@ static short colorPair(short fg, short bg) {
return colorPairs++;
}
// XXX: Assuming terminals will be fine with these even if they're unsupported,
// since they're "private" modes.
static const char *EnterFocusMode = "\33[?1004h";
static const char *ExitFocusMode = "\33[?1004l";
static const char *EnterPasteMode = "\33[?2004h";
static const char *ExitPasteMode = "\33[?2004l";
// Gain use of C-q, C-s, C-c, C-z, C-y, C-v, C-o.
static void acquireKeys(void) {
struct termios term;
int error = tcgetattr(STDOUT_FILENO, &term);
if (error) err(EX_OSERR, "tcgetattr");
term.c_iflag &= ~IXON;
term.c_cc[VINTR] = _POSIX_VDISABLE;
term.c_cc[VSUSP] = _POSIX_VDISABLE;
#ifdef VDSUSP
term.c_cc[VDSUSP] = _POSIX_VDISABLE;
#endif
term.c_cc[VLNEXT] = _POSIX_VDISABLE;
term.c_cc[VDISCARD] = _POSIX_VDISABLE;
error = tcsetattr(STDOUT_FILENO, TCSADRAIN, &term);
if (error) err(EX_OSERR, "tcsetattr");
}
static void errExit(void) {
putp(ExitFocusMode);
putp(ExitPasteMode);
reset_shell_mode();
}
#define ENUM_KEY \
X(KeyMeta0, "\0330", "\33)") \
X(KeyMeta1, "\0331", "\33!") \
@ -248,6 +218,36 @@ enum {
#undef X
};
// Gain use of C-q, C-s, C-c, C-z, C-y, C-v, C-o.
static void acquireKeys(void) {
struct termios term;
int error = tcgetattr(STDOUT_FILENO, &term);
if (error) err(EX_OSERR, "tcgetattr");
term.c_iflag &= ~IXON;
term.c_cc[VINTR] = _POSIX_VDISABLE;
term.c_cc[VSUSP] = _POSIX_VDISABLE;
#ifdef VDSUSP
term.c_cc[VDSUSP] = _POSIX_VDISABLE;
#endif
term.c_cc[VLNEXT] = _POSIX_VDISABLE;
term.c_cc[VDISCARD] = _POSIX_VDISABLE;
error = tcsetattr(STDOUT_FILENO, TCSADRAIN, &term);
if (error) err(EX_OSERR, "tcsetattr");
}
// XXX: Assuming terminals will be fine with these even if they're unsupported,
// since they're "private" modes.
static const char *EnterFocusMode = "\33[?1004h";
static const char *ExitFocusMode = "\33[?1004l";
static const char *EnterPasteMode = "\33[?2004h";
static const char *ExitPasteMode = "\33[?2004l";
static void errExit(void) {
putp(ExitFocusMode);
putp(ExitPasteMode);
reset_shell_mode();
}
void uiInit(void) {
initscr();
cbreak();
@ -273,7 +273,7 @@ void uiInit(void) {
short fg = 8 + COLOR_BLACK;
wbkgd(marker, '~' | colorAttr(fg) | COLOR_PAIR(colorPair(fg, -1)));
input = newpad(1, 512);
input = newpad(1, 1024);
if (!input) err(EX_OSERR, "newpad");
keypad(input, true);
nodelay(input, true);
@ -357,7 +357,7 @@ static const short Colors[ColorCap] = {
enum { B = '\2', C = '\3', O = '\17', R = '\26', I = '\35', U = '\37' };
static void styleParse(struct Style *style, const char **str, size_t *len) {
static size_t styleParse(struct Style *style, const char **str) {
switch (**str) {
break; case B: (*str)++; style->attr ^= A_BOLD;
break; case O: (*str)++; *style = Reset;
@ -379,14 +379,13 @@ static void styleParse(struct Style *style, const char **str, size_t *len) {
if (isdigit(**str)) style->bg = style->bg * 10 + *(*str)++ - '0';
}
}
*len = strcspn(*str, (const char[]) { B, C, O, R, I, U, '\0' });
return strcspn(*str, (const char[]) { B, C, O, R, I, U, '\0' });
}
static void statusAdd(const char *str) {
size_t len;
struct Style style = Reset;
while (*str) {
styleParse(&style, &str, &len);
size_t len = styleParse(&style, &str);
wattr_set(
status,
style.attr | colorAttr(Colors[style.fg]),
@ -399,16 +398,18 @@ static void statusAdd(const char *str) {
}
static void statusUpdate(void) {
int otherUnread = 0;
enum Heat otherHeat = Cold;
wmove(status, 0, 0);
struct {
uint unread;
enum Heat heat;
} others = { 0, Cold };
wmove(status, 0, 0);
for (uint num = 0; num < windows.len; ++num) {
const struct Window *window = windows.ptrs[num];
if (!window->heat && num != windows.show) continue;
if (num != windows.show) {
otherUnread += window->unreadWarm;
if (window->heat > otherHeat) otherHeat = window->heat;
others.unread += window->unreadWarm;
if (window->heat > others.heat) others.heat = window->heat;
}
int trunc;
char buf[256];
@ -433,10 +434,10 @@ static void statusUpdate(void) {
window->unreadWarm, (window->heat > Warm ? "!" : "")
);
}
if (otherUnread) {
if (others.unread) {
catf(
title, sizeof(title), " (+%d%s)",
otherUnread, (otherHeat > Warm ? "!" : "")
others.unread, (others.heat > Warm ? "!" : "")
);
}
}
@ -444,7 +445,7 @@ static void statusUpdate(void) {
static void mark(struct Window *window) {
if (window->scroll) return;
window->mark = true;
window->unreadTotal = 0;
window->unread = 0;
window->unreadWarm = 0;
window->unreadLines = 0;
}
@ -508,9 +509,9 @@ static int wordWidth(const char *str) {
static int wordWrap(WINDOW *win, const char *str) {
int y, x, width;
getmaxyx(win, y, width);
waddch(win, '\n');
size_t len;
int lines = 0;
int lines = 1;
int align = 0;
struct Style style = Reset;
while (*str) {
@ -538,9 +539,10 @@ static int wordWrap(WINDOW *win, const char *str) {
}
}
styleParse(&style, &str, &len);
size_t len = styleParse(&style, &str);
size_t ws = strcspn(str, "\t ");
if (ws < len) len = ws;
if (!len) continue;
wattr_set(
win,
@ -562,9 +564,8 @@ static void notify(uint id, const char *str) {
utilPush(&util, idNames[id]);
char buf[1024] = "";
while (*str) {
size_t len;
struct Style style = Reset;
styleParse(&style, &str, &len);
size_t len = styleParse(&style, &str);
catf(buf, sizeof(buf), "%.*s", (int)len, str);
str += len;
}
@ -584,23 +585,24 @@ static void notify(uint id, const char *str) {
void uiWrite(uint id, enum Heat heat, const time_t *src, const char *str) {
struct Window *window = windows.ptrs[windowFor(id)];
time_t clock = (src ? *src : time(NULL));
bufferPush(&window->buffer, clock, str);
time_t ts = (src ? *src : time(NULL));
bufferPush(&window->buffer, ts, str);
int lines = 1;
waddch(window->pad, '\n');
window->unreadTotal++;
int lines = 0;
window->unread++;
if (window->mark && heat > Cold) {
if (window->heat < heat) window->heat = heat;
if (!window->unreadWarm++) {
waddch(window->pad, '\n');
lines++;
waddch(window->pad, '\n');
}
if (heat > window->heat) window->heat = heat;
statusUpdate();
}
lines += wordWrap(window->pad, str);
window->unreadLines += lines;
if (window->scroll) windowScroll(window, lines);
if (window->mark && heat > Warm) {
beep();
notify(id, str);
@ -622,18 +624,19 @@ void uiFormat(
static void reflow(struct Window *window) {
werase(window->pad);
wmove(window->pad, 0, 0);
int flowed = 0;
window->unreadLines = 0;
for (size_t i = 0; i < BufferCap; ++i) {
const char *line = bufferLine(&window->buffer, i);
if (!line) continue;
waddch(window->pad, '\n');
int lines = 1 + wordWrap(window->pad, line);
if (i >= (size_t)(BufferCap - window->unreadTotal)) {
int lines = wordWrap(window->pad, line);
if (i >= (size_t)(BufferCap - window->unread)) {
window->unreadLines += lines;
}
flowed += lines;
}
if (flowed < WindowLines) {
wscrl(window->pad, -(WindowLines - 1 - flowed));
wmove(window->pad, WindowLines - 1, RIGHT);
@ -656,19 +659,20 @@ static void resize(void) {
static void bufferList(const struct Buffer *buffer) {
uiHide();
waiting = true;
for (size_t i = 0; i < BufferCap; ++i) {
time_t time = bufferTime(buffer, i);
const char *line = bufferLine(buffer, i);
if (!line) continue;
time_t time = bufferTime(buffer, i);
struct tm *tm = localtime(&time);
if (!tm) continue;
char buf[sizeof("[00:00:00]")];
strftime(buf, sizeof(buf), "[%T]", tm);
vid_attr(colorAttr(Colors[Gray]), colorPair(Colors[Gray], -1), NULL);
printf("%s ", buf);
if (!tm) err(EX_OSERR, "localtime");
char buf[sizeof("00:00:00")];
strftime(buf, sizeof(buf), "%T", tm);
vid_attr(colorAttr(Colors[Gray]), colorPair(Colors[Gray], -1), NULL);
printf("[%s] ", buf);
size_t len;
bool align = false;
struct Style style = Reset;
while (*line) {
@ -677,15 +681,18 @@ static void bufferList(const struct Buffer *buffer) {
align = true;
line++;
}
styleParse(&style, &line, &len);
size_t len = styleParse(&style, &line);
size_t tab = strcspn(line, "\t");
if (tab < len) len = tab;
if (!len) continue;
vid_attr(
style.attr | colorAttr(Colors[style.fg]),
colorPair(Colors[style.fg], Colors[style.bg]),
NULL
);
if (len) printf("%.*s", (int)len, line);
printf("%.*s", (int)len, line);
line += len;
}
printf("\n");
@ -693,10 +700,9 @@ static void bufferList(const struct Buffer *buffer) {
}
static void inputAdd(struct Style *style, const char *str) {
size_t len;
while (*str) {
const char *code = str;
styleParse(style, &str, &len);
size_t len = styleParse(style, &str);
wattr_set(input, A_BOLD | A_REVERSE, 0, NULL);
switch (*code) {
break; case B: waddch(input, 'B');
@ -707,6 +713,7 @@ static void inputAdd(struct Style *style, const char *str) {
break; case U: waddch(input, 'U');
}
if (str - code > 1) waddnstr(input, &code[1], str - &code[1]);
if (!len) continue;
wattr_set(
input,
style->attr | colorAttr(Colors[style->fg]),
@ -719,52 +726,58 @@ static void inputAdd(struct Style *style, const char *str) {
}
static void inputUpdate(void) {
uint id = windows.ptrs[windows.show]->id;
size_t pos;
char *buf = editBuffer(&pos);
uint id = windows.ptrs[windows.show]->id;
const char *skip = NULL;
struct Style init = { .fg = self.color, .bg = Default };
struct Style rest = Reset;
const char *prefix = "";
const char *prompt = self.nick;
const char *suffix = "";
if (NULL != (skip = commandIsPrivmsg(id, buf))) {
const char *skip = buf;
struct Style stylePrompt = { .fg = self.color, .bg = Default };
struct Style styleInput = Reset;
const char *privmsg = commandIsPrivmsg(id, buf);
const char *notice = commandIsNotice(id, buf);
const char *action = commandIsAction(id, buf);
if (privmsg) {
prefix = "<"; suffix = "> ";
} else if (NULL != (skip = commandIsNotice(id, buf))) {
skip = privmsg;
} else if (notice) {
prefix = "-"; suffix = "- ";
rest.fg = LightGray;
} else if (NULL != (skip = commandIsAction(id, buf))) {
init.attr |= A_ITALIC;
styleInput.fg = LightGray;
skip = notice;
} else if (action) {
prefix = "* "; suffix = " ";
rest.attr |= A_ITALIC;
stylePrompt.attr |= A_ITALIC;
styleInput.attr |= A_ITALIC;
skip = action;
} else if (id == Debug && buf[0] != '/') {
skip = buf;
init.fg = Gray;
prompt = "<< ";
stylePrompt.fg = Gray;
} else {
prompt = "";
}
if (skip && skip > &buf[pos]) {
skip = NULL;
if (skip > &buf[pos]) {
prefix = prompt = suffix = "";
skip = buf;
}
int y, x;
wmove(input, 0, 0);
wattr_set(
input,
init.attr | colorAttr(Colors[init.fg]),
colorPair(Colors[init.fg], Colors[init.bg]),
stylePrompt.attr | colorAttr(Colors[stylePrompt.fg]),
colorPair(Colors[stylePrompt.fg], Colors[stylePrompt.bg]),
NULL
);
waddstr(input, prefix);
waddstr(input, prompt);
waddstr(input, suffix);
struct Style style = rest;
struct Style style = styleInput;
char p = buf[pos];
buf[pos] = '\0';
inputAdd(&style, (skip ? skip : buf));
inputAdd(&style, skip);
getyx(input, y, x);
buf[pos] = p;
inputAdd(&style, &buf[pos]);
@ -954,7 +967,7 @@ void uiRead(void) {
}
static const time_t Signatures[] = {
0x6C72696774616301, // no heat, unreadTotal, unreadWarm
0x6C72696774616301, // no heat, unread, unreadWarm
0x6C72696774616302,
};
@ -981,7 +994,7 @@ int uiSave(const char *name) {
const struct Window *window = windows.ptrs[num];
if (writeString(file, idNames[window->id])) return -1;
if (writeTime(file, window->heat)) return -1;
if (writeTime(file, window->unreadTotal)) return -1;
if (writeTime(file, window->unread)) return -1;
if (writeTime(file, window->unreadWarm)) return -1;
for (size_t i = 0; i < BufferCap; ++i) {
time_t time = bufferTime(&window->buffer, i);
@ -1033,7 +1046,7 @@ void uiLoad(const char *name) {
struct Window *window = windows.ptrs[windowFor(idFor(buf))];
if (version > 0) {
window->heat = readTime(file);
window->unreadTotal = readTime(file);
window->unread = readTime(file);
window->unreadWarm = readTime(file);
}
for (;;) {