2 * Copyright notice from original mutt:
3 * Copyright (C) 1996-2002 Michael R. Elkins <me@mutt.org>
5 * This file is part of mutt-ng, see http://www.muttng.org/.
6 * It's licensed under the GNU General Public License,
7 * please see the file GPL in the top level source directory.
10 #include <lib-ui/lib-ui.h>
18 int ColorDefs[MT_COLOR_MAX];
19 COLOR_LINE *ColorHdrList = NULL;
20 COLOR_LINE *ColorBodyList = NULL;
21 COLOR_LINE *ColorIndexList = NULL;
23 /* local to this file */
24 static int ColorQuoteSize;
26 #define COLOR_DEFAULT (-2)
28 typedef struct color_list {
33 struct color_list *next;
36 static struct mapping_t Colors[] = {
37 {"black", COLOR_BLACK},
40 {"green", COLOR_GREEN},
41 {"magenta", COLOR_MAGENTA},
43 {"white", COLOR_WHITE},
44 {"yellow", COLOR_YELLOW},
45 {"default", COLOR_DEFAULT},
49 static struct mapping_t Fields[] = {
50 {"hdrdefault", MT_COLOR_HDEFAULT},
51 {"quoted", MT_COLOR_QUOTED},
52 {"signature", MT_COLOR_SIGNATURE},
53 {"indicator", MT_COLOR_INDICATOR},
54 {"status", MT_COLOR_STATUS},
55 {"tree", MT_COLOR_TREE},
56 {"error", MT_COLOR_ERROR},
57 {"normal", MT_COLOR_NORMAL},
58 {"tilde", MT_COLOR_TILDE},
59 {"markers", MT_COLOR_MARKERS},
60 {"header", MT_COLOR_HEADER},
61 {"body", MT_COLOR_BODY},
62 {"message", MT_COLOR_MESSAGE},
63 {"attachment", MT_COLOR_ATTACHMENT},
64 {"search", MT_COLOR_SEARCH},
65 {"bold", MT_COLOR_BOLD},
66 {"underline", MT_COLOR_UNDERLINE},
67 {"index", MT_COLOR_INDEX},
68 {"sidebar_new", MT_COLOR_NEW},
69 {"sidebar", MT_COLOR_SIDEBAR},
70 {"sidebar_flagged", MT_COLOR_FLAGGED},
74 #define COLOR_QUOTE_INIT 8
76 static COLOR_LINE *mutt_new_color_line (void)
78 COLOR_LINE *p = p_new(COLOR_LINE, 1);
85 static void mutt_free_color_line(COLOR_LINE ** l)
93 /* we should really use the container type for regular expressions. */
95 pattern_list_wipe(&tmp->color_pattern);
96 p_delete(&tmp->pattern);
100 void ci_start_color (void)
102 memset(ColorDefs, A_NORMAL, sizeof(int) * MT_COLOR_MAX);
103 ColorQuote = p_new(int, COLOR_QUOTE_INIT);
104 memset(ColorQuote, A_NORMAL, sizeof(int) * COLOR_QUOTE_INIT);
105 ColorQuoteSize = COLOR_QUOTE_INIT;
108 /* set some defaults */
109 ColorDefs[MT_COLOR_STATUS] = A_REVERSE;
110 ColorDefs[MT_COLOR_INDICATOR] = A_REVERSE;
111 ColorDefs[MT_COLOR_SEARCH] = A_REVERSE;
112 ColorDefs[MT_COLOR_MARKERS] = A_REVERSE;
113 /* special meaning: toggle the relevant attribute */
114 ColorDefs[MT_COLOR_BOLD] = 0;
115 ColorDefs[MT_COLOR_UNDERLINE] = 0;
119 parse_color_name (const char *s, int *col, int *attr, int brite, BUFFER * err)
123 if (m_strncasecmp(s, "bright", 6) == 0) {
128 /* allow aliases for xterm color resources */
129 if (m_strncasecmp(s, "color", 5) == 0) {
131 *col = strtol (s, &eptr, 10);
132 if (!*s || *eptr || *col < 0 ||
133 (*col >= COLORS && !option (OPTNOCURSES) && has_colors ())) {
134 snprintf (err->data, err->dsize, _("%s: color not supported by term"),
139 else if ((*col = mutt_getvaluebyname (s, Colors)) == -1) {
140 snprintf (err->data, err->dsize, _("%s: no such color"), s);
147 /* usage: uncolor index pattern [pattern...] */
148 int mutt_parse_uncolor(BUFFER *buf, BUFFER *s, unsigned long data, BUFFER
151 int object = 0, do_cache = 0;
152 COLOR_LINE *tmp, *last = NULL;
154 mutt_extract_token (buf, s, 0);
156 if ((object = mutt_getvaluebyname (buf->data, Fields)) == -1) {
157 snprintf (err->data, err->dsize, _("%s: no such object"), buf->data);
161 if (m_strncmp(buf->data, "index", 5) != 0) {
162 snprintf (err->data, err->dsize,
163 _("%s: command valid only for index object"), "uncolor");
168 snprintf (err->data, err->dsize, _("%s: too few arguments"), "uncolor");
172 if (option(OPTNOCURSES) || !has_colors()) {
173 /* just eat the command, but don't do anything real about it */
175 mutt_extract_token (buf, s, 0);
176 } while (MoreArgs(s));
181 mutt_extract_token (buf, s, 0);
182 if (!m_strcmp("*", buf->data)) {
183 for (tmp = ColorIndexList; tmp;) {
188 mutt_free_color_line(&last);
190 ColorIndexList = NULL;
193 for (last = NULL, tmp = ColorIndexList; tmp;
194 last = tmp, tmp = tmp->next) {
195 if (!m_strcmp(buf->data, tmp->pattern)) {
199 last->next = tmp->next;
201 ColorIndexList = tmp->next;
202 mutt_free_color_line(&tmp);
208 while (MoreArgs (s));
211 if (do_cache && !option (OPTNOCURSES)) {
214 set_option (OPTFORCEREDRAWINDEX);
215 /* force re-caching of index colors */
216 for (i = 0; Context && i < Context->msgcount; i++)
217 Context->hdrs[i]->pair = 0;
224 add_pattern (COLOR_LINE ** top, const char *s, int sensitive,
225 int fg, int bg, int attr, BUFFER * err, int is_index)
228 /* is_index used to store compiled pattern
229 * only for `index' color object
230 * when called from mutt_parse_color() */
232 COLOR_LINE *tmp = *top;
236 if (m_strcmp(s, tmp->pattern) == 0)
240 if (m_strcasecmp(s, tmp->pattern) == 0)
247 if (fg != -1 && bg != -1) {
248 if (tmp->fg != fg || tmp->bg != bg) {
251 attr |= madtty_color_pair(fg, bg);
253 attr |= (tmp->pair & ~A_BOLD);
261 tmp = mutt_new_color_line ();
265 m_strcpy(buf, sizeof(buf), NONULL(s));
266 mutt_check_simple (buf, sizeof (buf), NONULL (SimpleSearch));
267 if ((tmp->color_pattern =
268 mutt_pattern_comp (buf, M_FULL_MSG, err)) == NULL) {
269 mutt_free_color_line(&tmp);
272 /* force re-caching of index colors */
273 for (i = 0; Context && i < Context->msgcount; i++)
274 Context->hdrs[i]->pair = 0;
278 REGCOMP (&tmp->rx, s,
279 (sensitive ? mutt_which_case (s) : REG_ICASE))) != 0) {
280 regerror (r, &tmp->rx, err->data, err->dsize);
281 mutt_free_color_line(&tmp);
285 tmp->pattern = m_strdup(s);
286 if (fg != -1 && bg != -1) {
289 attr |= madtty_color_pair(fg, bg);
299 parse_object (BUFFER * buf, BUFFER * s, int *o, int *ql, BUFFER * err)
305 m_strcpy(err->data, err->dsize, _("Missing arguments."));
309 mutt_extract_token (buf, s, 0);
310 if (!m_strncmp(buf->data, "quoted", 6)) {
312 *ql = strtol (buf->data + 6, &eptr, 10);
313 if (*eptr || q_level < 0) {
314 snprintf (err->data, err->dsize, _("%s: no such object"), buf->data);
321 *o = MT_COLOR_QUOTED;
323 else if ((*o = mutt_getvaluebyname (buf->data, Fields)) == -1) {
324 snprintf (err->data, err->dsize, _("%s: no such object"), buf->data);
331 typedef int (*parser_callback_t) (BUFFER *, BUFFER *, int *, int *, int *,
335 parse_color_pair (BUFFER * buf, BUFFER * s, int *fg, int *bg, int *attr,
339 m_strcpy(err->data, err->dsize, _("color: too few arguments"));
343 mutt_extract_token (buf, s, 0);
345 if (parse_color_name (buf->data, fg, attr, A_BOLD, err) != 0)
349 m_strcpy(err->data, err->dsize, _("color: too few arguments"));
353 mutt_extract_token (buf, s, 0);
355 if (parse_color_name (buf->data, bg, attr, A_BLINK, err) != 0)
363 parse_attr_spec (BUFFER * buf, BUFFER * s, int *fg, int *bg, int *attr,
373 m_strcpy(err->data, err->dsize, _("mono: too few arguments"));
377 mutt_extract_token (buf, s, 0);
379 if (ascii_strcasecmp ("bold", buf->data) == 0)
381 else if (ascii_strcasecmp ("underline", buf->data) == 0)
382 *attr |= A_UNDERLINE;
383 else if (ascii_strcasecmp ("none", buf->data) == 0)
385 else if (ascii_strcasecmp ("reverse", buf->data) == 0)
387 else if (ascii_strcasecmp ("standout", buf->data) == 0)
389 else if (ascii_strcasecmp ("normal", buf->data) == 0)
390 *attr = A_NORMAL; /* needs use = instead of |= to clear other bits */
392 snprintf (err->data, err->dsize, _("%s: no such attribute"), buf->data);
400 static int fgbgattr_to_color (int fg, int bg, int attr)
402 if (fg != -1 && bg != -1)
403 return attr | madtty_color_pair(fg, bg);
408 /* usage: color <object> <fg> <bg> [ <regexp> ] */
409 int mutt_parse_color(BUFFER *buf, BUFFER *s, unsigned long i, BUFFER *err)
411 int object = 0, attr = 0, fg = 0, bg = 0, q_level = 0;
413 int dry_run = option (OPTNOCURSES) || !has_colors ();
415 if (parse_object (buf, s, &object, &q_level, err) == -1)
418 if (parse_color_pair(buf, s, &fg, &bg, &attr, err) == -1)
421 /* extract a regular expression if needed */
423 if (object == MT_COLOR_HEADER || object == MT_COLOR_BODY
424 || object == MT_COLOR_INDEX) {
426 m_strcpy(err->data, err->dsize, _("too few arguments"));
430 mutt_extract_token (buf, s, 0);
434 m_strcpy(err->data, err->dsize, _("too many arguments"));
444 if (!option (OPTNOCURSES) && has_colors ()
445 /* delay use_default_colors() until needed, since it initializes things */
446 && (fg == COLOR_DEFAULT || bg == COLOR_DEFAULT)
447 && use_default_colors () != OK) {
448 m_strcpy(err->data, err->dsize, _("default colors not supported"));
452 if (object == MT_COLOR_HEADER)
453 r = add_pattern (&ColorHdrList, buf->data, 0, fg, bg, attr, err, 0);
454 else if (object == MT_COLOR_BODY)
455 r = add_pattern (&ColorBodyList, buf->data, 1, fg, bg, attr, err, 0);
456 else if (object == MT_COLOR_INDEX) {
457 r = add_pattern (&ColorIndexList, buf->data, 1, fg, bg, attr, err, 1);
458 set_option (OPTFORCEREDRAWINDEX);
460 else if (object == MT_COLOR_QUOTED) {
461 if (q_level >= ColorQuoteSize) {
462 p_realloc(&ColorQuote, ColorQuoteSize += 2);
463 ColorQuote[ColorQuoteSize - 2] = ColorDefs[MT_COLOR_QUOTED];
464 ColorQuote[ColorQuoteSize - 1] = ColorDefs[MT_COLOR_QUOTED];
466 if (q_level >= ColorQuoteUsed)
467 ColorQuoteUsed = q_level + 1;
469 ColorDefs[MT_COLOR_QUOTED] = fgbgattr_to_color (fg, bg, attr);
471 ColorQuote[0] = ColorDefs[MT_COLOR_QUOTED];
472 for (q_level = 1; q_level < ColorQuoteUsed; q_level++) {
473 if (ColorQuote[q_level] == A_NORMAL)
474 ColorQuote[q_level] = ColorDefs[MT_COLOR_QUOTED];
478 ColorQuote[q_level] = fgbgattr_to_color (fg, bg, attr);
481 ColorDefs[object] = fgbgattr_to_color (fg, bg, attr);
483 if (object == MT_COLOR_NORMAL && !option (OPTNOCURSES) && has_colors ())
484 BKGDSET(main_w, MT_COLOR_NORMAL);