From 9944dc484bf8cc7d5f1c506610a0593202bb5f92 Mon Sep 17 00:00:00 2001 From: "C. McEnroe" Date: Tue, 4 Feb 2020 20:23:55 -0500 Subject: [PATCH] Split showing style codes and word wrapping --- Makefile | 1 + chat.c | 2 +- chat.h | 4 ++ edit.c | 30 ++++++++++ ui.c | 168 ++++++++++++++++++++++++++++++++++++------------------- 5 files changed, 146 insertions(+), 59 deletions(-) create mode 100644 edit.c 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 + * + * 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 . + */ + +#include +#include +#include +#include + +#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(); }