summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ui.c195
1 files changed, 104 insertions, 91 deletions
diff --git a/ui.c b/ui.c
index e261289..f0e7b85 100644
--- a/ui.c
+++ b/ui.c
@@ -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);
+ 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);
+ 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 (;;) {