summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.c166
1 files changed, 139 insertions, 27 deletions
diff --git a/main.c b/main.c
index f9adb85..16b632c 100644
--- a/main.c
+++ b/main.c
@@ -65,6 +65,7 @@
#define CPAIR_ENUM_X(cp, fg, bg, name) cp,
#define CPAIR_NAME_X(cp, fg, bg, name) S(name),
#define CPAIR_INIT_X(cp, fg, bg, name) init_pair(cp, fg, bg);
+#define CPAIR_OPT_X(cp, f, b, name) [cp] = { .fg = f, .bg = b, .init = 1 },
#define COLOR_NORM -1
#define COLOR_FG COLOR_NORM
#define COLOR_BG COLOR_NORM
@@ -90,7 +91,7 @@ typedef enum {
} ColorPair;
Str cpair_name[CPAIR_MAX] = {
- S("N/A"),
+ S("default"),
CPAIR_LIST(CPAIR_NAME_X)
};
@@ -145,6 +146,9 @@ int utf8_cp_to_byte(Str s, int dest) {
/* options */
+/*
+ * If the high bit of fg or bg is set, the lower 24 bits are a RGB value.
+ */
typedef struct {
int fg, bg, init;
} ColorOpt;
@@ -158,7 +162,6 @@ typedef struct {
int left, right, top, bottom;
int text_x, text_y;
} margin;
- int default_colors;
ColorOpt color[CPAIR_MAX];
} Options;
@@ -180,7 +183,9 @@ Options opt = {
.text_x = GFX_TEXT_MARGIN_X,
.text_y = GFX_TEXT_MARGIN_Y,
},
- .default_colors = 1
+ .color = {
+ CPAIR_LIST(CPAIR_OPT_X)
+ }
};
/* msg & logging */
@@ -862,20 +867,44 @@ void new_post(Arena *temp) {
/* curses setup/cleanup */
+/* currently RGB colors are broken */
+int custom_color;
+int init_cfg_color(int c) {
+ if (c < 0 && c != -1) {
+ int r = (c >> 16) & 0xff;
+ int g = (c >> 8) & 0xff;
+ int b = c & 0xff;
+ init_color(custom_color,
+ ((r & 0xff) * 1000) / 0xff,
+ ((g & 0xff) * 1000) / 0xff,
+ ((b & 0xff) * 1000) / 0xff);
+ return custom_color--;
+ } else {
+ return c;
+ }
+}
+
void init_curses(void) {
setlocale(LC_ALL, "");
initscr();
- start_color();
- init_color(COLOR_BG, 0, 0, 0);
cbreak();
noecho();
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
curs_set(0);
- if (opt.default_colors) use_default_colors();
- CPAIR_LIST(CPAIR_INIT_X)
- for (ColorPair i = 0; i < CPAIR_MAX; i++) {
+ start_color();
+ custom_color = COLORS - 1;
+ for (size_t i = 0; i < sizeof opt.color / sizeof *opt.color; i++) {
+ opt.color[i].fg = init_cfg_color(opt.color[i].fg);
+ opt.color[i].bg = init_cfg_color(opt.color[i].bg);
+ }
+ if (opt.color[0].init) {
+ assume_default_colors(opt.color[0].fg, opt.color[0].bg);
+ } else {
+ use_default_colors();
+ }
+ for (ColorPair i = 1; i < CPAIR_MAX; i++) {
if (opt.color[i].init) {
init_pair(i, opt.color[i].fg, opt.color[i].bg);
}
@@ -904,35 +933,118 @@ typedef struct {
int (*fn)(Str key, Str value, Arena *perm);
} Section;
-int sect_margin(Str key, Str value, Arena *perm) {
- (void)perm;
+int prop_bool(Str name, Str key, Str value, int *ptr) {
+ uint64_t u;
+ if (!str_eql(name, key)) return 0;
+ if (str_to_u64(value, &u)) return 0;
+ if (u != !!u) return 0;
+ *ptr = u;
+ return 1;
+}
+
+int prop_int(Str name, Str key, Str value, int *ptr) {
uint64_t u;
- if (str_to_u64(value, &u)) return -1;
- if (str_eql(key, S("left"))) { opt.margin.left = u; return 0; }
- if (str_eql(key, S("right"))) { opt.margin.right = u; return 0; }
- if (str_eql(key, S("top"))) { opt.margin.top = u; return 0; }
- if (str_eql(key, S("bottom"))) { opt.margin.bottom = u; return 0; }
- if (str_eql(key, S("text.x"))) { opt.margin.text_x = u; return 0; }
- if (str_eql(key, S("text.y"))) { opt.margin.text_y = u; return 0; }
+ if (!str_eql(name, key)) return 0;
+ if (str_to_u64(value, &u)) return 0;
+ *ptr = u;
+ return 1;
+}
+
+int prop_cstr(Str name, Str key, Str value, const char **ptr, Arena *perm) {
+ if (!str_eql(name, key)) return 0;
+ *ptr = str_to_cstr(value, perm);
+ return 1;
+}
+
+int sect_margin(Str k, Str v, Arena *perm) {
+ (void)perm;
+ if (prop_int(S("left"), k, v, &opt.margin.left)) return 0;
+ if (prop_int(S("right"), k, v, &opt.margin.right)) return 0;
+ if (prop_int(S("top"), k, v, &opt.margin.top)) return 0;
+ if (prop_int(S("bottom"), k, v, &opt.margin.bottom)) return 0;
+ if (prop_int(S("text.x"), k, v, &opt.margin.text_x)) return 0;
+ if (prop_int(S("text.y"), k, v, &opt.margin.text_y)) return 0;
+ return -1;
+}
+
+int sect_post(Str k, Str v, Arena *perm) {
+ if (prop_cstr(S("datefmt"), k, v, &opt.post.datefmt, perm)) return 0;
+ if (prop_bool(S("pfp"), k, v, &opt.post.pfp)) return 0;
+ if (prop_bool(S("pronouns"), k, v, &opt.post.pronouns)) return 0;
+ if (prop_bool(S("date"), k, v, &opt.post.date)) return 0;
+ return -1;
+}
+
+#define BAD_COLOR -2
+
+/* i can't tell if RGB colors are broken, or just the terminal doesn't support it */
+int parse_hex_nybble(char c) {
+ if (c >= '0' && c <= '9') return c - '0';
+ if (c >= 'a' && c <= 'f') return 10 + c - 'a';
+ if (c >= 'A' && c <= 'F') return 10 + c - 'A';
return -1;
}
+int parse_hex_byte(const char *s) {
+ int l = parse_hex_nybble(s[0]);
+ int r = parse_hex_nybble(s[1]);
+ if (l == -1 || r == -1) return -1;
+ return ((l&0xf) << 4) | (r&0xf);
+}
+int parse_rgb(Str s) {
+ if (s.n != 6) return BAD_COLOR;
+ int r = parse_hex_byte(&s.s[0]);
+ int g = parse_hex_byte(&s.s[2]);
+ int b = parse_hex_byte(&s.s[4]);
+ if (r == -1 || g == -1 || b == -1) return BAD_COLOR;
+ return (1 << 31) | (r << 16) | (g << 8) | b;
+}
-int sect_post(Str key, Str value, Arena *perm) {
+int parse_color(Str s) {
+ if (!s.n) return -1; /* default */
+ if (s.s[0] == '#') {
+ return parse_rgb(str_skip(s, 1));
+ }
+ static struct {
+ Str s;
+ int v;
+ } color_map[] = {
+ { S("default"), -1 },
+ { S("black"), COLOR_BLACK },
+ { S("red"), COLOR_RED },
+ { S("green"), COLOR_GREEN },
+ { S("yellow"), COLOR_YELLOW },
+ { S("blue"), COLOR_BLUE },
+ { S("magenta"), COLOR_MAGENTA },
+ { S("cyan"), COLOR_CYAN },
+ { S("white"), COLOR_WHITE },
+ };
+ for (size_t i = 0; i < sizeof color_map / sizeof *color_map; i++) {
+ if (str_eql(s, color_map[i].s)) return color_map[i].v;
+ }
+ return BAD_COLOR;
+}
+
+int sect_color(Str k, Str v, Arena *perm) {
(void)perm;
- if (str_eql(key, S("datefmt"))) { opt.post.datefmt = str_to_cstr(value, perm); return 0; }
- /* bools */
- uint64_t u;
- if (str_to_u64(value, &u)) return -1;
- if (u != !!u) return -1;
- if (str_eql(key, S("pfp"))) { opt.post.pfp = u; return 0; }
- if (str_eql(key, S("pronouns"))) { opt.post.pronouns = u; return 0; }
- if (str_eql(key, S("date"))) { opt.post.date = u; return 0; }
- return 0;
+ for (int i = 0; i < CPAIR_MAX; i++) {
+ if (!str_eql(k, cpair_name[i])) continue;
+ Cut c = str_cut(v, ':');
+ int fg = parse_color(str_trim(c.head));
+ int bg = parse_color(str_trim(c.tail));
+ if (fg == BAD_COLOR || bg == BAD_COLOR) return -1;
+ opt.color[i] = (ColorOpt) {
+ .fg = fg,
+ .bg = bg,
+ .init = 1
+ };
+ }
+ return -1;
}
Section sections[] = {
{ "margin", &sect_margin },
{ "post", &sect_post },
+ { "color", &sect_color },
};
int load_config(Arena *perm, Arena *temp) {