NeoMutt  2025-01-09-37-ge46230
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
regex.c
Go to the documentation of this file.
1
31#include "config.h"
32#include <stdbool.h>
33#include <stddef.h>
34#include <stdint.h>
35#include "mutt/lib.h"
36#include "config/lib.h"
37#include "core/lib.h"
38#include "index/lib.h"
39#include "pattern/lib.h"
40#include "attr.h"
41#include "color.h"
42#include "command2.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 IndexCollapsedList;
53struct RegexColorList IndexDateList;
54struct RegexColorList IndexFlagsList;
55struct RegexColorList IndexLabelList;
56struct RegexColorList IndexList;
57struct RegexColorList IndexNumberList;
58struct RegexColorList IndexSizeList;
59struct RegexColorList IndexSubjectList;
60struct RegexColorList IndexTagList;
61struct RegexColorList IndexTagsList;
62struct RegexColorList StatusList;
63// clang-format on
64
69{
70 color_debug(LL_DEBUG5, "init AttachList, BodyList, etc\n");
86}
87
92{
93 color_debug(LL_DEBUG5, "reset regex\n");
109}
110
115{
117}
118
126{
127 if (!rcol)
128 return;
129
130 rcol->match = 0;
131 rcol->stop_matching = false;
132
134 FREE(&rcol->pattern);
135 regfree(&rcol->regex);
137}
138
144void regex_color_free(struct RegexColorList *list, struct RegexColor **ptr)
145{
146 if (!ptr || !*ptr)
147 return;
148
149 struct RegexColor *rcol = *ptr;
150 regex_color_clear(rcol);
151
152 FREE(ptr);
153}
154
160{
161 return MUTT_MEM_CALLOC(1, struct RegexColor);
162}
163
172void regex_color_list_clear(struct RegexColorList *rcl)
173{
174 if (!rcl)
175 return;
176
177 struct RegexColor *np = NULL, *tmp = NULL;
178 STAILQ_FOREACH_SAFE(np, rcl, entries, tmp)
179 {
180 STAILQ_REMOVE(rcl, np, RegexColor, entries);
181 regex_color_free(rcl, &np);
182 }
183}
184
190struct RegexColorList *regex_colors_get_list(enum ColorId cid)
191{
192 switch (cid)
193 {
195 return &AttachList;
196 case MT_COLOR_BODY:
197 return &BodyList;
198 case MT_COLOR_HEADER:
199 return &HeaderList;
200 case MT_COLOR_INDEX:
201 return &IndexList;
203 return &IndexAuthorList;
205 return &IndexCollapsedList;
207 return &IndexDateList;
209 return &IndexFlagsList;
211 return &IndexLabelList;
213 return &IndexNumberList;
215 return &IndexSizeList;
217 return &IndexSubjectList;
219 return &IndexTagList;
221 return &IndexTagsList;
222 case MT_COLOR_STATUS:
223 return &StatusList;
224 default:
225 return NULL;
226 }
227}
228
242static enum CommandResult add_pattern(struct RegexColorList *rcl, const char *s,
243 struct AttrColor *ac_val,
244 struct Buffer *err, bool is_index, int match)
245{
246 struct RegexColor *rcol = NULL;
247
248 STAILQ_FOREACH(rcol, rcl, entries)
249 {
250 if (mutt_str_equal(s, rcol->pattern))
251 break;
252 }
253
254 if (rcol) // found a matching regex
255 {
256 struct AttrColor *ac = &rcol->attr_color;
257 attr_color_overwrite(ac, ac_val);
258 }
259 else
260 {
261 rcol = regex_color_new();
262 if (is_index)
263 {
264 struct Buffer *buf = buf_pool_get();
265 buf_strcpy(buf, s);
266 const char *const c_simple_search = cs_subset_string(NeoMutt->sub, "simple_search");
267 mutt_check_simple(buf, NONULL(c_simple_search));
268 struct MailboxView *mv_cur = get_current_mailbox_view();
269 struct Menu *menu = get_current_menu();
270 rcol->color_pattern = mutt_pattern_comp(mv_cur, menu, buf->data, MUTT_PC_FULL_MSG, err);
271 buf_pool_release(&buf);
272 if (!rcol->color_pattern)
273 {
274 regex_color_free(rcl, &rcol);
275 return MUTT_CMD_ERROR;
276 }
277 }
278 else
279 {
280 // Smart case matching
281 uint16_t flags = mutt_mb_is_lower(s) ? REG_ICASE : 0;
282
283 const int r = REG_COMP(&rcol->regex, s, flags);
284 if (r != 0)
285 {
286 regerror(r, &rcol->regex, err->data, err->dsize);
287 regex_color_free(rcl, &rcol);
288 return MUTT_CMD_ERROR;
289 }
290 }
291 rcol->pattern = mutt_str_dup(s);
292 rcol->match = match;
293
294 struct AttrColor *ac = &rcol->attr_color;
295
296 attr_color_overwrite(ac, ac_val);
297
298 STAILQ_INSERT_TAIL(rcl, rcol, entries);
299 }
300
301 if (is_index)
302 {
303 /* force re-caching of index colors */
304 struct EventColor ev_c = { MT_COLOR_INDEX, NULL };
306 }
307
308 return MUTT_CMD_SUCCESS;
309}
310
322bool regex_colors_parse_color_list(enum ColorId cid, const char *pat,
323 struct AttrColor *ac, int *rc, struct Buffer *err)
324
325{
326 if (cid == MT_COLOR_STATUS)
327 return false;
328
329 struct RegexColorList *rcl = regex_colors_get_list(cid);
330 if (!rcl)
331 return false;
332
333 bool is_index = false;
334 switch (cid)
335 {
337 case MT_COLOR_BODY:
338 break;
339 case MT_COLOR_HEADER:
340 break;
341 case MT_COLOR_INDEX:
352 is_index = true;
353 break;
354 default:
355 return false;
356 }
357
358 *rc = add_pattern(rcl, pat, ac, err, is_index, 0);
359
360 struct Buffer *buf = buf_pool_get();
361 get_colorid_name(cid, buf);
362 color_debug(LL_DEBUG5, "NT_COLOR_SET: %s\n", buf->data);
363 buf_pool_release(&buf);
364
365 if (!is_index) // else it will be logged in add_pattern()
366 {
367 struct EventColor ev_c = { cid, NULL };
369 }
370
371 return true;
372}
373
384 struct AttrColor *ac, int match, struct Buffer *err)
385{
386 if (cid != MT_COLOR_STATUS)
387 return MUTT_CMD_ERROR;
388
389 int rc = add_pattern(&StatusList, pat, ac, err, false, match);
390 if (rc != MUTT_CMD_SUCCESS)
391 return rc;
392
393 struct Buffer *buf = buf_pool_get();
394 get_colorid_name(cid, buf);
395 color_debug(LL_DEBUG5, "NT_COLOR_SET: %s\n", buf->data);
396 buf_pool_release(&buf);
397
398 struct EventColor ev_c = { cid, NULL };
400
401 return rc;
402}
403
411bool regex_colors_parse_uncolor(enum ColorId cid, const char *pat, bool uncolor)
412{
413 struct RegexColorList *cl = regex_colors_get_list(cid);
414 if (!cl)
415 return false;
416
417 if (!pat) // Reset all patterns
418 {
419 if (STAILQ_EMPTY(cl))
420 return true;
421
422 mutt_debug(LL_NOTIFY, "NT_COLOR_RESET: [ALL]\n");
423 struct EventColor ev_c = { cid, NULL };
425
427 return true;
428 }
429
430 bool rc = false;
431 struct RegexColor *np = NULL, *prev = NULL;
432 prev = NULL;
433 STAILQ_FOREACH(np, cl, entries)
434 {
435 if (mutt_str_equal(pat, np->pattern))
436 {
437 rc = true;
438
439 color_debug(LL_DEBUG1, "Freeing pattern \"%s\" from XXX\n", pat);
440 if (prev)
441 STAILQ_REMOVE_AFTER(cl, prev, entries);
442 else
443 STAILQ_REMOVE_HEAD(cl, entries);
444
445 mutt_debug(LL_NOTIFY, "NT_COLOR_RESET: XXX\n");
446 struct EventColor ev_c = { cid, &np->attr_color };
448
449 regex_color_free(cl, &np);
450 break;
451 }
452 prev = np;
453 }
454
455 return rc;
456}
void attr_color_overwrite(struct AttrColor *ac_old, struct AttrColor *ac_new)
Update an AttrColor in-place.
Definition: attr.c:395
void attr_color_clear(struct AttrColor *ac)
Free the contents of an AttrColor.
Definition: attr.c:48
Colour and attributes.
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
void get_colorid_name(unsigned int cid, struct Buffer *buf)
Get the name of a Colour ID.
Definition: command.c:128
struct Notify * ColorsNotify
Notifications: ColorId, EventColor.
Definition: notify.c:36
struct RegexColorList IndexCollapsedList
List of colours applied to a collapsed thread in the index.
Definition: regex.c:52
struct RegexColorList IndexFlagsList
List of colours applied to the flags in the index.
Definition: regex.c:54
static enum CommandResult add_pattern(struct RegexColorList *rcl, const char *s, struct AttrColor *ac_val, struct Buffer *err, bool is_index, int match)
Associate a colour to a pattern.
Definition: regex.c:242
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:59
struct RegexColorList IndexLabelList
List of colours applied to the label in the index.
Definition: regex.c:55
struct RegexColorList * regex_colors_get_list(enum ColorId cid)
Return the RegexColorList for a Colour ID.
Definition: regex.c:190
int regex_colors_parse_status_list(enum ColorId cid, const char *pat, struct AttrColor *ac, int match, struct Buffer *err)
Parse a Regex 'color status' command.
Definition: regex.c:383
bool regex_colors_parse_color_list(enum ColorId cid, const char *pat, struct AttrColor *ac, int *rc, struct Buffer *err)
Parse a Regex 'color' command.
Definition: regex.c:322
struct RegexColorList StatusList
List of colours applied to the status bar.
Definition: regex.c:62
void regex_colors_init(void)
Initialise the Regex colours.
Definition: regex.c:68
struct RegexColorList IndexList
List of default colours applied to the index.
Definition: regex.c:56
void regex_color_free(struct RegexColorList *list, struct RegexColor **ptr)
Free a Regex colour.
Definition: regex.c:144
struct RegexColorList IndexTagList
List of colours applied to tags in the index.
Definition: regex.c:60
struct RegexColorList BodyList
List of colours applied to the email body.
Definition: regex.c:49
struct RegexColorList IndexTagsList
List of colours applied to the tags in the index.
Definition: regex.c:61
bool regex_colors_parse_uncolor(enum ColorId cid, const char *pat, bool uncolor)
Parse a Regex 'uncolor' command.
Definition: regex.c:411
void regex_colors_reset(void)
Reset the Regex colours.
Definition: regex.c:91
struct RegexColorList HeaderList
List of colours applied to the email headers.
Definition: regex.c:50
struct RegexColorList AttachList
List of colours applied to the attachment headers.
Definition: regex.c:48
void regex_colors_cleanup(void)
Cleanup the Regex colours.
Definition: regex.c:114
struct RegexColorList IndexDateList
List of colours applied to the date in the index.
Definition: regex.c:53
struct RegexColor * regex_color_new(void)
Create a new RegexColor.
Definition: regex.c:159
struct RegexColorList IndexNumberList
List of colours applied to the message number in the index.
Definition: regex.c:57
void regex_color_list_clear(struct RegexColorList *rcl)
Free the contents of a RegexColorList.
Definition: regex.c:172
struct RegexColorList IndexSizeList
List of colours applied to the size in the index.
Definition: regex.c:58
void regex_color_clear(struct RegexColor *rcol)
Free the contents of a Regex colour.
Definition: regex.c:125
Color and attribute parsing.
ColorId
List of all coloured objects.
Definition: color.h:36
@ MT_COLOR_INDEX_AUTHOR
Index: author field.
Definition: color.h:89
@ MT_COLOR_HEADER
Message headers (takes a pattern)
Definition: color.h:49
@ MT_COLOR_STATUS
Status bar (takes a pattern)
Definition: color.h:80
@ MT_COLOR_INDEX_SIZE
Index: size field.
Definition: color.h:95
@ MT_COLOR_INDEX_TAGS
Index: tags field (g, J)
Definition: color.h:98
@ MT_COLOR_INDEX_SUBJECT
Index: subject field.
Definition: color.h:96
@ MT_COLOR_BODY
Pager: highlight body of message (takes a pattern)
Definition: color.h:40
@ MT_COLOR_INDEX_DATE
Index: date field.
Definition: color.h:91
@ MT_COLOR_INDEX_TAG
Index: tag field (G)
Definition: color.h:97
@ MT_COLOR_ATTACH_HEADERS
MIME attachment test (takes a pattern)
Definition: color.h:39
@ MT_COLOR_INDEX_LABEL
Index: label field.
Definition: color.h:93
@ MT_COLOR_INDEX
Index: default colour.
Definition: color.h:88
@ MT_COLOR_INDEX_NUMBER
Index: index number.
Definition: color.h:94
@ MT_COLOR_INDEX_FLAGS
Index: flags field.
Definition: color.h:92
@ MT_COLOR_INDEX_COLLAPSED
Index: number of messages in collapsed thread.
Definition: color.h:90
Parse colour commands.
CommandResult
Error codes for command_t parse functions.
Definition: command.h:36
@ MUTT_CMD_SUCCESS
Success: Command worked.
Definition: command.h:39
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition: command.h:37
struct PatternList * mutt_pattern_comp(struct MailboxView *mv, struct Menu *menu, const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: compile.c:906
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: compile.c:778
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:291
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
Colour Debugging.
static int color_debug(enum LogLevel level, const char *format,...)
Definition: debug.h:52
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
GUI manage the main index (list of emails)
struct MailboxView * get_current_mailbox_view(void)
Get the current Mailbox view.
Definition: index.c:683
struct Menu * get_current_menu(void)
Get the current Menu.
Definition: index.c:731
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
@ LL_NOTIFY
Log of notifications.
Definition: logging2.h:48
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
Definition: mbyte.c:354
#define FREE(x)
Definition: memory.h:55
#define MUTT_MEM_CALLOC(n, type)
Definition: memory.h:40
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:173
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
Colour notifications.
@ NT_COLOR_RESET
Color has been reset/removed.
Definition: notify2.h:44
@ NT_COLOR_SET
Color has been set.
Definition: notify2.h:43
@ 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:69
void mutt_check_simple(struct Buffer *s, const char *simple)
Convert a simple search into a real request.
Definition: pattern.c:112
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
#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:50
Regex Colour.
#define NONULL(x)
Definition: string2.h:37
A curses colour and its attributes.
Definition: attr.h:66
String manipulation buffer.
Definition: buffer.h:36
size_t dsize
Length of data.
Definition: buffer.h:39
char * data
Pointer to data.
Definition: buffer.h:37
An Event that happened to a Colour.
Definition: notify2.h:55
enum ColorId cid
Colour ID that has changed.
Definition: notify2.h:56
View of a Mailbox.
Definition: mview.h:40
Definition: lib.h:79
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
A regular expression and a color to highlight a line.
Definition: regex4.h:36
regex_t regex
Compiled regex.
Definition: regex4.h:39
struct PatternList * color_pattern
Compiled pattern to speed up index color calculation.
Definition: regex4.h:41
struct AttrColor attr_color
Colour and attributes to apply.
Definition: regex4.h:37
char * pattern
Pattern to match.
Definition: regex4.h:38
bool stop_matching
Used by the pager for body patterns, to prevent the color from being retried once it fails.
Definition: regex4.h:43
int match
Substring to match, 0 for old behaviour.
Definition: regex4.h:40