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 * unmono index pattern [pattern...]
152 _mutt_parse_uncolor (BUFFER * buf, BUFFER * s, unsigned long data,
153 BUFFER * err, short parse_uncolor);
155 int mutt_parse_uncolor (BUFFER * buf, BUFFER * s, unsigned long data,
158 return _mutt_parse_uncolor (buf, s, data, err, 1);
161 int mutt_parse_unmono (BUFFER * buf, BUFFER * s, unsigned long data,
164 return _mutt_parse_uncolor (buf, s, data, err, 0);
168 _mutt_parse_uncolor (BUFFER * buf, BUFFER * s, unsigned long data __attribute__ ((unused)),
169 BUFFER * err, short parse_uncolor)
171 int object = 0, do_cache = 0;
172 COLOR_LINE *tmp, *last = NULL;
174 mutt_extract_token (buf, s, 0);
176 if ((object = mutt_getvaluebyname (buf->data, Fields)) == -1) {
177 snprintf (err->data, err->dsize, _("%s: no such object"), buf->data);
181 if (m_strncmp(buf->data, "index", 5) != 0) {
182 snprintf (err->data, err->dsize,
183 _("%s: command valid only for index object"),
184 parse_uncolor ? "uncolor" : "unmono");
189 snprintf (err->data, err->dsize,
190 _("%s: too few arguments"),
191 parse_uncolor ? "uncolor" : "unmono");
195 if (option (OPTNOCURSES) || (parse_uncolor != has_colors())) {
196 /* just eat the command, but don't do anything real about it */
198 mutt_extract_token (buf, s, 0);
199 } while (MoreArgs(s));
204 mutt_extract_token (buf, s, 0);
205 if (!m_strcmp("*", buf->data)) {
206 for (tmp = ColorIndexList; tmp;) {
211 mutt_free_color_line(&last);
213 ColorIndexList = NULL;
216 for (last = NULL, tmp = ColorIndexList; tmp;
217 last = tmp, tmp = tmp->next) {
218 if (!m_strcmp(buf->data, tmp->pattern)) {
222 last->next = tmp->next;
224 ColorIndexList = tmp->next;
225 mutt_free_color_line(&tmp);
231 while (MoreArgs (s));
234 if (do_cache && !option (OPTNOCURSES)) {
237 set_option (OPTFORCEREDRAWINDEX);
238 /* force re-caching of index colors */
239 for (i = 0; Context && i < Context->msgcount; i++)
240 Context->hdrs[i]->pair = 0;
247 add_pattern (COLOR_LINE ** top, const char *s, int sensitive,
248 int fg, int bg, int attr, BUFFER * err, int is_index)
251 /* is_index used to store compiled pattern
252 * only for `index' color object
253 * when called from mutt_parse_color() */
255 COLOR_LINE *tmp = *top;
259 if (m_strcmp(s, tmp->pattern) == 0)
263 if (m_strcasecmp(s, tmp->pattern) == 0)
270 if (fg != -1 && bg != -1) {
271 if (tmp->fg != fg || tmp->bg != bg) {
274 attr |= madtty_color_pair(fg, bg);
276 attr |= (tmp->pair & ~A_BOLD);
284 tmp = mutt_new_color_line ();
288 m_strcpy(buf, sizeof(buf), NONULL(s));
289 mutt_check_simple (buf, sizeof (buf), NONULL (SimpleSearch));
290 if ((tmp->color_pattern =
291 mutt_pattern_comp (buf, M_FULL_MSG, err)) == NULL) {
292 mutt_free_color_line(&tmp);
295 /* force re-caching of index colors */
296 for (i = 0; Context && i < Context->msgcount; i++)
297 Context->hdrs[i]->pair = 0;
301 REGCOMP (&tmp->rx, s,
302 (sensitive ? mutt_which_case (s) : REG_ICASE))) != 0) {
303 regerror (r, &tmp->rx, err->data, err->dsize);
304 mutt_free_color_line(&tmp);
308 tmp->pattern = m_strdup(s);
309 if (fg != -1 && bg != -1) {
312 attr |= madtty_color_pair(fg, bg);
322 parse_object (BUFFER * buf, BUFFER * s, int *o, int *ql, BUFFER * err)
328 m_strcpy(err->data, err->dsize, _("Missing arguments."));
332 mutt_extract_token (buf, s, 0);
333 if (!m_strncmp(buf->data, "quoted", 6)) {
335 *ql = strtol (buf->data + 6, &eptr, 10);
336 if (*eptr || q_level < 0) {
337 snprintf (err->data, err->dsize, _("%s: no such object"), buf->data);
344 *o = MT_COLOR_QUOTED;
346 else if ((*o = mutt_getvaluebyname (buf->data, Fields)) == -1) {
347 snprintf (err->data, err->dsize, _("%s: no such object"), buf->data);
354 typedef int (*parser_callback_t) (BUFFER *, BUFFER *, int *, int *, int *,
358 parse_color_pair (BUFFER * buf, BUFFER * s, int *fg, int *bg, int *attr,
362 m_strcpy(err->data, err->dsize, _("color: too few arguments"));
366 mutt_extract_token (buf, s, 0);
368 if (parse_color_name (buf->data, fg, attr, A_BOLD, err) != 0)
372 m_strcpy(err->data, err->dsize, _("color: too few arguments"));
376 mutt_extract_token (buf, s, 0);
378 if (parse_color_name (buf->data, bg, attr, A_BLINK, err) != 0)
385 parse_attr_spec (BUFFER * buf, BUFFER * s, int *fg, int *bg, int *attr,
395 m_strcpy(err->data, err->dsize, _("mono: too few arguments"));
399 mutt_extract_token (buf, s, 0);
401 if (ascii_strcasecmp ("bold", buf->data) == 0)
403 else if (ascii_strcasecmp ("underline", buf->data) == 0)
404 *attr |= A_UNDERLINE;
405 else if (ascii_strcasecmp ("none", buf->data) == 0)
407 else if (ascii_strcasecmp ("reverse", buf->data) == 0)
409 else if (ascii_strcasecmp ("standout", buf->data) == 0)
411 else if (ascii_strcasecmp ("normal", buf->data) == 0)
412 *attr = A_NORMAL; /* needs use = instead of |= to clear other bits */
414 snprintf (err->data, err->dsize, _("%s: no such attribute"), buf->data);
421 static int fgbgattr_to_color (int fg, int bg, int attr)
423 if (fg != -1 && bg != -1)
424 return attr | madtty_color_pair(fg, bg);
429 /* usage: color <object> <fg> <bg> [ <regexp> ]
430 * mono <object> <attr> [ <regexp> ]
434 _mutt_parse_color (BUFFER * buf, BUFFER * s, BUFFER * err,
435 parser_callback_t callback, short dry_run)
437 int object = 0, attr = 0, fg = 0, bg = 0, q_level = 0;
440 if (parse_object (buf, s, &object, &q_level, err) == -1)
443 if (callback (buf, s, &fg, &bg, &attr, err) == -1)
446 /* extract a regular expression if needed */
448 if (object == MT_COLOR_HEADER || object == MT_COLOR_BODY
449 || object == MT_COLOR_INDEX) {
451 m_strcpy(err->data, err->dsize, _("too few arguments"));
455 mutt_extract_token (buf, s, 0);
459 m_strcpy(err->data, err->dsize, _("too many arguments"));
469 if (!option (OPTNOCURSES) && has_colors ()
470 /* delay use_default_colors() until needed, since it initializes things */
471 && (fg == COLOR_DEFAULT || bg == COLOR_DEFAULT)
472 && use_default_colors () != OK) {
473 m_strcpy(err->data, err->dsize, _("default colors not supported"));
477 if (object == MT_COLOR_HEADER)
478 r = add_pattern (&ColorHdrList, buf->data, 0, fg, bg, attr, err, 0);
479 else if (object == MT_COLOR_BODY)
480 r = add_pattern (&ColorBodyList, buf->data, 1, fg, bg, attr, err, 0);
481 else if (object == MT_COLOR_INDEX) {
482 r = add_pattern (&ColorIndexList, buf->data, 1, fg, bg, attr, err, 1);
483 set_option (OPTFORCEREDRAWINDEX);
485 else if (object == MT_COLOR_QUOTED) {
486 if (q_level >= ColorQuoteSize) {
487 p_realloc(&ColorQuote, ColorQuoteSize += 2);
488 ColorQuote[ColorQuoteSize - 2] = ColorDefs[MT_COLOR_QUOTED];
489 ColorQuote[ColorQuoteSize - 1] = ColorDefs[MT_COLOR_QUOTED];
491 if (q_level >= ColorQuoteUsed)
492 ColorQuoteUsed = q_level + 1;
494 ColorDefs[MT_COLOR_QUOTED] = fgbgattr_to_color (fg, bg, attr);
496 ColorQuote[0] = ColorDefs[MT_COLOR_QUOTED];
497 for (q_level = 1; q_level < ColorQuoteUsed; q_level++) {
498 if (ColorQuote[q_level] == A_NORMAL)
499 ColorQuote[q_level] = ColorDefs[MT_COLOR_QUOTED];
503 ColorQuote[q_level] = fgbgattr_to_color (fg, bg, attr);
506 ColorDefs[object] = fgbgattr_to_color (fg, bg, attr);
508 if (object == MT_COLOR_NORMAL && !option (OPTNOCURSES) && has_colors ())
509 BKGDSET(main_w, MT_COLOR_NORMAL);
514 int mutt_parse_color (BUFFER * buff, BUFFER * s, unsigned long data __attribute__ ((unused)),
519 if (option (OPTNOCURSES) || !has_colors ())
522 return _mutt_parse_color (buff, s, err, parse_color_pair, dry_run);
525 int mutt_parse_mono (BUFFER * buff, BUFFER * s, unsigned long data __attribute__ ((unused)),
530 if (option (OPTNOCURSES) || has_colors ())
533 return _mutt_parse_color (buff, s, err, parse_attr_spec, dry_run);