• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

neomutt / neomutt / 21576993800

02 Feb 2026 01:15AM UTC coverage: 42.169% (+0.2%) from 42.019%
21576993800

push

github

flatcap
build: force all-docs before validation

11846 of 28092 relevant lines covered (42.17%)

447.19 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/pattern/dlg_pattern.c
1
/**
2
 * @file
3
 * Pattern Selection Dialog
4
 *
5
 * @authors
6
 * Copyright (C) 2019 Pietro Cerutti <gahr@gahr.ch>
7
 * Copyright (C) 2020-2024 Richard Russon <rich@flatcap.org>
8
 * Copyright (C) 2023-2024 Tóth János <gomba007@gmail.com>
9
 *
10
 * @copyright
11
 * This program is free software: you can redistribute it and/or modify it under
12
 * the terms of the GNU General Public License as published by the Free Software
13
 * Foundation, either version 2 of the License, or (at your option) any later
14
 * version.
15
 *
16
 * This program is distributed in the hope that it will be useful, but WITHOUT
17
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
19
 * details.
20
 *
21
 * You should have received a copy of the GNU General Public License along with
22
 * this program.  If not, see <http://www.gnu.org/licenses/>.
23
 */
24

25
/**
26
 * @page pattern_dlg_pattern Pattern Selection Dialog
27
 *
28
 * The Pattern Selection Dialog lets the user select a pattern.
29
 *
30
 * This is a @ref gui_simple
31
 *
32
 * ## Windows
33
 *
34
 * | Name                     | Type           | See Also      |
35
 * | :----------------------- | :------------- | :------------ |
36
 * | Pattern Selection Dialog | WT_DLG_PATTERN | dlg_pattern() |
37
 *
38
 * **Parent**
39
 * - @ref gui_dialog
40
 *
41
 * **Children**
42
 * - See: @ref gui_simple
43
 *
44
 * ## Data
45
 * - #Menu
46
 * - #Menu::mdata
47
 * - #PatternEntry
48
 *
49
 * The @ref gui_simple holds a Menu.  The Pattern Selection Dialog stores its
50
 * data (#PatternEntry) in Menu::mdata.
51
 *
52
 * ## Events
53
 *
54
 * Once constructed, it is controlled by the following events:
55
 *
56
 * | Event Type  | Handler                   |
57
 * | :---------- | :------------------------ |
58
 * | #NT_CONFIG  | pattern_config_observer() |
59
 * | #NT_WINDOW  | pattern_window_observer() |
60
 *
61
 * The Pattern Selection Dialog doesn't have any specific colours, so it
62
 * doesn't need to support #NT_COLOR.
63
 *
64
 * The Pattern Selection Dialog does not implement MuttWindow::recalc() or
65
 * MuttWindow::repaint().
66
 *
67
 * Some other events are handled by the @ref gui_simple.
68
 */
69

70
#include "config.h"
71
#include <stdbool.h>
72
#include <stddef.h>
73
#include "private.h"
74
#include "mutt/lib.h"
75
#include "config/lib.h"
76
#include "core/lib.h"
77
#include "gui/lib.h"
78
#include "lib.h"
79
#include "expando/lib.h"
80
#include "key/lib.h"
81
#include "menu/lib.h"
82
#include "expando.h"
83
#include "functions.h"
84
#include "mutt_logging.h"
85
#include "pattern_data.h"
86

87
/// Help Bar for the Pattern selection dialog
88
static const struct Mapping PatternHelp[] = {
89
  // clang-format off
90
  { N_("Exit"),   OP_EXIT },
91
  { N_("Select"), OP_GENERIC_SELECT_ENTRY },
92
  { N_("Help"),   OP_HELP },
93
  { NULL, 0 },
94
  // clang-format on
95
};
96

97
/**
98
 * pattern_make_entry - Create a Pattern for the Menu - Implements Menu::make_entry() - @ingroup menu_make_entry
99
 *
100
 * @sa $pattern_format
101
 */
102
static int pattern_make_entry(struct Menu *menu, int line, int max_cols, struct Buffer *buf)
×
103
{
104
  struct PatternData *pd = menu->mdata;
×
105

106
  struct PatternEntry *entry = ARRAY_GET(&pd->entries, line);
×
107

108
  const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
×
109
  if (c_arrow_cursor)
×
110
  {
111
    const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
×
112
    if (max_cols > 0)
×
113
      max_cols -= (mutt_strwidth(c_arrow_string) + 1);
×
114
  }
115

116
  const struct Expando *c_pattern_format = cs_subset_expando(NeoMutt->sub, "pattern_format");
×
117
  return expando_filter(c_pattern_format, PatternRenderCallbacks, entry,
×
118
                        MUTT_FORMAT_ARROWCURSOR, max_cols, NeoMutt->env, buf);
×
119
}
120

121
/**
122
 * create_pattern_entries - Create the Pattern Entries
123
 * @param pea Pattern Entry Array to fill
124
 */
