Browse Source

Move nick and tag coloring to color.c

Causal Agent 2 months ago
parent
commit
4cda410b57
Signed by: Curtis McEnroe <june@causal.agency> GPG Key ID: CEA2F97ADCFCD77C
10 changed files with 117 additions and 88 deletions
  1. 1
    0
      Makefile
  2. 2
    1
      README
  3. 3
    1
      catgirl.7
  4. 16
    14
      chat.h
  5. 50
    0
      color.c
  6. 0
    20
      format.c
  7. 32
    33
      handle.c
  8. 2
    2
      input.c
  9. 7
    13
      tag.c
  10. 4
    4
      ui.c

+ 1
- 0
Makefile View File

@@ -15,6 +15,7 @@ MAN1 = catgirl.1
15 15
 -include config.mk
16 16
 
17 17
 OBJS += chat.o
18
+OBJS += color.o
18 19
 OBJS += edit.o
19 20
 OBJS += event.o
20 21
 OBJS += format.o

+ 2
- 1
README View File

@@ -39,6 +39,7 @@ FILES
39 39
      input.c    input command handling
40 40
      irc.c      TLS client connection
41 41
      format.c   IRC formatting
42
+     color.c    nick and channel coloring
42 43
      ui.c       cursed UI
43 44
      term.c     terminal features unsupported by curses
44 45
      edit.c     line editing
@@ -53,4 +54,4 @@ FILES
53 54
 SEE ALSO
54 55
      catgirl(1), sandman(1)
55 56
 
56
-Causal Agency                  January 25, 2019                  Causal Agency
57
+Causal Agency                  February 25, 2019                 Causal Agency

+ 3
- 1
catgirl.7 View File

@@ -1,4 +1,4 @@
1
-.Dd January 25, 2019
1
+.Dd February 25, 2019
2 2
 .Dt CATGIRL 7
3 3
 .Os "Causal Agency"
4 4
 .
@@ -79,6 +79,8 @@ input command handling
79 79
 TLS client connection
80 80
 .It Pa format.c
81 81
 IRC formatting
82
+.It Pa color.c
83
+nick and channel coloring
82 84
 .It Pa ui.c
83 85
 cursed UI
84 86
 .It Pa term.c

+ 16
- 14
chat.h View File

@@ -52,6 +52,18 @@ void eventWait(const char *argv[static 2]);
52 52
 void eventPipe(const char *argv[static 2]);
53 53
 noreturn void eventLoop(void);
54 54
 
