NeoMutt  2025-12-11-177-g48e272
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
functions.c
Go to the documentation of this file.
1
23
29
30#include "config.h"
31#include <stdbool.h>
32#include <stddef.h>
33#include "private.h"
34#include "mutt/lib.h"
35#include "config/lib.h"
36#include "core/lib.h"
37#include "gui/lib.h"
38#include "functions.h"
39#include "lib.h"
40#include "index/lib.h"
41#include "key/lib.h"
42#include "menu/lib.h"
43
45static struct SubMenu *SmSidebar = NULL;
46
47// clang-format off
51static const struct MenuFuncOp OpSidebar[] = { /* map: sidebar */
52 { "sidebar-first", OP_SIDEBAR_FIRST },
53 { "sidebar-last", OP_SIDEBAR_LAST },
54 { "sidebar-next", OP_SIDEBAR_NEXT },
55 { "sidebar-next-new", OP_SIDEBAR_NEXT_NEW },
56 { "sidebar-open", OP_SIDEBAR_OPEN },
57 { "sidebar-page-down", OP_SIDEBAR_PAGE_DOWN },
58 { "sidebar-page-up", OP_SIDEBAR_PAGE_UP },
59 { "sidebar-prev", OP_SIDEBAR_PREV },
60 { "sidebar-prev-new", OP_SIDEBAR_PREV_NEW },
61 { "sidebar-toggle-virtual", OP_SIDEBAR_TOGGLE_VIRTUAL },
62 { "sidebar-toggle-visible", OP_SIDEBAR_TOGGLE_VISIBLE },
63 { NULL, 0 },
64};
65// clang-format on
66
70void sidebar_init_keys(struct SubMenu *sm_generic)
71{
72 struct MenuDefinition *md = NULL;
73 struct SubMenu *sm = NULL;
74
76 md = km_register_menu(MENU_SIDEBAR, "sidebar");
77 km_menu_add_submenu(md, sm);
78
79 SmSidebar = sm;
80}
81
83{
84 return SmSidebar;
85}
86
92bool sb_next(struct SidebarWindowData *wdata)
93{
94 struct SbEntry **sbep = NULL;
95 ARRAY_FOREACH_FROM(sbep, &wdata->entries, wdata->hil_index + 1)
96 {
97 if (!(*sbep)->is_hidden)
98 {
99 wdata->hil_index = ARRAY_FOREACH_IDX_sbep;
100 return true;
101 }
102 }
103
104 return false;
105}
106
115static struct SbEntry **sb_next_new(struct SidebarWindowData *wdata, size_t begin, size_t end)
116{
117 struct SbEntry **sbep = NULL;
118 ARRAY_FOREACH_FROM_TO(sbep, &wdata->entries, begin, end)
119 {
120 if ((*sbep)->mailbox->has_new || ((*sbep)->mailbox->msg_unread != 0))
121 return sbep;
122 }
123 return NULL;
124}
125
131bool sb_prev(struct SidebarWindowData *wdata)
132{
133 struct SbEntry **sbep = NULL, **prev = NULL;
134 ARRAY_FOREACH_TO(sbep, &wdata->entries, wdata->hil_index)
135 {
136 if (!(*sbep)->is_hidden)
137 prev = sbep;
138 }
139
140 if (prev)
141 {
142 wdata->hil_index = ARRAY_IDX(&wdata->entries, prev);
143 return true;
144 }
145
146 return false;
147}
148
157static struct SbEntry **sb_prev_new(struct SidebarWindowData *wdata, size_t begin, size_t end)
158{
159 struct SbEntry **sbep = NULL, **prev = NULL;
160 ARRAY_FOREACH_FROM_TO(sbep, &wdata->entries, begin, end)
161 {
162 if ((*sbep)->mailbox->has_new || ((*sbep)->mailbox->msg_unread != 0))
163 prev = sbep;
164 }
165
166 return prev;
167}
168
169// -----------------------------------------------------------------------------
170
174static int op_sidebar_first(struct SidebarWindowData *wdata, const struct KeyEvent *event)
175{
176 if (!mutt_window_is_visible(wdata->win))
177 return FR_NO_ACTION;
178
179 if (ARRAY_EMPTY(&wdata->entries) || (wdata->hil_index < 0))
180 return FR_NO_ACTION;
181
182 int orig_hil_index = wdata->hil_index;
183
184 wdata->hil_index = 0;
185 if ((*ARRAY_GET(&wdata->entries, wdata->hil_index))->is_hidden)
186 if (!sb_next(wdata))
187 wdata->hil_index = orig_hil_index;
188
189 if (orig_hil_index == wdata->hil_index)
190 return FR_NO_ACTION;
191
192 wdata->win->actions |= WA_RECALC;
193 return FR_SUCCESS;
194}
195
199static int op_sidebar_last(struct SidebarWindowData *wdata, const struct KeyEvent *event)
200{
201 if (!mutt_window_is_visible(wdata->win))
202 return FR_NO_ACTION;
203
204 if (ARRAY_EMPTY(&wdata->entries) || (wdata->hil_index < 0))
205 return FR_NO_ACTION;
206
207 int orig_hil_index = wdata->hil_index;
208
209 wdata->hil_index = ARRAY_SIZE(&wdata->entries);
210 if (!sb_prev(wdata))
211 wdata->hil_index = orig_hil_index;
212
213 if (orig_hil_index == wdata->hil_index)
214 return FR_NO_ACTION;
215
216 wdata->win->actions |= WA_RECALC;
217 return FR_SUCCESS;
218}
219
223static int op_sidebar_next(struct SidebarWindowData *wdata, const struct KeyEvent *event)
224{
225 if (!mutt_window_is_visible(wdata->win))
226 return FR_NO_ACTION;
227
228 if (ARRAY_EMPTY(&wdata->entries) || (wdata->hil_index < 0))
229 return FR_NO_ACTION;
230
231 if (!sb_next(wdata))
232 return FR_NO_ACTION;
233
234 wdata->win->actions |= WA_RECALC;
235 return FR_SUCCESS;
236}
237
243static int op_sidebar_next_new(struct SidebarWindowData *wdata, const struct KeyEvent *event)
244{
245 if (!mutt_window_is_visible(wdata->win))
246 return FR_NO_ACTION;
247
248 const size_t max_entries = ARRAY_SIZE(&wdata->entries);
249 if ((max_entries == 0) || (wdata->hil_index < 0))
250 return FR_NO_ACTION;
251
252 const bool c_sidebar_next_new_wrap = cs_subset_bool(NeoMutt->sub, "sidebar_next_new_wrap");
253 struct SbEntry **sbep = NULL;
254 if ((sbep = sb_next_new(wdata, wdata->hil_index + 1, max_entries)) ||
255 (c_sidebar_next_new_wrap && (sbep = sb_next_new(wdata, 0, wdata->hil_index))))
256 {
257 wdata->hil_index = ARRAY_IDX(&wdata->entries, sbep);
258 wdata->win->actions |= WA_RECALC;
259 return FR_SUCCESS;
260 }
261
262 return FR_NO_ACTION;
263}
264
268static int op_sidebar_open(struct SidebarWindowData *wdata, const struct KeyEvent *event)
269{
270 struct MuttWindow *win_sidebar = wdata->win;
271 if (!mutt_window_is_visible(win_sidebar))
272 return FR_NO_ACTION;
273
274 struct MuttWindow *dlg = dialog_find(win_sidebar);
275 index_change_folder(dlg, sb_get_highlight(win_sidebar));
276 return FR_SUCCESS;
277}
278
282static int op_sidebar_page_down(struct SidebarWindowData *wdata, const struct KeyEvent *event)
283{
284 if (!mutt_window_is_visible(wdata->win))
285 return FR_NO_ACTION;
286
287 if (ARRAY_EMPTY(&wdata->entries) || (wdata->bot_index < 0))
288 return FR_NO_ACTION;
289
290 int orig_hil_index = wdata->hil_index;
291
292 wdata->hil_index = wdata->bot_index;
293 sb_next(wdata);
294 /* If the rest of the entries are hidden, go up to the last unhidden one */
295 if ((*ARRAY_GET(&wdata->entries, wdata->hil_index))->is_hidden)
296 sb_prev(wdata);
297
298 if (orig_hil_index == wdata->hil_index)
299 return FR_NO_ACTION;
300
301 wdata->win->actions |= WA_RECALC;
302 return FR_SUCCESS;
303}
304
308static int op_sidebar_page_up(struct SidebarWindowData *wdata, const struct KeyEvent *event)
309{
310 if (!mutt_window_is_visible(wdata->win))
311 return FR_NO_ACTION;
312
313 if (ARRAY_EMPTY(&wdata->entries) || (wdata->top_index < 0))
314 return FR_NO_ACTION;
315
316 int orig_hil_index = wdata->hil_index;
317
318 wdata->hil_index = wdata->top_index;
319 sb_prev(wdata);
320 /* If the rest of the entries are hidden, go down to the last unhidden one */
321 if ((*ARRAY_GET(&wdata->entries, wdata->hil_index))->is_hidden)
322 sb_next(wdata);
323
324 if (orig_hil_index == wdata->hil_index)
325 return FR_NO_ACTION;
326
327 wdata->win->actions |= WA_RECALC;
328 return FR_SUCCESS;
329}
330
334static int op_sidebar_prev(struct SidebarWindowData *wdata, const struct KeyEvent *event)
335{
336 if (!mutt_window_is_visible(wdata->win))
337 return FR_NO_ACTION;
338
339 if (ARRAY_EMPTY(&wdata->entries) || (wdata->hil_index < 0))
340 return FR_NO_ACTION;
341
342 if (!sb_prev(wdata))
343 return FR_NO_ACTION;
344
345 wdata->win->actions |= WA_RECALC;
346 return FR_SUCCESS;
347}
348
354static int op_sidebar_prev_new(struct SidebarWindowData *wdata, const struct KeyEvent *event)
355{
356 if (!mutt_window_is_visible(wdata->win))
357 return FR_NO_ACTION;
358
359 const size_t max_entries = ARRAY_SIZE(&wdata->entries);
360 if ((max_entries == 0) || (wdata->hil_index < 0))
361 return FR_NO_ACTION;
362
363 const bool c_sidebar_next_new_wrap = cs_subset_bool(NeoMutt->sub, "sidebar_next_new_wrap");
364 struct SbEntry **sbep = NULL;
365 if ((sbep = sb_prev_new(wdata, 0, wdata->hil_index)) ||
366 (c_sidebar_next_new_wrap &&
367 (sbep = sb_prev_new(wdata, wdata->hil_index + 1, max_entries))))
368 {
369 wdata->hil_index = ARRAY_IDX(&wdata->entries, sbep);
370 wdata->win->actions |= WA_RECALC;
371 return FR_SUCCESS;
372 }
373
374 return FR_NO_ACTION;
375}
376
381 const struct KeyEvent *event)
382{
383 bool_str_toggle(NeoMutt->sub, "sidebar_visible", NULL);
384 mutt_window_reflow(NULL);
385 return FR_SUCCESS;
386}
387
392 const struct KeyEvent *event)
393{
394 return FR_SUCCESS;
395}
396
397// -----------------------------------------------------------------------------
398
402static const struct SidebarFunction SidebarFunctions[] = {
403 // clang-format off
404 { OP_SIDEBAR_FIRST, op_sidebar_first },
405 { OP_SIDEBAR_LAST, op_sidebar_last },
406 { OP_SIDEBAR_NEXT, op_sidebar_next },
407 { OP_SIDEBAR_NEXT_NEW, op_sidebar_next_new },
408 { OP_SIDEBAR_OPEN, op_sidebar_open },
409 { OP_SIDEBAR_PAGE_DOWN, op_sidebar_page_down },
410 { OP_SIDEBAR_PAGE_UP, op_sidebar_page_up },
411 { OP_SIDEBAR_PREV, op_sidebar_prev },
412 { OP_SIDEBAR_PREV_NEW, op_sidebar_prev_new },
413 { OP_SIDEBAR_TOGGLE_VIRTUAL, op_sidebar_toggle_virtual },
414 { OP_SIDEBAR_TOGGLE_VISIBLE, op_sidebar_toggle_visible },
415 { 0, NULL },
416 // clang-format on
417};
418
422int sb_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
423{
424 if (!event || !win || !win->wdata)
425 return FR_UNKNOWN;
426
427 const int op = event->op;
428 struct SidebarWindowData *wdata = win->wdata;
429 int rc = FR_UNKNOWN;
430 for (size_t i = 0; SidebarFunctions[i].op != OP_NULL; i++)
431 {
432 const struct SidebarFunction *fn = &SidebarFunctions[i];
433 if (fn->op == op)
434 {
435 rc = fn->function(wdata, event);
436 break;
437 }
438 }
439
440 if (rc == FR_UNKNOWN) // Not our function
441 return rc;
442
443 const char *result = dispatcher_get_retval_name(rc);
444 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
445
446 return FR_SUCCESS; // Whatever the outcome, we handled it
447}
#define ARRAY_IDX(head, elem)
Return the index of an element of the array.
Definition array.h:324
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition array.h:74
#define ARRAY_FOREACH_TO(elem, head, to)
Iterate from the beginning to an index.
Definition array.h:247
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
#define ARRAY_FOREACH_FROM(elem, head, from)
Iterate from an index to the end.
Definition array.h:235
#define ARRAY_GET(head, idx)
Return the element at index.
Definition array.h:109
#define ARRAY_FOREACH_FROM_TO(elem, head, from, to)
Iterate between two indexes.
Definition array.h:261
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition bool.c:229
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
struct MuttWindow * dialog_find(struct MuttWindow *win)
Find the parent Dialog of a Window.
Definition dialog.c:89
const char * dispatcher_get_retval_name(int rv)
Get the name of a return value.
Definition dispatcher.c:54
@ FR_SUCCESS
Valid function - successfully performed.
Definition dispatcher.h:40
@ FR_UNKNOWN
Unknown function.
Definition dispatcher.h:34
@ FR_NO_ACTION
Valid function - no action performed.
Definition dispatcher.h:38
void index_change_folder(struct MuttWindow *dlg, struct Mailbox *m)
Change the current folder, cautiously.
Definition dlg_index.c:1463
int sb_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
Perform a Sidebar function - Implements function_dispatcher_t -.
Definition functions.c:422
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
static int op_sidebar_page_down(struct SidebarWindowData *wdata, const struct KeyEvent *event)
Selects the first entry in the next page of mailboxes - Implements sidebar_function_t -.
Definition functions.c:282
static int op_sidebar_page_up(struct SidebarWindowData *wdata, const struct KeyEvent *event)
Selects the last entry in the previous page of mailboxes - Implements sidebar_function_t -.
Definition functions.c:308
static int op_sidebar_last(struct SidebarWindowData *wdata, const struct KeyEvent *event)
Selects the last unhidden mailbox - Implements sidebar_function_t -.
Definition functions.c:199
static int op_sidebar_first(struct SidebarWindowData *wdata, const struct KeyEvent *event)
Selects the first unhidden mailbox - Implements sidebar_function_t -.
Definition functions.c:174
static int op_sidebar_prev(struct SidebarWindowData *wdata, const struct KeyEvent *event)
Selects the previous unhidden mailbox - Implements sidebar_function_t -.
Definition functions.c:334
static int op_sidebar_open(struct SidebarWindowData *wdata, const struct KeyEvent *event)
Open highlighted mailbox - Implements sidebar_function_t -.
Definition functions.c:268
static int op_sidebar_next(struct SidebarWindowData *wdata, const struct KeyEvent *event)
Selects the next unhidden mailbox - Implements sidebar_function_t -.
Definition functions.c:223
static int op_sidebar_toggle_visible(struct SidebarWindowData *wdata, const struct KeyEvent *event)
Make the sidebar (in)visible - Implements sidebar_function_t -.
Definition functions.c:380
static int op_sidebar_toggle_virtual(struct SidebarWindowData *wdata, const struct KeyEvent *event)
Deprecated - Implements sidebar_function_t -.
Definition functions.c:391
static int op_sidebar_next_new(struct SidebarWindowData *wdata, const struct KeyEvent *event)
Selects the next new mailbox - Implements sidebar_function_t -.
Definition functions.c:243
static int op_sidebar_prev_new(struct SidebarWindowData *wdata, const struct KeyEvent *event)
Selects the previous new mailbox - Implements sidebar_function_t -.
Definition functions.c:354
Convenience wrapper for the gui headers.
GUI manage the main index (list of emails)
void km_menu_add_submenu(struct MenuDefinition *md, struct SubMenu *sm)
Add a SubMenu to a Menu Definition.
Definition init.c:123
struct SubMenu * km_register_submenu(const struct MenuFuncOp functions[])
Register a submenu.
Definition init.c:91
struct MenuDefinition * km_register_menu(int menu, const char *name)
Register a menu.
Definition init.c:107
Manage keymappings.
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
GUI present the user with a selectable list.
Convenience wrapper for the library headers.
bool mutt_window_is_visible(struct MuttWindow *win)
Is the Window visible?
void mutt_window_reflow(struct MuttWindow *win)
Resize a Window and its children.
#define WA_RECALC
Recalculate the contents of the Window.
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition opcodes.c:48
void sidebar_init_keys(struct SubMenu *sm_generic)
Initialise the Sidebar Keybindings - Implements ::init_keys_api.
Definition functions.c:70
static const struct SidebarFunction SidebarFunctions[]
All the NeoMutt functions that the Sidebar supports.
Definition functions.c:402
bool sb_prev(struct SidebarWindowData *wdata)
Find the previous unhidden Mailbox.
Definition functions.c:131
static struct SubMenu * SmSidebar
Sidebar functions.
Definition functions.c:45
static struct SbEntry ** sb_prev_new(struct SidebarWindowData *wdata, size_t begin, size_t end)
Return the previous mailbox with new messages.
Definition functions.c:157
struct SubMenu * sidebar_get_submenu(void)
Definition functions.c:82
bool sb_next(struct SidebarWindowData *wdata)
Find the next unhidden Mailbox.
Definition functions.c:92
static const struct MenuFuncOp OpSidebar[]
Functions for the Sidebar Window.
Definition functions.c:51
static struct SbEntry ** sb_next_new(struct SidebarWindowData *wdata, size_t begin, size_t end)
Return the next mailbox with new messages.
Definition functions.c:115
Sidebar functions.
GUI display the mailboxes in a side panel.
GUI display the mailboxes in a side panel.
struct Mailbox * sb_get_highlight(struct MuttWindow *win)
Get the Mailbox that's highlighted in the sidebar.
Definition sidebar.c:75
#define NONULL(x)
Definition string2.h:44
An event such as a keypress.
Definition get.h:50
Functions for a Dialog or Window.
Definition menu.h:81
Mapping between a function and an operation.
Definition menu.h:39
void * wdata
Private data.
WindowActionFlags actions
Actions to be performed, e.g. WA_RECALC.
Container for Accounts, Notifications.
Definition neomutt.h:128
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:134
Info about folders in the sidebar.
Definition private.h:40
A NeoMutt function.
Definition functions.h:49
int op
Op code, e.g. OP_SIDEBAR_NEXT.
Definition functions.h:50
sidebar_function_t function
Function to call.
Definition functions.h:51
Sidebar private Window data -.
Definition private.h:87
int hil_index
Highlighted mailbox.
Definition private.h:94
struct MuttWindow * win
Sidebar Window.
Definition private.h:88
struct SbEntryArray entries
Items to display in the sidebar.
Definition private.h:90
Collection of related functions.
Definition menu.h:69
@ MENU_SIDEBAR
Sidebar menu.
Definition type.h:49