about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2018-08-03 23:54:28 -0400
committerJune McEnroe <june@causal.agency>2018-08-03 23:54:28 -0400
commit269662d9ca3c178fcc0e1c340391ca1cf0818264 (patch)
treed26cfa10605507e99663d3c8dcbf17aa6a18e98d
parentTrack own username (diff)
downloadcatgirl-269662d9ca3c178fcc0e1c340391ca1cf0818264.tar.gz
catgirl-269662d9ca3c178fcc0e1c340391ca1cf0818264.zip
Handle input
This turned out a lot better than expected. Still a long way to go in
terms of line-editing, but at least backspace works!
-rw-r--r--chat.c93
1 files changed, 72 insertions, 21 deletions
diff --git a/chat.c b/chat.c
index c0a8231..711f2c2 100644
--- a/chat.c
+++ b/chat.c
@@ -14,6 +14,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#define _XOPEN_SOURCE_EXTENDED
+
 #include <curses.h>
 #include <err.h>
 #include <errno.h>
@@ -30,10 +32,23 @@
 #include <sysexits.h>
 #include <tls.h>
 #include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
 
 #define err(...) do { endwin(); err(__VA_ARGS__); } while (0)
 #define errx(...) do { endwin(); errx(__VA_ARGS__); } while (0)
 
+static wchar_t *wcssep(wchar_t **stringp, const wchar_t *delim) {
+	wchar_t *orig = *stringp;
+	size_t i = wcscspn(orig, delim);
+	*stringp = NULL;
+	if (orig[i]) {
+		orig[i] = '\0';
+		*stringp = &orig[i + 1];
+	}
+	return orig;
+}
+
 static void curse(void) {
 	setlocale(LC_CTYPE, "");
 	initscr();
@@ -51,6 +66,7 @@ static void curse(void) {
 
 static const int TOPIC_COLS = 512;
 static const int CHAT_LINES = 100;
+static const int INPUT_COLS = 512;
 static struct {
 	WINDOW *topic;
 	WINDOW *chat;
@@ -66,8 +82,8 @@ static void uiInit(void) {
 	scrollok(ui.chat, true);
 	wmove(ui.chat, CHAT_LINES - (LINES - 4) - 1, 0);
 
-	ui.input = newwin(2, COLS, LINES - 2, 0);
-	mvwhline(ui.input, 0, 0, ACS_HLINE, COLS);
+	ui.input = newpad(2, INPUT_COLS);
+	mvwhline(ui.input, 0, 0, ACS_HLINE, INPUT_COLS);
 	wmove(ui.input, 1, 0);
 	cbreak();
 	noecho();
@@ -80,7 +96,12 @@ static void uiDraw(void) {
 		CHAT_LINES - (LINES - 4), 0,
 		2, 0, LINES - 1, COLS - 1
 	);
-	wnoutrefresh(ui.input);
+	pnoutrefresh(
+		ui.input,
+		0, 0,
+		LINES - 2, 0,
+		LINES - 1, COLS - 1
+	);
 	doupdate();
 }
 
@@ -431,29 +452,59 @@ static void clientRead(void) {
 	memmove(buf, line, fill);
 }
 
-static void uiRead(void) {
-	static char buf[256];
-	static size_t fill;
+static void privmsg(bool action, const wchar_t *mesg) {
+	char *line;
+	int send;
+	asprintf(
+		&line, ":%s!%s %nPRIVMSG %s :%s%ls%s",
+		client.nick, client.user, &send, client.chan,
+		(action ? "\1ACTION " : ""), mesg, (action ? "\1" : "")
+	);
+	if (!line) err(EX_OSERR, "asprintf");
+	clientFmt("%s\r\n", &line[send]);
+	handle(line);
+	free(line);
+}
 
-	// TODO:
-	int ch = wgetch(ui.input);
-	if (ch == '\n') {
-		buf[fill] = '\0';
-		char *params;
-		asprintf(&params, "%s :%s", client.chan, buf);
-		if (!params) err(EX_OSERR, "asprintf");
-		clientFmt("PRIVMSG %s\r\n", params);
-		handlePrivmsg(client.nick, params); // FIXME: username
-		free(params);
-		fill = 0;
-		wmove(ui.input, 1, 0);
-		wclrtoeol(ui.input);
+static void input(wchar_t *input) {
+	if (input[0] != '/') {
+		privmsg(false, input);
+		return;
+	}
+	input++;
+	wchar_t *cmd = wcssep(&input, L" ");
+	if (!wcscmp(cmd, L"me")) {
+		privmsg(true, input ? input : L"");
 	} else {
-		buf[fill++] = ch;
-		waddch(ui.input, ch);
+		uiFmt("/%ls isn't a recognized command", cmd);
 	}
 }
 
+static void uiRead(void) {
+	static wchar_t buf[512];
+	static size_t len;
+
+	wint_t ch;
+	wget_wch(ui.input, &ch);
+	switch (ch) {
+		break; case '\b': case '\177': {
+			if (len) len--;
+		}
+		break; case '\n': {
+			if (!len) break;
+			buf[len] = '\0';
+			input(buf);
+			len = 0;
+		}
+		break; default: {
+			if (iswprint(ch)) buf[len++] = ch;
+		}
+	}
+	wmove(ui.input, 1, 0);
+	waddnwstr(ui.input, buf, len);
+	wclrtoeol(ui.input);
+}
+
 static void webirc(const char *pass) {
 	const char *ssh = getenv("SSH_CLIENT");
 	if (!ssh) return;