55
+struct Tag {
56
+	size_t id;
57
+	const char *name;
58
+};
59
+
60
+enum { TagsLen = 256 };
61
+const struct Tag TagNone;
62
+const struct Tag TagStatus;
63
+const struct Tag TagRaw;
64
+struct Tag tagFind(const char *name);
65
+struct Tag tagFor(const char *name);
66
+
55 67
 enum IRCColor {
56 68
 	IRCWhite,
57 69
 	IRCBlack,
@@ -80,19 +92,6 @@ enum {
80 92
 	IRCUnderline = 037,
81 93
 };
82 94
 
83
-struct Tag {
84
-	size_t id;
85
-	const char *name;
86
-	enum IRCColor color;
87
-};
88
-
89
-enum { TagsLen = 256 };
90
-const struct Tag TagNone;
91
-const struct Tag TagStatus;
92
-const struct Tag TagRaw;
93
-struct Tag tagFind(const char *name);
94
-struct Tag tagFor(const char *name, enum IRCColor color);
95
-
96 95
 struct Format {
97 96
 	const wchar_t *str;
98 97
 	size_t len;
@@ -102,7 +101,10 @@ struct Format {
102 101
 };
103 102
 void formatReset(struct Format *format);
104 103
 bool formatParse(struct Format *format, const wchar_t *split);
105
-enum IRCColor formatColor(const char *str);
104
+
105
+enum IRCColor colorGen(const char *str);
106
+struct Tag colorTag(struct Tag tag, const char *gen);
107
+enum IRCColor colorFor(struct Tag tag);
106 108
 
107 109
 void handle(char *line);
108 110
 void input(struct Tag tag, char *line);

+ 50
- 0
color.c View File

@@ -0,0 +1,50 @@
1
+/* Copyright (C) 2019  C. McEnroe <june@causal.agency>
2
+ *
3
+ * This program is free software: you can redistribute it and/or modify
4
+ * it under the terms of the GNU Affero General Public License as published by
5
+ * the Free Software Foundation, either version 3 of the License, or
6
+ * (at your option) any later version.
7
+ *
8
+ * This program is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
+ * GNU Affero General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Affero General Public License
14
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
+ */
16
+
17
+#include <stdint.h>
18
+
19
+#include "chat.h"
20
+
21
+// Adapted from <https://github.com/cbreeden/fxhash/blob/master/lib.rs>.
22
+static uint32_t hashChar(uint32_t hash, char ch) {
23
+	hash = (hash << 5) | (hash >> 27);
24
+	hash ^= ch;
25
+	hash *= 0x27220A95;
26
+	return hash;
27
+}
28
+
29
+enum IRCColor colorGen(const char *str) {
30
+	if (!str) return IRCDefault;
31
+	uint32_t hash = 0;
32
+	for (; str[0]; ++str) {
33
+		hash = hashChar(hash, str[0]);
34
+	}
35
+	while (IRCBlack == (hash & IRCLightGray)) {
36
+		hash = hashChar(hash, '\0');
37
+	}
38
+	return (hash & IRCLightGray);
39
+}
40
+
41
+static enum IRCColor colors[TagsLen];
42
+
43
+struct Tag colorTag(struct Tag tag, const char *gen) {
44
+	if (!colors[tag.id]) colors[tag.id] = 1 + colorGen(gen);
45
+	return tag;
46
+}
47
+
48
+enum IRCColor colorFor(struct Tag tag) {
49
+	return colors[tag.id] ? colors[tag.id] - 1 : IRCDefault;
50
+}

+ 0
- 20
format.c View File

@@ -21,26 +21,6 @@
21 21
 
22 22
 #include "chat.h"
23 23
 
24
-// Adapted from <https://github.com/cbreeden/fxhash/blob/master/lib.rs>.
25
-static uint32_t hashChar(uint32_t hash, char ch) {
26
-	hash = (hash << 5) | (hash >> 27);
27
-	hash ^= ch;
28
-	hash *= 0x27220A95;
29
-	return hash;
30
-}
31
-
32
-enum IRCColor formatColor(const char *str) {
33
-	if (!str) return IRCDefault;
34
-	uint32_t hash = 0;
35
-	for (; str[0]; ++str) {
36
-		hash = hashChar(hash, str[0]);
37
-	}
38
-	while (IRCBlack == (hash & IRCLightGray)) {
39
-		hash = hashChar(hash, '\0');
40
-	}
41
-	return (hash & IRCLightGray);
42
-}
43
-
44 24
 void formatReset(struct Format *format) {
45 25
 	format->bold = false;
46 26
 	format->italic = false;

+ 32
- 33
handle.c View File

@@ -160,7 +160,7 @@ static void handleReplyWhoisUser(char *prefix, char *params) {
160 160
 		prefix, NULL, NULL, NULL,
161 161
 		params, 6, 0, NULL, &nick, &user, &host, NULL, &real
162 162
 	);
163
-	whoisColor = formatColor(user[0] == '~' ? &user[1] : user);
163
+	whoisColor = colorGen(user[0] == '~' ? &user[1] : user);
164 164
 	uiFmt(
165 165
 		TagStatus, UIWarm,
166 166
 		"\3%d%s\3 is %s@%s, \"%s\"",
@@ -214,7 +214,7 @@ static void handleErrorNoSuchNick(char *prefix, char *params) {
214 214
 static void handleJoin(char *prefix, char *params) {
215 215
 	char *nick, *user, *chan;
216 216
 	parse(prefix, &nick, &user, NULL, params, 1, 0, &chan);
217
-	struct Tag tag = tagFor(chan, formatColor(chan));
217
+	struct Tag tag = colorTag(tagFor(chan), chan);
218 218
 
219 219
 	if (!strcmp(nick, self.nick)) {
220 220
 		tabTouch(TagNone, chan);
@@ -226,7 +226,7 @@ static void handleJoin(char *prefix, char *params) {
226 226
 	uiFmt(
227 227
 		tag, UICold,
228 228
 		"\3%d%s\3 arrives in \3%d%s\3",
229
-		formatColor(user), nick, formatColor(chan), chan
229
+		colorGen(user), nick, colorGen(chan), chan
230 230
 	);
231 231
 	logFmt(tag, NULL, "%s arrives in %s", nick, chan);
232 232
 }
@@ -234,7 +234,7 @@ static void handleJoin(char *prefix, char *params) {
234 234
 static void handlePart(char *prefix, char *params) {
235 235
 	char *nick, *user, *chan, *mesg;
236 236
 	parse(prefix, &nick, &user, NULL, params, 1, 1, &chan, &mesg);
237
-	struct Tag tag = tagFor(chan, formatColor(chan));
237
+	struct Tag tag = colorTag(tagFor(chan), chan);
238 238
 
239 239
 	if (!strcmp(nick, self.nick)) {
240 240
 		tabClear(tag);
@@ -247,14 +247,14 @@ static void handlePart(char *prefix, char *params) {
247 247
 		uiFmt(
248 248
 			tag, UICold,
249 249
 			"\3%d%s\3 leaves \3%d%s\3, \"%s\"",
250
-			formatColor(user), nick, formatColor(chan), chan, dequote(mesg)
250
+			colorGen(user), nick, colorGen(chan), chan, dequote(mesg)
251 251
 		);
252 252
 		logFmt(tag, NULL, "%s leaves %s, \"%s\"", nick, chan, dequote(mesg));
253 253
 	} else {
254 254
 		uiFmt(
255 255
 			tag, UICold,
256 256
 			"\3%d%s\3 leaves \3%d%s\3",
257
-			formatColor(user), nick, formatColor(chan), chan
257
+			colorGen(user), nick, colorGen(chan), chan
258 258
 		);
259 259
 		logFmt(tag, NULL, "%s leaves %s", nick, chan);
260 260
 	}
@@ -263,7 +263,7 @@ static void handlePart(char *prefix, char *params) {
263 263
 static void handleKick(char *prefix, char *params) {
264 264
 	char *nick, *user, *chan, *kick, *mesg;
265 265
 	parse(prefix, &nick, &user, NULL, params, 2, 1, &chan, &kick, &mesg);
266
-	struct Tag tag = tagFor(chan, formatColor(chan));
266
+	struct Tag tag = colorTag(tagFor(chan), chan);
267 267
 	bool kicked = !strcmp(kick, self.nick);
268 268
 
269 269
 	if (kicked) {
@@ -277,9 +277,9 @@ static void handleKick(char *prefix, char *params) {
277 277
 		uiFmt(
278 278
 			tag, (kicked ? UIHot : UICold),
279 279
 			"\3%d%s\3 kicks \3%d%s\3 out of \3%d%s\3, \"%s\"",
280
-			formatColor(user), nick,
281
-			formatColor(kick), kick,
282
-			formatColor(chan), chan,
280
+			colorGen(user), nick,
281
+			colorGen(kick), kick,
282
+			colorGen(chan), chan,
283 283
 			dequote(mesg)
284 284
 		);
285 285
 		logFmt(
@@ -290,9 +290,9 @@ static void handleKick(char *prefix, char *params) {
290 290
 		uiFmt(
291 291
 			tag, (kicked ? UIHot : UICold),
292 292
 			"\3%d%s\3 kicks \3%d%s\3 out of \3%d%s\3",
293
-			formatColor(user), nick,
294
-			formatColor(kick), kick,
295
-			formatColor(chan), chan
293
+			colorGen(user), nick,
294
+			colorGen(kick), kick,
295
+			colorGen(chan), chan
296 296
 		);
297 297
 		logFmt(tag, NULL, "%s kicks %s out of %s", nick, kick, chan);
298 298
 	}
@@ -311,11 +311,11 @@ static void handleQuit(char *prefix, char *params) {
311 311
 			uiFmt(
312 312
 				tag, UICold,
313 313
 				"\3%d%s\3 leaves, \"%s\"",
314
-				formatColor(user), nick, dequote(mesg)
314
+				colorGen(user), nick, dequote(mesg)
315 315
 			);
316 316
 			logFmt(tag, NULL, "%s leaves, \"%s\"", nick, dequote(mesg));
317 317
 		} else {
318
-			uiFmt(tag, UICold, "\3%d%s\3 leaves", formatColor(user), nick);
318
+			uiFmt(tag, UICold, "\3%d%s\3 leaves", colorGen(user), nick);
319 319
 			logFmt(tag, NULL, "%s leaves", nick);
320 320
 		}
321 321
 	}
@@ -324,13 +324,13 @@ static void handleQuit(char *prefix, char *params) {
324 324
 static void handleReplyTopic(char *prefix, char *params) {
325 325
 	char *chan, *topic;
326 326
 	parse(prefix, NULL, NULL, NULL, params, 3, 0, NULL, &chan, &topic);
327
-	struct Tag tag = tagFor(chan, formatColor(chan));
327
+	struct Tag tag = colorTag(tagFor(chan), chan);
328 328
 
329 329
 	urlScan(tag, topic);
330 330
 	uiFmt(
331 331
 		tag, UICold,
332 332
 		"The sign in \3%d%s\3 reads, \"%s\"",
333
-		formatColor(chan), chan, topic
333
+		colorGen(chan), chan, topic
334 334
 	);
335 335
 	logFmt(tag, NULL, "The sign in %s reads, \"%s\"", chan, topic);
336 336
 }
@@ -338,7 +338,7 @@ static void handleReplyTopic(char *prefix, char *params) {
338 338
 static void handleTopic(char *prefix, char *params) {
339 339
 	char *nick, *user, *chan, *topic;
340 340
 	parse(prefix, &nick, &user, NULL, params, 2, 0, &chan, &topic);
341
-	struct Tag tag = tagFor(chan, formatColor(chan));
341
+	struct Tag tag = colorTag(tagFor(chan), chan);
342 342
 
343 343
 	if (strcmp(nick, self.nick)) tabTouch(tag, nick);
344 344
 
@@ -346,7 +346,7 @@ static void handleTopic(char *prefix, char *params) {
346 346
 	uiFmt(
347 347
 		tag, UICold,
348 348
 		"\3%d%s\3 places a new sign in \3%d%s\3, \"%s\"",
349
-		formatColor(user), nick, formatColor(chan), chan, topic
349
+		colorGen(user), nick, colorGen(chan), chan, topic
350 350
 	);
351 351
 	logFmt(tag, NULL, "%s places a new sign in %s, \"%s\"", nick, chan, topic);
352 352
 }
@@ -369,7 +369,7 @@ static void handleReplyWho(char *prefix, char *params) {
369 369
 		params, 6, 0, NULL, &chan, &user, NULL, NULL, &nick
370 370
 	);
371 371
 	if (user[0] == '~') user = &user[1];
372
-	struct Tag tag = tagFor(chan, formatColor(chan));
372
+	struct Tag tag = colorTag(tagFor(chan), chan);
373 373
 
374 374
 	tabAdd(tag, nick);
375 375
 
@@ -377,7 +377,7 @@ static void handleReplyWho(char *prefix, char *params) {
377 377
 	int len = snprintf(
378 378
 		&who.buf[who.len], cap,
379 379
 		"%s\3%d%s\3",
380
-		(who.len ? ", " : ""), formatColor(user), nick
380
+		(who.len ? ", " : ""), colorGen(user), nick
381 381
 	);
382 382
 	if ((size_t)len < cap) who.len += len;
383 383
 }
@@ -385,12 +385,12 @@ static void handleReplyWho(char *prefix, char *params) {
385 385
 static void handleReplyEndOfWho(char *prefix, char *params) {
386 386
 	char *chan;
387 387
 	parse(prefix, NULL, NULL, NULL, params, 2, 0, NULL, &chan);
388
-	struct Tag tag = tagFor(chan, formatColor(chan));
388
+	struct Tag tag = colorTag(tagFor(chan), chan);
389 389
 
390 390
 	uiFmt(
391 391
 		tag, UICold,
392 392
 		"In \3%d%s\3 are %s",
393
-		formatColor(chan), chan, who.buf
393
+		colorGen(chan), chan, who.buf
394 394
 	);
395 395
 	who.len = 0;
396 396
 }
@@ -413,7 +413,7 @@ static void handleNick(char *prefix, char *params) {
413 413
 		uiFmt(
414 414
 			tag, UICold,
415 415
 			"\3%d%s\3 is now known as \3%d%s\3",
416
-			formatColor(user), prev, formatColor(user), next
416
+			colorGen(user), prev, colorGen(user), next
417 417
 		);
418 418
 		logFmt(tag, NULL, "%s is now known as %s", prev, next);
419 419
 	}
@@ -432,7 +432,7 @@ static void handleCTCP(struct Tag tag, char *nick, char *user, char *mesg) {
432 432
 	uiFmt(
433 433
 		tag, (ping ? UIHot : UIWarm),
434 434
 		"%c\3%d* %s\17 %s",
435
-		ping["\17\26"], formatColor(user), nick, params
435
+		ping["\17\26"], colorGen(user), nick, params
436 436
 	);
437 437
 	logFmt(tag, NULL, "* %s %s", nick, params);
438 438
 }
@@ -441,9 +441,8 @@ static void handlePrivmsg(char *prefix, char *params) {
441 441
 	char *nick, *user, *chan, *mesg;
442 442
 	parse(prefix, &nick, &user, NULL, params, 2, 0, &chan, &mesg);
443 443
 	bool direct = !strcmp(chan, self.nick);
444
-	struct Tag tag = direct
445
-		? tagFor(nick, formatColor(user))
446
-		: tagFor(chan, formatColor(chan));
444
+	struct Tag tag = tagFor(direct ? nick : chan);
445
+	colorTag(tag, direct ? user : chan);
447 446
 	if (mesg[0] == '\1') {
448 447
 		handleCTCP(tag, nick, user, mesg);
449 448
 		return;
@@ -459,7 +458,7 @@ static void handlePrivmsg(char *prefix, char *params) {
459 458
 		tag, (hot ? UIHot : UIWarm),
460 459
 		"%c%c\3%d<%s>%c %s",
461 460
 		(me ? IRCUnderline : IRCColor), (ping ? IRCReverse : IRCColor),
462
-		formatColor(user), nick, IRCReset, mesg
461
+		colorGen(user), nick, IRCReset, mesg
463 462
 	);
464 463
 	logFmt(tag, NULL, "<%s> %s", nick, mesg);
465 464
 }
@@ -467,11 +466,11 @@ static void handlePrivmsg(char *prefix, char *params) {
467 466
 static void handleNotice(char *prefix, char *params) {
468 467
 	char *nick, *user, *chan, *mesg;
469 468
 	parse(prefix, &nick, &user, NULL, params, 2, 0, &chan, &mesg);
469
+	bool direct = !strcmp(chan, self.nick);
470 470
 	struct Tag tag = TagStatus;
471 471
 	if (user) {
472
-		tag = strcmp(chan, self.nick)
473
-			? tagFor(chan, formatColor(chan))
474
-			: tagFor(nick, formatColor(user));
472
+		tag = tagFor(direct ? nick : chan);
473
+		colorTag(tag, direct ? user : chan);
475 474
 	}
476 475
 
477 476
 	if (strcmp(nick, self.nick)) tabTouch(tag, nick);
@@ -481,7 +480,7 @@ static void handleNotice(char *prefix, char *params) {
481 480
 	uiFmt(
482 481
 		tag, (ping ? UIHot : UIWarm),
483 482
 		"%c\3%d-%s-\17 %s",
484
-		ping["\17\26"], formatColor(user), nick, mesg
483
+		ping["\17\26"], colorGen(user), nick, mesg
485 484
 	);
486 485
 	logFmt(tag, NULL, "-%s- %s", nick, mesg);
487 486
 }

+ 2
- 2
input.c View File

@@ -66,8 +66,8 @@ static void inputQuery(struct Tag tag, char *params) {
66 66
 	char *nick = strsep(&params, " ");
67 67
 	if (nick) {
68 68
 		tabTouch(TagNone, nick);
69
-		uiShowTag(tagFor(nick, IRCDefault));
70
-		logReplay(tagFor(nick, IRCDefault));
69
+		uiShowTag(tagFor(nick));
70
+		logReplay(tagFor(nick));
71 71
 	} else {
72 72
 		uiLog(tag, UIHot, L"/query requires a nickname");
73 73
 	}

+ 7
- 13
tag.c View File

@@ -23,37 +23,31 @@
23 23
 
24 24
 static struct {
25 25
 	char *name[TagsLen];
26
-	enum IRCColor color[TagsLen];
27 26
 	size_t len;
28 27
 } tags = {
29 28
 	.name = { "<none>", "<status>", "<raw>" },
30
-	.color = { IRCBlack, IRCDefault, IRCRed },
31 29
 	.len = 3,
32 30
 };
33 31
 
34
-const struct Tag TagNone   = { 0, "<none>", IRCBlack };
35
-const struct Tag TagStatus = { 1, "<status>", IRCDefault };
36
-const struct Tag TagRaw    = { 2, "<raw>", IRCRed };
32
+const struct Tag TagNone   = { 0, "<none>" };
33
+const struct Tag TagStatus = { 1, "<status>" };
34
+const struct Tag TagRaw    = { 2, "<raw>" };
37 35
 
38 36
 struct Tag tagFind(const char *name) {
39 37
 	for (size_t id = 0; id < tags.len; ++id) {
40 38
 		if (strcmp(tags.name[id], name)) continue;
41
-		return (struct Tag) { id, tags.name[id], tags.color[id] };
39
+		return (struct Tag) { id, tags.name[id] };
42 40
 	}
43 41
 	return TagNone;
44 42
 }
45 43
 
46
-struct Tag tagFor(const char *name, enum IRCColor color) {
44
+struct Tag tagFor(const char *name) {
47 45
 	struct Tag tag = tagFind(name);
48
-	if (tag.id != TagNone.id) {
49
-		tag.color = tags.color[tag.id] = color;
50
-		return tag;
51
-	}
46
+	if (tag.id != TagNone.id) return tag;
52 47
 	if (tags.len == TagsLen) return TagStatus;
53 48
 
54 49
 	size_t id = tags.len++;
55 50
 	tags.name[id] = strdup(name);
56
-	tags.color[id] = color;
57 51
 	if (!tags.name[id]) err(EX_OSERR, "strdup");
58
-	return (struct Tag) { id, tags.name[id], color };
52
+	return (struct Tag) { id, tags.name[id] };
59 53
 }

+ 4
- 4
ui.c View File

@@ -339,10 +339,10 @@ static void uiStatus(void) {
339 339
 		wchar_t *str;
340 340
 		int len = aswprintf(
341 341
 			&str, L"%c\3%d %d %s %n(\3%02d%u\3%d) ",
342
-			(windows.active == win ? IRCReverse : IRCReset), win->tag.color,
342
+			(windows.active == win ? IRCReverse : IRCReset), colorFor(win->tag),
343 343
 			num, win->tag.name,
344
-			&unread, (win->hot ? IRCWhite : win->tag.color), win->unread,
345
-			win->tag.color
344
+			&unread, (win->hot ? IRCWhite : colorFor(win->tag)), win->unread,
345
+			colorFor(win->tag)
346 346
 		);
347 347
 		if (len < 0) err(EX_OSERR, "aswprintf");
348 348
 		if (!win->unread) str[unread] = L'\0';
@@ -557,7 +557,7 @@ void uiPrompt(bool nickChanged) {
557 557
 	if (nickChanged || !promptMesg || !promptAction) {
558 558
 		free(promptMesg);
559 559
 		free(promptAction);
560
-		enum IRCColor color = formatColor(self.user);
560
+		enum IRCColor color = colorGen(self.user);
561 561
 		int len = aswprintf(&promptMesg, L"\3%d<%s>\3 ", color, self.nick);
562 562
 		if (len < 0) err(EX_OSERR, "aswprintf");
563 563
 		len = aswprintf(&promptAction, L"\3%d* %s\3 ", color, self.nick);

Loading…
Cancel
Save