NeoMutt  2021-02-05-329-g9e03b7
Teaching an old dog new tricks
DOXYGEN
color.c
Go to the documentation of this file.
1 
30 #include "config.h"
31 #include <stdbool.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include "mutt/lib.h"
36 #include "config/lib.h"
37 #include "email/lib.h"
38 #include "core/lib.h"
39 #include "mutt.h"
40 #include "color.h"
41 #include "pattern/lib.h"
42 #include "context.h"
43 #include "init.h"
44 #include "mutt_commands.h"
45 #include "mutt_curses.h"
46 #include "mutt_globals.h"
47 #include "options.h"
48 #ifdef USE_SLANG_CURSES
49 #include <assert.h>
50 #endif
51 
52 #define COLOR_UNSET UINT32_MAX
53 #define COLOR_QUOTES_MAX \
54  10
55 
56 
59 struct ColorList
60 {
61  /* TrueColor uses 24bit. Use fixed-width integer type to make sure it fits.
62  * Use the upper 8 bits to store flags. */
63  uint32_t fg;
64  uint32_t bg;
65  short index;
66  short count;
67  struct ColorList *next;
68 };
69 
73 static struct
74 {
76 
77  /* These are lazily initialized, so make sure to always refer to them using
78  * the mutt_color_<object>() wrappers. */
79  struct ColorLineList attach_list;
80  struct ColorLineList body_list;
81  struct ColorLineList hdr_list;
82  struct ColorLineList index_author_list;
83  struct ColorLineList index_flags_list;
84  struct ColorLineList index_list;
85  struct ColorLineList index_subject_list;
86  struct ColorLineList index_tag_list;
87  struct ColorLineList status_list;
88 
91 
94 
95  struct Notify *notify;
96 } Colors;
97 
103 static struct ColorLineList *get_color_line_list(struct ColorLineList *cll)
104 {
105  if (cll->stqh_last == NULL)
106  {
107  STAILQ_INIT(cll);
108  }
109  return cll;
110 }
111 
123 typedef int (*parser_callback_t)(struct Buffer *buf, struct Buffer *s, uint32_t *fg,
124  uint32_t *bg, int *attr, struct Buffer *err);
125 
126 #ifdef HAVE_COLOR
127 
128 #define COLOR_DEFAULT (-2)
129 
130 /*
131  * Flags for the high 8bits of the color value.
132  *
133  * Note that no flag means it's a palette color.
134  */
135 #define RGB24 (1U << 24)
136 
137 // clang-format off
138 static const struct Mapping ColorNames[] = {
139  { "black", COLOR_BLACK },
140  { "blue", COLOR_BLUE },
141  { "cyan", COLOR_CYAN },
142  { "green", COLOR_GREEN },
143  { "magenta", COLOR_MAGENTA },
144  { "red", COLOR_RED },
145  { "white", COLOR_WHITE },
146  { "yellow", COLOR_YELLOW },
147 #if defined(USE_SLANG_CURSES) || defined(HAVE_USE_DEFAULT_COLORS)
148  { "default", COLOR_DEFAULT },
149 #endif
150  { 0, 0 },
151 };
152 // clang-format on
153 #endif /* HAVE_COLOR */
154 
155 // clang-format off
156 const struct Mapping Fields[] = {
157  { "attachment", MT_COLOR_ATTACHMENT },
158  { "attach_headers", MT_COLOR_ATTACH_HEADERS },
159  { "body", MT_COLOR_BODY },
160  { "bold", MT_COLOR_BOLD },
161  { "error", MT_COLOR_ERROR },
162  { "hdrdefault", MT_COLOR_HDRDEFAULT },
163  { "header", MT_COLOR_HEADER },
164  { "index", MT_COLOR_INDEX },
165  { "index_author", MT_COLOR_INDEX_AUTHOR },
166  { "index_collapsed", MT_COLOR_INDEX_COLLAPSED },
167  { "index_date", MT_COLOR_INDEX_DATE },
168  { "index_flags", MT_COLOR_INDEX_FLAGS },
169  { "index_label", MT_COLOR_INDEX_LABEL },
170  { "index_number", MT_COLOR_INDEX_NUMBER },
171  { "index_size", MT_COLOR_INDEX_SIZE },
172  { "index_subject", MT_COLOR_INDEX_SUBJECT },
173  { "index_tag", MT_COLOR_INDEX_TAG },
174  { "index_tags", MT_COLOR_INDEX_TAGS },
175  { "indicator", MT_COLOR_INDICATOR },
176  { "markers", MT_COLOR_MARKERS },
177  { "message", MT_COLOR_MESSAGE },
178  { "normal", MT_COLOR_NORMAL },
179  { "options", MT_COLOR_OPTIONS },
180  { "progress", MT_COLOR_PROGRESS },
181  { "prompt", MT_COLOR_PROMPT },
182  { "quoted", MT_COLOR_QUOTED },
183  { "search", MT_COLOR_SEARCH },
184 #ifdef USE_SIDEBAR
185  { "sidebar_divider", MT_COLOR_SIDEBAR_DIVIDER },
186  { "sidebar_flagged", MT_COLOR_SIDEBAR_FLAGGED },
187  { "sidebar_highlight", MT_COLOR_SIDEBAR_HIGHLIGHT },
188  { "sidebar_indicator", MT_COLOR_SIDEBAR_INDICATOR },
189  { "sidebar_new", MT_COLOR_SIDEBAR_NEW },
190  { "sidebar_ordinary", MT_COLOR_SIDEBAR_ORDINARY },
191  { "sidebar_spool_file", MT_COLOR_SIDEBAR_SPOOLFILE },
192  { "sidebar_unread", MT_COLOR_SIDEBAR_UNREAD },
193 #endif
194  { "signature", MT_COLOR_SIGNATURE },
195  { "status", MT_COLOR_STATUS },
196  { "tilde", MT_COLOR_TILDE },
197  { "tree", MT_COLOR_TREE },
198  { "underline", MT_COLOR_UNDERLINE },
199  { "warning", MT_COLOR_WARNING },
200  { NULL, 0 },
201 };
202 
203 const struct Mapping ComposeFields[] = {
204  { "header", MT_COLOR_COMPOSE_HEADER },
205  { "security_encrypt", MT_COLOR_COMPOSE_SECURITY_ENCRYPT },
206  { "security_sign", MT_COLOR_COMPOSE_SECURITY_SIGN },
207  { "security_both", MT_COLOR_COMPOSE_SECURITY_BOTH },
208  { "security_none", MT_COLOR_COMPOSE_SECURITY_NONE },
209  { NULL, 0 }
210 };
211 // clang-format off
212 
216 static void defs_init(void)
217 {
218  memset(Colors.defs, A_NORMAL, MT_COLOR_MAX * sizeof(int));
219 
220  // Set some defaults
221  Colors.defs[MT_COLOR_INDICATOR] = A_REVERSE;
222  Colors.defs[MT_COLOR_MARKERS] = A_REVERSE;
223  Colors.defs[MT_COLOR_SEARCH] = A_REVERSE;
224 #ifdef USE_SIDEBAR
225  Colors.defs[MT_COLOR_SIDEBAR_HIGHLIGHT] = A_UNDERLINE;
226 #endif
227  Colors.defs[MT_COLOR_STATUS] = A_REVERSE;
228 }
229 
233 static void defs_clear(void)
234 {
235  memset(Colors.defs, A_NORMAL, MT_COLOR_MAX * sizeof(int));
236 }
237 
241 static void quotes_init(void)
242 {
243  memset(Colors.quotes, A_NORMAL, COLOR_QUOTES_MAX * sizeof(int));
244  Colors.quotes_used = 0;
245 }
246 
250 static void quotes_clear(void)
251 {
252  memset(Colors.quotes, A_NORMAL, COLOR_QUOTES_MAX * sizeof(int));
253  Colors.quotes_used = 0;
254 }
255 
260 static void color_list_free(struct ColorList **ptr)
261 {
262  if (!ptr || !*ptr)
263  return;
264 
265  struct ColorList *cl = *ptr;
266  struct ColorList *next = NULL;
267 
268  while (cl)
269  {
270  next = cl->next;
271  FREE(&cl);
272  cl = next;
273  }
274  *ptr = NULL;
275 }
276 
284 void mutt_color_free(uint32_t fg, uint32_t bg)
285 {
286  struct ColorList *q = NULL;
287 
288  struct ColorList *p = Colors.user_colors;
289  while (p)
290  {
291  if ((p->fg == fg) && (p->bg == bg))
292  {
293  (p->count)--;
294  if (p->count > 0)
295  return;
296 
297  Colors.num_user_colors--;
298  mutt_debug(LL_DEBUG1, "Color pairs used so far: %d\n", Colors.num_user_colors);
299 
300  if (p == Colors.user_colors)
301  {
302  Colors.user_colors = Colors.user_colors->next;
303  FREE(&p);
304  return;
305  }
306  q = Colors.user_colors;
307  while (q)
308  {
309  if (q->next == p)
310  {
311  q->next = p->next;
312  FREE(&p);
313  return;
314  }
315  q = q->next;
316  }
317  /* can't get here */
318  }
319  p = p->next;
320  }
321 }
322 
328 static void color_line_free(struct ColorLine **ptr, bool free_colors)
329 {
330  if (!ptr || !*ptr)
331  return;
332 
333  struct ColorLine *cl = *ptr;
334 
335 #ifdef HAVE_COLOR
336  if (free_colors && (cl->fg != COLOR_UNSET) && (cl->bg != COLOR_UNSET))
337  mutt_color_free(cl->fg, cl->bg);
338 #endif
339 
340  regfree(&cl->regex);
342  FREE(&cl->pattern);
343  FREE(ptr);
344 }
345 
350 static void color_line_list_clear(struct ColorLineList *list)
351 {
352  struct ColorLine *np = NULL, *tmp = NULL;
353  STAILQ_FOREACH_SAFE(np, list, entries, tmp)
354  {
355  STAILQ_REMOVE(list, np, ColorLine, entries);
356  color_line_free(&np, true);
357  }
358 }
359 
363 static void colors_clear(void)
364 {
374 
375  defs_clear();
376  quotes_clear();
377 
378  color_list_free(&Colors.user_colors);
379 }
380 
385 {
386  colors_clear();
387  notify_free(&Colors.notify);
388 }
389 
394 {
395  Colors.notify = notify_new();
396 
397  quotes_init();
398  defs_init();
399 
400 #ifdef HAVE_COLOR
401  start_color();
402 #endif
403 
405 }
406 
411 static struct ColorLine *color_line_new(void)
412 {
413  struct ColorLine *cl = mutt_mem_calloc(1, sizeof(struct ColorLine));
414 
415  cl->fg = COLOR_UNSET;
416  cl->bg = COLOR_UNSET;
417 
418  return cl;
419 }
420 
421 #ifdef HAVE_COLOR
422 #ifdef USE_SLANG_CURSES
423 
430 static char *get_color_name(char *dest, size_t destlen, uint32_t val)
431 {
432  static const char *const missing[3] = { "brown", "lightgray", "default" };
433 
434  if (val & RGB24)
435  {
436  assert(snprintf(dest, destlen, "#%06X", val & 0xffffff) == 7);
437  return dest;
438  }
439 
440  switch (val)
441  {
442  case COLOR_YELLOW:
443  mutt_str_copy(dest, missing[0], destlen);
444  return dest;
445 
446  case COLOR_WHITE:
447  mutt_str_copy(dest, missing[1], destlen);
448  return dest;
449 
450  case COLOR_DEFAULT:
451  mutt_str_copy(dest, missing[2], destlen);
452  return dest;
453  }
454 
455  for (int i = 0; ColorNames[i].name; i++)
456  {
457  if (ColorNames[i].value == val)
458  {
459  mutt_str_copy(dest, ColorNames[i].name, destlen);
460  return dest;
461  }
462  }
463 
464  /* Sigh. If we got this far, the color is of the form 'colorN'
465  * Slang can handle this itself, so just return 'colorN' */
466  snprintf(dest, destlen, "color%d", val);
467 
468  return dest;
469 }
470 #endif
471 
478 int mutt_color_alloc(uint32_t fg, uint32_t bg)
479 {
480 #ifdef USE_SLANG_CURSES
481  char fgc[128], bgc[128];
482 #endif
483  struct ColorList *p = Colors.user_colors;
484 
485  /* check to see if this color is already allocated to save space */
486  while (p)
487  {
488  if ((p->fg == fg) && (p->bg == bg))
489  {
490  (p->count)++;
491  return COLOR_PAIR(p->index);
492  }
493  p = p->next;
494  }
495 
496  /* check to see if there are colors left */
497  if (++Colors.num_user_colors > COLOR_PAIRS)
498  return A_NORMAL;
499 
500  /* find the smallest available index (object) */
501  int i = 1;
502  while (true)
503  {
504  p = Colors.user_colors;
505  while (p)
506  {
507  if (p->index == i)
508  break;
509  p = p->next;
510  }
511  if (!p)
512  break;
513  i++;
514  }
515 
516  p = mutt_mem_malloc(sizeof(struct ColorList));
517  p->next = Colors.user_colors;
518  Colors.user_colors = p;
519 
520  p->index = i;
521  p->count = 1;
522  p->bg = bg;
523  p->fg = fg;
524 
525 #ifdef USE_SLANG_CURSES
526  /*
527  * If using s-lang always use SLtt_set_color which allows using truecolor
528  * values. Note that I couldn't figure out if s-lang somehow reports
529  * truecolor support.
530  */
531  SLtt_set_color(i, NULL, get_color_name(fgc, sizeof(fgc), fg),
532  get_color_name(bgc, sizeof(bgc), bg));
533 #else
534 #ifdef HAVE_USE_DEFAULT_COLORS
535  if (fg == COLOR_DEFAULT)
536  fg = COLOR_UNSET;
537  if (bg == COLOR_DEFAULT)
538  bg = COLOR_UNSET;
539 #endif
540  init_pair(i, fg, bg);
541 #endif
542 
543  mutt_debug(LL_DEBUG3, "Color pairs used so far: %d\n", Colors.num_user_colors);
544 
545  return COLOR_PAIR(p->index);
546 }
547 
556 static int mutt_lookup_color(short pair, uint32_t *fg, uint32_t *bg)
557 {
558  struct ColorList *p = Colors.user_colors;
559 
560  while (p)
561  {
562  if (COLOR_PAIR(p->index) == pair)
563  {
564  if (fg)
565  *fg = p->fg;
566  if (bg)
567  *bg = p->bg;
568  return 0;
569  }
570  p = p->next;
571  }
572  return -1;
573 }
574 
581 int mutt_color_combine(uint32_t fg_attr, uint32_t bg_attr)
582 {
583  uint32_t fg = COLOR_DEFAULT;
584  uint32_t bg = COLOR_DEFAULT;
585 
586  mutt_lookup_color(fg_attr, &fg, NULL);
587  mutt_lookup_color(bg_attr, NULL, &bg);
588 
589  if ((fg == COLOR_DEFAULT) && (bg == COLOR_DEFAULT))
590  return A_NORMAL;
591  return mutt_color_alloc(fg, bg);
592 }
593 #endif /* HAVE_COLOR */
594 
595 #ifdef HAVE_COLOR
596 
607 static enum CommandResult parse_color_name(const char *s, uint32_t *col, int *attr,
608  bool is_fg, struct Buffer *err)
609 {
610  char *eptr = NULL;
611  bool is_alert = false, is_bright = false, is_light = false;
612  int clen;
613 
614  if ((clen = mutt_istr_startswith(s, "bright")))
615  {
616  is_bright = true;
617  s += clen;
618  }
619  else if ((clen = mutt_istr_startswith(s, "alert")))
620  {
621  is_alert = true;
622  is_bright = true;
623  s += clen;
624  }
625  else if ((clen = mutt_istr_startswith(s, "light")))
626  {
627  is_light = true;
628  s += clen;
629  }
630 
631  /* allow aliases for xterm color resources */
632  if ((clen = mutt_istr_startswith(s, "color")))
633  {
634  s += clen;
635  *col = strtoul(s, &eptr, 10);
636  if ((*s == '\0') || (*eptr != '\0') || ((*col >= COLORS) && !OptNoCurses && has_colors()))
637  {
638  mutt_buffer_printf(err, _("%s: color not supported by term"), s);
639  return MUTT_CMD_ERROR;
640  }
641  }
642 #ifdef HAVE_DIRECTCOLOR
643  else if (*s == '#')
644  {
645  s += 1;
646  *col = strtoul(s, &eptr, 16);
647  if ((*s == '\0') || (*eptr != '\0') || ((*col == COLOR_UNSET) && !OptNoCurses && has_colors()))
648  {
649  snprintf(err->data, err->dsize, _("%s: color not supported by term"), s);
650  return MUTT_CMD_ERROR;
651  }
652  *col |= RGB24;
653  }
654 #endif
655  else if ((*col = mutt_map_get_value(s, ColorNames)) == -1)
656  {
657  mutt_buffer_printf(err, _("%s: no such color"), s);
658  return MUTT_CMD_WARNING;
659  }
660 
661  if (is_bright || is_light)
662  {
663  if (is_alert)
664  {
665  *attr |= A_BOLD;
666  *attr |= A_BLINK;
667  }
668  else if (is_fg)
669  {
670  if ((COLORS >= 16) && is_light)
671  {
672  if (*col <= 7)
673  {
674  /* Advance the color 0-7 by 8 to get the light version */
675  *col += 8;
676  }
677  }
678  else
679  {
680  *attr |= A_BOLD;
681  }
682  }
683  else if (!(*col & RGB24))
684  {
685  if (COLORS >= 16)
686  {
687  if (*col <= 7)
688  {
689  /* Advance the color 0-7 by 8 to get the light version */
690  *col += 8;
691  }
692  }
693  }
694  }
695 
696  return MUTT_CMD_SUCCESS;
697 }
698 #endif
699 
709 static enum CommandResult parse_object(struct Buffer *buf, struct Buffer *s,
710  enum ColorId *obj, int *ql, struct Buffer *err)
711 {
712  int rc;
713 
714  if (mutt_str_startswith(buf->data, "quoted") != 0)
715  {
716  int val = 0;
717  if (buf->data[6] != '\0')
718  {
719  rc = mutt_str_atoi(buf->data + 6, &val);
720  if ((rc != 0) || (val > COLOR_QUOTES_MAX))
721  {
722  mutt_buffer_printf(err, _("%s: no such object"), buf->data);
723  return MUTT_CMD_WARNING;
724  }
725  }
726 
727  *ql = val;
728  *obj = MT_COLOR_QUOTED;
729  return MUTT_CMD_SUCCESS;
730  }
731 
732  if (mutt_istr_equal(buf->data, "compose"))
733  {
734  if (!MoreArgs(s))
735  {
736  mutt_buffer_printf(err, _("%s: too few arguments"), "color");
737  return MUTT_CMD_WARNING;
738  }
739 
741 
742  rc = mutt_map_get_value(buf->data, ComposeFields);
743  if (rc == -1)
744  {
745  mutt_buffer_printf(err, _("%s: no such object"), buf->data);
746  return MUTT_CMD_WARNING;
747  }
748 
749  *obj = rc;
750  return MUTT_CMD_SUCCESS;
751  }
752 
753  rc = mutt_map_get_value(buf->data, Fields);
754  if (rc == -1)
755  {
756  mutt_buffer_printf(err, _("%s: no such object"), buf->data);
757  return MUTT_CMD_WARNING;
758  }
759 
760  *obj = rc;
761  return MUTT_CMD_SUCCESS;
762 }
763 
772 static bool do_uncolor(struct Buffer *buf, struct Buffer *s,
773  struct ColorLineList *cl, bool uncolor)
774 {
775  struct ColorLine *np = NULL, *prev = NULL;
776  bool rc = false;
777 
778  do
779  {
781  if (mutt_str_equal("*", buf->data))
782  {
783  rc = STAILQ_FIRST(cl);
785  return rc;
786  }
787 
788  prev = NULL;
789  STAILQ_FOREACH(np, cl, entries)
790  {
791  if (mutt_str_equal(buf->data, np->pattern))
792  {
793  rc = true;
794 
795  mutt_debug(LL_DEBUG1, "Freeing pattern \"%s\" from user_colors\n", buf->data);
796  if (prev)
797  STAILQ_REMOVE_AFTER(cl, prev, entries);
798  else
799  STAILQ_REMOVE_HEAD(cl, entries);
800  color_line_free(&np, uncolor);
801  break;
802  }
803  prev = np;
804  }
805  } while (MoreArgs(s));
806 
807  return rc;
808 }
809 
822 static enum CommandResult parse_uncolor(struct Buffer *buf, struct Buffer *s,
823  struct Buffer *err, bool uncolor)
824 {
826 
827  if (mutt_str_equal(buf->data, "*"))
828  {
829  colors_clear();
830  struct EventColor ec = { MT_COLOR_MAX };
831  notify_send(Colors.notify, NT_COLOR, NT_COLOR_RESET, &ec);
832  return MUTT_CMD_SUCCESS;
833  }
834 
835  unsigned int object = MT_COLOR_NONE;
836  int ql = 0;
837  enum CommandResult rc = parse_object(buf, s, &object, &ql, err);
838  if (rc != MUTT_CMD_SUCCESS)
839  return rc;
840 
841  if (object == -1)
842  {
843  mutt_buffer_printf(err, _("%s: no such object"), buf->data);
844  return MUTT_CMD_ERROR;
845  }
846 
847  if (object == MT_COLOR_QUOTED)
848  {
849  Colors.quotes[ql] = A_NORMAL;
850  /* fallthrough to simple case */
851  }
852 
853  if ((object != MT_COLOR_ATTACH_HEADERS) && (object != MT_COLOR_BODY) &&
854  (object != MT_COLOR_HEADER) && (object != MT_COLOR_INDEX) &&
855  (object != MT_COLOR_INDEX_AUTHOR) && (object != MT_COLOR_INDEX_FLAGS) &&
856  (object != MT_COLOR_INDEX_SUBJECT) && (object != MT_COLOR_INDEX_TAG) &&
857  (object != MT_COLOR_STATUS))
858  {
859  // Simple colours
860  Colors.defs[object] = A_NORMAL;
861 
862  struct EventColor ec = { object };
863  notify_send(Colors.notify, NT_COLOR, NT_COLOR_RESET, &ec);
864  return MUTT_CMD_SUCCESS;
865  }
866 
867  if (!MoreArgs(s))
868  {
869  mutt_buffer_printf(err, _("%s: too few arguments"), uncolor ? "uncolor" : "unmono");
870  return MUTT_CMD_WARNING;
871  }
872 
873 #ifdef HAVE_COLOR
874  if (OptNoCurses || // running without curses
875  (uncolor && !has_colors()) || // parsing an uncolor command, and have no colors
876  (!uncolor && has_colors())) // parsing an unmono command, and have colors
877 #else
878  if (uncolor) // We don't even have colors compiled in
879 #endif
880  {
881  do
882  {
883  /* just eat the command, but don't do anything real about it */
885  } while (MoreArgs(s));
886 
887  return MUTT_CMD_SUCCESS;
888  }
889 
890  bool changed = false;
891  if (object == MT_COLOR_ATTACH_HEADERS)
892  changed |= do_uncolor(buf, s, mutt_color_attachments(), uncolor);
893  else if (object == MT_COLOR_BODY)
894  changed |= do_uncolor(buf, s, mutt_color_body(), uncolor);
895  else if (object == MT_COLOR_HEADER)
896  changed |= do_uncolor(buf, s, mutt_color_headers(), uncolor);
897  else if (object == MT_COLOR_INDEX)
898  changed |= do_uncolor(buf, s, mutt_color_index(), uncolor);
899  else if (object == MT_COLOR_INDEX_AUTHOR)
900  changed |= do_uncolor(buf, s, mutt_color_index_author(), uncolor);
901  else if (object == MT_COLOR_INDEX_FLAGS)
902  changed |= do_uncolor(buf, s, mutt_color_index_flags(), uncolor);
903  else if (object == MT_COLOR_INDEX_SUBJECT)
904  changed |= do_uncolor(buf, s, mutt_color_index_subject(), uncolor);
905  else if (object == MT_COLOR_INDEX_TAG)
906  changed |= do_uncolor(buf, s, mutt_color_index_tags(), uncolor);
907  else if (object == MT_COLOR_STATUS)
908  changed |= do_uncolor(buf, s, mutt_color_status_line(), uncolor);
909 
910  if (changed)
911  {
912  struct EventColor ec = { object };
913  notify_send(Colors.notify, NT_COLOR, NT_COLOR_RESET, &ec);
914  }
915 
916  return MUTT_CMD_SUCCESS;
917 }
918 
919 #ifdef HAVE_COLOR
920 
923 enum CommandResult mutt_parse_uncolor(struct Buffer *buf, struct Buffer *s,
924  intptr_t data, struct Buffer *err)
925 {
926  if (OptNoCurses || !has_colors())
927  {
928  *s->dptr = '\0'; /* fake that we're done parsing */
929  return MUTT_CMD_SUCCESS;
930  }
931  return parse_uncolor(buf, s, err, true);
932 }
933 #endif
934 
938 enum CommandResult mutt_parse_unmono(struct Buffer *buf, struct Buffer *s,
939  intptr_t data, struct Buffer *err)
940 {
941  if (OptNoCurses || !has_colors())
942  {
943  *s->dptr = '\0'; /* fake that we're done parsing */
944  return MUTT_CMD_SUCCESS;
945  }
946  return parse_uncolor(buf, s, err, false);
947 }
948 
965 static enum CommandResult add_pattern(struct ColorLineList *top, const char *s,
966  bool sensitive, uint32_t fg, uint32_t bg, int attr,
967  struct Buffer *err, bool is_index, int match)
968 {
969  struct ColorLine *tmp = NULL;
970 
971  STAILQ_FOREACH(tmp, top, entries)
972  {
973  if ((sensitive && mutt_str_equal(s, tmp->pattern)) ||
974  (!sensitive && mutt_istr_equal(s, tmp->pattern)))
975  {
976  break;
977  }
978  }
979 
980  if (tmp)
981  {
982 #ifdef HAVE_COLOR
983  if ((fg != COLOR_UNSET) && (bg != COLOR_UNSET))
984  {
985  if ((tmp->fg != fg) || (tmp->bg != bg))
986  {
987  mutt_color_free(tmp->fg, tmp->bg);
988  tmp->fg = fg;
989  tmp->bg = bg;
990  attr |= mutt_color_alloc(fg, bg);
991  }
992  else
993  attr |= (tmp->pair & ~A_BOLD);
994  }
995 #endif /* HAVE_COLOR */
996  tmp->pair = attr;
997  }
998  else
999  {
1000  tmp = color_line_new();
1001  if (is_index)
1002  {
1003  struct Buffer *buf = mutt_buffer_pool_get();
1004  mutt_buffer_strcpy(buf, s);
1005  const char *const c_simple_search =
1006  cs_subset_string(NeoMutt->sub, "simple_search");
1007  mutt_check_simple(buf, NONULL(c_simple_search));
1010  if (!tmp->color_pattern)
1011  {
1012  color_line_free(&tmp, true);
1013  return MUTT_CMD_ERROR;
1014  }
1015  }
1016  else
1017  {
1018  uint16_t flags = 0;
1019  if (sensitive)
1020  flags = mutt_mb_is_lower(s) ? REG_ICASE : 0;
1021  else
1022  flags = REG_ICASE;
1023 
1024  const int r = REG_COMP(&tmp->regex, s, flags);
1025  if (r != 0)
1026  {
1027  regerror(r, &tmp->regex, err->data, err->dsize);
1028  color_line_free(&tmp, true);
1029  return MUTT_CMD_ERROR;
1030  }
1031  }
1032  tmp->pattern = mutt_str_dup(s);
1033  tmp->match = match;
1034 #ifdef HAVE_COLOR
1035  if ((fg != COLOR_UNSET) && (bg != COLOR_UNSET))
1036  {
1037  tmp->fg = fg;
1038  tmp->bg = bg;
1039  attr |= mutt_color_alloc(fg, bg);
1040  }
1041 #endif
1042  tmp->pair = attr;
1043  STAILQ_INSERT_HEAD(top, tmp, entries);
1044  }
1045 
1046  /* force re-caching of index colors */
1047  const struct Mailbox *m = ctx_mailbox(Context);
1048  if (is_index && m)
1049  {
1050  for (int i = 0; i < m->msg_count; i++)
1051  {
1052  struct Email *e = m->emails[i];
1053  if (!e)
1054  break;
1055  e->pair = 0;
1056  }
1057  }
1058 
1059  return MUTT_CMD_SUCCESS;
1060 }
1061 
1062 #ifdef HAVE_COLOR
1063 
1066 static enum CommandResult parse_color_pair(struct Buffer *buf, struct Buffer *s,
1067  uint32_t *fg, uint32_t *bg,
1068  int *attr, struct Buffer *err)
1069 {
1070  while (true)
1071  {
1072  if (!MoreArgs(s))
1073  {
1074  mutt_buffer_printf(err, _("%s: too few arguments"), "color");
1075  return MUTT_CMD_WARNING;
1076  }
1077 
1079 
1080  if (mutt_istr_equal("bold", buf->data))
1081  *attr |= A_BOLD;
1082  else if (mutt_istr_equal("none", buf->data))
1083  *attr = A_NORMAL; // Use '=' to clear other bits
1084  else if (mutt_istr_equal("normal", buf->data))
1085  *attr = A_NORMAL; // Use '=' to clear other bits
1086  else if (mutt_istr_equal("reverse", buf->data))
1087  *attr |= A_REVERSE;
1088  else if (mutt_istr_equal("standout", buf->data))
1089  *attr |= A_STANDOUT;
1090  else if (mutt_istr_equal("underline", buf->data))
1091  *attr |= A_UNDERLINE;
1092  else
1093  {
1094  enum CommandResult rc = parse_color_name(buf->data, fg, attr, true, err);
1095  if (rc != MUTT_CMD_SUCCESS)
1096  return rc;
1097  break;
1098  }
1099  }
1100 
1101  if (!MoreArgs(s))
1102  {
1103  mutt_buffer_printf(err, _("%s: too few arguments"), "color");
1104  return MUTT_CMD_WARNING;
1105  }
1106 
1108 
1109  return parse_color_name(buf->data, bg, attr, false, err);
1110 }
1111 #endif
1112 
1116 static enum CommandResult parse_attr_spec(struct Buffer *buf, struct Buffer *s,
1117  uint32_t *fg, uint32_t *bg, int *attr,
1118  struct Buffer *err)
1119 {
1120  if (fg)
1121  *fg = COLOR_UNSET;
1122  if (bg)
1123  *bg = COLOR_UNSET;
1124 
1125  if (!MoreArgs(s))
1126  {
1127  mutt_buffer_printf(err, _("%s: too few arguments"), "mono");
1128  return MUTT_CMD_WARNING;
1129  }
1130 
1132 
1133  if (mutt_istr_equal("bold", buf->data))
1134  *attr |= A_BOLD;
1135  else if (mutt_istr_equal("none", buf->data))
1136  *attr = A_NORMAL; // Use '=' to clear other bits
1137  else if (mutt_istr_equal("normal", buf->data))
1138  *attr = A_NORMAL; // Use '=' to clear other bits
1139  else if (mutt_istr_equal("reverse", buf->data))
1140  *attr |= A_REVERSE;
1141  else if (mutt_istr_equal("standout", buf->data))
1142  *attr |= A_STANDOUT;
1143  else if (mutt_istr_equal("underline", buf->data))
1144  *attr |= A_UNDERLINE;
1145  else
1146  {
1147  mutt_buffer_printf(err, _("%s: no such attribute"), buf->data);
1148  return MUTT_CMD_WARNING;
1149  }
1150 
1151  return MUTT_CMD_SUCCESS;
1152 }
1153 
1161 static int fgbgattr_to_color(int fg, int bg, int attr)
1162 {
1163 #ifdef HAVE_COLOR
1164  if ((fg != COLOR_UNSET) && (bg != COLOR_UNSET))
1165  return attr | mutt_color_alloc(fg, bg);
1166 #endif
1167  return attr;
1168 }
1169 
1183 static enum CommandResult parse_color(struct Buffer *buf, struct Buffer *s,
1184  struct Buffer *err, parser_callback_t callback,
1185  bool dry_run, bool color)
1186 {
1187  int attr = 0, q_level = 0;
1188  uint32_t fg = 0, bg = 0, match = 0;
1189  enum ColorId object = MT_COLOR_NONE;
1190  enum CommandResult rc;
1191 
1192  if (!MoreArgs(s))
1193  {
1194  mutt_buffer_printf(err, _("%s: too few arguments"), "color");
1195  return MUTT_CMD_WARNING;
1196  }
1197 
1199 
1200  rc = parse_object(buf, s, &object, &q_level, err);
1201  if (rc != MUTT_CMD_SUCCESS)
1202  return rc;
1203 
1204  rc = callback(buf, s, &fg, &bg, &attr, err);
1205  if (rc != MUTT_CMD_SUCCESS)
1206  return rc;
1207 
1208  /* extract a regular expression if needed */
1209 
1210  if ((object == MT_COLOR_ATTACH_HEADERS) || (object == MT_COLOR_BODY) ||
1211  (object == MT_COLOR_HEADER) || (object == MT_COLOR_INDEX) ||
1212  (object == MT_COLOR_INDEX_AUTHOR) || (object == MT_COLOR_INDEX_FLAGS) ||
1213  (object == MT_COLOR_INDEX_SUBJECT) || (object == MT_COLOR_INDEX_TAG))
1214  {
1215  if (!MoreArgs(s))
1216  {
1217  mutt_buffer_printf(err, _("%s: too few arguments"), color ? "color" : "mono");
1218  return MUTT_CMD_WARNING;
1219  }
1220 
1222  }
1223 
1224  if (MoreArgs(s) && (object != MT_COLOR_STATUS))
1225  {
1226  mutt_buffer_printf(err, _("%s: too many arguments"), color ? "color" : "mono");
1227  return MUTT_CMD_WARNING;
1228  }
1229 
1230  if (dry_run)
1231  {
1232  *s->dptr = '\0'; /* fake that we're done parsing */
1233  return MUTT_CMD_SUCCESS;
1234  }
1235 
1236 #ifdef HAVE_COLOR
1237 #ifdef HAVE_USE_DEFAULT_COLORS
1238  if (!OptNoCurses &&
1239  has_colors()
1240  /* delay use_default_colors() until needed, since it initializes things */
1241  && ((fg == COLOR_DEFAULT) || (bg == COLOR_DEFAULT) || (object == MT_COLOR_TREE)) &&
1242  (use_default_colors() != OK))
1243  /* the case of the tree object is special, because a non-default fg color of
1244  * the tree element may be combined dynamically with the default bg color of
1245  * an index line, not necessarily defined in a rc file. */
1246  {
1247  mutt_buffer_strcpy(err, _("default colors not supported"));
1248  return MUTT_CMD_ERROR;
1249  }
1250 #endif /* HAVE_USE_DEFAULT_COLORS */
1251 #endif
1252 
1253  if (object == MT_COLOR_ATTACH_HEADERS)
1254  rc = add_pattern(mutt_color_attachments(), buf->data, true, fg, bg, attr, err, false, match);
1255  else if (object == MT_COLOR_BODY)
1256  rc = add_pattern(mutt_color_body(), buf->data, true, fg, bg, attr, err, false, match);
1257  else if (object == MT_COLOR_HEADER)
1258  rc = add_pattern(mutt_color_headers(), buf->data, false, fg, bg, attr, err, false, match);
1259  else if (object == MT_COLOR_INDEX)
1260  {
1261  rc = add_pattern(mutt_color_index(), buf->data, true, fg, bg, attr, err, true, match);
1262  }
1263  else if (object == MT_COLOR_INDEX_AUTHOR)
1264  {
1265  rc = add_pattern(mutt_color_index_author(), buf->data, true, fg, bg, attr,
1266  err, true, match);
1267  }
1268  else if (object == MT_COLOR_INDEX_FLAGS)
1269  {
1270  rc = add_pattern(mutt_color_index_flags(), buf->data, true, fg, bg, attr, err, true, match);
1271  }
1272  else if (object == MT_COLOR_INDEX_SUBJECT)
1273  {
1274  rc = add_pattern(mutt_color_index_subject(), buf->data, true, fg, bg, attr,
1275  err, true, match);
1276  }
1277  else if (object == MT_COLOR_INDEX_TAG)
1278  {
1279  rc = add_pattern(mutt_color_index_tags(), buf->data, true, fg, bg, attr, err, true, match);
1280  }
1281  else if (object == MT_COLOR_QUOTED)
1282  {
1283  if (q_level >= COLOR_QUOTES_MAX)
1284  {
1285  mutt_buffer_printf(err, _("Maximum quoting level is %d"), COLOR_QUOTES_MAX - 1);
1286  return MUTT_CMD_WARNING;
1287  }
1288 
1289  if (q_level >= Colors.quotes_used)
1290  Colors.quotes_used = q_level + 1;
1291  if (q_level == 0)
1292  {
1293  Colors.defs[MT_COLOR_QUOTED] = fgbgattr_to_color(fg, bg, attr);
1294 
1295  Colors.quotes[0] = Colors.defs[MT_COLOR_QUOTED];
1296  for (q_level = 1; q_level < Colors.quotes_used; q_level++)
1297  {
1298  if (Colors.quotes[q_level] == A_NORMAL)
1299  Colors.quotes[q_level] = Colors.defs[MT_COLOR_QUOTED];
1300  }
1301  }
1302  else
1303  {
1304  Colors.quotes[q_level] = fgbgattr_to_color(fg, bg, attr);
1305  }
1306  rc = MUTT_CMD_SUCCESS;
1307  }
1308  else if ((object == MT_COLOR_STATUS) && MoreArgs(s))
1309  {
1310  /* 'color status fg bg' can have up to 2 arguments:
1311  * 0 arguments: sets the default status color (handled below by else part)
1312  * 1 argument : colorize pattern on match
1313  * 2 arguments: colorize nth submatch of pattern */
1315 
1316  if (MoreArgs(s))
1317  {
1318  struct Buffer tmp = mutt_buffer_make(0);
1320  if (mutt_str_atoui(tmp.data, &match) < 0)
1321  {
1322  mutt_buffer_printf(err, _("%s: invalid number: %s"),
1323  color ? "color" : "mono", tmp.data);
1324  mutt_buffer_dealloc(&tmp);
1325  return MUTT_CMD_WARNING;
1326  }
1327  mutt_buffer_dealloc(&tmp);
1328  }
1329 
1330  if (MoreArgs(s))
1331  {
1332  mutt_buffer_printf(err, _("%s: too many arguments"), color ? "color" : "mono");
1333  return MUTT_CMD_WARNING;
1334  }
1335 
1336  rc = add_pattern(mutt_color_status_line(), buf->data, true, fg, bg, attr, err, false, match);
1337  }
1338  else // Remaining simple colours
1339  {
1340  Colors.defs[object] = fgbgattr_to_color(fg, bg, attr);
1341  rc = MUTT_CMD_SUCCESS;
1342  }
1343 
1344  if (rc == MUTT_CMD_SUCCESS)
1345  {
1346  struct EventColor ec = { object };
1347  notify_send(Colors.notify, NT_COLOR, NT_COLOR_SET, &ec);
1348  }
1349 
1350  return rc;
1351 }
1352 
1353 #ifdef HAVE_COLOR
1354 
1357 enum CommandResult mutt_parse_color(struct Buffer *buf, struct Buffer *s,
1358  intptr_t data, struct Buffer *err)
1359 {
1360  bool dry_run = false;
1361 
1362  if (OptNoCurses || !has_colors())
1363  dry_run = true;
1364 
1365  return parse_color(buf, s, err, parse_color_pair, dry_run, true);
1366 }
1367 #endif
1368 
1372 enum CommandResult mutt_parse_mono(struct Buffer *buf, struct Buffer *s,
1373  intptr_t data, struct Buffer *err)
1374 {
1375  bool dry_run = false;
1376 
1377 #ifdef HAVE_COLOR
1378  if (OptNoCurses || has_colors())
1379  dry_run = true;
1380 #else
1381  if (OptNoCurses)
1382  dry_run = true;
1383 #endif
1384 
1385  return parse_color(buf, s, err, parse_attr_spec, dry_run, false);
1386 }
1387 
1393 int mutt_color(enum ColorId id)
1394 {
1395  return Colors.defs[id];
1396 }
1397 
1402 struct ColorLineList *mutt_color_status_line(void)
1403 {
1404  return get_color_line_list(&Colors.status_list);
1405 }
1406 
1411 struct ColorLineList *mutt_color_index(void)
1412 {
1413  return get_color_line_list(&Colors.index_list);
1414 }
1415 
1420 struct ColorLineList *mutt_color_headers(void)
1421 {
1422  return get_color_line_list(&Colors.hdr_list);
1423 }
1424 
1429 struct ColorLineList *mutt_color_body(void)
1430 {
1431  return get_color_line_list(&Colors.body_list);
1432 }
1433 
1438 struct ColorLineList *mutt_color_attachments(void)
1439 {
1440  return get_color_line_list(&Colors.attach_list);
1441 }
1442 
1447 struct ColorLineList *mutt_color_index_author(void)
1448 {
1449  return get_color_line_list(&Colors.index_author_list);
1450 }
1451 
1456 struct ColorLineList *mutt_color_index_flags(void)
1457 {
1458  return get_color_line_list(&Colors.index_flags_list);
1459 }
1460 
1465 struct ColorLineList *mutt_color_index_subject(void)
1466 {
1467  return get_color_line_list(&Colors.index_subject_list);
1468 }
1469 
1474 struct ColorLineList *mutt_color_index_tags(void)
1475 {
1476  return get_color_line_list(&Colors.index_tag_list);
1477 }
1478 
1485 {
1486  const int used = Colors.quotes_used;
1487  if (used == 0)
1488  return 0;
1489  return Colors.quotes[q % used];
1490 }
1491 
1497 {
1498  return Colors.quotes_used;
1499 }
1500 
1506 void mutt_color_observer_add(observer_t callback, void *global_data)
1507 {
1508  notify_observer_add(Colors.notify, NT_COLOR, callback, global_data);
1509 }
1510 
1516 void mutt_color_observer_remove(observer_t callback, void *global_data)
1517 {
1518  notify_observer_remove(Colors.notify, callback, global_data);
1519 }
1520 
1526 bool mutt_color_is_header(enum ColorId color_id)
1527 {
1528  return (color_id == MT_COLOR_HEADER) || (color_id == MT_COLOR_HDRDEFAULT);
1529 }
Mail will be encrypted.
Definition: color.h:48
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:871
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
int defs[MT_COLOR_MAX]
Array of all fixed colours, see enum ColorId.
Definition: color.c:75
MIME attachment test (takes a pattern)
Definition: color.h:43
The "current" mailbox.
Definition: context.h:37
#define COLOR_UNSET
Definition: color.c:52
Bold text.
Definition: color.h:45
void mutt_colors_init(void)
Initialize colours.
Definition: color.c:393
Index: index number.
Definition: color.h:90
Header default colour.
Definition: color.h:52
Underlined text.
Definition: color.h:78
Progress bar.
Definition: color.h:60
#define NONULL(x)
Definition: string2.h:37
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define STAILQ_REMOVE(head, elm, type, field)
Definition: queue.h:399
Define wrapper functions around Curses/Slang.
int msg_count
Total number of messages.
Definition: mailbox.h:91
static enum CommandResult parse_uncolor(struct Buffer *buf, struct Buffer *s, struct Buffer *err, bool uncolor)
Parse an &#39;uncolor&#39; command.
Definition: color.c:822
#define COLOR_DEFAULT
Definition: color.c:128
int mutt_color_alloc(uint32_t fg, uint32_t bg)
Allocate a colour pair.
Definition: color.c:478
int mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition: string.c:252
The envelope/body of an email.
Definition: email.h:37
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
Index: tags field (g, J)
Definition: color.h:92
CommandResult
Error codes for command_t parse functions.
Definition: mutt_commands.h:34
Config/command parsing.
struct Mailbox * ctx_mailbox(struct Context *ctx)
wrapper to get the mailbox in a Context, or NULL
Definition: context.c:440
Error: Can&#39;t help the user.
Definition: mutt_commands.h:36
Informational message.
Definition: color.h:56
Structs that make up an email.
An Event that happened to a Colour.
Definition: color.h:122
int quotes[COLOR_QUOTES_MAX]
Array of colours for quoted email text.
Definition: color.c:89
The "currently-open" mailbox.
struct ColorLineList index_subject_list
List of colours applied to the subject in the index.
Definition: color.c:85
bool mutt_color_is_header(enum ColorId color_id)
Colour is for an Email header.
Definition: color.c:1526
Pager: highlight body of message (takes a pattern)
Definition: color.h:44
struct ColorLineList * mutt_color_index_subject(void)
Return the ColorLineList for subject in the index.
Definition: color.c:1465
void notify_free(struct Notify **ptr)
Free a notification handler.
Definition: notify.c:62
Mailbox with no new or flagged messages.
Definition: color.h:70
static void defs_init(void)
Initialise the simple colour definitions.
Definition: color.c:216
struct ColorLineList * mutt_color_index_flags(void)
Return the ColorLineList for flags in the index.
Definition: color.c:1456
struct Notify * notify
Notifications: ColorId, EventColor.
Definition: color.c:95
struct PatternList * color_pattern
Compiled pattern to speed up index color calculation.
Definition: color.h:104
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
struct ColorLineList * mutt_color_index(void)
Return the ColorLineList for the index.
Definition: color.c:1411
char * pattern
Pattern to match.
Definition: color.h:103
int pair
Colour pair index.
Definition: color.h:107
String manipulation buffer.
Definition: buffer.h:33
struct ColorLineList * mutt_color_index_tags(void)
Return the ColorLineList for tags in the index.
Definition: color.c:1474
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
Line dividing sidebar from the index/pager.
Definition: color.h:65
#define _(a)
Definition: message.h:28
enum CommandResult mutt_parse_mono(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;mono&#39; command - Implements Command::parse()
Definition: color.c:1372
static struct ColorLine * color_line_new(void)
Create a new ColorLine.
Definition: color.c:411
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:54
Pager: signature lines.
Definition: color.h:74
#define COLOR_QUOTES_MAX
Ten colours, quoted0..quoted9 (quoted and quoted0 are equivalent)
Definition: color.c:53
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:48
Select cursor.
Definition: color.h:67
#define STAILQ_REMOVE_HEAD(head, field)
Definition: queue.h:419
void mutt_check_simple(struct Buffer *s, const char *simple)
Convert a simple search into a real request.
Definition: pattern.c:113
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
#define RGB24
Definition: color.c:135
Pager: quoted text.
Definition: color.h:62
static void quotes_clear(void)
Reset the quoted-email colours.
Definition: color.c:250
Index: number of messages in collapsed thread.
Definition: color.h:87
short count
Definition: color.c:66
int num_user_colors
Definition: color.c:93
Container for Accounts, Notifications.
Definition: neomutt.h:36
Mailbox with new mail.
Definition: color.h:69
Current open mailbox.
Definition: color.h:68
Convenience wrapper for the config headers.
void mutt_color_observer_remove(observer_t callback, void *global_data)
Remove an observer.
Definition: color.c:1516
int match
Substring to match, 0 for old behaviour.
Definition: color.h:102
int(* parser_callback_t)(struct Buffer *buf, struct Buffer *s, uint32_t *fg, uint32_t *bg, int *attr, struct Buffer *err)
Prototype for a function to parse color config.
Definition: color.c:123
struct ColorLineList status_list
List of colours applied to the status bar.
Definition: color.c:87
size_t dsize
Length of data.
Definition: buffer.h:37
Index: author field (takes a pattern)
Definition: color.h:82
#define MoreArgs(buf)
Definition: buffer.h:40
short index
Definition: color.c:65
static int mutt_lookup_color(short pair, uint32_t *fg, uint32_t *bg)
Get the colours from a colour pair.
Definition: color.c:556
Pager: empty lines after message.
Definition: color.h:76
int(* observer_t)(struct NotifyCallback *nc)
Prototype for a notification callback function.
Definition: observer.h:54
Many unsorted constants and some structs.
struct ColorLineList index_tag_list
List of colours applied to tags in the index.
Definition: color.c:86
static enum CommandResult parse_object(struct Buffer *buf, struct Buffer *s, enum ColorId *obj, int *ql, struct Buffer *err)
Identify a colour object.
Definition: color.c:709
Message headers (takes a pattern)
Definition: color.h:53
#define STAILQ_INIT(head)
Definition: queue.h:369
Index: tag field (g, takes a pattern)
Definition: color.h:85
Convenience wrapper for the core headers.
ColorId
List of all colored objects.
Definition: color.h:39
uint32_t bg
Definition: color.c:64
struct ColorLineList index_list
List of default colours applied to the index.
Definition: color.c:84
static enum CommandResult add_pattern(struct ColorLineList *top, const char *s, bool sensitive, uint32_t fg, uint32_t bg, int attr, struct Buffer *err, bool is_index, int match)
Associate a colour to a pattern.
Definition: color.c:965
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
Index: tree-drawing characters.
Definition: color.h:77
static enum CommandResult parse_attr_spec(struct Buffer *buf, struct Buffer *s, uint32_t *fg, uint32_t *bg, int *attr, struct Buffer *err)
Parse an attribute description - Implements parser_callback_t.
Definition: color.c:1116
static void color_line_free(struct ColorLine **ptr, bool free_colors)
Free a ColorLine.
Definition: color.c:328
Pager: markers, line continuation.
Definition: color.h:55
struct Menu * menu
Needed for pattern compilation.
Definition: context.h:45
bool notify_observer_add(struct Notify *notify, enum NotifyType type, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:173
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:359
struct ColorList * user_colors
Definition: color.c:92
int mutt_color_quote(int q)
Return the color of a quote, cycling through the used quotes.
Definition: color.c:1484
Plain text.
Definition: color.h:58
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
struct ColorLineList * mutt_color_attachments(void)
Return the ColorLineList for the attachments.
Definition: color.c:1438
struct PatternList * mutt_pattern_comp(struct Mailbox *m, struct Menu *menu, const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: compile.c:1092
A new Color has been set.
Definition: color.h:134
uint32_t fg
Foreground colour.
Definition: color.h:105
struct Notify * notify_new(void)
Create a new notifications handler.
Definition: notify.c:49
Index: date field.
Definition: color.h:88
Colour has changed, NotifyColor, EventColor.
Definition: notify_type.h:39
struct ColorLineList * mutt_color_index_author(void)
Return the ColorLineList for author in the index.
Definition: color.c:1447
struct ColorList * next
Definition: color.c:67
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
Index: size field.
Definition: color.h:91
Status bar (takes a pattern)
Definition: color.h:75
A mailbox.
Definition: mailbox.h:81
uint32_t bg
Background colour.
Definition: color.h:106
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:395
Header labels, e.g. From:
Definition: color.h:46
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
char * dptr
Current read/write position.
Definition: buffer.h:36
struct ColorLineList attach_list
List of colours applied to the attachment headers.
Definition: color.c:79
struct ColorLineList index_author_list
List of colours applied to the author in the index.
Definition: color.c:82
Match patterns to emails.
char * data
Pointer to data.
Definition: buffer.h:35
Color has been reset/removed.
Definition: color.h:135
uint32_t fg
Definition: color.c:63
Selected item in list.
Definition: color.h:54
Definitions of NeoMutt commands.
struct ColorLineList hdr_list
List of colours applied to the email headers.
Definition: color.c:81
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:295
Mail will be signed.
Definition: color.h:50
static void colors_clear(void)
Reset all the colours.
Definition: color.c:363
int mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: string.c:282
#define STAILQ_INSERT_HEAD(head, elm, field)
Definition: queue.h:380
static int fgbgattr_to_color(int fg, int bg, int attr)
Convert a foreground, background, attribute triplet into a colour.
Definition: color.c:1161
Notification API.
Definition: notify.c:39
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
struct ColorLineList body_list
List of colours applied to the email body.
Definition: color.c:80
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
enum CommandResult mutt_parse_uncolor(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;uncolor&#39; command - Implements Command::parse()
Definition: color.c:923
struct ColorLineList * mutt_color_body(void)
Return the ColorLineList for the body.
Definition: color.c:1429
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
int mutt_color(enum ColorId id)
Return the color of an object.
Definition: color.c:1393
Color and attribute parsing.
void mutt_colors_cleanup(void)
Cleanup all the colours.
Definition: color.c:384
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
enum CommandResult mutt_parse_unmono(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;unmono&#39; command - Implements Command::parse()
Definition: color.c:938
regex_t regex
Compiled regex.
Definition: color.h:101
enum CommandResult mutt_parse_color(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;color&#39; command - Implements Command::parse()
Definition: color.c:1357
Mail will be encrypted and signed.
Definition: color.h:47
Index: label field.
Definition: color.h:89
static enum CommandResult parse_color(struct Buffer *buf, struct Buffer *s, struct Buffer *err, parser_callback_t callback, bool dry_run, bool color)
Parse a &#39;color&#39; command.
Definition: color.c:1183
Success: Command worked.
Definition: mutt_commands.h:38
Index: subject field (takes a pattern)
Definition: color.h:84
Error message.
Definition: color.h:51
Log at debug level 1.
Definition: logging.h:40
Warning: Help given to the user.
Definition: mutt_commands.h:37
int mutt_color_quotes_used(void)
Return the number of used quotes.
Definition: color.c:1496
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:716
static void defs_clear(void)
Reset the simple colour definitions.
Definition: color.c:233
struct ColorLineList * mutt_color_status_line(void)
Return the ColorLineList for the status_line.
Definition: color.c:1402
MIME attachments text (entire line)
Definition: color.h:42
struct ColorLineList index_flags_list
List of colours applied to the flags in the index.
Definition: color.c:83
static bool do_uncolor(struct Buffer *buf, struct Buffer *s, struct ColorLineList *cl, bool uncolor)
Parse the &#39;uncolor&#39; or &#39;unmono&#39; command.
Definition: color.c:772
A set of colors.
Definition: color.c:59
#define FREE(x)
Definition: memory.h:40
Mailbox with unread mail.
Definition: color.h:72
Mapping between user-readable string and a constant.
Definition: mapping.h:31
Pager: search matches.
Definition: color.h:63
bool notify_observer_remove(struct Notify *notify, observer_t callback, void *global_data)
Remove an observer from an object.
Definition: notify.c:212
static void quotes_init(void)
Initialise the quoted-email colours.
Definition: color.c:241
void notify_set_parent(struct Notify *notify, struct Notify *parent)
Set the parent notification handler.
Definition: notify.c:82
Mail will not be encrypted or signed.
Definition: color.h:49
Options in prompt.
Definition: color.h:59
Hundreds of global variables to back the user variables.
Handling of global boolean variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
static enum CommandResult parse_color_name(const char *s, uint32_t *col, int *attr, bool is_fg, struct Buffer *err)
Parse a colour name.
Definition: color.c:607
static enum CommandResult parse_color_pair(struct Buffer *buf, struct Buffer *s, uint32_t *fg, uint32_t *bg, int *attr, struct Buffer *err)
Parse a pair of colours - Implements parser_callback_t.
Definition: color.c:1066
const char * name
Definition: mapping.h:33
Index: default colour (takes a pattern)
Definition: color.h:81
void mutt_color_free(uint32_t fg, uint32_t bg)
Free a colour.
Definition: color.c:284
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: compile.c:1038
int mutt_color_combine(uint32_t fg_attr, uint32_t bg_attr)
Combine two colours.
Definition: color.c:581
static struct ColorLineList * get_color_line_list(struct ColorLineList *cll)
Sanitize and return a ColorLineList.
Definition: color.c:103
#define MUTT_PC_FULL_MSG
Enable body and header matching.
Definition: lib.h:61
Convenience wrapper for the library headers.
struct ColorLineList * mutt_color_headers(void)
Return the ColorLineList for headers.
Definition: color.c:1420
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
Definition: mbyte.c:357
#define STAILQ_FIRST(head)
Definition: queue.h:347
#define STAILQ_REMOVE_AFTER(head, elm, field)
Definition: queue.h:413
int pair
Color-pair to use when displaying in the index.
Definition: email.h:80
Log at debug level 3.
Definition: logging.h:42
Question/user input.
Definition: color.h:61
Mailbox with flagged messages.
Definition: color.h:66
void mutt_color_observer_add(observer_t callback, void *global_data)
Add an observer.
Definition: color.c:1506
Warning messages.
Definition: color.h:79
Index: flags field (takes a pattern)
Definition: color.h:83
A regular expression and a color to highlight a line.
Definition: color.h:99
$spool_file (Spool mailbox)
Definition: color.h:71
static void color_line_list_clear(struct ColorLineList *list)
Clear a list of colours.
Definition: color.c:350
#define MUTT_TOKEN_NO_FLAGS
No flags are set.
Definition: mutt.h:66
static struct @2 Colors
Wrapper for all the colours.
int quotes_used
Number of colours for quoted email text.
Definition: color.c:90
int mutt_map_get_value(const char *name, const struct Mapping *map)
Lookup the constant for a string.
Definition: mapping.c:85
static void color_list_free(struct ColorList **ptr)
Free the list of curses colours.
Definition: color.c:260
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:156