Switch to cache interfaces

weechat-hashes
June McEnroe 2022-07-30 18:47:26 -04:00
parent c0be6fe4b2
commit 14a6486b9b
9 changed files with 75 additions and 269 deletions

View File

@ -16,7 +16,6 @@ OBJS += buffer.o
OBJS += cache.o OBJS += cache.o
OBJS += chat.o OBJS += chat.o
OBJS += command.o OBJS += command.o
OBJS += complete.o
OBJS += config.o OBJS += config.o
OBJS += edit.o OBJS += edit.o
OBJS += filter.o OBJS += filter.o

View File

@ -1,5 +1,5 @@
.\" To view this file, run: man ./README.7 .\" To view this file: $ man ./README.7
.Dd March 31, 2022 .Dd July 30, 2022
.Dt README 7 .Dt README 7
.Os "Causal Agency" .Os "Causal Agency"
. .
@ -9,7 +9,7 @@
. .
.Sh DESCRIPTION .Sh DESCRIPTION
.Xr catgirl 1 .Xr catgirl 1
is a TLS-only terminal IRC client. is a terminal IRC client.
. .
.Pp .Pp
Screenshot: Screenshot:
@ -180,7 +180,7 @@ $ make -C scripts sandman
.Ed .Ed
. .
.Sh FILES .Sh FILES
.Bl -tag -width "complete.c" -compact .Bl -tag -width "command.c" -compact
.It Pa chat.h .It Pa chat.h
global state and declarations global state and declarations
.It Pa chat.c .It Pa chat.c
@ -201,8 +201,8 @@ command handling
line wrapping line wrapping
.It Pa edit.c .It Pa edit.c
line editing line editing
.It Pa complete.c .It Pa cache.c
tab complete ordered cache
.It Pa url.c .It Pa url.c
URL detection URL detection
.It Pa filter.c .It Pa filter.c
@ -270,4 +270,4 @@ IRC bouncer:
.%D June 19, 2020 .%D June 19, 2020
.Re .Re
. .
.\" To view this file, run: man ./README.7 .\" To view this file: $ man ./README.7

2
chat.c
View File