125
static void create_pattern_entries(struct PatternEntryArray *pea)
×
126
{
127
  int num_entries = 0;
128
  while (Flags[num_entries].tag != 0)
×
129
    num_entries++;
×
130

131
  /* Add three more hard-coded entries for thread patterns */
132
  ARRAY_RESERVE(pea, num_entries + 3);
×
133

134
  struct Buffer *buf = buf_pool_get();
×
135

136
  struct PatternEntry entry = { 0 };
137
  for (int i = 0; Flags[i].tag != '\0'; i++)
×
138
  {
139
    entry.num = i + 1;
×
140

141
    buf_printf(buf, "%c%c", Flags[i].prefix, Flags[i].tag);
×
142
    entry.tag = buf_strdup(buf);
×
143

144
    switch (Flags[i].eat_arg)
×
145
    {
146
      case EAT_DATE:
×
147
        /* L10N:
148
           Pattern Completion Menu argument type: a date range
149
           Used by ~d, ~r.
150
        */
151
        buf_add_printf(buf, " %s", _("DATERANGE"));
×
152
        break;
×
153
      case EAT_GROUP:
×
154
        /* L10N:
155
           Pattern Completion Menu argument type: an address group
156
           Used by %c, %C, %e, %f, %L.
157
        */
158
        buf_add_printf(buf, " %s", _("GROUP"));
×
159
        break;
×
160
      case EAT_MESSAGE_RANGE:
×
161
        /* L10N:
162
           Pattern Completion Menu argument type: a message range.
163
           Used by ~m.
164
        */
165
        buf_add_printf(buf, " %s", _("MSGRANGE"));
×
166
        break;
×
167
      case EAT_QUERY:
×
168
        /* L10N:
169
           Pattern Completion Menu argument type: a query
170
           Used by ~I.
171
        */
172
        buf_add_printf(buf, " %s", _("QUERY"));
×
173
        break;
×
174
      case EAT_RANGE:
×
175
        /* L10N:
176
           Pattern Completion Menu argument type: a numeric range.
177
           Used by ~n, ~X, ~z.
178
        */
179
        buf_add_printf(buf, " %s", _("RANGE"));
×
180
        break;
×
181
      case EAT_REGEX:
×
182
        /* L10N:
183
           Pattern Completion Menu argument type: a regular expression
184
        */
185
        buf_add_printf(buf, " %s", _("REGEX"));
×
186
        break;
×
187
      case EAT_STRING:
×
188
        /* L10N:
189
           Pattern Completion Menu argument type: a string (for IMAP patterns)
190
           Used by =b, =B, =h, =/.
191
        */
192
        buf_add_printf(buf, " %s", _("STRING"));
×
193
        break;
×
194
      default:
195
        break;
196
    }
197

198
    entry.expr = buf_strdup(buf);
×
199
    entry.desc = mutt_str_dup(_(Flags[i].desc));
×
200

201
    ARRAY_ADD(pea, entry);
×
202
  }
203

204
  /* Add struct MuttThread patterns manually.
205
   * Note we allocated 3 extra slots for these above. */
206

207
  /* L10N:
208
     Pattern Completion Menu argument type: a nested pattern.
209
     Used by ~(), ~<(), ~>().
210
  */
211
  const char *patternstr = _("PATTERN");
×
212

213
  entry.num = ARRAY_SIZE(pea) + 1;
×
214
  entry.tag = mutt_str_dup("~()");
×
215
  buf_printf(buf, "~(%s)", patternstr);
×
216
  entry.expr = buf_strdup(buf);
×
217
  // L10N: Pattern Completion Menu description for ~()
218
  entry.desc = mutt_str_dup(_("messages in threads containing messages matching PATTERN"));
×
219
  ARRAY_ADD(pea, entry);
×
220

221
  entry.num = ARRAY_SIZE(pea) + 1;
×
222
  entry.tag = mutt_str_dup("~<()");
×
223
  buf_printf(buf, "~<(%s)", patternstr);
×
224
  entry.expr = buf_strdup(buf);
×
225
  // L10N: Pattern Completion Menu description for ~<()
226
  entry.desc = mutt_str_dup(_("messages whose immediate parent matches PATTERN"));
×
227
  ARRAY_ADD(pea, entry);
×
228

229
  entry.num = ARRAY_SIZE(pea) + 1;
×
230
  entry.tag = mutt_str_dup("~>()");
×
231
  buf_printf(buf, "~>(%s)", patternstr);
×
232
  entry.expr = buf_strdup(buf);
×
233
  // L10N: Pattern Completion Menu description for ~>()
234
  entry.desc = mutt_str_dup(_("messages having an immediate child matching PATTERN"));
×
235
  ARRAY_ADD(pea, entry);
×
236

237
  buf_pool_release(&buf);
×
238
}
×
239

240
/**
241
 * pattern_config_observer - Notification that a Config Variable has changed - Implements ::observer_t - @ingroup observer_api
242
 *
243
 * The Address Book Window is affected by changes to `$sort_pattern`.
244
 */
