NeoMutt  2022-04-29-178-g3b62e6
Teaching an old dog new tricks
DOXYGEN
regex.c
Go to the documentation of this file.
1
30#include "config.h"
31#include <stddef.h>
32#include <stdbool.h>
33#include <stdint.h>
34#include "mutt/lib.h"
35#include "config/lib.h"
36#include "core/lib.h"
37#include "index/lib.h"
38#include "pattern/lib.h"
39#include "attr.h"
40#include "color.h"
41#include "command2.h"
42#include "curses2.h"
43#include "debug.h"
44#include "notify2.h"
45#include "regex4.h"
46
47// clang-format off
48struct RegexColorList AttachList;
49struct RegexColorList BodyList;
50struct RegexColorList HeaderList;
51struct RegexColorList IndexAuthorList;
52struct RegexColorList IndexFlagsList;
53struct RegexColorList IndexList;
54struct RegexColorList IndexSubjectList;
55struct RegexColorList IndexTagList;
56struct RegexColorList StatusList;
57// clang-format on
58
63{
64 color_debug(LL_DEBUG5, "init AttachList, BodyList, etc\n");
74}
75
80{
81 color_debug(LL_DEBUG5, "clean up regex\n");
91}
92
99void regex_color_clear(struct RegexColor *rcol)
100{
101 if (!rcol)
102 return;
103
104 rcol->match = 0;
105 rcol->stop_matching = false;
106
108 FREE(&rcol->pattern);
109 regfree(&rcol->regex);
111}
112
118void regex_color_free(struct RegexColorList *list, struct RegexColor **ptr)
119{
120 if (!ptr || !*ptr)
121 return;
122
123 struct RegexColor *rcol = *ptr;
124 regex_color_clear(rcol);
125
126 FREE(ptr);
127}
128
134{
135 struct RegexColor *rcol = mutt_mem_calloc(1, sizeof(*rcol));
136
137 return rcol;
138}
139
148void regex_color_list_clear(struct RegexColorList *rcl)
149{
150 if (!rcl)
151 return;
152
153 struct RegexColor *np = NULL, *tmp = NULL;
154 STAILQ_FOREACH_SAFE(np, rcl, entries, tmp)
155 {
156 STAILQ_REMOVE(rcl, np, RegexColor, entries);
157 regex_color_free(rcl, &np);
158 }
159}
160
166struct RegexColorList *regex_colors_get_list(enum ColorId cid)
167{
168 switch (cid)
169 {
171 return &AttachList;
172 case MT_COLOR_BODY:
173 return &BodyList;
174 case MT_COLOR_HEADER:
175 return &HeaderList;
176 case MT_COLOR_INDEX:
177 return &IndexList;
179 return &IndexAuthorList;
181 return &IndexFlagsList;
183 return &IndexSubjectList;
185 return &IndexTagList;
186 case MT_COLOR_STATUS:
187 return &StatusList;
188 default:
189 return NULL;
190 }
191}
192
209static enum CommandResult add_pattern(struct RegexColorList *rcl, const char *s,
210 bool sensitive, uint32_t fg, uint32_t bg, int attrs,
211 struct Buffer *err, bool is_index, int match)
212{
213 struct RegexColor *rcol = NULL;
214
215 STAILQ_FOREACH(rcol, rcl, entries)
216 {
217 if ((sensitive && mutt_str_equal(s, rcol->pattern)) ||
218 (!sensitive && mutt_istr_equal(s, rcol->pattern)))
219 {
220 break;
221 }
222 }
223
224 if (rcol) // found a matching regex
225 {
226 struct AttrColor *ac = &rcol->attr_color;
227 struct CursesColor *cc = ac->curses_color;
228
229 // different colours
230 if (!cc || (cc && ((cc->fg != fg) || (cc->bg != bg))))
231 {
232 cc = curses_color_new(fg, bg);
233 if (cc)
234 {
236 cc->fg = fg;
237 cc->bg = bg;
238 }
239 ac->curses_color = cc;
240 }
241 ac->attrs = attrs;
242 }
243 else
244 {
245 rcol = regex_color_new();
246 if (is_index)
247 {
248 struct Buffer *buf = mutt_buffer_pool_get();
249 mutt_buffer_strcpy(buf, s);
250 const char *const c_simple_search = cs_subset_string(NeoMutt->sub, "simple_search");
251 mutt_check_simple(buf, NONULL(c_simple_search));
252 struct Mailbox *m_cur = get_current_mailbox();
253 struct Menu *menu = get_current_menu();
254 rcol->color_pattern = mutt_pattern_comp(m_cur, menu, buf->data, MUTT_PC_FULL_MSG, err);
256 if (!rcol->color_pattern)
257 {
258 regex_color_free(rcl, &rcol);
259 return MUTT_CMD_ERROR;
260 }
261 }
262 else
263 {
264 uint16_t flags = 0;
265 if (sensitive)
266 flags = mutt_mb_is_lower(s) ? REG_ICASE : 0;
267 else
268 flags = REG_ICASE;
269
270 const int r = REG_COMP(&rcol->regex, s, flags);
271 if (r != 0)
272 {
273 regerror(r, &rcol->regex, err->data, err->dsize);
274 regex_color_free(rcl, &rcol);
275 return MUTT_CMD_ERROR;
276 }
277 }
278 rcol->pattern = mutt_str_dup(s);
279 rcol->match = match;
280 struct CursesColor *cc = curses_color_new(fg, bg);
281 struct AttrColor *ac = &rcol->attr_color;
282 ac->curses_color = cc;
283 ac->attrs = attrs;
284 STAILQ_INSERT_TAIL(rcl, rcol, entries);
285 }
286
287 if (is_index)
288 {
289 /* force re-caching of index colors */
290 struct EventColor ev_c = { MT_COLOR_INDEX, NULL };
292 }
293
294 return MUTT_CMD_SUCCESS;
295}
296
310bool regex_colors_parse_color_list(enum ColorId cid, const char *pat, uint32_t fg,
311 uint32_t bg, int attrs, int *rc, struct Buffer *err)
312
313{
314 if (cid == MT_COLOR_STATUS)
315 return false;
316
317 struct RegexColorList *rcl = regex_colors_get_list(cid);
318 if (!rcl)
319 return false;
320
321 bool sensitive = false;
322 bool is_index = false;
323 switch (cid)
324 {
326 case MT_COLOR_BODY:
327 sensitive = true;
328 is_index = false;
329 break;
330 case MT_COLOR_HEADER:
331 sensitive = false;
332 is_index = false;
333 break;
334 case MT_COLOR_INDEX:
339 sensitive = true;
340 is_index = true;
341 break;
342 default:
343 return false;
344 }
345
346 *rc = add_pattern(rcl, pat, sensitive, fg, bg, attrs, err, is_index, 0);
347
348 struct Buffer *buf = mutt_buffer_pool_get();
349 get_colorid_name(cid, buf);
350 color_debug(LL_DEBUG5, "NT_COLOR_SET: %s\n", buf->data);
352
353 if (!is_index) // else it will be logged in add_pattern()
354 {
355 struct EventColor ev_c = { cid, NULL };
357 }
358
360 return true;
361}
362
374int regex_colors_parse_status_list(enum ColorId cid, const char *pat, uint32_t fg,
375 uint32_t bg, int attrs, int match, struct Buffer *err)
376{
377 if (cid != MT_COLOR_STATUS)
378 return MUTT_CMD_ERROR;
379
380 int rc = add_pattern(&StatusList, pat, true, fg, bg, attrs, err, false, match);
381 if (rc != MUTT_CMD_SUCCESS)
382 return rc;
383
384 struct Buffer *buf = mutt_buffer_pool_get();
385 get_colorid_name(cid, buf);
386 color_debug(LL_DEBUG5, "NT_COLOR_SET: %s\n", buf->data);
388
389 struct EventColor ev_c = { cid, NULL };
391
393 return rc;
394}
395
403bool regex_colors_parse_uncolor(enum ColorId cid, const char *pat, bool uncolor)
404{
405 struct RegexColorList *cl = regex_colors_get_list(cid);
406 if (!cl)
407 return false;
408
409 if (!pat) // Reset all patterns
410 {
411 if (STAILQ_EMPTY(cl))
412 return true;
413
414 mutt_debug(LL_NOTIFY, "NT_COLOR_RESET: [ALL]\n");
415 struct EventColor ev_c = { cid, NULL };
417
419 return true;
420 }
421
422 bool rc = false;
423 struct RegexColor *np = NULL, *prev = NULL;
424 prev = NULL;
425 STAILQ_FOREACH(np, cl, entries)
426 {
427 if (mutt_str_equal(pat, np->pattern))
428 {
429 rc = true;
430
431 mutt_debug(LL_DEBUG1, "Freeing pattern \"%s\" from XXX\n", pat);
432 if (prev)
433 STAILQ_REMOVE_AFTER(cl, prev, entries);
434 else
435 STAILQ_REMOVE_HEAD(cl, entries);
436
437 mutt_debug(LL_NOTIFY, "NT_COLOR_RESET: XXX\n");
438 struct EventColor ev_c = { cid, &np->attr_color };
440
441 regex_color_free(cl, &np);
442 break;
443 }
444 prev = np;
445 }
446
447 return rc;
448}
void attr_color_clear(struct AttrColor *ac)
Free the contents of an AttrColor.
Definition: attr.c:44
Colour and attributes.
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:310
void get_colorid_name(unsigned int cid, struct Buffer *buf)
Get the name of a color id.
Definition: command.c:329
struct Notify * ColorsNotify
Notifications: ColorId, EventColor.
Definition: notify.c:34
struct RegexColorList IndexFlagsList
List of colours applied to the flags in the index.
Definition: regex.c:52
struct RegexColorList IndexAuthorList
List of colours applied to the author in the index.
Definition: regex.c:51
struct RegexColorList IndexSubjectList
List of colours applied to the subject in the index.
Definition: regex.c:54
struct RegexColorList * regex_colors_get_list(enum ColorId cid)
Return the RegexColorList for a colour id.
Definition: regex.c:166
void regex_colors_clear(void)
Clear the Regex colours.
Definition: regex.c:79
struct RegexColorList StatusList
List of colours applied to the status bar.
Definition: regex.c:56
void regex_colors_init(void)
Initialise the Regex colours.
Definition: regex.c:62
struct RegexColorList IndexList
List of default colours applied to the index.
Definition: regex.c:53
void regex_color_free(struct RegexColorList *list, struct RegexColor **ptr)
Free a Regex colour.
Definition: regex.c:118
struct RegexColorList IndexTagList
List of colours applied to tags in the index.
Definition: regex.c:55
struct RegexColorList BodyList
List of colours applied to the email body.
Definition: regex.c:49
bool regex_colors_parse_uncolor(enum ColorId cid, const char *pat, bool uncolor)
Parse a Regex 'uncolor' command.
Definition: regex.c:403
static enum CommandResult add_pattern(struct RegexColorList *rcl, const char *s, bool sensitive, uint32_t fg, uint32_t bg, int attrs, struct Buffer *err, bool is_index, int match)
Associate a colour to a pattern.
Definition: regex.c:209
struct RegexColorList HeaderList
List of colours applied to the email headers.
Definition: regex.c:50
bool regex_colors_parse_color_list(enum ColorId cid, const char *pat, uint32_t fg, uint32_t bg, int attrs, int *rc, struct Buffer *err)
Parse a Regex 'color' command.
Definition: regex.c:310
struct RegexColorList AttachList
List of colours applied to the attachment headers.
Definition: regex.c:48
struct RegexColor * regex_color_new(void)
Create a new RegexColor.
Definition: regex.c:133
int regex_colors_parse_status_list(enum ColorId cid, const char *pat, uint32_t fg, uint32_t bg, int attrs, int match, struct Buffer *err)
Parse a Regex 'color status' command.
Definition: regex.c:374
void regex_color_list_clear(struct RegexColorList *rcl)
Free the contents of a RegexColorList.
Definition: regex.c:148
void regex_color_clear(struct RegexColor *rcol)
Free the contents of a Regex colour.
Definition: regex.c:99
Color and attribute parsing.
ColorId
List of all colored objects.
Definition: color.h:35
@ MT_COLOR_INDEX_AUTHOR
Index: author field (takes a pattern)
Definition: color.h:78
@ MT_COLOR_HEADER
Message headers (takes a pattern)
Definition: color.h:48
@ MT_COLOR_STATUS
Status bar (takes a pattern)
Definition: color.h:71
@ MT_COLOR_INDEX_SUBJECT
Index: subject field (takes a pattern)
Definition: color.h:80
@ MT_COLOR_BODY
Pager: highlight body of message (takes a pattern)
Definition: color.h:39
@ MT_COLOR_INDEX_TAG
Index: tag field (g, takes a pattern)
Definition: color.h:81
@ MT_COLOR_ATTACH_HEADERS
MIME attachment test (takes a pattern)
Definition: color.h:38
@ MT_COLOR_INDEX
Index: default colour (takes a pattern)
Definition: color.h:77
@ MT_COLOR_INDEX_FLAGS
Index: flags field (takes a pattern)
Definition: color.h:79
Parse colour commands.
CommandResult
Error codes for command_t parse functions.
Definition: command.h:34
@ MUTT_CMD_SUCCESS
Success: Command worked.
Definition: command.h:37
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition: command.h:35
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:1160
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: compile.c:1038
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
Curses Colour.
struct CursesColor * curses_color_new(int fg, int bg)
Create a new CursesColor.
Definition: curses.c:148
void regex_colors_dump_all(void)
Dump all the Regex colours to the log.
Definition: debug.c:380
int color_debug(enum LogLevel level, const char *format,...)
Write to the log file.
Definition: debug.c:44
Colour Debugging.
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
GUI manage the main index (list of emails)
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition: index.c:624
struct Menu * get_current_menu(void)
Get the current Menu.
Definition: index.c:650
@ LL_DEBUG5
Log at debug level 5.
Definition: logging.h:44
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
@ LL_NOTIFY
Log of notifications.
Definition: logging.h:45
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
Definition: mbyte.c:355
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define FREE(x)
Definition: memory.h:43
Convenience wrapper for the library headers.
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:171
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:796
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:784
Colour notifications.
@ NT_COLOR_RESET
Color has been reset/removed.
Definition: notify2.h:42
@ NT_COLOR_SET
Color has been set.
Definition: notify2.h:41
@ NT_COLOR
Colour has changed, NotifyColor, EventColor.
Definition: notify_type.h:41
Match patterns to emails.
#define MUTT_PC_FULL_MSG
Enable body and header matching.
Definition: lib.h:62
void mutt_check_simple(struct Buffer *s, const char *simple)
Convert a simple search into a real request.
Definition: pattern.c:116
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define STAILQ_REMOVE_HEAD(head, field)
Definition: queue.h:422
#define STAILQ_REMOVE(head, elm, type, field)
Definition: queue.h:402
#define STAILQ_INIT(head)
Definition: queue.h:372
#define STAILQ_REMOVE_AFTER(head, elm, field)
Definition: queue.h:416
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define STAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:389
#define STAILQ_EMPTY(head)
Definition: queue.h:348
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:362
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:53
Regex Colour.
#define NONULL(x)
Definition: string2.h:37
A curses colour and its attributes.
Definition: attr.h:35
int attrs
Text attributes, e.g. A_BOLD.
Definition: attr.h:37
struct CursesColor * curses_color
Underlying Curses colour.
Definition: attr.h:36
String manipulation buffer.
Definition: buffer.h:34
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35
Colour in the ncurses palette.
Definition: curses2.h:38
uint32_t fg
Foreground colour.
Definition: curses2.h:41
uint32_t bg
Background colour.
Definition: curses2.h:42
An Event that happened to a Colour.
Definition: notify2.h:53
enum ColorId cid
Colour ID that has changed.
Definition: notify2.h:54
A mailbox.
Definition: mailbox.h:79
Definition: lib.h:69
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
A regular expression and a color to highlight a line.
Definition: regex4.h:37
regex_t regex
Compiled regex.
Definition: regex4.h:40
struct PatternList * color_pattern
Compiled pattern to speed up index color calculation.
Definition: regex4.h:42
struct AttrColor attr_color
Colour and attributes to apply.
Definition: regex4.h:38
char * pattern
Pattern to match.
Definition: regex4.h:39
bool stop_matching
Used by the pager for body patterns, to prevent the color from being retried once it fails.
Definition: regex4.h:44
int match
Substring to match, 0 for old behaviour.
Definition: regex4.h:41