@ -374,7 +374,7 @@ int main(int argc, char *argv[]) {
set(&network.name, host); set(&network.name, host);
set(&self.nick, "*"); set(&self.nick, "*");
inputCompleteAdd(); inputCache();
ircConfig(insecure, trust, cert, priv); ircConfig(insecure, trust, cert, priv);

16
chat.h
View File

@ -292,7 +292,7 @@ const char *commandIsPrivmsg(uint id, const char *input);
const char *commandIsNotice(uint id, const char *input); const char *commandIsNotice(uint id, const char *input);
const char *commandIsAction(uint id, const char *input); const char *commandIsAction(uint id, const char *input);
size_t commandWillSplit(uint id, const char *input); size_t commandWillSplit(uint id, const char *input);
void commandCompleteAdd(void); void commandCache(void);
enum Heat { enum Heat {
Ice, Ice,
@ -334,7 +334,7 @@ void inputWait(void);
void inputUpdate(void); void inputUpdate(void);
bool inputPending(uint id); bool inputPending(uint id);
void inputRead(void); void inputRead(void);
void inputCompleteAdd(void); void inputCache(void);
int inputSave(FILE *file); int inputSave(FILE *file);
void inputLoad(FILE *file, size_t version); void inputLoad(FILE *file, size_t version);
@ -412,18 +412,6 @@ void cacheReject(struct Cursor *curs);
void cacheRemove(uint id, const char *key); void cacheRemove(uint id, const char *key);
void cacheClear(uint id); void cacheClear(uint id);
const char *complete(uint id, const char *prefix);
const char *completeSubstr(uint id, const char *substr);
void completeAccept(void);
void completeReject(void);
void completeAdd(uint id, const char *str, enum Color color);
void completeTouch(uint id, const char *str, enum Color color);
void completeReplace(uint id, const char *old, const char *new);
void completeRemove(uint id, const char *str);
void completeClear(uint id);
uint completeID(const char *str);
enum Color completeColor(uint id, const char *str);
extern struct Util urlOpenUtil; extern struct Util urlOpenUtil;
extern struct Util urlCopyUtil; extern struct Util urlCopyUtil;
void urlScan(uint id, const char *nick, const char *mesg); void urlScan(uint id, const char *nick, const char *mesg);

View File

@ -139,7 +139,7 @@ static void commandMsg(uint id, char *params) {
char *nick = strsep(&params, " "); char *nick = strsep(&params, " ");
uint msg = idFor(nick); uint msg = idFor(nick);
if (idColors[msg] == Default) { if (idColors[msg] == Default) {
idColors[msg] = completeColor(id, nick); idColors[msg] = cacheColor(id, nick);
} }
if (params) { if (params) {
splitMessage("PRIVMSG", msg, params); splitMessage("PRIVMSG", msg, params);
@ -380,7 +380,7 @@ static void commandQuery(uint id, char *params) {
if (!params) return; if (!params) return;
uint query = idFor(params); uint query = idFor(params);
if (idColors[query] == Default) { if (idColors[query] == Default) {
idColors[query] = completeColor(id, params); idColors[query] = cacheColor(id, params);
} }
windowShow(windowFor(query)); windowShow(windowFor(query));
} }
@ -396,10 +396,11 @@ static void commandWindow(uint id, char *params) {
windowShow(windowFor(id)); windowShow(windowFor(id));
return; return;
} }
for (const char *match; (match = completeSubstr(None, params));) { struct Cursor curs = {0};
for (const char *match; (match = cacheSubstr(&curs, None, params));) {
id = idFind(match); id = idFind(match);
if (!id) continue; if (!id) continue;
completeAccept(); cacheAccept(&curs);
windowShow(windowFor(id)); windowShow(windowFor(id));
break; break;
} }
@ -669,11 +670,11 @@ void command(uint id, char *input) {
return; return;
} }
struct Cursor curs = {0};
const char *cmd = strsep(&input, " "); const char *cmd = strsep(&input, " ");
const char *unique = complete(None, cmd); const char *unique = cachePrefix(&curs, None, cmd);
if (unique && !complete(None, cmd)) { if (unique && !cachePrefix(&curs, None, cmd)) {
cmd = unique; cmd = unique;
completeReject();
} }
const struct Handler *handler = bsearch( const struct Handler *handler = bsearch(
@ -700,9 +701,9 @@ void command(uint id, char *input) {
handler->fn(id, input); handler->fn(id, input);
} }
void commandCompleteAdd(void) { void commandCache(void) {
for (size_t i = 0; i < ARRAY_LEN(Commands); ++i) { for (size_t i = 0; i < ARRAY_LEN(Commands); ++i) {
if (!commandAvailable(&Commands[i])) continue; if (!commandAvailable(&Commands[i])) continue;
completeAdd(None, Commands[i].cmd, Default); cacheInsert(false, None, Commands[i].cmd);
} }
} }

View File

@ -1,187 +0,0 @@
/* Copyright (C) 2020 June McEnroe <june@causal.agency>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Additional permission under GNU GPL version 3 section 7:
*
* If you modify this Program, or any covered work, by linking or
* combining it with OpenSSL (or a modified version of that library),
* containing parts covered by the terms of the OpenSSL License and the
* original SSLeay license, the licensors of this Program grant you
* additional permission to convey the resulting work. Corresponding
* Source for a non-source form of such a combination shall include the
* source code for the parts of OpenSSL used as well as that of the
* covered work.
*/
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include "chat.h"
struct Node {
uint id;
char *str;
enum Color color;
struct Node *prev;
struct Node *next;
};
static struct Node *alloc(uint id, const char *str, enum Color color) {
struct Node *node = malloc(sizeof(*node));
if (!node) err(EX_OSERR, "malloc");
node->id = id;
node->str = strdup(str);
node->color = color;
node->prev = NULL;
node->next = NULL;
if (!node->str) err(EX_OSERR, "strdup");
return node;
}
static struct Node *head;
static struct Node *tail;
static struct Node *detach(struct Node *node) {
if (node->prev) node->prev->next = node->next;
if (node->next) node->next->prev = node->prev;
if (head == node) head = node->next;
if (tail == node) tail = node->prev;
node->prev = NULL;
node->next = NULL;
return node;
}
static struct Node *prepend(struct Node *node) {
node->prev = NULL;
node->next = head;
if (head) head->prev = node;
head = node;
tail = (tail ?: node);
return node;
}
static struct Node *append(struct Node *node) {
node->next = NULL;
node->prev = tail;
if (tail) tail->next = node;
tail = node;
head = (head ?: node);
return node;
}
static struct Node *find(uint id, const char *str) {
for (struct Node *node = head; node; node = node->next) {
if (node->id != id) continue;
if (strcmp(node->str, str)) continue;
return node;
}
return NULL;
}
void completeAdd(uint id, const char *str, enum Color color) {
if (!find(id, str)) append(alloc(id, str, color));
}
void completeTouch(uint id, const char *str, enum Color color) {
struct Node *node = find(id, str);
if (node) node->color = color;
prepend(node ? detach(node) : alloc(id, str, color));
}
enum Color completeColor(uint id, const char *str) {
struct Node *node = find(id, str);
return (node ? node->color : Default);
}
static struct Node *match;
const char *complete(uint id, const char *prefix) {
for (match = (match ? match->next : head); match; match = match->next) {
if (match->id && match->id != id) continue;
if (strncasecmp(match->str, prefix, strlen(prefix))) continue;
return match->str;
}
return NULL;
}
const char *completeSubstr(uint id, const char *substr) {
for (match = (match ? match->next : head); match; match = match->next) {
if (match->id && match->id != id) continue;
if (!strstr(match->str, substr)) continue;
return match->str;
}
return NULL;
}
void completeAccept(void) {
if (match) prepend(detach(match));
match = NULL;
}
void completeReject(void) {
match = NULL;
}
static struct Node *iter;
uint completeID(const char *str) {
for (iter = (iter ? iter->next : head); iter; iter = iter->next) {
if (iter->id && !strcmp(iter->str, str)) return iter->id;
}
return None;
}
void completeReplace(uint id, const char *old, const char *new) {
struct Node *next = NULL;
for (struct Node *node = head; node; node = next) {
next = node->next;
if (id && node->id != id) continue;
if (strcmp(node->str, old)) continue;
free(node->str);
node->str = strdup(new);
prepend(detach(node));
if (!node->str) err(EX_OSERR, "strdup");
}
}
void completeRemove(uint id, const char *str) {
struct Node *next = NULL;
for (struct Node *node = head; node; node = next) {
next = node->next;
if (id && node->id != id) continue;
if (strcmp(node->str, str)) continue;
if (match == node) match = NULL;
if (iter == node) iter = NULL;
detach(node);
free(node->str);
free(node);
}
}
void completeClear(uint id) {
struct Node *next = NULL;
for (struct Node *node = head; node; node = next) {
next = node->next;
if (node->id != id) continue;
if (match == node) match = NULL;
if (iter == node) iter = NULL;
detach(node);
free(node->str);
free(node);
}
}

View File

@ -266,7 +266,7 @@ static void handleErrorSASLFail(struct Message *msg) {
static void handleReplyWelcome(struct Message *msg) { static void handleReplyWelcome(struct Message *msg) {
require(msg, false, 1); require(msg, false, 1);
set(&self.nick, msg->params[0]); set(&self.nick, msg->params[0]);
completeTouch(Network, self.nick, Default); cacheInsert(true, Network, self.nick);
if (self.mode) ircFormat("MODE %s %s\r\n", self.nick, self.mode); if (self.mode) ircFormat("MODE %s %s\r\n", self.nick, self.mode);
if (self.join) { if (self.join) {
uint count = 1; uint count = 1;
@ -278,7 +278,7 @@ static void handleReplyWelcome(struct Message *msg) {
replies[ReplyTopicAuto] += count; replies[ReplyTopicAuto] += count;
replies[ReplyNamesAuto] += count; replies[ReplyNamesAuto] += count;
} }
commandCompleteAdd(); commandCache();
handleReplyGeneric(msg); handleReplyGeneric(msg);
} }
@ -372,13 +372,13 @@ static void handleJoin(struct Message *msg) {
set(&self.host, msg->host); set(&self.host, msg->host);
} }
idColors[id] = hash(msg->params[0]); idColors[id] = hash(msg->params[0]);
completeTouch(None, msg->params[0], idColors[id]); cacheInsertColor(true, None, msg->params[0], idColors[id]);
if (replies[ReplyJoin]) { if (replies[ReplyJoin]) {
windowShow(windowFor(id)); windowShow(windowFor(id));
replies[ReplyJoin]--; replies[ReplyJoin]--;
} }
} }
completeTouch(id, msg->nick, hash(msg->user)); cacheInsertColor(true, id, msg->nick, hash(msg->user));
if (msg->params[2] && !strcasecmp(msg->params[2], msg->nick)) { if (msg->params[2] && !strcasecmp(msg->params[2], msg->nick)) {
msg->params[2] = NULL; msg->params[2] = NULL;
} }
@ -410,9 +410,9 @@ static void handlePart(struct Message *msg) {
require(msg, true, 1); require(msg, true, 1);
uint id = idFor(msg->params[0]); uint id = idFor(msg->params[0]);
if (!strcmp(msg->nick, self.nick)) { if (!strcmp(msg->nick, self.nick)) {
completeClear(id); cacheClear(id);
} }
completeRemove(id, msg->nick); cacheRemove(id, msg->nick);
enum Heat heat = filterCheck(Cold, id, msg); enum Heat heat = filterCheck(Cold, id, msg);
if (heat > Ice) urlScan(id, msg->nick, msg->params[1]); if (heat > Ice) urlScan(id, msg->nick, msg->params[1]);
uiFormat( uiFormat(
@ -432,14 +432,14 @@ static void handleKick(struct Message *msg) {
require(msg, true, 2); require(msg, true, 2);
uint id = idFor(msg->params[0]); uint id = idFor(msg->params[0]);
bool kicked = !strcmp(msg->params[1], self.nick); bool kicked = !strcmp(msg->params[1], self.nick);
completeTouch(id, msg->nick, hash(msg->user)); cacheInsertColor(true, id, msg->nick, hash(msg->user));
urlScan(id, msg->nick, msg->params[2]); urlScan(id, msg->nick, msg->params[2]);
uiFormat( uiFormat(
id, (kicked ? Hot : Cold), tagTime(msg), id, (kicked ? Hot : Cold), tagTime(msg),
"%s\3%02d%s\17\tkicks \3%02d%s\3 out of \3%02d%s\3%s%s", "%s\3%02d%s\17\tkicks \3%02d%s\3 out of \3%02d%s\3%s%s",
(kicked ? "\26" : ""), (kicked ? "\26" : ""),
hash(msg->user), msg->nick, hash(msg->user), msg->nick,
completeColor(id, msg->params[1]), msg->params[1], cacheColor(id, msg->params[1]), msg->params[1],
hash(msg->params[0]), msg->params[0], hash(msg->params[0]), msg->params[0],
(msg->params[2] ? ": " : ""), (msg->params[2] ?: "") (msg->params[2] ? ": " : ""), (msg->params[2] ?: "")
); );
@ -448,8 +448,8 @@ static void handleKick(struct Message *msg) {
msg->nick, msg->params[1], msg->params[0], msg->nick, msg->params[1], msg->params[0],
(msg->params[2] ? ": " : ""), (msg->params[2] ?: "") (msg->params[2] ? ": " : ""), (msg->params[2] ?: "")
); );
completeRemove(id, msg->params[1]); cacheRemove(id, msg->params[1]);
if (kicked) completeClear(id); if (kicked) cacheClear(id);
} }
static void handleNick(struct Message *msg) { static void handleNick(struct Message *msg) {
@ -458,7 +458,8 @@ static void handleNick(struct Message *msg) {
set(&self.nick, msg->params[0]); set(&self.nick, msg->params[0]);
inputUpdate(); inputUpdate();
} }
for (uint id; (id = completeID(msg->nick));) { struct Cursor curs = {0};
for (uint id; (id = cacheID(&curs, msg->nick));) {
if (!strcmp(idNames[id], msg->nick)) { if (!strcmp(idNames[id], msg->nick)) {
set(&idNames[id], msg->params[0]); set(&idNames[id], msg->params[0]);
} }
@ -473,12 +474,13 @@ static void handleNick(struct Message *msg) {
msg->nick, msg->params[0] msg->nick, msg->params[0]
); );
} }
completeReplace(None, msg->nick, msg->params[0]); cacheReplace(true, msg->nick, msg->params[0]);
} }
static void handleSetname(struct Message *msg) { static void handleSetname(struct Message *msg) {
require(msg, true, 1); require(msg, true, 1);
for (uint id; (id = completeID(msg->nick));) { struct Cursor curs = {0};
for (uint id; (id = cacheID(&curs, msg->nick));) {
uiFormat( uiFormat(
id, filterCheck(Cold, id, msg), tagTime(msg), id, filterCheck(Cold, id, msg), tagTime(msg),
"\3%02d%s\3\tis now known as \3%02d%s\3 (%s\17)", "\3%02d%s\3\tis now known as \3%02d%s\3 (%s\17)",
@ -490,7 +492,8 @@ static void handleSetname(struct Message *msg) {
static void handleQuit(struct Message *msg) { static void handleQuit(struct Message *msg) {
require(msg, true, 0); require(msg, true, 0);
for (uint id; (id = completeID(msg->nick));) { struct Cursor curs = {0};
for (uint id; (id = cacheID(&curs, msg->nick));) {
enum Heat heat = filterCheck(Cold, id, msg); enum Heat heat = filterCheck(Cold, id, msg);
if (heat > Ice) urlScan(id, msg->nick, msg->params[0]); if (heat > Ice) urlScan(id, msg->nick, msg->params[0]);
uiFormat( uiFormat(
@ -506,7 +509,7 @@ static void handleQuit(struct Message *msg) {
(msg->params[0] ? ": " : ""), (msg->params[0] ?: "") (msg->params[0] ? ": " : ""), (msg->params[0] ?: "")
); );
} }
completeRemove(None, msg->nick); cacheRemove(None, msg->nick);
} }
static void handleInvite(struct Message *msg) { static void handleInvite(struct Message *msg) {
@ -552,7 +555,7 @@ static void handleErrorUserOnChannel(struct Message *msg) {
uiFormat( uiFormat(
id, Warm, tagTime(msg), id, Warm, tagTime(msg),
"\3%02d%s\3 is already in \3%02d%s\3", "\3%02d%s\3 is already in \3%02d%s\3",
completeColor(id, msg->params[1]), msg->params[1], cacheColor(id, msg->params[1]), msg->params[1],
hash(msg->params[2]), msg->params[2] hash(msg->params[2]), msg->params[2]
); );
} }
@ -568,7 +571,7 @@ static void handleReplyNames(struct Message *msg) {
char *nick = &prefixes[strspn(prefixes, network.prefixes)]; char *nick = &prefixes[strspn(prefixes, network.prefixes)];
char *user = strsep(&name, "@"); char *user = strsep(&name, "@");
enum Color color = (user ? hash(user) : Default); enum Color color = (user ? hash(user) : Default);
completeAdd(id, nick, color); cacheInsertColor(false, id, nick, color);
if (!replies[ReplyNames] && !replies[ReplyNamesAuto]) continue; if (!replies[ReplyNames] && !replies[ReplyNamesAuto]) continue;
ptr = seprintf( ptr = seprintf(
ptr, end, "%s\3%02d%s\3", (ptr > buf ? ", " : ""), color, prefixes ptr, end, "%s\3%02d%s\3", (ptr > buf ? ", " : ""), color, prefixes
@ -635,23 +638,24 @@ static void handleReplyNoTopic(struct Message *msg) {
); );
} }
static void topicComplete(uint id, const char *topic) { static void topicCache(uint id, const char *topic) {
char buf[512]; char buf[512];
const char *prev = complete(id, "/topic "); struct Cursor curs = {0};
const char *prev = cachePrefix(&curs, id, "/topic ");
if (prev) { if (prev) {
snprintf(buf, sizeof(buf), "%s", prev); snprintf(buf, sizeof(buf), "%s", prev);
completeRemove(id, buf); cacheRemove(id, buf);
} }
if (topic) { if (topic) {
snprintf(buf, sizeof(buf), "/topic %s", topic); snprintf(buf, sizeof(buf), "/topic %s", topic);
completeAdd(id, buf, Default); cacheInsert(false, id, buf);
} }
} }
static void handleReplyTopic(struct Message *msg) { static void handleReplyTopic(struct Message *msg) {
require(msg, false, 3); require(msg, false, 3);
uint id = idFor(msg->params[1]); uint id = idFor(msg->params[1]);
topicComplete(id, msg->params[2]); topicCache(id, msg->params[2]);
if (!replies[ReplyTopic] && !replies[ReplyTopicAuto]) return; if (!replies[ReplyTopic] && !replies[ReplyTopicAuto]) return;
urlScan(id, NULL, msg->params[2]); urlScan(id, NULL, msg->params[2]);
uiFormat( uiFormat(
@ -702,7 +706,7 @@ static void handleTopic(struct Message *msg) {
require(msg, true, 2); require(msg, true, 2);
uint id = idFor(msg->params[0]); uint id = idFor(msg->params[0]);
if (!msg->params[1][0]) { if (!msg->params[1][0]) {
topicComplete(id, NULL); topicCache(id, NULL);
uiFormat( uiFormat(
id, Warm, tagTime(msg), id, Warm, tagTime(msg),
"\3%02d%s\3\tremoves the sign in \3%02d%s\3", "\3%02d%s\3\tremoves the sign in \3%02d%s\3",
@ -715,8 +719,8 @@ static void handleTopic(struct Message *msg) {
return; return;
} }
const char *prev = complete(id, "/topic "); struct Cursor curs = {0};
completeReject(); const char *prev = cachePrefix(&curs, id, "/topic ");
if (prev) { if (prev) {
prev += 7; prev += 7;
} else { } else {
@ -766,7 +770,7 @@ log:
id, tagTime(msg), "%s places a new sign in %s: %s", id, tagTime(msg), "%s places a new sign in %s: %s",
msg->nick, msg->params[0], msg->params[1] msg->nick, msg->params[0], msg->params[1]
); );
topicComplete(id, msg->params[1]); topicCache(id, msg->params[1]);
urlScan(id, msg->nick, msg->params[1]); urlScan(id, msg->nick, msg->params[1]);
} }
@ -893,7 +897,7 @@ static void handleMode(struct Message *msg) {
id, Cold, tagTime(msg), id, Cold, tagTime(msg),
"\3%02d%s\3\t%s \3%02d%c%s\3 %s%s in \3%02d%s\3", "\3%02d%s\3\t%s \3%02d%c%s\3 %s%s in \3%02d%s\3",
hash(msg->user), msg->nick, verb, hash(msg->user), msg->nick, verb,
completeColor(id, nick), prefix, nick, cacheColor(id, nick), prefix, nick,
mode, name, hash(msg->params[0]), msg->params[0] mode, name, hash(msg->params[0]), msg->params[0]
); );
logFormat( logFormat(
@ -1031,7 +1035,7 @@ static void handleReplyBanList(struct Message *msg) {
id, Warm, tagTime(msg), id, Warm, tagTime(msg),
"Banned from \3%02d%s\3 since %s by \3%02d%s\3: %s", "Banned from \3%02d%s\3 since %s by \3%02d%s\3: %s",
hash(msg->params[1]), msg->params[1], hash(msg->params[1]), msg->params[1],
since, completeColor(id, msg->params[3]), msg->params[3], since, cacheColor(id, msg->params[3]), msg->params[3],
msg->params[2] msg->params[2]
); );
} else { } else {
@ -1054,7 +1058,7 @@ static void onList(const char *list, struct Message *msg) {
id, Warm, tagTime(msg), id, Warm, tagTime(msg),
"On the \3%02d%s\3 %s list since %s by \3%02d%s\3: %s", "On the \3%02d%s\3 %s list since %s by \3%02d%s\3: %s",
hash(msg->params[1]), msg->params[1], list, hash(msg->params[1]), msg->params[1], list,
since, completeColor(id, msg->params[3]), msg->params[3], since, cacheColor(id, msg->params[3]), msg->params[3],
msg->params[2] msg->params[2]
); );
} else { } else {
@ -1087,7 +1091,7 @@ static void handleReplyList(struct Message *msg) {
static void handleReplyWhoisUser(struct Message *msg) { static void handleReplyWhoisUser(struct Message *msg) {
require(msg, false, 6); require(msg, false, 6);
completeTouch(Network, msg->params[1], hash(msg->params[2])); cacheInsertColor(true, Network, msg->params[1], hash(msg->params[2]));
uiFormat( uiFormat(
Network, Warm, tagTime(msg), Network, Warm, tagTime(msg),
"\3%02d%s\3\tis %s!%s@%s (%s\17)", "\3%02d%s\3\tis %s!%s@%s (%s\17)",
@ -1102,7 +1106,7 @@ static void handleReplyWhoisServer(struct Message *msg) {
uiFormat( uiFormat(
Network, Warm, tagTime(msg), Network, Warm, tagTime(msg),
"\3%02d%s\3\t%s connected to %s (%s)", "\3%02d%s\3\t%s connected to %s (%s)",
completeColor(Network, msg->params[1]), msg->params[1], cacheColor(Network, msg->params[1]), msg->params[1],
(replies[ReplyWhowas] ? "was" : "is"), msg->params[2], msg->params[3] (replies[ReplyWhowas] ? "was" : "is"), msg->params[2], msg->params[3]
); );
} }
@ -1126,7 +1130,7 @@ static void handleReplyWhoisIdle(struct Message *msg) {
uiFormat( uiFormat(
Network, Warm, tagTime(msg), Network, Warm, tagTime(msg),
"\3%02d%s\3\tis idle for %lu %s%s%s%s", "\3%02d%s\3\tis idle for %lu %s%s%s%s",
completeColor(Network, msg->params[1]), msg->params[1], cacheColor(Network, msg->params[1]), msg->params[1],
idle, unit, (idle != 1 ? "s" : ""), idle, unit, (idle != 1 ? "s" : ""),
(msg->params[3] ? ", signed on " : ""), (msg->params[3] ? signon : "") (msg->params[3] ? ", signed on " : ""), (msg->params[3] ? signon : "")
); );
@ -1148,7 +1152,7 @@ static void handleReplyWhoisChannels(struct Message *msg) {
uiFormat( uiFormat(
Network, Warm, tagTime(msg), Network, Warm, tagTime(msg),
"\3%02d%s\3\tis in %s", "\3%02d%s\3\tis in %s",
completeColor(Network, msg->params[1]), msg->params[1], buf cacheColor(Network, msg->params[1]), msg->params[1], buf
); );
} }
@ -1162,7 +1166,7 @@ static void handleReplyWhoisGeneric(struct Message *msg) {
uiFormat( uiFormat(
Network, Warm, tagTime(msg), Network, Warm, tagTime(msg),
"\3%02d%s\3\t%s%s%s", "\3%02d%s\3\t%s%s%s",
completeColor(Network, msg->params[1]), msg->params[1], cacheColor(Network, msg->params[1]), msg->params[1],
msg->params[2], (msg->params[3] ? " " : ""), (msg->params[3] ?: "") msg->params[2], (msg->params[3] ? " " : ""), (msg->params[3] ?: "")
); );
} }
@ -1170,13 +1174,13 @@ static void handleReplyWhoisGeneric(struct Message *msg) {
static void handleReplyEndOfWhois(struct Message *msg) { static void handleReplyEndOfWhois(struct Message *msg) {
require(msg, false, 2); require(msg, false, 2);
if (strcmp(msg->params[1], self.nick)) { if (strcmp(msg->params[1], self.nick)) {
completeRemove(Network, msg->params[1]); cacheRemove(Network, msg->params[1]);
} }
} }
static void handleReplyWhowasUser(struct Message *msg) { static void handleReplyWhowasUser(struct Message *msg) {
require(msg, false, 6); require(msg, false, 6);
completeTouch(Network, msg->params[1], hash(msg->params[2])); cacheInsertColor(true, Network, msg->params[1], hash(msg->params[2]));
uiFormat( uiFormat(
Network, Warm, tagTime(msg), Network, Warm, tagTime(msg),
"\3%02d%s\3\twas %s!%s@%s (%s)", "\3%02d%s\3\twas %s!%s@%s (%s)",
@ -1188,7 +1192,7 @@ static void handleReplyWhowasUser(struct Message *msg) {
static void handleReplyEndOfWhowas(struct Message *msg) { static void handleReplyEndOfWhowas(struct Message *msg) {
require(msg, false, 2); require(msg, false, 2);
if (strcmp(msg->params[1], self.nick)) { if (strcmp(msg->params[1], self.nick)) {
completeRemove(Network, msg->params[1]); cacheRemove(Network, msg->params[1]);
} }
} }
@ -1196,7 +1200,7 @@ static void handleReplyAway(struct Message *msg) {
require(msg, false, 3); require(msg, false, 3);
// Might be part of a WHOIS response. // Might be part of a WHOIS response.
uint id; uint id;
if (completeColor(Network, msg->params[1]) != Default) { if (cacheColor(Network, msg->params[1]) != Default) {
id = Network; id = Network;
} else { } else {
id = idFor(msg->params[1]); id = idFor(msg->params[1]);
@ -1204,7 +1208,7 @@ static void handleReplyAway(struct Message *msg) {
uiFormat( uiFormat(
id, (id == Network ? Warm : Cold), tagTime(msg), id, (id == Network ? Warm : Cold), tagTime(msg),
"\3%02d%s\3\tis away: %s", "\3%02d%s\3\tis away: %s",
completeColor(id, msg->params[1]), msg->params[1], msg->params[2] cacheColor(id, msg->params[1]), msg->params[1], msg->params[2]
); );
logFormat( logFormat(
id, tagTime(msg), "%s is away: %s", id, tagTime(msg), "%s is away: %s",
@ -1275,7 +1279,7 @@ static char *colorMentions(char *ptr, char *end, uint id, const char *msg) {
size_t len = strcspn(msg, ",:<> "); size_t len = strcspn(msg, ",:<> ");
char *p = seprintf(ptr, end, "%.*s", (int)len, msg); char *p = seprintf(ptr, end, "%.*s", (int)len, msg);
enum Color color = completeColor(id, ptr); enum Color color = cacheColor(id, ptr);
if (color != Default) { if (color != Default) {
ptr = seprintf(ptr, end, "\3%02d%.*s\3", color, (int)len, msg); ptr = seprintf(ptr, end, "\3%02d%.*s\3", color, (int)len, msg);
} else { } else {
@ -1315,7 +1319,7 @@ static void handlePrivmsg(struct Message *msg) {
heat = filterCheck(heat, id, msg); heat = filterCheck(heat, id, msg);
if (heat > Warm && !mine && !query) highlight = true; if (heat > Warm && !mine && !query) highlight = true;
if (!notice && !mine && heat > Ice) { if (!notice && !mine && heat > Ice) {
completeTouch(id, msg->nick, hash(msg->user)); cacheInsertColor(true, id, msg->nick, hash(msg->user));
} }
if (heat > Ice) urlScan(id, msg->nick, msg->params[1]); if (heat > Ice) urlScan(id, msg->nick, msg->params[1]);

13
input.c
View File

@ -261,12 +261,12 @@ static const struct {
{ L"\\wave", L"ヾ(^∇^)" }, { L"\\wave", L"ヾ(^∇^)" },
}; };
void inputCompleteAdd(void) { void inputCache(void) {
char mbs[256]; char mbs[256];
for (size_t i = 0; i < ARRAY_LEN(Macros); ++i) { for (size_t i = 0; i < ARRAY_LEN(Macros); ++i) {
size_t n = wcstombs(mbs, Macros[i].name, sizeof(mbs)); size_t n = wcstombs(mbs, Macros[i].name, sizeof(mbs));
assert(n != (size_t)-1); assert(n != (size_t)-1);
completeAdd(None, mbs, Default); cacheInsert(false, None, mbs);
} }
} }
@ -296,15 +296,16 @@ static struct {
size_t pos; size_t pos;
size_t len; size_t len;
bool suffix; bool suffix;
struct Cursor curs;
} tab; } tab;
static void tabAccept(void) { static void tabAccept(void) {
completeAccept(); cacheAccept(&tab.curs);
tab.len = 0; tab.len = 0;
} }
static void tabReject(void) { static void tabReject(void) {
completeReject(); cacheReject(&tab.curs);
tab.len = 0; tab.len = 0;
} }
@ -332,9 +333,9 @@ static int tabComplete(struct Edit *e, uint id) {
tab.suffix = true; tab.suffix = true;
} }
const char *comp = complete(id, tab.pre); const char *comp = cachePrefix(&tab.curs, id, tab.pre);
if (!comp) { if (!comp) {
comp = complete(id, tab.pre); comp = cachePrefix(&tab.curs, id, tab.pre);
tab.suffix ^= true; tab.suffix ^= true;
} }
if (!comp) { if (!comp) {

View File

@ -93,7 +93,7 @@ static struct Window *windowRemove(uint num) {
} }
static void windowFree(struct Window *window) { static void windowFree(struct Window *window) {
completeRemove(None, idNames[window->id]); cacheRemove(None, idNames[window->id]);
bufferFree(window->buffer); bufferFree(window->buffer);
free(window); free(window);
} }
@ -118,7 +118,7 @@ uint windowFor(uint id) {
window->thresh = windowThreshold; window->thresh = windowThreshold;
} }
window->buffer = bufferAlloc(); window->buffer = bufferAlloc();
completeAdd(None, idNames[id], idColors[id]); cacheInsertColor(false, None, idNames[id], idColors[id]);
return windowPush(window); return windowPush(window);
} }
@ -477,7 +477,7 @@ void windowClose(uint num) {
if (num >= count) return; if (num >= count) return;
if (windows[num]->id == Network) return; if (windows[num]->id == Network) return;
struct Window *window = windowRemove(num); struct Window *window = windowRemove(num);
completeClear(window->id); cacheClear(window->id);
windowFree(window); windowFree(window);
if (swap >= num) swap--; if (swap >= num) swap--;
if (show == num) { if (show == num) {