parent
ccb54d36d9
commit
240f9ebf84
12
chat.c
12
chat.c
|
@ -60,7 +60,7 @@ static union {
|
||||||
|
|
||||||
void spawn(char *const argv[]) {
|
void spawn(char *const argv[]) {
|
||||||
if (fds.pipe.events) {
|
if (fds.pipe.events) {
|
||||||
uiLog(TAG_STATUS, UI_WARM, L"spawn: existing pipe");
|
uiLog(TagStatus, UIWarm, L"spawn: existing pipe");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ static void pipeRead(void) {
|
||||||
if (len) {
|
if (len) {
|
||||||
buf[len] = '\0';
|
buf[len] = '\0';
|
||||||
len = strcspn(buf, "\n");
|
len = strcspn(buf, "\n");
|
||||||
uiFmt(TAG_STATUS, UI_WARM, "spawn: %.*s", (int)len, buf);
|
uiFmt(TagStatus, UIWarm, "spawn: %.*s", (int)len, buf);
|
||||||
} else {
|
} else {
|
||||||
close(fds.pipe.fd);
|
close(fds.pipe.fd);
|
||||||
fds.pipe.events = 0;
|
fds.pipe.events = 0;
|
||||||
|
@ -124,15 +124,15 @@ static void sigchld(int sig) {
|
||||||
pid_t pid = wait(&status);
|
pid_t pid = wait(&status);
|
||||||
if (pid < 0) err(EX_OSERR, "wait");
|
if (pid < 0) err(EX_OSERR, "wait");
|
||||||
if (WIFEXITED(status) && WEXITSTATUS(status)) {
|
if (WIFEXITED(status) && WEXITSTATUS(status)) {
|
||||||
uiFmt(TAG_STATUS, UI_WARM, "spawn: exit %d", WEXITSTATUS(status));
|
uiFmt(TagStatus, UIWarm, "spawn: exit %d", WEXITSTATUS(status));
|
||||||
} else if (WIFSIGNALED(status)) {
|
} else if (WIFSIGNALED(status)) {
|
||||||
uiFmt(TAG_STATUS, UI_WARM, "spawn: signal %d", WTERMSIG(status));
|
uiFmt(TagStatus, UIWarm, "spawn: signal %d", WTERMSIG(status));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sigint(int sig) {
|
static void sigint(int sig) {
|
||||||
(void)sig;
|
(void)sig;
|
||||||
input(TAG_STATUS, "/quit");
|
input(TagStatus, "/quit");
|
||||||
uiExit();
|
uiExit();
|
||||||
exit(EX_OK);
|
exit(EX_OK);
|
||||||
}
|
}
|
||||||
|
@ -183,7 +183,7 @@ int main(int argc, char *argv[]) {
|
||||||
inputTab();
|
inputTab();
|
||||||
|
|
||||||
uiInit();
|
uiInit();
|
||||||
uiLog(TAG_STATUS, UI_WARM, L"Traveling...");
|
uiLog(TagStatus, UIWarm, L"Traveling...");
|
||||||
uiDraw();
|
uiDraw();
|
||||||
|
|
||||||
fds.irc.fd = ircConnect(host, port, pass, webirc);
|
fds.irc.fd = ircConnect(host, port, pass, webirc);
|
||||||
|
|
100
chat.h
100
chat.h
|
@ -42,38 +42,38 @@ struct Tag {
|
||||||
const char *name;
|
const char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { TAGS_LEN = 256 };
|
enum { TagsLen = 256 };
|
||||||
const struct Tag TAG_NONE;
|
const struct Tag TagNone;
|
||||||
const struct Tag TAG_STATUS;
|
const struct Tag TagStatus;
|
||||||
const struct Tag TAG_VERBOSE;
|
const struct Tag TagVerbose;
|
||||||
struct Tag tagFind(const char *name);
|
struct Tag tagFind(const char *name);
|
||||||
struct Tag tagFor(const char *name);
|
struct Tag tagFor(const char *name);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
IRC_WHITE,
|
IRCWhite,
|
||||||
IRC_BLACK,
|
IRCBlack,
|
||||||
IRC_BLUE,
|
IRCBlue,
|
||||||
IRC_GREEN,
|
IRCGreen,
|
||||||
IRC_RED,
|
IRCRed,
|
||||||
IRC_BROWN,
|
IRCBrown,
|
||||||
IRC_MAGENTA,
|
IRCMagenta,
|
||||||
IRC_ORANGE,
|
IRCOrange,
|
||||||
IRC_YELLOW,
|
IRCYellow,
|
||||||
IRC_LIGHT_GREEN,
|
IRCLightGreen,
|
||||||
IRC_CYAN,
|
IRCCyan,
|
||||||
IRC_LIGHT_CYAN,
|
IRCLightCyan,
|
||||||
IRC_LIGHT_BLUE,
|
IRCLightBlue,
|
||||||
IRC_PINK,
|
IRCPink,
|
||||||
IRC_GRAY,
|
IRCGray,
|
||||||
IRC_LIGHT_GRAY,
|
IRCLightGray,
|
||||||
};
|
};
|
||||||
enum {
|
enum {
|
||||||
IRC_BOLD = 002,
|
IRCBold = 002,
|
||||||
IRC_COLOR = 003,
|
IRCColor = 003,
|
||||||
IRC_REVERSE = 026,
|
IRCReverse = 026,
|
||||||
IRC_RESET = 017,
|
IRCReset = 017,
|
||||||
IRC_ITALIC = 035,
|
IRCItalic = 035,
|
||||||
IRC_UNDERLINE = 037,
|
IRCUnderline = 037,
|
||||||
};
|
};
|
||||||
|
|
||||||
void handle(char *line);
|
void handle(char *line);
|
||||||
|
@ -98,24 +98,24 @@ void uiViewNum(int num);
|
||||||
void uiCloseTag(struct Tag tag);
|
void uiCloseTag(struct Tag tag);
|
||||||
|
|
||||||
enum UIHeat {
|
enum UIHeat {
|
||||||
UI_COLD,
|
UICold,
|
||||||
UI_WARM,
|
UIWarm,
|
||||||
UI_HOT,
|
UIHot,
|
||||||
};
|
};
|
||||||
void uiTopic(struct Tag tag, const char *topic);
|
void uiTopic(struct Tag tag, const char *topic);
|
||||||
void uiLog(struct Tag tag, enum UIHeat heat, const wchar_t *line);
|
void uiLog(struct Tag tag, enum UIHeat heat, const wchar_t *line);
|
||||||
void uiFmt(struct Tag tag, enum UIHeat heat, const wchar_t *format, ...);
|
void uiFmt(struct Tag tag, enum UIHeat heat, const wchar_t *format, ...);
|
||||||
|
|
||||||
enum TermMode {
|
enum TermMode {
|
||||||
TERM_FOCUS,
|
TermFocus,
|
||||||
TERM_PASTE,
|
TermPaste,
|
||||||
};
|
};
|
||||||
enum TermEvent {
|
enum TermEvent {
|
||||||
TERM_NONE,
|
TermNone,
|
||||||
TERM_FOCUS_IN,
|
TermFocusIn,
|
||||||
TERM_FOCUS_OUT,
|
TermFocusOut,
|
||||||
TERM_PASTE_START,
|
TermPasteStart,
|
||||||
TERM_PASTE_END,
|
TermPasteEnd,
|
||||||
};
|
};
|
||||||
void termInit(void);
|
void termInit(void);
|
||||||
void termTitle(const char *title);
|
void termTitle(const char *title);
|
||||||
|
@ -123,20 +123,20 @@ void termMode(enum TermMode mode, bool set);
|
||||||
enum TermEvent termEvent(char ch);
|
enum TermEvent termEvent(char ch);
|
||||||
|
|
||||||
enum Edit {
|
enum Edit {
|
||||||
EDIT_LEFT,
|
EditLeft,
|
||||||
EDIT_RIGHT,
|
EditRight,
|
||||||
EDIT_HOME,
|
EditHome,
|
||||||
EDIT_END,
|
EditEnd,
|
||||||
EDIT_BACK_WORD,
|
EditBackWord,
|
||||||
EDIT_FORE_WORD,
|
EditForeWord,
|
||||||
EDIT_INSERT,
|
EditInsert,
|
||||||
EDIT_BACKSPACE,
|
EditBackspace,
|
||||||
EDIT_DELETE,
|
EditDelete,
|
||||||
EDIT_KILL_BACK_WORD,
|
EditKillBackWord,
|
||||||
EDIT_KILL_FORE_WORD,
|
EditKillForeWord,
|
||||||
EDIT_KILL_LINE,
|
EditKillLine,
|
||||||
EDIT_COMPLETE,
|
EditComplete,
|
||||||
EDIT_ENTER,
|
EditEnter,
|
||||||
};
|
};
|
||||||
void edit(struct Tag tag, enum Edit op, wchar_t ch);
|
void edit(struct Tag tag, enum Edit op, wchar_t ch);
|
||||||
const wchar_t *editHead(void);
|
const wchar_t *editHead(void);
|
||||||
|
|
34
edit.c
34
edit.c
|
@ -22,9 +22,9 @@
|
||||||
|
|
||||||
#include "chat.h"
|
#include "chat.h"
|
||||||
|
|
||||||
enum { BUF_LEN = 512 };
|
enum { BufLen = 512 };
|
||||||
static struct {
|
static struct {
|
||||||
wchar_t buf[BUF_LEN];
|
wchar_t buf[BufLen];
|
||||||
wchar_t *ptr;
|
wchar_t *ptr;
|
||||||
wchar_t *end;
|
wchar_t *end;
|
||||||
wchar_t *tab;
|
wchar_t *tab;
|
||||||
|
@ -66,7 +66,7 @@ static void foreWord(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void insert(wchar_t ch) {
|
static void insert(wchar_t ch) {
|
||||||
if (line.end == &line.buf[BUF_LEN - 1]) return;
|
if (line.end == &line.buf[BufLen - 1]) return;
|
||||||
if (line.ptr != line.end) {
|
if (line.ptr != line.end) {
|
||||||
wmemmove(line.ptr + 1, line.ptr, line.end - line.ptr);
|
wmemmove(line.ptr + 1, line.ptr, line.end - line.ptr);
|
||||||
}
|
}
|
||||||
|
@ -166,24 +166,24 @@ static void enter(struct Tag tag) {
|
||||||
|
|
||||||
void edit(struct Tag tag, enum Edit op, wchar_t ch) {
|
void edit(struct Tag tag, enum Edit op, wchar_t ch) {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
break; case EDIT_LEFT: reject(); left();
|
break; case EditLeft: reject(); left();
|
||||||
break; case EDIT_RIGHT: reject(); right();
|
break; case EditRight: reject(); right();
|
||||||
break; case EDIT_HOME: reject(); line.ptr = line.buf;
|
break; case EditHome: reject(); line.ptr = line.buf;
|
||||||
break; case EDIT_END: reject(); line.ptr = line.end;
|
break; case EditEnd: reject(); line.ptr = line.end;
|
||||||
|
|
||||||
break; case EDIT_BACK_WORD: reject(); backWord();
|
break; case EditBackWord: reject(); backWord();
|
||||||
break; case EDIT_FORE_WORD: reject(); foreWord();
|
break; case EditForeWord: reject(); foreWord();
|
||||||
|
|
||||||
break; case EDIT_INSERT: accept(); insert(ch);
|
break; case EditInsert: accept(); insert(ch);
|
||||||
break; case EDIT_BACKSPACE: reject(); backspace();
|
break; case EditBackspace: reject(); backspace();
|
||||||
break; case EDIT_DELETE: reject(); delete();
|
break; case EditDelete: reject(); delete();
|
||||||
|
|
||||||
break; case EDIT_KILL_BACK_WORD: reject(); killBackWord();
|
break; case EditKillBackWord: reject(); killBackWord();
|
||||||
break; case EDIT_KILL_FORE_WORD: reject(); killForeWord();
|
break; case EditKillForeWord: reject(); killForeWord();
|
||||||
break; case EDIT_KILL_LINE: reject(); line.end = line.ptr;
|
break; case EditKillLine: reject(); line.end = line.ptr;
|
||||||
|
|
||||||
break; case EDIT_COMPLETE: complete(tag);
|
break; case EditComplete: complete(tag);
|
||||||
|
|
||||||
break; case EDIT_ENTER: accept(); enter(tag);
|
break; case EditEnter: accept(); enter(tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
64
handle.c
64
handle.c
|
@ -33,15 +33,15 @@ static uint32_t hashChar(uint32_t hash, char ch) {
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
static int color(const char *str) {
|
static int color(const char *str) {
|
||||||
if (!str) return IRC_GRAY;
|
if (!str) return IRCGray;
|
||||||
uint32_t hash = 0;
|
uint32_t hash = 0;
|
||||||
for (; str[0]; ++str) {
|
for (; str[0]; ++str) {
|
||||||
hash = hashChar(hash, str[0]);
|
hash = hashChar(hash, str[0]);
|
||||||
}
|
}
|
||||||
while (IRC_BLACK == (hash & IRC_LIGHT_GRAY)) {
|
while (IRCBlack == (hash & IRCLightGray)) {
|
||||||
hash = hashChar(hash, '\0');
|
hash = hashChar(hash, '\0');
|
||||||
}
|
}
|
||||||
return (hash & IRC_LIGHT_GRAY);
|
return (hash & IRCLightGray);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *paramField(char **params) {
|
static char *paramField(char **params) {
|
||||||
|
@ -125,8 +125,8 @@ static void handlePing(char *prefix, char *params) {
|
||||||
static void handleReplyErroneousNickname(char *prefix, char *params) {
|
static void handleReplyErroneousNickname(char *prefix, char *params) {
|
||||||
char *mesg;
|
char *mesg;
|
||||||
shift(prefix, NULL, NULL, NULL, params, 3, 0, NULL, NULL, &mesg);
|
shift(prefix, NULL, NULL, NULL, params, 3, 0, NULL, NULL, &mesg);
|
||||||
uiFmt(TAG_STATUS, UI_HOT, "You can't use that name here: \"%s\"", mesg);
|
uiFmt(TagStatus, UIHot, "You can't use that name here: \"%s\"", mesg);
|
||||||
uiLog(TAG_STATUS, UI_COLD, L"Type /nick <name> to choose a new one");
|
uiLog(TagStatus, UICold, L"Type /nick <name> to choose a new one");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleReplyWelcome(char *prefix, char *params) {
|
static void handleReplyWelcome(char *prefix, char *params) {
|
||||||
|
@ -135,9 +135,9 @@ static void handleReplyWelcome(char *prefix, char *params) {
|
||||||
|
|
||||||
if (strcmp(nick, self.nick)) selfNick(nick);
|
if (strcmp(nick, self.nick)) selfNick(nick);
|
||||||
if (self.join) ircFmt("JOIN %s\r\n", self.join);
|
if (self.join) ircFmt("JOIN %s\r\n", self.join);
|
||||||
tabTouch(TAG_STATUS, self.nick);
|
tabTouch(TagStatus, self.nick);
|
||||||
|
|
||||||
uiLog(TAG_STATUS, UI_WARM, L"You have arrived");
|
uiLog(TagStatus, UIWarm, L"You have arrived");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleReplyMOTD(char *prefix, char *params) {
|
static void handleReplyMOTD(char *prefix, char *params) {
|
||||||
|
@ -145,8 +145,8 @@ static void handleReplyMOTD(char *prefix, char *params) {
|
||||||
shift(prefix, NULL, NULL, NULL, params, 2, 0, NULL, &mesg);
|
shift(prefix, NULL, NULL, NULL, params, 2, 0, NULL, &mesg);
|
||||||
if (mesg[0] == '-' && mesg[1] == ' ') mesg = &mesg[2];
|
if (mesg[0] == '-' && mesg[1] == ' ') mesg = &mesg[2];
|
||||||
|
|
||||||
urlScan(TAG_STATUS, mesg);
|
urlScan(TagStatus, mesg);
|
||||||
uiFmt(TAG_STATUS, UI_COLD, "%s", mesg);
|
uiFmt(TagStatus, UICold, "%s", mesg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleJoin(char *prefix, char *params) {
|
static void handleJoin(char *prefix, char *params) {
|
||||||
|
@ -155,13 +155,13 @@ static void handleJoin(char *prefix, char *params) {
|
||||||
struct Tag tag = tagFor(chan);
|
struct Tag tag = tagFor(chan);
|
||||||
|
|
||||||
if (isSelf(nick, user)) {
|
if (isSelf(nick, user)) {
|
||||||
tabTouch(TAG_NONE, chan);
|
tabTouch(TagNone, chan);
|
||||||
uiViewTag(tag);
|
uiViewTag(tag);
|
||||||
}
|
}
|
||||||
tabTouch(tag, nick);
|
tabTouch(tag, nick);
|
||||||
|
|
||||||
uiFmt(
|
uiFmt(
|
||||||
tag, UI_COLD,
|
tag, UICold,
|
||||||
"\3%d%s\3 arrives in \3%d%s\3",
|
"\3%d%s\3 arrives in \3%d%s\3",
|
||||||
color(user), nick, color(chan), chan
|
color(user), nick, color(chan), chan
|
||||||
);
|
);
|
||||||
|
@ -182,14 +182,14 @@ static void handlePart(char *prefix, char *params) {
|
||||||
if (mesg) {
|
if (mesg) {
|
||||||
urlScan(tag, mesg);
|
urlScan(tag, mesg);
|
||||||
uiFmt(
|
uiFmt(
|
||||||
tag, UI_COLD,
|
tag, UICold,
|
||||||
"\3%d%s\3 leaves \3%d%s\3, \"%s\"",
|
"\3%d%s\3 leaves \3%d%s\3, \"%s\"",
|
||||||
color(user), nick, color(chan), chan, dequote(mesg)
|
color(user), nick, color(chan), chan, dequote(mesg)
|
||||||
);
|
);
|
||||||
logFmt(tag, NULL, "%s leaves %s, \"%s\"", nick, chan, dequote(mesg));
|
logFmt(tag, NULL, "%s leaves %s, \"%s\"", nick, chan, dequote(mesg));
|
||||||
} else {
|
} else {
|
||||||
uiFmt(
|
uiFmt(
|
||||||
tag, UI_COLD,
|
tag, UICold,
|
||||||
"\3%d%s\3 leaves \3%d%s\3",
|
"\3%d%s\3 leaves \3%d%s\3",
|
||||||
color(user), nick, color(chan), chan
|
color(user), nick, color(chan), chan
|
||||||
);
|
);
|
||||||
|
@ -212,7 +212,7 @@ static void handleKick(char *prefix, char *params) {
|
||||||
if (mesg) {
|
if (mesg) {
|
||||||
urlScan(tag, mesg);
|
urlScan(tag, mesg);
|
||||||
uiFmt(
|
uiFmt(
|
||||||
tag, (kicked ? UI_HOT : UI_COLD),
|
tag, (kicked ? UIHot : UICold),
|
||||||
"\3%d%s\3 kicks \3%d%s\3 out of \3%d%s\3, \"%s\"",
|
"\3%d%s\3 kicks \3%d%s\3 out of \3%d%s\3, \"%s\"",
|
||||||
color(user), nick, color(kick), kick, color(chan), chan,
|
color(user), nick, color(kick), kick, color(chan), chan,
|
||||||
dequote(mesg)
|
dequote(mesg)
|
||||||
|
@ -223,7 +223,7 @@ static void handleKick(char *prefix, char *params) {
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
uiFmt(
|
uiFmt(
|
||||||
tag, (kicked ? UI_HOT : UI_COLD),
|
tag, (kicked ? UIHot : UICold),
|
||||||
"\3%d%s\3 kicks \3%d%s\3 out of \3%d%s\3",
|
"\3%d%s\3 kicks \3%d%s\3 out of \3%d%s\3",
|
||||||
color(user), nick, color(kick), kick, color(chan), chan
|
color(user), nick, color(kick), kick, color(chan), chan
|
||||||
);
|
);
|
||||||
|
@ -236,19 +236,19 @@ static void handleQuit(char *prefix, char *params) {
|
||||||
shift(prefix, &nick, &user, NULL, params, 0, 1, &mesg);
|
shift(prefix, &nick, &user, NULL, params, 0, 1, &mesg);
|
||||||
|
|
||||||
struct Tag tag;
|
struct Tag tag;
|
||||||
while (TAG_NONE.id != (tag = tabTag(nick)).id) {
|
while (TagNone.id != (tag = tabTag(nick)).id) {
|
||||||
tabRemove(tag, nick);
|
tabRemove(tag, nick);
|
||||||
|
|
||||||
if (mesg) {
|
if (mesg) {
|
||||||
urlScan(tag, mesg);
|
urlScan(tag, mesg);
|
||||||
uiFmt(
|
uiFmt(
|
||||||
tag, UI_COLD,
|
tag, UICold,
|
||||||
"\3%d%s\3 leaves, \"%s\"",
|
"\3%d%s\3 leaves, \"%s\"",
|
||||||
color(user), nick, dequote(mesg)
|
color(user), nick, dequote(mesg)
|
||||||
);
|
);
|
||||||
logFmt(tag, NULL, "%s leaves, \"%s\"", nick, dequote(mesg));
|
logFmt(tag, NULL, "%s leaves, \"%s\"", nick, dequote(mesg));
|
||||||
} else {
|
} else {
|
||||||
uiFmt(tag, UI_COLD, "\3%d%s\3 leaves", color(user), nick);
|
uiFmt(tag, UICold, "\3%d%s\3 leaves", color(user), nick);
|
||||||
logFmt(tag, NULL, "%s leaves", nick);
|
logFmt(tag, NULL, "%s leaves", nick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -262,7 +262,7 @@ static void handleReplyTopic(char *prefix, char *params) {
|
||||||
urlScan(tag, topic);
|
urlScan(tag, topic);
|
||||||
uiTopic(tag, topic);
|
uiTopic(tag, topic);
|
||||||
uiFmt(
|
uiFmt(
|
||||||
tag, UI_COLD,
|
tag, UICold,
|
||||||
"The sign in \3%d%s\3 reads, \"%s\"",
|
"The sign in \3%d%s\3 reads, \"%s\"",
|
||||||
color(chan), chan, topic
|
color(chan), chan, topic
|
||||||
);
|
);
|
||||||
|
@ -279,7 +279,7 @@ static void handleTopic(char *prefix, char *params) {
|
||||||
urlScan(tag, topic);
|
urlScan(tag, topic);
|
||||||
uiTopic(tag, topic);
|
uiTopic(tag, topic);
|
||||||
uiFmt(
|
uiFmt(
|
||||||
tag, UI_COLD,
|
tag, UICold,
|
||||||
"\3%d%s\3 places a new sign in \3%d%s\3, \"%s\"",
|
"\3%d%s\3 places a new sign in \3%d%s\3, \"%s\"",
|
||||||
color(user), nick, color(chan), chan, topic
|
color(user), nick, color(chan), chan, topic
|
||||||
);
|
);
|
||||||
|
@ -322,7 +322,7 @@ static void handleReplyEndOfWho(char *prefix, char *params) {
|
||||||
struct Tag tag = tagFor(chan);
|
struct Tag tag = tagFor(chan);
|
||||||
|
|
||||||
uiFmt(
|
uiFmt(
|
||||||
tag, UI_COLD,
|
tag, UICold,
|
||||||
"In \3%d%s\3 are %s",
|
"In \3%d%s\3 are %s",
|
||||||
color(chan), chan, who.buf
|
color(chan), chan, who.buf
|
||||||
);
|
);
|
||||||
|
@ -336,11 +336,11 @@ static void handleNick(char *prefix, char *params) {
|
||||||
if (isSelf(prev, user)) selfNick(next);
|
if (isSelf(prev, user)) selfNick(next);
|
||||||
|
|
||||||
struct Tag tag;
|
struct Tag tag;
|
||||||
while (TAG_NONE.id != (tag = tabTag(prev)).id) {
|
while (TagNone.id != (tag = tabTag(prev)).id) {
|
||||||
tabReplace(tag, prev, next);
|
tabReplace(tag, prev, next);
|
||||||
|
|
||||||
uiFmt(
|
uiFmt(
|
||||||
tag, UI_COLD,
|
tag, UICold,
|
||||||
"\3%d%s\3 is now known as \3%d%s\3",
|
"\3%d%s\3 is now known as \3%d%s\3",
|
||||||
color(user), prev, color(user), next
|
color(user), prev, color(user), next
|
||||||
);
|
);
|
||||||
|
@ -360,7 +360,7 @@ static void handleCTCP(struct Tag tag, char *nick, char *user, char *mesg) {
|
||||||
urlScan(tag, params);
|
urlScan(tag, params);
|
||||||
bool ping = !self && isPing(params);
|
bool ping = !self && isPing(params);
|
||||||
uiFmt(
|
uiFmt(
|
||||||
tag, (ping ? UI_HOT : UI_WARM),
|
tag, (ping ? UIHot : UIWarm),
|
||||||
"%c\3%d* %s\17 %s",
|
"%c\3%d* %s\17 %s",
|
||||||
ping["\17\26"], color(user), nick, params
|
ping["\17\26"], color(user), nick, params
|
||||||
);
|
);
|
||||||
|
@ -383,7 +383,7 @@ static void handlePrivmsg(char *prefix, char *params) {
|
||||||
urlScan(tag, mesg);
|
urlScan(tag, mesg);
|
||||||
bool ping = !self && (direct || isPing(mesg));
|
bool ping = !self && (direct || isPing(mesg));
|
||||||
uiFmt(
|
uiFmt(
|
||||||
tag, (ping ? UI_HOT : UI_WARM),
|
tag, (ping ? UIHot : UIWarm),
|
||||||
"%c\3%d%c%s%c\17 %s",
|
"%c\3%d%c%s%c\17 %s",
|
||||||
ping["\17\26"], color(user), self["<("], nick, self[">)"], mesg
|
ping["\17\26"], color(user), self["<("], nick, self[">)"], mesg
|
||||||
);
|
);
|
||||||
|
@ -393,7 +393,7 @@ static void handlePrivmsg(char *prefix, char *params) {
|
||||||
static void handleNotice(char *prefix, char *params) {
|
static void handleNotice(char *prefix, char *params) {
|
||||||
char *nick, *user, *chan, *mesg;
|
char *nick, *user, *chan, *mesg;
|
||||||
shift(prefix, &nick, &user, NULL, params, 2, 0, &chan, &mesg);
|
shift(prefix, &nick, &user, NULL, params, 2, 0, &chan, &mesg);
|
||||||
struct Tag tag = TAG_STATUS;
|
struct Tag tag = TagStatus;
|
||||||
if (user) tag = (strcmp(chan, self.nick) ? tagFor(chan) : tagFor(nick));
|
if (user) tag = (strcmp(chan, self.nick) ? tagFor(chan) : tagFor(nick));
|
||||||
|
|
||||||
bool self = isSelf(nick, user);
|
bool self = isSelf(nick, user);
|
||||||
|
@ -402,7 +402,7 @@ static void handleNotice(char *prefix, char *params) {
|
||||||
urlScan(tag, mesg);
|
urlScan(tag, mesg);
|
||||||
bool ping = !self && isPing(mesg);
|
bool ping = !self && isPing(mesg);
|
||||||
uiFmt(
|
uiFmt(
|
||||||
tag, (ping ? UI_HOT : UI_WARM),
|
tag, (ping ? UIHot : UIWarm),
|
||||||
"%c\3%d-%s-\17 %s",
|
"%c\3%d-%s-\17 %s",
|
||||||
ping["\17\26"], color(user), nick, mesg
|
ping["\17\26"], color(user), nick, mesg
|
||||||
);
|
);
|
||||||
|
@ -412,7 +412,7 @@ static void handleNotice(char *prefix, char *params) {
|
||||||
static const struct {
|
static const struct {
|
||||||
const char *command;
|
const char *command;
|
||||||
Handler handler;
|
Handler handler;
|
||||||
} HANDLERS[] = {
|
} Handlers[] = {
|
||||||
{ "001", handleReplyWelcome },
|
{ "001", handleReplyWelcome },
|
||||||
{ "315", handleReplyEndOfWho },
|
{ "315", handleReplyEndOfWho },
|
||||||
{ "332", handleReplyTopic },
|
{ "332", handleReplyTopic },
|
||||||
|
@ -432,7 +432,7 @@ static const struct {
|
||||||
{ "QUIT", handleQuit },
|
{ "QUIT", handleQuit },
|
||||||
{ "TOPIC", handleTopic },
|
{ "TOPIC", handleTopic },
|
||||||
};
|
};
|
||||||
static const size_t HANDLERS_LEN = sizeof(HANDLERS) / sizeof(HANDLERS[0]);
|
static const size_t HandlersLen = sizeof(Handlers) / sizeof(Handlers[0]);
|
||||||
|
|
||||||
void handle(char *line) {
|
void handle(char *line) {
|
||||||
char *prefix = NULL;
|
char *prefix = NULL;
|
||||||
|
@ -441,9 +441,9 @@ void handle(char *line) {
|
||||||
if (!line) errx(EX_PROTOCOL, "unexpected eol");
|
if (!line) errx(EX_PROTOCOL, "unexpected eol");
|
||||||
}
|
}
|
||||||
char *command = strsep(&line, " ");
|
char *command = strsep(&line, " ");
|
||||||
for (size_t i = 0; i < HANDLERS_LEN; ++i) {
|
for (size_t i = 0; i < HandlersLen; ++i) {
|
||||||
if (strcmp(command, HANDLERS[i].command)) continue;
|
if (strcmp(command, Handlers[i].command)) continue;
|
||||||
HANDLERS[i].handler(prefix, line);
|
Handlers[i].handler(prefix, line);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
34
input.c
34
input.c
|
@ -40,7 +40,7 @@ static void privmsg(struct Tag tag, bool action, const char *mesg) {
|
||||||
static char *param(const char *command, char **params, const char *name) {
|
static char *param(const char *command, char **params, const char *name) {
|
||||||
char *param = strsep(params, " ");
|
char *param = strsep(params, " ");
|
||||||
if (param) return param;
|
if (param) return param;
|
||||||
uiFmt(TAG_STATUS, UI_WARM, "%s requires a %s", command, name);
|
uiFmt(TagStatus, UIHot, "%s requires a %s", command, name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ static void inputQuery(struct Tag tag, char *params) {
|
||||||
(void)tag;
|
(void)tag;
|
||||||
char *nick = param("/query", ¶ms, "nick");
|
char *nick = param("/query", ¶ms, "nick");
|
||||||
if (!nick) return;
|
if (!nick) return;
|
||||||
tabTouch(TAG_NONE, nick);
|
tabTouch(TagNone, nick);
|
||||||
uiViewTag(tagFor(nick));
|
uiViewTag(tagFor(nick));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,10 +121,10 @@ static void inputView(struct Tag tag, char *params) {
|
||||||
uiViewNum(num);
|
uiViewNum(num);
|
||||||
} else {
|
} else {
|
||||||
struct Tag tag = tagFind(view);
|
struct Tag tag = tagFind(view);
|
||||||
if (tag.id != TAG_NONE.id) {
|
if (tag.id != TagNone.id) {
|
||||||
uiViewTag(tag);
|
uiViewTag(tag);
|
||||||
} else {
|
} else {
|
||||||
uiFmt(TAG_STATUS, UI_WARM, "No view for %s", view);
|
uiFmt(TagStatus, UIHot, "No view for %s", view);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,13 +132,13 @@ static void inputView(struct Tag tag, char *params) {
|
||||||
static void inputClose(struct Tag tag, char *params) {
|
static void inputClose(struct Tag tag, char *params) {
|
||||||
(void)params;
|
(void)params;
|
||||||
uiCloseTag(tag);
|
uiCloseTag(tag);
|
||||||
tabRemove(TAG_NONE, tag.name);
|
tabRemove(TagNone, tag.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
const char *command;
|
const char *command;
|
||||||
Handler handler;
|
Handler handler;
|
||||||
} COMMANDS[] = {
|
} Commands[] = {
|
||||||
{ "/close", inputClose },
|
{ "/close", inputClose },
|
||||||
{ "/join", inputJoin },
|
{ "/join", inputJoin },
|
||||||
{ "/me", inputMe },
|
{ "/me", inputMe },
|
||||||
|
@ -153,7 +153,7 @@ static const struct {
|
||||||
{ "/view", inputView },
|
{ "/view", inputView },
|
||||||
{ "/who", inputWho },
|
{ "/who", inputWho },
|
||||||
};
|
};
|
||||||
static const size_t COMMANDS_LEN = sizeof(COMMANDS) / sizeof(COMMANDS[0]);
|
static const size_t CommandsLen = sizeof(Commands) / sizeof(Commands[0]);
|
||||||
|
|
||||||
void input(struct Tag tag, char *input) {
|
void input(struct Tag tag, char *input) {
|
||||||
bool slash = (input[0] == '/');
|
bool slash = (input[0] == '/');
|
||||||
|
@ -164,9 +164,9 @@ void input(struct Tag tag, char *input) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!slash) {
|
if (!slash) {
|
||||||
if (tag.id == TAG_VERBOSE.id) {
|
if (tag.id == TagVerbose.id) {
|
||||||
ircFmt("%s\r\n", input);
|
ircFmt("%s\r\n", input);
|
||||||
} else if (tag.id != TAG_STATUS.id) {
|
} else if (tag.id != TagStatus.id) {
|
||||||
privmsg(tag, false, input);
|
privmsg(tag, false, input);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -183,24 +183,24 @@ void input(struct Tag tag, char *input) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *command = word;
|
const char *command = word;
|
||||||
const char *uniq = tabNext(TAG_NONE, command);
|
const char *uniq = tabNext(TagNone, command);
|
||||||
if (uniq && uniq == tabNext(TAG_NONE, command)) {
|
if (uniq && uniq == tabNext(TagNone, command)) {
|
||||||
command = uniq;
|
command = uniq;
|
||||||
tabAccept();
|
tabAccept();
|
||||||
} else {
|
} else {
|
||||||
tabReject();
|
tabReject();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < COMMANDS_LEN; ++i) {
|
for (size_t i = 0; i < CommandsLen; ++i) {
|
||||||
if (strcasecmp(command, COMMANDS[i].command)) continue;
|
if (strcasecmp(command, Commands[i].command)) continue;
|
||||||
COMMANDS[i].handler(tag, input);
|
Commands[i].handler(tag, input);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uiFmt(TAG_STATUS, UI_WARM, "%s isn't a recognized command", command);
|
uiFmt(TagStatus, UIHot, "%s isn't a recognized command", command);
|
||||||
}
|
}
|
||||||
|
|
||||||
void inputTab(void) {
|
void inputTab(void) {
|
||||||
for (size_t i = 0; i < COMMANDS_LEN; ++i) {
|
for (size_t i = 0; i < CommandsLen; ++i) {
|
||||||
tabTouch(TAG_NONE, COMMANDS[i].command);
|
tabTouch(TagNone, Commands[i].command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
8
irc.c
8
irc.c
|
@ -108,8 +108,8 @@ void ircFmt(const char *format, ...) {
|
||||||
if (!buf) err(EX_OSERR, "vasprintf");
|
if (!buf) err(EX_OSERR, "vasprintf");
|
||||||
if (self.verbose) {
|
if (self.verbose) {
|
||||||
uiFmt(
|
uiFmt(
|
||||||
TAG_VERBOSE, UI_COLD,
|
TagVerbose, UICold,
|
||||||
"\3%d<<<\3 %.*s", IRC_WHITE, len - 2, buf
|
"\3%d<<<\3 %.*s", IRCWhite, len - 2, buf
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ircWrite(buf, len);
|
ircWrite(buf, len);
|
||||||
|
@ -133,8 +133,8 @@ void ircRead(void) {
|
||||||
crlf[0] = '\0';
|
crlf[0] = '\0';
|
||||||
if (self.verbose) {
|
if (self.verbose) {
|
||||||
uiFmt(
|
uiFmt(
|
||||||
TAG_VERBOSE, UI_COLD,
|
TagVerbose, UICold,
|
||||||
"\3%d>>>\3 %s", IRC_GRAY, line
|
"\3%d>>>\3 %s", IRCGray, line
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
handle(line);
|
handle(line);
|
||||||
|
|
2
log.c
2
log.c
|
@ -34,7 +34,7 @@ static struct Log {
|
||||||
int month;
|
int month;
|
||||||
int day;
|
int day;
|
||||||
FILE *file;
|
FILE *file;
|
||||||
} logs[TAGS_LEN];
|
} logs[TagsLen];
|
||||||
|
|
||||||
void logOpen(const char *path) {
|
void logOpen(const char *path) {
|
||||||
logRoot = open(path, O_RDONLY | O_CLOEXEC);
|
logRoot = open(path, O_RDONLY | O_CLOEXEC);
|
||||||
|
|
4
tab.c
4
tab.c
|
@ -121,14 +121,14 @@ struct Tag tabTag(const char *word) {
|
||||||
return entry->tag;
|
return entry->tag;
|
||||||
}
|
}
|
||||||
iter = NULL;
|
iter = NULL;
|
||||||
return TAG_NONE;
|
return TagNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *tabNext(struct Tag tag, const char *prefix) {
|
const char *tabNext(struct Tag tag, const char *prefix) {
|
||||||
size_t len = strlen(prefix);
|
size_t len = strlen(prefix);
|
||||||
struct Entry *start = (iter ? iter->next : head);
|
struct Entry *start = (iter ? iter->next : head);
|
||||||
for (struct Entry *entry = start; entry; entry = entry->next) {
|
for (struct Entry *entry = start; entry; entry = entry->next) {
|
||||||
if (entry->tag.id != TAG_NONE.id && entry->tag.id != tag.id) continue;
|
if (entry->tag.id != TagNone.id && entry->tag.id != tag.id) continue;
|
||||||
if (strncasecmp(entry->word, prefix, len)) continue;
|
if (strncasecmp(entry->word, prefix, len)) continue;
|
||||||
iter = entry;
|
iter = entry;
|
||||||
return entry->word;
|
return entry->word;
|
||||||
|
|
14
tag.c
14
tag.c
|
@ -21,12 +21,12 @@
|
||||||
|
|
||||||
#include "chat.h"
|
#include "chat.h"
|
||||||
|
|
||||||
const struct Tag TAG_NONE = { 0, "" };
|
const struct Tag TagNone = { 0, "" };
|
||||||
const struct Tag TAG_STATUS = { 1, "(status)" };
|
const struct Tag TagStatus = { 1, "(status)" };
|
||||||
const struct Tag TAG_VERBOSE = { 2, "(irc)" };
|
const struct Tag TagVerbose = { 2, "(irc)" };
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
char *name[TAGS_LEN];
|
char *name[TagsLen];
|
||||||
size_t len;
|
size_t len;
|
||||||
} tags = {
|
} tags = {
|
||||||
.name = { "", "(status)", "(irc)" },
|
.name = { "", "(status)", "(irc)" },
|
||||||
|
@ -42,13 +42,13 @@ struct Tag tagFind(const char *name) {
|
||||||
if (strcmp(tags.name[id], name)) continue;
|
if (strcmp(tags.name[id], name)) continue;
|
||||||
return Tag(id);
|
return Tag(id);
|
||||||
}
|
}
|
||||||
return TAG_NONE;
|
return TagNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Tag tagFor(const char *name) {
|
struct Tag tagFor(const char *name) {
|
||||||
struct Tag tag = tagFind(name);
|
struct Tag tag = tagFind(name);
|
||||||
if (tag.id != TAG_NONE.id) return tag;
|
if (tag.id != TagNone.id) return tag;
|
||||||
if (tags.len == TAGS_LEN) return TAG_STATUS;
|
if (tags.len == TagsLen) return TagStatus;
|
||||||
size_t id = tags.len++;
|
size_t id = tags.len++;
|
||||||
tags.name[id] = strdup(name);
|
tags.name[id] = strdup(name);
|
||||||
if (!tags.name[id]) err(EX_OSERR, "strdup");
|
if (!tags.name[id]) err(EX_OSERR, "strdup");
|
||||||
|
|
17
term.c
17
term.c
|
@ -42,27 +42,28 @@ static void privateMode(const char *mode, bool set) {
|
||||||
|
|
||||||
void termMode(enum TermMode mode, bool set) {
|
void termMode(enum TermMode mode, bool set) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
break; case TERM_FOCUS: privateMode("1004", set);
|
break; case TermFocus: privateMode("1004", set);
|
||||||
break; case TERM_PASTE: privateMode("2004", set);
|
break; case TermPaste: privateMode("2004", set);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ESC '\33'
|
|
||||||
#define T(s, i) ((s) << 8 | (i))
|
#define T(s, i) ((s) << 8 | (i))
|
||||||
|
|
||||||
|
enum { Esc = '\33' };
|
||||||
|
|
||||||
enum TermEvent termEvent(char ch) {
|
enum TermEvent termEvent(char ch) {
|
||||||
static int state = 0;
|
static int state = 0;
|
||||||
switch (T(state, ch)) {
|
switch (T(state, ch)) {
|
||||||
case T(0, ESC): state = 1; return 0;
|
case T(0, Esc): state = 1; return 0;
|
||||||
case T(1, '['): state = 2; return 0;
|
case T(1, '['): state = 2; return 0;
|
||||||
case T(2, 'I'): state = 0; return TERM_FOCUS_IN;
|
case T(2, 'I'): state = 0; return TermFocusIn;
|
||||||
case T(2, 'O'): state = 0; return TERM_FOCUS_OUT;
|
case T(2, 'O'): state = 0; return TermFocusOut;
|
||||||
case T(2, '2'): state = 3; return 0;
|
case T(2, '2'): state = 3; return 0;
|
||||||
case T(3, '0'): state = 4; return 0;
|
case T(3, '0'): state = 4; return 0;
|
||||||
case T(4, '0'): state = 5; return 0;
|
case T(4, '0'): state = 5; return 0;
|
||||||
case T(5, '~'): state = 0; return TERM_PASTE_START;
|
case T(5, '~'): state = 0; return TermPasteStart;
|
||||||
case T(4, '1'): state = 6; return 0;
|
case T(4, '1'): state = 6; return 0;
|
||||||
case T(6, '~'): state = 0; return TERM_PASTE_END;
|
case T(6, '~'): state = 0; return TermPasteEnd;
|
||||||
default: state = 0; return 0;
|
default: state = 0; return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
181
ui.c
181
ui.c
|
@ -85,7 +85,7 @@ struct View {
|
||||||
static struct {
|
static struct {
|
||||||
struct View *head;
|
struct View *head;
|
||||||
struct View *tail;
|
struct View *tail;
|
||||||
struct View *tags[TAGS_LEN];
|
struct View *tags[TagsLen];
|
||||||
} views;
|
} views;
|
||||||
|
|
||||||
static void viewAppend(struct View *view) {
|
static void viewAppend(struct View *view) {
|
||||||
|
@ -105,13 +105,13 @@ static void viewRemove(struct View *view) {
|
||||||
views.tags[view->tag.id] = NULL;
|
views.tags[view->tag.id] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const int LOG_LINES = 256;
|
static const int LogLines = 256;
|
||||||
|
|
||||||
static int logHeight(const struct View *view) {
|
static int logHeight(const struct View *view) {
|
||||||
return LINES - (view->topic ? 2 : 0) - 2;
|
return LINES - (view->topic ? 2 : 0) - 2;
|
||||||
}
|
}
|
||||||
static int lastLogLine(void) {
|
static int lastLogLine(void) {
|
||||||
return LOG_LINES - 1;
|
return LogLines - 1;
|
||||||
}
|
}
|
||||||
static int lastLine(void) {
|
static int lastLine(void) {
|
||||||
return LINES - 1;
|
return LINES - 1;
|
||||||
|
@ -128,11 +128,11 @@ static struct View *viewTag(struct Tag tag) {
|
||||||
if (!view) err(EX_OSERR, "calloc");
|
if (!view) err(EX_OSERR, "calloc");
|
||||||
|
|
||||||
view->tag = tag;
|
view->tag = tag;
|
||||||
view->log = newpad(LOG_LINES, COLS);
|
view->log = newpad(LogLines, COLS);
|
||||||
wsetscrreg(view->log, 0, lastLogLine());
|
wsetscrreg(view->log, 0, lastLogLine());
|
||||||
scrollok(view->log, true);
|
scrollok(view->log, true);
|
||||||
wmove(view->log, lastLogLine() - logHeight(view) + 2, 0);
|
wmove(view->log, lastLogLine() - logHeight(view) + 2, 0);
|
||||||
view->scroll = LOG_LINES;
|
view->scroll = LogLines;
|
||||||
view->mark = true;
|
view->mark = true;
|
||||||
|
|
||||||
viewAppend(view);
|
viewAppend(view);
|
||||||
|
@ -141,7 +141,7 @@ static struct View *viewTag(struct Tag tag) {
|
||||||
|
|
||||||
static void viewResize(void) {
|
static void viewResize(void) {
|
||||||
for (struct View *view = views.head; view; view = view->next) {
|
for (struct View *view = views.head; view; view = view->next) {
|
||||||
wresize(view->log, LOG_LINES, COLS);
|
wresize(view->log, LogLines, COLS);
|
||||||
wmove(view->log, lastLogLine(), lastCol());
|
wmove(view->log, lastLogLine(), lastCol());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,8 +162,6 @@ static void viewUnmark(struct View *view) {
|
||||||
view->mark = false;
|
view->mark = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const int COLS_MAX = 512;
|
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
bool hide;
|
bool hide;
|
||||||
struct View *view;
|
struct View *view;
|
||||||
|
@ -173,12 +171,12 @@ static struct {
|
||||||
|
|
||||||
static void uiShow(void) {
|
static void uiShow(void) {
|
||||||
ui.hide = false;
|
ui.hide = false;
|
||||||
termMode(TERM_FOCUS, true);
|
termMode(TermFocus, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiHide(void) {
|
void uiHide(void) {
|
||||||
ui.hide = true;
|
ui.hide = true;
|
||||||
termMode(TERM_FOCUS, false);
|
termMode(TermFocus, false);
|
||||||
endwin();
|
endwin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,23 +223,23 @@ static void uiRedraw(void) {
|
||||||
clearok(curscr, true);
|
clearok(curscr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const short IRC_COLORS[] = {
|
static const short IRCColors[] = {
|
||||||
[IRC_WHITE] = 8 + COLOR_WHITE,
|
[IRCWhite] = 8 + COLOR_WHITE,
|
||||||
[IRC_BLACK] = 0 + COLOR_BLACK,
|
[IRCBlack] = 0 + COLOR_BLACK,
|
||||||
[IRC_BLUE] = 0 + COLOR_BLUE,
|
[IRCBlue] = 0 + COLOR_BLUE,
|
||||||
[IRC_GREEN] = 0 + COLOR_GREEN,
|
[IRCGreen] = 0 + COLOR_GREEN,
|
||||||
[IRC_RED] = 8 + COLOR_RED,
|
[IRCRed] = 8 + COLOR_RED,
|
||||||
[IRC_BROWN] = 0 + COLOR_RED,
|
[IRCBrown] = 0 + COLOR_RED,
|
||||||
[IRC_MAGENTA] = 0 + COLOR_MAGENTA,
|
[IRCMagenta] = 0 + COLOR_MAGENTA,
|
||||||
[IRC_ORANGE] = 0 + COLOR_YELLOW,
|
[IRCOrange] = 0 + COLOR_YELLOW,
|
||||||
[IRC_YELLOW] = 8 + COLOR_YELLOW,
|
[IRCYellow] = 8 + COLOR_YELLOW,
|
||||||
[IRC_LIGHT_GREEN] = 8 + COLOR_GREEN,
|
[IRCLightGreen] = 8 + COLOR_GREEN,
|
||||||
[IRC_CYAN] = 0 + COLOR_CYAN,
|
[IRCCyan] = 0 + COLOR_CYAN,
|
||||||
[IRC_LIGHT_CYAN] = 8 + COLOR_CYAN,
|
[IRCLightCyan] = 8 + COLOR_CYAN,
|
||||||
[IRC_LIGHT_BLUE] = 8 + COLOR_BLUE,
|
[IRCLightBlue] = 8 + COLOR_BLUE,
|
||||||
[IRC_PINK] = 8 + COLOR_MAGENTA,
|
[IRCPink] = 8 + COLOR_MAGENTA,
|
||||||
[IRC_GRAY] = 8 + COLOR_BLACK,
|
[IRCGray] = 8 + COLOR_BLACK,
|
||||||
[IRC_LIGHT_GRAY] = 0 + COLOR_WHITE,
|
[IRCLightGray] = 0 + COLOR_WHITE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const wchar_t *parseColor(short *pair, const wchar_t *str) {
|
static const wchar_t *parseColor(short *pair, const wchar_t *str) {
|
||||||
|
@ -262,8 +260,8 @@ static const wchar_t *parseColor(short *pair, const wchar_t *str) {
|
||||||
if (bgLen) str = &str[1 + bgLen];
|
if (bgLen) str = &str[1 + bgLen];
|
||||||
|
|
||||||
if (*pair == -1) *pair = 0;
|
if (*pair == -1) *pair = 0;
|
||||||
*pair = (*pair & 0xF0) | IRC_COLORS[fg & 0x0F];
|
*pair = (*pair & 0xF0) | IRCColors[fg & 0x0F];
|
||||||
if (bgLen) *pair = (*pair & 0x0F) | (IRC_COLORS[bg & 0x0F] << 4);
|
if (bgLen) *pair = (*pair & 0x0F) | (IRCColors[bg & 0x0F] << 4);
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
@ -286,14 +284,14 @@ static void wordWrap(WINDOW *win, const wchar_t *str) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const wchar_t IRC_CODES[] = {
|
static const wchar_t IRCCodes[] = {
|
||||||
L' ',
|
L' ',
|
||||||
IRC_BOLD,
|
IRCBold,
|
||||||
IRC_COLOR,
|
IRCColor,
|
||||||
IRC_REVERSE,
|
IRCReverse,
|
||||||
IRC_RESET,
|
IRCReset,
|
||||||
IRC_ITALIC,
|
IRCItalic,
|
||||||
IRC_UNDERLINE,
|
IRCUnderline,
|
||||||
L'\0',
|
L'\0',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -301,7 +299,7 @@ static void addIRC(WINDOW *win, const wchar_t *str) {
|
||||||
attr_t attr = A_NORMAL;
|
attr_t attr = A_NORMAL;
|
||||||
short pair = -1;
|
short pair = -1;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
size_t cc = wcscspn(str, IRC_CODES);
|
size_t cc = wcscspn(str, IRCCodes);
|
||||||
wattr_set(win, attr | attr8(pair), 1 + pair8(pair), NULL);
|
wattr_set(win, attr | attr8(pair), 1 + pair8(pair), NULL);
|
||||||
waddnwstr(win, str, cc);
|
waddnwstr(win, str, cc);
|
||||||
if (!str[cc]) break;
|
if (!str[cc]) break;
|
||||||
|
@ -309,12 +307,12 @@ static void addIRC(WINDOW *win, const wchar_t *str) {
|
||||||
str = &str[cc];
|
str = &str[cc];
|
||||||
switch (*str++) {
|
switch (*str++) {
|
||||||
break; case L' ': wordWrap(win, str);
|
break; case L' ': wordWrap(win, str);
|
||||||
break; case IRC_BOLD: attr ^= A_BOLD;
|
break; case IRCBold: attr ^= A_BOLD;
|
||||||
break; case IRC_ITALIC: attr ^= A_ITALIC;
|
break; case IRCItalic: attr ^= A_ITALIC;
|
||||||
break; case IRC_UNDERLINE: attr ^= A_UNDERLINE;
|
break; case IRCUnderline: attr ^= A_UNDERLINE;
|
||||||
break; case IRC_REVERSE: attr ^= A_REVERSE;
|
break; case IRCReverse: attr ^= A_REVERSE;
|
||||||
break; case IRC_COLOR: str = parseColor(&pair, str);
|
break; case IRCColor: str = parseColor(&pair, str);
|
||||||
break; case IRC_RESET: attr = A_NORMAL; pair = -1;
|
break; case IRCReset: attr = A_NORMAL; pair = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -327,13 +325,13 @@ static void uiStatus(void) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (const struct View *view = views.head; view; view = view->next, ++num) {
|
for (const struct View *view = views.head; view; view = view->next, ++num) {
|
||||||
if (!view->unread) continue;
|
if (!view->unread) continue;
|
||||||
bool status = (view->tag.id == TAG_STATUS.id);
|
bool status = (view->tag.id == TagStatus.id);
|
||||||
|
|
||||||
int unread;
|
int unread;
|
||||||
wchar_t *str;
|
wchar_t *str;
|
||||||
int len = aswprintf(
|
int len = aswprintf(
|
||||||
&str, L",\3%02d%d\3%s%s%n(%d)",
|
&str, L",\3%02d%d\3%s%s%n(%d)",
|
||||||
(view->hot ? IRC_YELLOW : IRC_WHITE), num,
|
(view->hot ? IRCYellow : IRCWhite), num,
|
||||||
&status[":"], (status ? "" : view->tag.name),
|
&status[":"], (status ? "" : view->tag.name),
|
||||||
&unread, view->unread
|
&unread, view->unread
|
||||||
);
|
);
|
||||||
|
@ -396,11 +394,13 @@ void uiViewNum(int num) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const int ColsMax = 512;
|
||||||
|
|
||||||
void uiTopic(struct Tag tag, const char *topic) {
|
void uiTopic(struct Tag tag, const char *topic) {
|
||||||
struct View *view = viewTag(tag);
|
struct View *view = viewTag(tag);
|
||||||
if (!view->topic) {
|
if (!view->topic) {
|
||||||
view->topic = newpad(2, COLS_MAX);
|
view->topic = newpad(2, ColsMax);
|
||||||
mvwhline(view->topic, 1, 0, ACS_HLINE, COLS_MAX);
|
mvwhline(view->topic, 1, 0, ACS_HLINE, ColsMax);
|
||||||
}
|
}
|
||||||
wchar_t *wcs = ambstowcs(topic);
|
wchar_t *wcs = ambstowcs(topic);
|
||||||
if (!wcs) err(EX_DATAERR, "ambstowcs");
|
if (!wcs) err(EX_DATAERR, "ambstowcs");
|
||||||
|
@ -413,9 +413,9 @@ void uiTopic(struct Tag tag, const char *topic) {
|
||||||
void uiLog(struct Tag tag, enum UIHeat heat, const wchar_t *line) {
|
void uiLog(struct Tag tag, enum UIHeat heat, const wchar_t *line) {
|
||||||
struct View *view = viewTag(tag);
|
struct View *view = viewTag(tag);
|
||||||
waddch(view->log, '\n');
|
waddch(view->log, '\n');
|
||||||
if (view->mark && heat > UI_COLD) {
|
if (view->mark && heat > UICold) {
|
||||||
if (!view->unread++) waddch(view->log, '\n');
|
if (!view->unread++) waddch(view->log, '\n');
|
||||||
if (heat > UI_WARM) {
|
if (heat > UIWarm) {
|
||||||
view->hot = true;
|
view->hot = true;
|
||||||
beep(); // TODO: Notification.
|
beep(); // TODO: Notification.
|
||||||
}
|
}
|
||||||
|
@ -444,13 +444,13 @@ void uiInit(void) {
|
||||||
colorInit();
|
colorInit();
|
||||||
termInit();
|
termInit();
|
||||||
|
|
||||||
ui.status = newpad(1, COLS_MAX);
|
ui.status = newpad(1, ColsMax);
|
||||||
ui.input = newpad(1, COLS_MAX);
|
ui.input = newpad(1, ColsMax);
|
||||||
keypad(ui.input, true);
|
keypad(ui.input, true);
|
||||||
nodelay(ui.input, true);
|
nodelay(ui.input, true);
|
||||||
|
|
||||||
ui.view = viewTag(TAG_STATUS);
|
ui.view = viewTag(TagStatus);
|
||||||
uiViewTag(TAG_STATUS);
|
uiViewTag(TagStatus);
|
||||||
uiStatus();
|
uiStatus();
|
||||||
uiShow();
|
uiShow();
|
||||||
}
|
}
|
||||||
|
@ -466,13 +466,13 @@ void uiExit(void) {
|
||||||
static void logScrollUp(int lines) {
|
static void logScrollUp(int lines) {
|
||||||
int height = logHeight(ui.view);
|
int height = logHeight(ui.view);
|
||||||
if (ui.view->scroll == height) return;
|
if (ui.view->scroll == height) return;
|
||||||
if (ui.view->scroll == LOG_LINES) viewMark(ui.view);
|
if (ui.view->scroll == LogLines) viewMark(ui.view);
|
||||||
ui.view->scroll = MAX(ui.view->scroll - lines, height);
|
ui.view->scroll = MAX(ui.view->scroll - lines, height);
|
||||||
}
|
}
|
||||||
static void logScrollDown(int lines) {
|
static void logScrollDown(int lines) {
|
||||||
if (ui.view->scroll == LOG_LINES) return;
|
if (ui.view->scroll == LogLines) return;
|
||||||
ui.view->scroll = MIN(ui.view->scroll + lines, LOG_LINES);
|
ui.view->scroll = MIN(ui.view->scroll + lines, LogLines);
|
||||||
if (ui.view->scroll == LOG_LINES) viewUnmark(ui.view);
|
if (ui.view->scroll == LogLines) viewUnmark(ui.view);
|
||||||
}
|
}
|
||||||
static void logPageUp(void) {
|
static void logPageUp(void) {
|
||||||
logScrollUp(logHeight(ui.view) / 2);
|
logScrollUp(logHeight(ui.view) / 2);
|
||||||
|
@ -485,11 +485,14 @@ static bool keyChar(wchar_t ch) {
|
||||||
if (ch < 0200) {
|
if (ch < 0200) {
|
||||||
enum TermEvent event = termEvent((char)ch);
|
enum TermEvent event = termEvent((char)ch);
|
||||||
switch (event) {
|
switch (event) {
|
||||||
break; case TERM_FOCUS_IN: viewUnmark(ui.view);
|
break; case TermFocusIn: viewUnmark(ui.view);
|
||||||
break; case TERM_FOCUS_OUT: viewMark(ui.view);
|
break; case TermFocusOut: viewMark(ui.view);
|
||||||
break; default: {}
|
break; default: {}
|
||||||
}
|
}
|
||||||
if (event) return false;
|
if (event) {
|
||||||
|
uiStatus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool meta;
|
static bool meta;
|
||||||
|
@ -501,10 +504,10 @@ static bool keyChar(wchar_t ch) {
|
||||||
if (meta) {
|
if (meta) {
|
||||||
bool update = true;
|
bool update = true;
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
break; case L'b': edit(ui.view->tag, EDIT_BACK_WORD, 0);
|
break; case L'b': edit(ui.view->tag, EditBackWord, 0);
|
||||||
break; case L'f': edit(ui.view->tag, EDIT_FORE_WORD, 0);
|
break; case L'f': edit(ui.view->tag, EditForeWord, 0);
|
||||||
break; case L'\b': edit(ui.view->tag, EDIT_KILL_BACK_WORD, 0);
|
break; case L'\b': edit(ui.view->tag, EditKillBackWord, 0);
|
||||||
break; case L'd': edit(ui.view->tag, EDIT_KILL_FORE_WORD, 0);
|
break; case L'd': edit(ui.view->tag, EditKillForeWord, 0);
|
||||||
break; default: {
|
break; default: {
|
||||||
update = false;
|
update = false;
|
||||||
if (ch < L'0' || ch > L'9') break;
|
if (ch < L'0' || ch > L'9') break;
|
||||||
|
@ -519,29 +522,29 @@ static bool keyChar(wchar_t ch) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
break; case CTRL(L'L'): uiRedraw(); return false;
|
break; case CTRL(L'L'): uiRedraw(); return false;
|
||||||
|
|
||||||
break; case CTRL(L'A'): edit(ui.view->tag, EDIT_HOME, 0);
|
break; case CTRL(L'A'): edit(ui.view->tag, EditHome, 0);
|
||||||
break; case CTRL(L'B'): edit(ui.view->tag, EDIT_LEFT, 0);
|
break; case CTRL(L'B'): edit(ui.view->tag, EditLeft, 0);
|
||||||
break; case CTRL(L'D'): edit(ui.view->tag, EDIT_DELETE, 0);
|
break; case CTRL(L'D'): edit(ui.view->tag, EditDelete, 0);
|
||||||
break; case CTRL(L'E'): edit(ui.view->tag, EDIT_END, 0);
|
break; case CTRL(L'E'): edit(ui.view->tag, EditEnd, 0);
|
||||||
break; case CTRL(L'F'): edit(ui.view->tag, EDIT_RIGHT, 0);
|
break; case CTRL(L'F'): edit(ui.view->tag, EditRight, 0);
|
||||||
break; case CTRL(L'K'): edit(ui.view->tag, EDIT_KILL_LINE, 0);
|
break; case CTRL(L'K'): edit(ui.view->tag, EditKillLine, 0);
|
||||||
break; case CTRL(L'W'): edit(ui.view->tag, EDIT_KILL_BACK_WORD, 0);
|
break; case CTRL(L'W'): edit(ui.view->tag, EditKillBackWord, 0);
|
||||||
|
|
||||||
break; case CTRL(L'C'): edit(ui.view->tag, EDIT_INSERT, IRC_COLOR);
|
break; case CTRL(L'C'): edit(ui.view->tag, EditInsert, IRCColor);
|
||||||
break; case CTRL(L'N'): edit(ui.view->tag, EDIT_INSERT, IRC_RESET);
|
break; case CTRL(L'N'): edit(ui.view->tag, EditInsert, IRCReset);
|
||||||
break; case CTRL(L'O'): edit(ui.view->tag, EDIT_INSERT, IRC_BOLD);
|
break; case CTRL(L'O'): edit(ui.view->tag, EditInsert, IRCBold);
|
||||||
break; case CTRL(L'R'): edit(ui.view->tag, EDIT_INSERT, IRC_COLOR);
|
break; case CTRL(L'R'): edit(ui.view->tag, EditInsert, IRCColor);
|
||||||
break; case CTRL(L'T'): edit(ui.view->tag, EDIT_INSERT, IRC_ITALIC);
|
break; case CTRL(L'T'): edit(ui.view->tag, EditInsert, IRCItalic);
|
||||||
break; case CTRL(L'U'): edit(ui.view->tag, EDIT_INSERT, IRC_UNDERLINE);
|
break; case CTRL(L'U'): edit(ui.view->tag, EditInsert, IRCUnderline);
|
||||||
break; case CTRL(L'V'): edit(ui.view->tag, EDIT_INSERT, IRC_REVERSE);
|
break; case CTRL(L'V'): edit(ui.view->tag, EditInsert, IRCReverse);
|
||||||
|
|
||||||
break; case L'\b': edit(ui.view->tag, EDIT_BACKSPACE, 0);
|
break; case L'\b': edit(ui.view->tag, EditBackspace, 0);
|
||||||
break; case L'\t': edit(ui.view->tag, EDIT_COMPLETE, 0);
|
break; case L'\t': edit(ui.view->tag, EditComplete, 0);
|
||||||
break; case L'\n': edit(ui.view->tag, EDIT_ENTER, 0);
|
break; case L'\n': edit(ui.view->tag, EditEnter, 0);
|
||||||
|
|
||||||
break; default: {
|
break; default: {
|
||||||
if (!iswprint(ch)) return false;
|
if (!iswprint(ch)) return false;
|
||||||
edit(ui.view->tag, EDIT_INSERT, ch);
|
edit(ui.view->tag, EditInsert, ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -554,13 +557,13 @@ static bool keyCode(wchar_t ch) {
|
||||||
break; case KEY_SRIGHT: logScrollDown(1); return false;
|
break; case KEY_SRIGHT: logScrollDown(1); return false;
|
||||||
break; case KEY_PPAGE: logPageUp(); return false;
|
break; case KEY_PPAGE: logPageUp(); return false;
|
||||||
break; case KEY_NPAGE: logPageDown(); return false;
|
break; case KEY_NPAGE: logPageDown(); return false;
|
||||||
break; case KEY_LEFT: edit(ui.view->tag, EDIT_LEFT, 0);
|
break; case KEY_LEFT: edit(ui.view->tag, EditLeft, 0);
|
||||||
break; case KEY_RIGHT: edit(ui.view->tag, EDIT_RIGHT, 0);
|
break; case KEY_RIGHT: edit(ui.view->tag, EditRight, 0);
|
||||||
break; case KEY_HOME: edit(ui.view->tag, EDIT_HOME, 0);
|
break; case KEY_HOME: edit(ui.view->tag, EditHome, 0);
|
||||||
break; case KEY_END: edit(ui.view->tag, EDIT_END, 0);
|
break; case KEY_END: edit(ui.view->tag, EditEnd, 0);
|
||||||
break; case KEY_DC: edit(ui.view->tag, EDIT_DELETE, 0);
|
break; case KEY_DC: edit(ui.view->tag, EditDelete, 0);
|
||||||
break; case KEY_BACKSPACE: edit(ui.view->tag, EDIT_BACKSPACE, 0);
|
break; case KEY_BACKSPACE: edit(ui.view->tag, EditBackspace, 0);
|
||||||
break; case KEY_ENTER: edit(ui.view->tag, EDIT_ENTER, 0);
|
break; case KEY_ENTER: edit(ui.view->tag, EditEnter, 0);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
26
url.c
26
url.c
|
@ -23,23 +23,23 @@
|
||||||
|
|
||||||
#include "chat.h"
|
#include "chat.h"
|
||||||
|
|
||||||
static const char *SCHEMES[] = {
|
static const char *Schemes[] = {
|
||||||
"https:",
|
"https:",
|
||||||
"http:",
|
"http:",
|
||||||
"ftp:",
|
"ftp:",
|
||||||
};
|
};
|
||||||
static const size_t SCHEMES_LEN = sizeof(SCHEMES) / sizeof(SCHEMES[0]);
|
static const size_t SchemesLen = sizeof(Schemes) / sizeof(Schemes[0]);
|
||||||
|
|
||||||
struct Entry {
|
struct Entry {
|
||||||
size_t tag;
|
size_t tag;
|
||||||
char *url;
|
char *url;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { RING_LEN = 32 };
|
enum { RingLen = 32 };
|
||||||
static_assert(!(RING_LEN & (RING_LEN - 1)), "power of two RING_LEN");
|
static_assert(!(RingLen & (RingLen - 1)), "power of two RingLen");
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
struct Entry buf[RING_LEN];
|
struct Entry buf[RingLen];
|
||||||
size_t end;
|
size_t end;
|
||||||
} ring;
|
} ring;
|
||||||
|
|
||||||
|
@ -48,14 +48,14 @@ static void push(struct Tag tag, const char *url, size_t len) {
|
||||||
ring.buf[ring.end].tag = tag.id;
|
ring.buf[ring.end].tag = tag.id;
|
||||||
ring.buf[ring.end].url = strndup(url, len);
|
ring.buf[ring.end].url = strndup(url, len);
|
||||||
if (!ring.buf[ring.end].url) err(EX_OSERR, "strndup");
|
if (!ring.buf[ring.end].url) err(EX_OSERR, "strndup");
|
||||||
ring.end = (ring.end + 1) & (RING_LEN - 1);
|
ring.end = (ring.end + 1) & (RingLen - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void urlScan(struct Tag tag, const char *str) {
|
void urlScan(struct Tag tag, const char *str) {
|
||||||
while (str[0]) {
|
while (str[0]) {
|
||||||
size_t len = 1;
|
size_t len = 1;
|
||||||
for (size_t i = 0; i < SCHEMES_LEN; ++i) {
|
for (size_t i = 0; i < SchemesLen; ++i) {
|
||||||
if (strncmp(str, SCHEMES[i], strlen(SCHEMES[i]))) continue;
|
if (strncmp(str, Schemes[i], strlen(Schemes[i]))) continue;
|
||||||
len = strcspn(str, " >\"");
|
len = strcspn(str, " >\"");
|
||||||
push(tag, str, len);
|
push(tag, str, len);
|
||||||
}
|
}
|
||||||
|
@ -65,8 +65,8 @@ void urlScan(struct Tag tag, const char *str) {
|
||||||
|
|
||||||
void urlList(struct Tag tag) {
|
void urlList(struct Tag tag) {
|
||||||
uiHide();
|
uiHide();
|
||||||
for (size_t i = 0; i < RING_LEN; ++i) {
|
for (size_t i = 0; i < RingLen; ++i) {
|
||||||
struct Entry entry = ring.buf[(ring.end + i) & (RING_LEN - 1)];
|
struct Entry entry = ring.buf[(ring.end + i) & (RingLen - 1)];
|
||||||
if (!entry.url || entry.tag != tag.id) continue;
|
if (!entry.url || entry.tag != tag.id) continue;
|
||||||
printf("%s\n", entry.url);
|
printf("%s\n", entry.url);
|
||||||
}
|
}
|
||||||
|
@ -74,10 +74,10 @@ void urlList(struct Tag tag) {
|
||||||
|
|
||||||
void urlOpen(struct Tag tag, size_t at, size_t to) {
|
void urlOpen(struct Tag tag, size_t at, size_t to) {
|
||||||
size_t argc = 1;
|
size_t argc = 1;
|
||||||
char *argv[2 + RING_LEN] = { "open" };
|
char *argv[2 + RingLen] = { "open" };
|
||||||
size_t tagIndex = 0;
|
size_t tagIndex = 0;
|
||||||
for (size_t i = 0; i < RING_LEN; ++i) {
|
for (size_t i = 0; i < RingLen; ++i) {
|
||||||
struct Entry entry = ring.buf[(ring.end - i) & (RING_LEN - 1)];
|
struct Entry entry = ring.buf[(ring.end - i) & (RingLen - 1)];
|
||||||
if (!entry.url || entry.tag != tag.id) continue;
|
if (!entry.url || entry.tag != tag.id) continue;
|
||||||
if (tagIndex >= at && tagIndex < to) argv[argc++] = entry.url;
|
if (tagIndex >= at && tagIndex < to) argv[argc++] = entry.url;
|
||||||
tagIndex++;
|
tagIndex++;
|
||||||
|
|
Loading…
Reference in New Issue