NeoMutt  2025-12-11-949-g4870ee
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
functions_fuzzy.c
Go to the documentation of this file.
1
22
28
29#include "config.h"
30#include <stdbool.h>
31#include <string.h>
32#include "private.h"
33#include "mutt/lib.h"
34#include "config/lib.h"
35#include "core/lib.h"
36#include "gui/lib.h"
37#include "editor/lib.h"
38#include "fuzzy/lib.h"
39#include "history/lib.h"
40#include "index/lib.h"
41#include "key/lib.h"
42#include "functions_sidebar.h"
43
49{
50 struct MenuDefinition *md = menudef_new();
51
52 struct SubMenu *sm_fuzzy = fuzzy_get_submenu();
53 ASSERT(sm_fuzzy);
54 struct SubMenu *sm_editor = editor_get_submenu();
55 ASSERT(sm_editor);
56
57 km_menu_add_submenu(md, sm_fuzzy);
58 km_menu_add_submenu(md, sm_editor);
59
60 return md;
61}
62
66static const struct SidebarFunction FuzzyFunctions[] = {
67 // clang-format off
68 { OP_FIRST_ENTRY, op_sidebar_first },
69 { OP_LAST_ENTRY, op_sidebar_last },
70 { OP_NEXT_ENTRY, op_sidebar_next },
71 { OP_NEXT_PAGE, op_sidebar_page_down },
72 { OP_PREV_ENTRY, op_sidebar_prev },
73 { OP_PREV_PAGE, op_sidebar_page_up },
74 { 0, NULL },
75 // clang-format on
76};
77
81int sb_fuzzy_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
82{
83 if (!event || !win || !win->wdata)
84 return FR_UNKNOWN;
85
86 const int op = event->op;
87
89
90 struct SidebarFunctionData fdata = {
91 .n = NeoMutt,
92 .mod_data = mod_data,
93 .wdata = win->wdata,
94 };
95
96 int rc = FR_UNKNOWN;
97 for (size_t i = 0; FuzzyFunctions[i].op != OP_NULL; i++)
98 {
99 const struct SidebarFunction *fn = &FuzzyFunctions[i];
100 if (fn->op == op)
101 {
102 rc = fn->function(&fdata, event);
103 break;
104 }
105 }
106
107 if (rc == FR_UNKNOWN) // Not our function
108 return rc;
109
110 const char *result = dispatcher_get_retval_name(rc);
111 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
112
114 return rc;
115}
116
120static void sidebar_matcher_cb(const char *text, void *data)
121{
122 struct MuttWindow *win = data;
123 struct SidebarWindowData *wdata = win->wdata;
124 wdata->hil_index = -1;
125 wdata->repage = true;
126
127 struct SbEntry **sbep = NULL;
128
129 if (text[0] == '\0')
130 {
131 ARRAY_FOREACH(sbep, &wdata->entries)
132 {
133 struct SbEntry *sbe = *sbep;
134 sbe->mailbox->visible = true;
135 sbe->score = -1;
136 if (wdata->hil_index == -1)
137 wdata->hil_index = ARRAY_FOREACH_IDX_sbep;
138 }
139 wdata->win->actions |= WA_RECALC;
140 return;
141 }
142
143 struct FuzzyOptions opts = { .smart_case = true };
144 struct FuzzyResult result = { 0 };
145 int best_score = -1;
146 int best_index = -1;
147 struct Buffer *buf = buf_pool_get();
148
149 ARRAY_FOREACH(sbep, &wdata->entries)
150 {
151 struct SbEntry *sbe = *sbep;
152 buf_printf(buf, "%s %s", sbe->box, sbe->display);
153 int score = fuzzy_match(text, buf_string(buf), FUZZY_ALGO_SUBSEQ, &opts, &result);
154 if (score > 0)
155 {
156 // Extra 2 points for new (unseen) mail
157 // 1 point for old (seen) mail
158 score += (2 * sbe->mailbox->msg_new);
159 score += (sbe->mailbox->msg_unread - sbe->mailbox->msg_new);
160 }
161 sbe->score = score;
162 if (score >= 0)
163 {
164 if ((best_score == -1) || (score > best_score))
165 {
166 best_score = score;
167 best_index = ARRAY_FOREACH_IDX_sbep;
168 }
169 sbe->mailbox->visible = true;
170 }
171 else
172 {
173 sbe->mailbox->visible = false;
174 }
175 }
176
177 wdata->hil_index = best_index;
178 wdata->win->actions |= WA_RECALC;
179 buf_pool_release(&buf);
180}
181
185int op_sidebar_start_search(struct SidebarFunctionData *fdata, const struct KeyEvent *event)
186{
187 struct SidebarWindowData *wdata = fdata->wdata;
188 if (ARRAY_EMPTY(&wdata->entries) || (wdata->hil_index < 0))
189 {
190 mutt_warning(_("There are no mailboxes"));
191 return FR_ERROR;
192 }
193
194 const bool was_visible = cs_subset_bool(fdata->n->sub, "sidebar_visible");
195 if (!was_visible)
196 {
197 cs_subset_str_native_set(fdata->n->sub, "sidebar_visible", true, NULL);
198 mutt_window_reflow(NULL);
199 }
200
201 struct MenuDefinition *md = NULL;
202 struct Buffer *buf = buf_pool_get();
203 const int old_hil_index = wdata->hil_index;
204
205 struct SbEntry **sbep = NULL;
206 ARRAY_FOREACH(sbep, &wdata->entries)
207 {
208 struct SbEntry *sbe = *sbep;
209 if (sbe->box[0] == '\0')
211 }
212
213 int rc = FR_NO_ACTION;
214 wdata->search_active = true;
215
216 md = sb_fuzzy_init_menu();
217
218 if (mw_get_field_notify(_("Sidebar search: "), buf, MUTT_COMP_UNBUFFERED,
219 HC_NONE, NULL, NULL, sidebar_matcher_cb, wdata->win,
221 {
222 wdata->hil_index = old_hil_index;
223 goto done;
224 }
225
226 if (!buf || buf_is_empty(buf) || (wdata->hil_index == wdata->opn_index))
227 {
228 wdata->hil_index = old_hil_index;
229 goto done;
230 }
231
232 ARRAY_FOREACH(sbep, &wdata->entries)
233 {
234 struct SbEntry *sbe = *sbep;
235 sbe->score = -1;
236 }
237 rc = FR_SUCCESS;
238
239done:
240 ARRAY_FOREACH(sbep, &wdata->entries)
241 {
242 (*sbep)->mailbox->visible = true;
243 }
244 wdata->search_active = false;
245 wdata->repage = false;
246 wdata->win->actions |= WA_RECALC;
247
248 if (rc == FR_SUCCESS)
249 {
250 struct MuttWindow *dlg = dialog_find(wdata->win);
252 }
253
254 if (!was_visible)
255 {
256 cs_subset_str_native_set(fdata->n->sub, "sidebar_visible", false, NULL);
257 mutt_window_reflow(NULL);
258 }
259
260 menudef_free(&md);
261 buf_pool_release(&buf);
262 return rc;
263}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition array.h:74
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:168
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:298
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
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:55
void dispatcher_flush_on_error(int rv)
Flush pending keys after a dispatch error.
Definition dispatcher.c:65
@ FR_SUCCESS
Valid function - successfully performed.
Definition dispatcher.h:40
@ FR_UNKNOWN
Unknown function.
Definition dispatcher.h:34
@ FR_ERROR
Valid function - error occurred.
Definition dispatcher.h:39
@ 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:1490
struct SubMenu * editor_get_submenu(void)
Get the Editor SubMenu.
Definition functions.c:587
Edit a string.
int mw_get_field_notify(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata, get_field_callback_t callback, void *cb_data, const struct MenuDefinition *md, function_dispatcher_t fn_disp)
Ask the user for a string and call a notify function on keypress.
Definition window.c:299
@ MUTT_COMP_UNBUFFERED
Ignore macro buffer.
Definition wdata.h:49
static void sidebar_matcher_cb(const char *text, void *data)
React to keys as they are entered - Implements get_field_callback_t.
static const struct SidebarFunction FuzzyFunctions[]
All the NeoMutt functions that the Sidebar Fuzzy Search supports.
struct MenuDefinition * sb_fuzzy_init_menu(void)
Initialise the Fuzzy Search Menu - Implements ::init_keys_api.
Sidebar functions.
struct SubMenu * fuzzy_get_submenu(void)
Get the Fuzzy SubMenu.
Definition functions.c:91
Fuzzy matching library.
@ FUZZY_ALGO_SUBSEQ
Subsequence matching algorithm.
Definition lib.h:82
int fuzzy_match(const char *pattern, const char *candidate, enum FuzzyAlgo algo, const struct FuzzyOptions *opts, struct FuzzyResult *out)
Perform fuzzy matching.
Definition fuzzy.c:58
int sb_fuzzy_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
Perform a Fuzzy Search function - Implements function_dispatcher_t -.
#define mutt_warning(...)
Definition logging2.h:92
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
int op_sidebar_start_search(struct SidebarFunctionData *fdata, const struct KeyEvent *event)
Selects the last unhidden mailbox - Implements sidebar_function_t -.
int op_sidebar_page_down(struct SidebarFunctionData *fdata, const struct KeyEvent *event)
Selects the first entry in the next page of mailboxes - Implements sidebar_function_t -.
int op_sidebar_prev(struct SidebarFunctionData *fdata, const struct KeyEvent *event)
Selects the previous unhidden mailbox - Implements sidebar_function_t -.
int op_sidebar_page_up(struct SidebarFunctionData *fdata, const struct KeyEvent *event)
Selects the last entry in the previous page of mailboxes - Implements sidebar_function_t -.
int op_sidebar_next(struct SidebarFunctionData *fdata, const struct KeyEvent *event)
Selects the next unhidden mailbox - Implements sidebar_function_t -.
int op_sidebar_first(struct SidebarFunctionData *fdata, const struct KeyEvent *event)
Selects the first unhidden mailbox - Implements sidebar_function_t -.
int op_sidebar_last(struct SidebarFunctionData *fdata, const struct KeyEvent *event)
Selects the last unhidden mailbox - Implements sidebar_function_t -.
Convenience wrapper for the gui headers.
Read/write command history from/to a file.
@ HC_NONE
No History.
Definition lib.h:64
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
Manage keymappings.
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
struct MenuDefinition * menudef_new(void)
Create a new MenuDefinition.
Definition menudef.c:84
void menudef_free(struct MenuDefinition **pptr)
Free a MenuDefinition.
Definition menudef.c:66
@ MODULE_ID_SIDEBAR
ModuleSidebar, Sidebar
Definition module_api.h:93
Convenience wrapper for the library headers.
#define _(a)
Definition message.h:28
void mutt_window_reflow(struct MuttWindow *win)
Resize a Window and its children.
@ WA_RECALC
Recalculate the contents of the Window.
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:666
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition opcodes.c:48
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
GUI display the mailboxes in a side panel.
void sb_entry_set_display_name(struct SbEntry *entry)
Set the display name for an SbEntry.
Definition window.c:306
struct Mailbox * sb_get_highlight(struct MuttWindow *win)
Get the Mailbox that's highlighted in the sidebar.
Definition sidebar.c:73
#define ASSERT(COND)
Definition signal2.h:59
#define NONULL(x)
Definition string2.h:44
String manipulation buffer.
Definition buffer.h:36
Options for fuzzy matching.
Definition lib.h:92
Result of a fuzzy match.
Definition lib.h:103
An event such as a keypress.
Definition get.h:75
int msg_new
Number of new messages.
Definition mailbox.h:94
bool visible
True if a result of "mailboxes".
Definition mailbox.h:132
int msg_unread
Number of unread messages.
Definition mailbox.h:91
Functions for a Dialog or Window.
Definition menudef.h:44
void * wdata
Private data.
WindowActionFlags actions
Actions to be performed, e.g. WA_RECALC.
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
Info about folders in the sidebar.
Definition private.h:40
int score
Fuzzy-match score.
Definition private.h:47
char display[256]
Formatted string to display.
Definition private.h:42
struct Mailbox * mailbox
Mailbox this represents.
Definition private.h:44
char box[256]
Mailbox path (possibly abbreviated)
Definition private.h:41
Data passed to Sidebar worker functions.
struct SidebarWindowData * wdata
Sidebar window data.
struct NeoMutt * n
NeoMutt application data.
struct SidebarModuleData * mod_data
Sidebar module data.
A NeoMutt function.
int op
Op code, e.g. OP_SIDEBAR_NEXT.
sidebar_function_t function
Function to call.
Sidebar private Module data.
Definition module_data.h:32
Sidebar private Window data -.
Definition private.h:89
int hil_index
Highlighted mailbox.
Definition private.h:96
int opn_index
Current (open) mailbox.
Definition private.h:95
bool search_active
Sidebar Search is running.
Definition private.h:99
struct MuttWindow * win
Sidebar Window.
Definition private.h:90
struct SbEntryArray entries
Items to display in the sidebar.
Definition private.h:92
bool repage
Force RECALC to recompute the paging used for the overlays.
Definition private.h:98
Collection of related functions.
Definition menudef.h:33
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition subset.c:303