245
static int pattern_config_observer(struct NotifyCallback *nc)
×
246
{
247
  if (nc->event_type != NT_CONFIG)
×
248
    return 0;
249
  if (!nc->global_data || !nc->event_data)
×
250
    return -1;
251

252
  struct EventConfig *ev_c = nc->event_data;
253

254
  if (!mutt_str_equal(ev_c->name, "pattern_format"))
×
255
    return 0;
256

257
  struct Menu *menu = nc->global_data;
×
258
  menu_queue_redraw(menu, MENU_REDRAW_FULL);
×
259
  mutt_debug(LL_DEBUG5, "config done, request WA_RECALC, MENU_REDRAW_FULL\n");
×
260

261
  return 0;
×
262
}
263

264
/**
265
 * pattern_window_observer - Notification that a Window has changed - Implements ::observer_t - @ingroup observer_api
266
 *
267
 * This function is triggered by changes to the windows.
268
 *
269
 * - Delete (this window): clean up the resources held by the Help Bar
270
 */
271
static int pattern_window_observer(struct NotifyCallback *nc)
×
272
{
273
  if (nc->event_type != NT_WINDOW)
×
274
    return 0;
275
  if (!nc->global_data || !nc->event_data)
×
276
    return -1;
277
  if (nc->event_subtype != NT_WINDOW_DELETE)
×
278
    return 0;
279

280
  struct MuttWindow *win_menu = nc->global_data;
281
  struct EventWindow *ev_w = nc->event_data;
282
  if (ev_w->win != win_menu)
×
283
    return 0;
284

285
  struct Menu *menu = win_menu->wdata;
×
286

287
  notify_observer_remove(NeoMutt->sub->notify, pattern_config_observer, menu);
×
288
  notify_observer_remove(win_menu->notify, pattern_window_observer, win_menu);
×
289

290
  mutt_debug(LL_DEBUG5, "window delete done\n");
×
291
  return 0;
×
292
}
293

294
/**
295
 * dlg_pattern - Show menu to select a Pattern - @ingroup gui_dlg
296
 * @param buf Buffer for the selected Pattern
297
 * @retval true A selection was made
298
 *
299
 * The Select Pattern Dialog shows the user a help page of Patterns.
300
 * They can select one to auto-complete some functions, e.g. `<limit>`
301
 */
302
bool dlg_pattern(struct Buffer *buf)
×
303
{
304
  struct PatternData *pd = pattern_data_new();
×
305

306
  struct SimpleDialogWindows sdw = simple_dialog_new(MENU_DIALOG, WT_DLG_PATTERN, PatternHelp);
×
307
  create_pattern_entries(&pd->entries);
×
308

309
  struct Menu *menu = sdw.menu;
×
310
  pd->menu = menu;
×
311
  pd->buf = buf;
×
312

313
  menu->mdata = pd;
×
314
  menu->mdata_free = pattern_data_free;
×
315
  menu->make_entry = pattern_make_entry;
×
316
  menu->max = ARRAY_SIZE(&pd->entries);
×
317

318
  // L10N: Pattern completion menu title
319
  sbar_set_title(sdw.sbar, _("Patterns"));
×
320

321
  // NT_COLOR is handled by the SimpleDialog
322
  notify_observer_add(NeoMutt->sub->notify, NT_CONFIG, pattern_config_observer, menu);
×
323
  notify_observer_add(menu->win->notify, NT_WINDOW, pattern_window_observer, menu->win);
×
324

325
  struct MuttWindow *old_focus = window_set_focus(menu->win);
×
326
  // ---------------------------------------------------------------------------
327
  // Event Loop
328
  int op = OP_NULL;
329
  struct KeyEvent event = { 0, OP_NULL };
×
330
  do
331
  {
332
    menu_tagging_dispatcher(menu->win, &event);
×
333
    window_redraw(NULL);
×
334

335
    event = km_dokey(MENU_DIALOG, GETCH_NO_FLAGS);
×
336
    op = event.op;
×
337
    mutt_debug(LL_DEBUG1, "Got op %s (%d)\n", opcodes_get_name(op), op);
×
338
    if (op < 0)
×
339
      continue;
×
340
    if (op == OP_NULL)
×
341
    {
342
      km_error_key(MENU_GENERIC);
×
343
      continue;
×
344
    }
345
    mutt_clear_error();
×
346

347
    int rc = pattern_function_dispatcher(sdw.dlg, &event);
×
348
    if (rc == FR_UNKNOWN)
×
349
      rc = menu_function_dispatcher(menu->win, &event);
×
350
    if (rc == FR_UNKNOWN)
×
351
      rc = global_function_dispatcher(menu->win, &event);
×
352
  } while (!pd->done);
×
353
  // ---------------------------------------------------------------------------
354

355
  bool rc = pd->selection;
×
356

357
  window_set_focus(old_focus);
×
358
  simple_dialog_free(&sdw.dlg);
×
359

360
  return rc;
×
361
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc