about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--chat.c2
-rw-r--r--chat.h4
-rw-r--r--edit.c30
-rw-r--r--ui.c168
5 files changed, 146 insertions, 59 deletions
diff --git a/Makefile b/Makefile
index 6ba0ba5..63f719d 100644
--- a/Makefile
+++ b/Makefile
@@ -6,6 +6,7 @@ CFLAGS += -std=c11 -Wall -Wextra -Wpedantic
 LDLIBS = -lcurses -lcrypto -ltls
 
 OBJS += chat.o
+OBJS += edit.o
 OBJS += handle.o
 OBJS += irc.o
 OBJS += ui.o
diff --git a/chat.c b/chat.c
index 1656a53..545eca6 100644
--- a/chat.c
+++ b/chat.c
@@ -41,7 +41,7 @@ enum Color idColors[IDCap] = {
 
 size_t idNext = Network + 1;
 
-struct Self self;
+struct Self self = { .color = Default };
 
 static volatile sig_atomic_t signals[NSIG];
 static void signalHandler(int signal) {
diff --git a/chat.h b/chat.h
index 8de5df1..c754357 100644
--- a/chat.h
+++ b/chat.h
@@ -72,6 +72,7 @@ extern struct Self {
 	char *chanTypes;
 	char *prefixes;
 	char *nick;
+	enum Color color;
 } self;
 
 static inline void set(char **field, const char *value) {
@@ -121,6 +122,9 @@ void uiFormat(
 	size_t id, enum Heat heat, const time_t *time, const char *format, ...
 ) __attribute__((format(printf, 4, 5)));
 
+const char *editHead(void);
+const char *editTail(void);
+
 static inline enum Color hash(const char *str) {
 	if (*str == '~') str++;
 	uint32_t hash = 0;
diff --git a/edit.c b/edit.c
new file mode 100644
index 0000000..446e0e9
--- /dev/null
+++ b/edit.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 2020  C. 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/>.
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sysexits.h>
+
+#include "chat.h"
+
+const char *editHead(void) {
+	return "foo\0033bar";
+}
+
+const char *editTail(void) {
+	return "baz\3";
+}
diff --git a/ui.c b/ui.c
index e93c08c..568df8d 100644
--- a/ui.c
+++ b/ui.c
@@ -268,71 +268,18 @@ static void styleParse(struct Style *style, const char **str, size_t *len) {
 	*len = strcspn(*str, "\2\3\17\26\35\37");
 }
 
-static int wordWidth(const char *str) {
-	size_t len = strcspn(str, " ");
-	int width = 0;
-	while (len) {
-		wchar_t wc;
-		int n = mbtowc(&wc, str, len);
-		if (n < 1) return width + len;
-		width += (iswprint(wc) ? wcwidth(wc) : 0);
-		str += n;
-		len -= n;
-	}
-	return width;
-}
-
-static void styleAdd(WINDOW *win, const char *str, bool show) {
-	int y, x, width;
-	getmaxyx(win, y, width);
-
+static void statusAdd(const char *str) {
 	size_t len;
-	int align = 0;
 	struct Style style = Reset;
 	while (*str) {
-		if (*str == '\t') {
-			waddch(win, ' ');
-			getyx(win, y, align);
-			str++;
-		} else if (*str == ' ') {
-			getyx(win, y, x);
-			const char *word = &str[strspn(str, " ")];
-			if (width - x - 1 <= wordWidth(word)) {
-				waddch(win, '\n');
-				getyx(win, y, x);
-				wmove(win, y, align);
-				str = word;
-			} else {
-				waddch(win, ' ');
-				str++;
-			}
-		}
-
-		const char *code = str;
 		styleParse(&style, &str, &len);
-		if (show) {
-			wattr_set(win, A_BOLD | A_REVERSE, 0, NULL);
-			switch (*code) {
-				break; case '\2':  waddch(win, 'B');
-				break; case '\3':  waddch(win, 'C');
-				break; case '\17': waddch(win, 'O');
-				break; case '\26': waddch(win, 'R');
-				break; case '\35': waddch(win, 'I');
-				break; case '\37': waddch(win, 'U');
-			}
-			if (str - code > 1) waddnstr(win, &code[1], str - &code[1]);
-		}
-
-		size_t ws = strcspn(str, "\t ");
-		if (ws < len) len = ws;
-
 		wattr_set(
-			win,
+			status,
 			style.attr | colorAttr(mapColor(style.fg)),
 			colorPair(mapColor(style.fg), mapColor(style.bg)),
 			NULL
 		);
-		waddnstr(win, str, len);
+		waddnstr(status, str, len);
 		str += len;
 	}
 }
@@ -354,7 +301,7 @@ static void statusUpdate(void) {
 			idColors[window->id]
 		);
 		if (!window->unread) buf[unread] = '\0';
-		styleAdd(status, buf, false);
+		statusAdd(buf);
 	}
 	wclrtoeol(status);
 
@@ -399,6 +346,61 @@ void uiShowNum(size_t num) {
 	windowShow(window);
 }
 
+static int wordWidth(const char *str) {
+	size_t len = strcspn(str, " ");
+	int width = 0;
+	while (len) {
+		wchar_t wc;
+		int n = mbtowc(&wc, str, len);
+		if (n < 1) return width + len;
+		width += (iswprint(wc) ? wcwidth(wc) : 0);
+		str += n;
+		len -= n;
+	}
+	return width;
+}
+
+static void wordWrap(WINDOW *win, const char *str) {
+	int y, x, width;
+	getmaxyx(win, y, width);
+
+	size_t len;
+	int align = 0;
+	struct Style style = Reset;
+	while (*str) {
+		if (*str == '\t') {
+			waddch(win, ' ');
+			getyx(win, y, align);
+			str++;
+		} else if (*str == ' ') {
+			getyx(win, y, x);
+			const char *word = &str[strspn(str, " ")];
+			if (width - x - 1 <= wordWidth(word)) {
+				waddch(win, '\n');
+				getyx(win, y, x);
+				wmove(win, y, align);
+				str = word;
+			} else {
+				waddch(win, ' ');
+				str++;
+			}
+		}
+
+		styleParse(&style, &str, &len);
+		size_t ws = strcspn(str, "\t ");
+		if (ws < len) len = ws;
+
+		wattr_set(
+			win,
+			style.attr | colorAttr(mapColor(style.fg)),
+			colorPair(mapColor(style.fg), mapColor(style.bg)),
+			NULL
+		);
+		waddnstr(win, str, len);
+		str += len;
+	}
+}
+
 void uiWrite(size_t id, enum Heat heat, const time_t *time, const char *str) {
 	(void)time;
 	struct Window *window = windowFor(id);
@@ -410,7 +412,7 @@ void uiWrite(size_t id, enum Heat heat, const time_t *time, const char *str) {
 		window->heat = heat;
 		statusUpdate();
 	}
-	styleAdd(window->pad, str, false);
+	wordWrap(window->pad, str);
 }
 
 void uiFormat(
@@ -425,6 +427,55 @@ void uiFormat(
 	uiWrite(id, heat, time, buf);
 }
 
+static void inputAdd(struct Style *style, const char *str) {
+	size_t len;
+	while (*str) {
+		const char *code = str;
+		styleParse(style, &str, &len);
+		wattr_set(input, A_BOLD | A_REVERSE, 0, NULL);
+		switch (*code) {
+			break; case '\2':  waddch(input, 'B');
+			break; case '\3':  waddch(input, 'C');
+			break; case '\17': waddch(input, 'O');
+			break; case '\26': waddch(input, 'R');
+			break; case '\35': waddch(input, 'I');
+			break; case '\37': waddch(input, 'U');
+		}
+		if (str - code > 1) waddnstr(input, &code[1], str - &code[1]);
+		wattr_set(
+			input,
+			style->attr | colorAttr(mapColor(style->fg)),
+			colorPair(mapColor(style->fg), mapColor(style->bg)),
+			NULL
+		);
+		waddnstr(input, str, len);
+		str += len;
+	}
+}
+
+static void inputUpdate(void) {
+	wmove(input, 0, 0);
+	wattr_set(
+		input,
+		colorAttr(mapColor(self.color)),
+		colorPair(mapColor(self.color), -1),
+		NULL
+	);
+	if (self.nick) {
+		waddch(input, '<');
+		waddstr(input, self.nick);
+		waddstr(input, "> ");
+	}
+
+	int y, x;
+	struct Style style = Reset;
+	inputAdd(&style, editHead());
+	getyx(input, y, x);
+	inputAdd(&style, editTail());
+	wclrtoeol(input);
+	wmove(input, y, x);
+}
+
 static void keyCode(int code) {
 	switch (code) {
 		break; case KEY_RESIZE:; // TODO
@@ -467,4 +518,5 @@ void uiRead(void) {
 		}
 		meta = false;
 	}
+	inputUpdate();
 }