From: Alexey Gladkov Date: Mon, 22 Jul 2019 20:03:52 +0000 (+0200) Subject: Add color groups for header and body X-Git-Url: http://git.altlinux.org/people/glebfm/packages/neomutt.git?p=neomutt.git;a=commitdiff_plain;h=f91e40fd6940d847c557083c33a01440e399fc3d Add color groups for header and body Co-authored-by: Gleb Fotengauer-Malinovskiy Signed-off-by: Alexey Gladkov Signed-off-by: Gleb Fotengauer-Malinovskiy --- diff --git a/gui/color.c b/gui/color.c index c21570f..6bdf196 100644 --- a/gui/color.c +++ b/gui/color.c @@ -153,6 +153,13 @@ const struct Mapping ComposeFields[] = { }; // clang-format off +static const struct Mapping ColorGroupFields[] = +{ + { "start", MT_COLOR_GROUP_START }, + { "end", MT_COLOR_GROUP_END }, + { NULL, 0 }, +}; + /** * defs_free - Free the simple colour definitions * @param c Colours @@ -364,6 +371,8 @@ void mutt_colors_free(struct Colors **ptr) defs_free(c); quotes_free(c); notify_free(&c->notify); + mutt_free_color_group_stack(&c->group_header_stack); + mutt_free_color_group_stack(&c->group_body_stack); FREE(ptr); } @@ -388,6 +397,8 @@ struct Colors *mutt_colors_new(void) STAILQ_INIT(&c->index_subject_list); STAILQ_INIT(&c->index_tag_list); STAILQ_INIT(&c->status_list); + c->group_header_stack = NULL; + c->group_body_stack = NULL; #ifdef HAVE_COLOR start_color(); @@ -953,7 +964,7 @@ enum CommandResult mutt_parse_unmono(struct Buffer *buf, struct Buffer *s, */ static enum CommandResult add_pattern(struct Colors *c, struct ColorLineList *top, const char *s, bool sensitive, uint32_t fg, uint32_t bg, int attr, - struct Buffer *err, bool is_index, int match) + struct Buffer *err, bool is_index, int match, struct ColorGroupStack *cgs) { struct ColorLine *tmp = NULL; @@ -1043,6 +1054,8 @@ static enum CommandResult add_pattern(struct Colors *c, struct ColorLineList *to } } + if (cgs) + tmp->group = cgs->group; return MUTT_CMD_SUCCESS; } @@ -1240,32 +1253,36 @@ static enum CommandResult parse_color(struct Colors *c, struct Buffer *buf, stru #endif if (object == MT_COLOR_ATTACH_HEADERS) - rc = add_pattern(c, &c->attach_list, buf->data, true, fg, bg, attr, err, false, match); + rc = add_pattern(c, &c->attach_list, buf->data, true, fg, bg, attr, err, false, match, NULL); else if (object == MT_COLOR_BODY) - rc = add_pattern(c, &c->body_list, buf->data, true, fg, bg, attr, err, false, match); + rc = add_pattern(c, &c->body_list, buf->data, true, fg, bg, attr, + err, false, match, c->group_body_stack); else if (object == MT_COLOR_HEADER) - rc = add_pattern(c, &c->hdr_list, buf->data, false, fg, bg, attr, err, false, match); + { + rc = add_pattern(c, &c->hdr_list, buf->data, false, fg, bg, attr, + err, false, match, c->group_header_stack); + } else if (object == MT_COLOR_INDEX) { - rc = add_pattern(c, &c->index_list, buf->data, true, fg, bg, attr, err, true, match); + rc = add_pattern(c, &c->index_list, buf->data, true, fg, bg, attr, err, true, match, NULL); } else if (object == MT_COLOR_INDEX_AUTHOR) { rc = add_pattern(c, &c->index_author_list, buf->data, true, fg, bg, attr, - err, true, match); + err, true, match, NULL); } else if (object == MT_COLOR_INDEX_FLAGS) { - rc = add_pattern(c, &c->index_flags_list, buf->data, true, fg, bg, attr, err, true, match); + rc = add_pattern(c, &c->index_flags_list, buf->data, true, fg, bg, attr, err, true, match, NULL); } else if (object == MT_COLOR_INDEX_SUBJECT) { rc = add_pattern(c, &c->index_subject_list, buf->data, true, fg, bg, attr, - err, true, match); + err, true, match, NULL); } else if (object == MT_COLOR_INDEX_TAG) { - rc = add_pattern(c, &c->index_tag_list, buf->data, true, fg, bg, attr, err, true, match); + rc = add_pattern(c, &c->index_tag_list, buf->data, true, fg, bg, attr, err, true, match, NULL); } else if (object == MT_COLOR_QUOTED) { @@ -1322,7 +1339,7 @@ static enum CommandResult parse_color(struct Colors *c, struct Buffer *buf, stru return MUTT_CMD_WARNING; } - rc = add_pattern(c, &c->status_list, buf->data, true, fg, bg, attr, err, false, match); + rc = add_pattern(c, &c->status_list, buf->data, true, fg, bg, attr, err, false, match, NULL); } else // Remaining simple colours { @@ -1373,3 +1390,128 @@ enum CommandResult mutt_parse_mono(struct Buffer *buf, struct Buffer *s, return parse_color(Colors, buf, s, err, parse_attr_spec, dry_run, false); } + +#ifdef HAVE_COLOR +/* usage: color-group { header | body } { start | end } + */ +enum CommandResult mutt_parse_color_group(struct Buffer *buf, struct Buffer *s, + intptr_t data, struct Buffer *err) +{ + int target = 0; + int object = 0; + int r = 0; + regex_t *rx; + struct ColorGroup *grp; + struct ColorGroupStack **stack, *newStack; + + if(!MoreArgs(s)) + { + mutt_str_copy(err->data, _("(0) Missing arguments."), err->dsize); + return MUTT_CMD_ERROR; + } + + mutt_extract_token(buf, s, 0); + + if ((target = mutt_map_get_value(buf->data, Fields)) == -1) + { + snprintf(err->data, err->dsize, _("%s: no such object"), buf->data); + return MUTT_CMD_ERROR; + } + + if (target == MT_COLOR_HEADER) + { + stack = &Colors->group_header_stack; + } + else if (target == MT_COLOR_BODY) + { + stack = &Colors->group_body_stack; + } + else + { + mutt_str_copy(err->data, _("Target must be 'header' or 'body'."), err->dsize); + return MUTT_CMD_ERROR; + } + + mutt_extract_token(buf, s, 0); + + if ((object = mutt_map_get_value(buf->data, ColorGroupFields)) == -1) + { + snprintf(err->data, err->dsize, _("%s: no such object"), buf->data); + return MUTT_CMD_ERROR; + } + + if (!MoreArgs(s)) + { + mutt_str_copy(err->data, _("(1) Missing arguments."), err->dsize); + return MUTT_CMD_ERROR; + } + + mutt_extract_token(buf, s, 0); + + if (MoreArgs(s)) + { + mutt_str_copy(err->data, _("too many arguments"), err->dsize); + return MUTT_CMD_ERROR; + } + + if (OptNoCurses || !has_colors()) + return MUTT_CMD_SUCCESS; + + rx = mutt_mem_calloc(1, sizeof(regex_t)); + + int flags = mutt_mb_is_lower(buf->data) ? REG_ICASE : 0; + if ((r = REG_COMP(rx, buf->data, flags)) != 0) + { + regerror(r, rx, err->data, err->dsize); + FREE(rx); + return MUTT_CMD_ERROR; + } + + if (object == MT_COLOR_GROUP_END) + { + if (!*stack) + { + mutt_str_copy(err->data, "Unexpected group ending.", err->dsize); + regfree(rx); + FREE(rx); + return MUTT_CMD_ERROR; + } + + (*stack)->group->pattern_end = mutt_str_dup(buf->data); + (*stack)->group->rx_end = rx; + + newStack = (*stack)->next; + FREE(stack); + *stack = newStack; + + return MUTT_CMD_SUCCESS; + } + + grp = mutt_mem_calloc(1, sizeof(struct ColorGroup)); + grp->pattern_start = mutt_str_dup(buf->data); + grp->rx_start = rx; + + newStack = mutt_mem_calloc(1, sizeof(struct ColorGroupStack)); + newStack->group = grp; + newStack->next = *stack; + + *stack = newStack; + + return MUTT_CMD_SUCCESS; +} +#endif + +void mutt_free_color_group_stack(struct ColorGroupStack **top) +{ + struct ColorGroupStack *t, *e; + if (!top) + return; + t = *top; + while (t) + { + e = t->next; + FREE(&t); + t = e; + } + *top = NULL; +} diff --git a/gui/color.h b/gui/color.h index 8f02b32..0bb19b9 100644 --- a/gui/color.h +++ b/gui/color.h @@ -29,6 +29,29 @@ #include "mutt/lib.h" #include "mutt_commands.h" +enum ColorGroupPart +{ + MT_COLOR_GROUP_START, + MT_COLOR_GROUP_END, +}; + +struct ColorGroup +{ + char *pattern_start; + char *pattern_end; + regex_t *rx_start; + regex_t *rx_end; + struct ColorGroup *next; +}; + +struct ColorGroupStack +{ + struct ColorGroup *group; + struct ColorGroupStack *next; +}; + +void mutt_free_color_group_stack(struct ColorGroupStack **top); + /** * struct ColorLine - A regular expression and a color to highlight a line */ @@ -38,6 +61,7 @@ struct ColorLine int match; ///< Substring to match, 0 for old behaviour char *pattern; ///< Pattern to match struct PatternList *color_pattern; ///< Compiled pattern to speed up index color calculation + struct ColorGroup *group; uint32_t fg; ///< Foreground colour uint32_t bg; ///< Background colour int pair; ///< Colour pair index @@ -140,6 +164,9 @@ struct Colors struct ColorLineList index_tag_list; ///< List of colours applied to tags in the index struct ColorLineList status_list; ///< List of colours applied to the status bar + struct ColorGroupStack *group_header_stack; + struct ColorGroupStack *group_body_stack; + int *quotes; ///< Array of colours for quoted email text int quotes_used; ///< Number of colours for quoted email text @@ -182,6 +209,7 @@ void mutt_colors_free(struct Colors **ptr); enum CommandResult mutt_parse_color (struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err); enum CommandResult mutt_parse_mono (struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err); enum CommandResult mutt_parse_uncolor(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err); +enum CommandResult mutt_parse_color_group(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err); enum CommandResult mutt_parse_unmono (struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err); #endif /* MUTT_COLOR_H */ diff --git a/init.c b/init.c index 458b07a..8ec1c51 100644 --- a/init.c +++ b/init.c @@ -964,6 +964,7 @@ int mutt_init(struct ConfigSet *cs, bool skip_sys_rc, struct ListHead *commands) done: mutt_buffer_dealloc(&err); mutt_buffer_dealloc(&buf); + return rc; } diff --git a/mutt_commands.c b/mutt_commands.c index 94f9855..7f23063 100644 --- a/mutt_commands.c +++ b/mutt_commands.c @@ -59,6 +59,7 @@ static const struct Command mutt_commands[] = { { "charset-hook", mutt_parse_hook, MUTT_CHARSET_HOOK }, #ifdef HAVE_COLOR { "color", mutt_parse_color, 0 }, + { "color-group", mutt_parse_color_group, 0 }, #endif { "crypt-hook", mutt_parse_hook, MUTT_CRYPT_HOOK }, { "echo", parse_echo, 0 }, diff --git a/pager.c b/pager.c index a180873..258c88b 100644 --- a/pager.c +++ b/pager.c @@ -197,6 +197,8 @@ struct PagerRedrawData struct Line *line_info; FILE *fp; struct stat sb; + struct ColorGroupStack *group_header_stack; + struct ColorGroupStack *group_body_stack; }; /* hack to return to position when returning from index to same message */ @@ -1006,10 +1008,12 @@ int mutt_is_quote_line(char *line, regmatch_t *pmatch) */ static void resolve_types(char *buf, char *raw, struct Line *line_info, int n, int last, struct QClass **quote_list, int *q_level, - bool *force_redraw, bool q_classify) + bool *force_redraw, bool q_classify, + struct PagerRedrawData *rd) { struct ColorLine *color_line = NULL; struct ColorLineList *head = NULL; + struct ColorGroupStack **color_stack; regmatch_t pmatch[1]; bool found; bool null_rx; @@ -1129,9 +1133,15 @@ static void resolve_types(char *buf, char *raw, struct Line *line_info, int n, offset = 0; line_info[n].chunks = 0; if (line_info[n].type == MT_COLOR_HDRDEFAULT) + { head = &Colors->hdr_list; + color_stack = &rd->group_header_stack; + } else + { head = &Colors->body_list; + color_stack = &rd->group_body_stack; + } STAILQ_FOREACH(color_line, head, entries) { color_line->stop_matching = false; @@ -1145,6 +1155,34 @@ static void resolve_types(char *buf, char *raw, struct Line *line_info, int n, null_rx = false; STAILQ_FOREACH(color_line, head, entries) { + if (color_line->group) + { + short is_start_group = (!*color_stack || (*color_stack)->group != color_line->group); + + regex_t *rx = is_start_group + ? color_line->group->rx_start + : color_line->group->rx_end; + if (rx && regexec (rx, buf + offset, 1, pmatch, (offset ? REG_NOTBOL : 0)) == 0) + { + struct ColorGroupStack *newStack; + + if (is_start_group) + { + newStack = mutt_mem_calloc(1, sizeof(struct ColorGroupStack)); + newStack->group = color_line->group; + newStack->next = *color_stack; + } + else + { + newStack = (*color_stack)->next; + FREE(color_stack); + } + + *color_stack = newStack; + } + else if (is_start_group) + continue; + } if (!color_line->stop_matching && (regexec(&color_line->regex, buf + offset, 1, pmatch, ((offset != 0) ? REG_NOTBOL : 0)) == 0)) @@ -1676,7 +1714,7 @@ static int format_line(struct Line **line_info, int n, unsigned char *buf, * @retval 0 normal exit, line was not displayed * @retval >0 normal exit, line was displayed */ -static int display_line(FILE *fp, LOFF_T *last_pos, struct Line **line_info, +static int display_line(struct PagerRedrawData *rd, LOFF_T *last_pos, struct Line **line_info, int n, int *last, int *max, PagerFlags flags, struct QClass **quote_list, int *q_level, bool *force_redraw, regex_t *search_re, struct MuttWindow *win_pager) @@ -1720,7 +1758,7 @@ static int display_line(FILE *fp, LOFF_T *last_pos, struct Line **line_info, if (flags & MUTT_PAGER_LOGS) { /* determine the line class */ - if (fill_buffer(fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0) + if (fill_buffer(rd->fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0) { if (change_last) (*last)--; @@ -1744,7 +1782,7 @@ static int display_line(FILE *fp, LOFF_T *last_pos, struct Line **line_info, if (curr_line->type == -1) { /* determine the line class */ - if (fill_buffer(fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0) + if (fill_buffer(rd->fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0) { if (change_last) (*last)--; @@ -1752,7 +1790,7 @@ static int display_line(FILE *fp, LOFF_T *last_pos, struct Line **line_info, } resolve_types((char *) fmt, (char *) buf, *line_info, n, *last, - quote_list, q_level, force_redraw, flags & MUTT_SHOWCOLOR); + quote_list, q_level, force_redraw, flags & MUTT_SHOWCOLOR, rd); /* avoid race condition for continuation lines when scrolling up */ for (m = n + 1; m < *last && (*line_info)[m].offset && (*line_info)[m].continuation; m++) @@ -1775,7 +1813,7 @@ static int display_line(FILE *fp, LOFF_T *last_pos, struct Line **line_info, if ((flags & MUTT_SHOWCOLOR) && !curr_line->continuation && (curr_line->type == MT_COLOR_QUOTED) && !curr_line->quote) { - if (fill_buffer(fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0) + if (fill_buffer(rd->fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0) { if (change_last) (*last)--; @@ -1796,7 +1834,7 @@ static int display_line(FILE *fp, LOFF_T *last_pos, struct Line **line_info, if ((flags & MUTT_SEARCH) && !curr_line->continuation && (curr_line->search_cnt == -1)) { - if (fill_buffer(fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0) + if (fill_buffer(rd->fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0) { if (change_last) (*last)--; @@ -1842,7 +1880,7 @@ static int display_line(FILE *fp, LOFF_T *last_pos, struct Line **line_info, goto out; /* fake display */ } - b_read = fill_buffer(fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready); + b_read = fill_buffer(rd->fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready); if (b_read < 0) { if (change_last) @@ -2090,7 +2128,7 @@ static void pager_custom_redraw(struct Menu *pager_menu) } int i = -1; int j = -1; - while (display_line(rd->fp, &rd->last_pos, &rd->line_info, ++i, &rd->last_line, + while (display_line(rd, &rd->last_pos, &rd->line_info, ++i, &rd->last_line, &rd->max_line, rd->has_types | rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP), &rd->quote_list, &rd->q_level, &rd->force_redraw, &rd->search_re, rd->extra->win_pager) == 0) @@ -2117,7 +2155,7 @@ static void pager_custom_redraw(struct Menu *pager_menu) while ((rd->lines < rd->extra->win_pager->state.rows) && (rd->line_info[rd->curline].offset <= rd->sb.st_size - 1)) { - if (display_line(rd->fp, &rd->last_pos, &rd->line_info, rd->curline, + if (display_line(rd, &rd->last_pos, &rd->line_info, rd->curline, &rd->last_line, &rd->max_line, (rd->flags & MUTT_DISPLAYFLAGS) | rd->hide_quoted | rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP), @@ -2760,7 +2798,7 @@ int mutt_pager(const char *banner, const char *fname, PagerFlags flags, struct P rd.search_compiled = true; /* update the search pointers */ int line_num = 0; - while (display_line(rd.fp, &rd.last_pos, &rd.line_info, line_num, + while (display_line(&rd, &rd.last_pos, &rd.line_info, line_num, &rd.last_line, &rd.max_line, MUTT_SEARCH | (flags & MUTT_PAGER_NSKIP) | (flags & MUTT_PAGER_NOWRAP), &rd.quote_list, &rd.q_level, &rd.force_redraw, @@ -2878,7 +2916,7 @@ int mutt_pager(const char *banner, const char *fname, PagerFlags flags, struct P { while (((new_topline < rd.last_line) || (0 == (dretval = display_line( - rd.fp, &rd.last_pos, &rd.line_info, new_topline, &rd.last_line, + &rd, &rd.last_pos, &rd.line_info, new_topline, &rd.last_line, &rd.max_line, MUTT_TYPES | (flags & MUTT_PAGER_NOWRAP), &rd.quote_list, &rd.q_level, &rd.force_redraw, &rd.search_re, rd.extra->win_pager)))) && @@ -2892,7 +2930,7 @@ int mutt_pager(const char *banner, const char *fname, PagerFlags flags, struct P while ((((new_topline + C_SkipQuotedOffset) < rd.last_line) || (0 == (dretval = display_line( - rd.fp, &rd.last_pos, &rd.line_info, new_topline, &rd.last_line, + &rd, &rd.last_pos, &rd.line_info, new_topline, &rd.last_line, &rd.max_line, MUTT_TYPES | (flags & MUTT_PAGER_NOWRAP), &rd.quote_list, &rd.q_level, &rd.force_redraw, &rd.search_re, rd.extra->win_pager)))) && @@ -2909,7 +2947,7 @@ int mutt_pager(const char *banner, const char *fname, PagerFlags flags, struct P while ((((new_topline + C_SkipQuotedOffset) < rd.last_line) || (0 == (dretval = display_line( - rd.fp, &rd.last_pos, &rd.line_info, new_topline, &rd.last_line, + &rd, &rd.last_pos, &rd.line_info, new_topline, &rd.last_line, &rd.max_line, MUTT_TYPES | (flags & MUTT_PAGER_NOWRAP), &rd.quote_list, &rd.q_level, &rd.force_redraw, &rd.search_re, rd.extra->win_pager)))) && @@ -2931,7 +2969,7 @@ int mutt_pager(const char *banner, const char *fname, PagerFlags flags, struct P { int line_num = rd.curline; /* make sure the types are defined to the end of file */ - while (display_line(rd.fp, &rd.last_pos, &rd.line_info, line_num, &rd.last_line, + while (display_line(&rd, &rd.last_pos, &rd.line_info, line_num, &rd.last_line, &rd.max_line, rd.has_types | (flags & MUTT_PAGER_NOWRAP), &rd.quote_list, &rd.q_level, &rd.force_redraw, &rd.search_re, rd.extra->win_pager) == 0) @@ -3617,5 +3655,8 @@ int mutt_pager(const char *banner, const char *fname, PagerFlags flags, struct P window_set_visible(rd.extra->win_pager->parent, false); mutt_window_reflow(dialog_find(rd.extra->win_pager)); + mutt_free_color_group_stack(&rd.group_header_stack); + mutt_free_color_group_stack(&rd.group_body_stack); + return (rc != -1) ? rc : 0; }