NeoMutt  2025-12-11-694-ga89709
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
functions.c
Go to the documentation of this file.
1
22
28
29#include "config.h"
30#include <inttypes.h>
31#include <stdbool.h>
32#include <stdio.h>
33#include <sys/stat.h>
34#include "mutt/lib.h"
35#include "config/lib.h"
36#include "email/lib.h"
37#include "core/lib.h"
38#include "gui/lib.h"
39#include "mutt.h"
40#include "functions.h"
41#include "lib.h"
42#include "attach/lib.h"
43#include "browser/lib.h"
44#include "color/lib.h"
45#include "editor/lib.h"
46#include "history/lib.h"
47#include "index/lib.h"
48#include "key/lib.h"
49#include "menu/lib.h"
50#include "pattern/lib.h"
51#include "sidebar/lib.h"
52#include "display.h"
53#include "muttlib.h"
54#include "private_data.h"
55
57static const char *Not_available_in_this_menu = N_("Not available in this menu");
58
59static int op_pager_search_next(struct IndexSharedData *shared,
60 struct PagerPrivateData *priv,
61 const struct KeyEvent *event);
62
64struct MenuDefinition *MdPager = NULL;
65
66// clang-format off
70static const struct MenuFuncOp OpPager[] = { /* map: pager */
71 { "bottom", OP_PAGER_BOTTOM },
72 { "bounce-message", OP_BOUNCE_MESSAGE },
73 { "break-thread", OP_MAIN_BREAK_THREAD },
74 { "change-folder", OP_MAIN_CHANGE_FOLDER },
75 { "change-folder-readonly", OP_MAIN_CHANGE_FOLDER_READONLY },
76 { "change-newsgroup", OP_MAIN_CHANGE_GROUP },
77 { "change-newsgroup-readonly", OP_MAIN_CHANGE_GROUP_READONLY },
78#ifdef USE_NOTMUCH
79 { "change-vfolder", OP_MAIN_CHANGE_VFOLDER },
80#endif
81 { "check-stats", OP_CHECK_STATS },
82 { "check-traditional-pgp", OP_CHECK_TRADITIONAL },
83 { "clear-flag", OP_MAIN_CLEAR_FLAG },
84 { "compose-to-sender", OP_COMPOSE_TO_SENDER },
85 { "copy-message", OP_COPY_MESSAGE },
86 { "create-alias", OP_CREATE_ALIAS },
87 { "decode-copy", OP_DECODE_COPY },
88 { "decode-save", OP_DECODE_SAVE },
89 { "decrypt-copy", OP_DECRYPT_COPY },
90 { "decrypt-save", OP_DECRYPT_SAVE },
91 { "delete-message", OP_DELETE },
92 { "delete-subthread", OP_DELETE_SUBTHREAD },
93 { "delete-thread", OP_DELETE_THREAD },
94 { "display-address", OP_DISPLAY_ADDRESS },
95 { "display-toggle-weed", OP_DISPLAY_HEADERS },
96 { "edit", OP_EDIT_RAW_MESSAGE },
97 { "edit-label", OP_EDIT_LABEL },
98 { "edit-or-view-raw-message", OP_EDIT_OR_VIEW_RAW_MESSAGE },
99 { "edit-raw-message", OP_EDIT_RAW_MESSAGE },
100 { "edit-type", OP_ATTACH_EDIT_TYPE },
101 { "enter-command", OP_ENTER_COMMAND },
102#ifdef USE_NOTMUCH
103 { "entire-thread", OP_MAIN_ENTIRE_THREAD },
104#endif
105 { "exit", OP_EXIT },
106 { "extract-keys", OP_EXTRACT_KEYS },
107 { "flag-message", OP_FLAG_MESSAGE },
108 { "followup-message", OP_FOLLOWUP },
109 { "forget-passphrase", OP_FORGET_PASSPHRASE },
110 { "forward-message", OP_FORWARD_MESSAGE },
111 { "forward-to-group", OP_FORWARD_TO_GROUP },
112 { "group-chat-reply", OP_GROUP_CHAT_REPLY },
113 { "group-reply", OP_GROUP_REPLY },
114 { "half-down", OP_HALF_DOWN },
115 { "half-up", OP_HALF_UP },
116 { "help", OP_HELP },
117 { "imap-fetch-mail", OP_MAIN_IMAP_FETCH },
118 { "imap-logout-all", OP_MAIN_IMAP_LOGOUT_ALL },
119 { "jump", OP_JUMP },
120 { "jump", OP_JUMP_1 },
121 { "jump", OP_JUMP_2 },
122 { "jump", OP_JUMP_3 },
123 { "jump", OP_JUMP_4 },
124 { "jump", OP_JUMP_5 },
125 { "jump", OP_JUMP_6 },
126 { "jump", OP_JUMP_7 },
127 { "jump", OP_JUMP_8 },
128 { "jump", OP_JUMP_9 },
129 { "link-threads", OP_MAIN_LINK_THREADS },
130 { "list-reply", OP_LIST_REPLY },
131 { "list-subscribe", OP_LIST_SUBSCRIBE },
132 { "list-unsubscribe", OP_LIST_UNSUBSCRIBE },
133 { "mail", OP_MAIL },
134 { "mail-key", OP_MAIL_KEY },
135 { "mailbox-list", OP_MAILBOX_LIST },
136 { "mark-as-new", OP_TOGGLE_NEW },
137 { "modify-labels", OP_MAIN_MODIFY_TAGS },
138 { "modify-labels-then-hide", OP_MAIN_MODIFY_TAGS_THEN_HIDE },
139 { "modify-tags", OP_MAIN_MODIFY_TAGS },
140 { "modify-tags-then-hide", OP_MAIN_MODIFY_TAGS_THEN_HIDE },
141 { "next-entry", OP_NEXT_ENTRY },
142 { "next-line", OP_NEXT_LINE },
143 { "next-new", OP_MAIN_NEXT_NEW },
144 { "next-new-then-unread", OP_MAIN_NEXT_NEW_THEN_UNREAD },
145 { "next-page", OP_NEXT_PAGE },
146 { "next-subthread", OP_MAIN_NEXT_SUBTHREAD },
147 { "next-thread", OP_MAIN_NEXT_THREAD },
148 { "next-undeleted", OP_MAIN_NEXT_UNDELETED },
149 { "next-unread", OP_MAIN_NEXT_UNREAD },
150 { "next-unread-mailbox", OP_MAIN_NEXT_UNREAD_MAILBOX },
151 { "parent-message", OP_MAIN_PARENT_MESSAGE },
152 { "pipe-entry", OP_PIPE },
153 { "pipe-message", OP_PIPE },
154 { "post-message", OP_POST },
155 { "previous-entry", OP_PREV_ENTRY },
156 { "previous-line", OP_PREV_LINE },
157 { "previous-new", OP_MAIN_PREV_NEW },
158 { "previous-new-then-unread", OP_MAIN_PREV_NEW_THEN_UNREAD },
159 { "previous-page", OP_PREV_PAGE },
160 { "previous-subthread", OP_MAIN_PREV_SUBTHREAD },
161 { "previous-thread", OP_MAIN_PREV_THREAD },
162 { "previous-undeleted", OP_MAIN_PREV_UNDELETED },
163 { "previous-unread", OP_MAIN_PREV_UNREAD },
164 { "print-entry", OP_ATTACH_PRINT },
165 { "print-message", OP_PRINT },
166 { "purge-message", OP_PURGE_MESSAGE },
167 { "purge-thread", OP_PURGE_THREAD },
168 { "quasi-delete", OP_MAIN_QUASI_DELETE },
169 { "quit", OP_QUIT },
170 { "read-subthread", OP_MAIN_READ_SUBTHREAD },
171 { "read-thread", OP_MAIN_READ_THREAD },
172 { "recall-message", OP_RECALL_MESSAGE },
173 { "reconstruct-thread", OP_RECONSTRUCT_THREAD },
174 { "redraw-screen", OP_REDRAW },
175 { "reply", OP_REPLY },
176 { "resend-message", OP_RESEND },
177 { "root-message", OP_MAIN_ROOT_MESSAGE },
178 { "save-entry", OP_ATTACH_SAVE },
179 { "save-message", OP_SAVE },
180 { "search", OP_SEARCH },
181 { "search-next", OP_SEARCH_NEXT },
182 { "search-opposite", OP_SEARCH_OPPOSITE },
183 { "search-reverse", OP_SEARCH_REVERSE },
184 { "search-toggle", OP_SEARCH_TOGGLE },
185 { "set-flag", OP_MAIN_SET_FLAG },
186 { "shell-escape", OP_SHELL_ESCAPE },
187 { "show-log-messages", OP_SHOW_LOG_MESSAGES },
188 { "show-version", OP_VERSION },
189 { "skip-headers", OP_PAGER_SKIP_HEADERS },
190 { "skip-quoted", OP_PAGER_SKIP_QUOTED },
191 { "sort-mailbox", OP_SORT },
192 { "sort-reverse", OP_SORT_REVERSE },
193 { "sync-mailbox", OP_MAIN_SYNC_FOLDER },
194 { "tag-message", OP_TAG },
195 { "toggle-quoted", OP_PAGER_HIDE_QUOTED },
196 { "toggle-write", OP_TOGGLE_WRITE },
197 { "top", OP_PAGER_TOP },
198 { "undelete-message", OP_UNDELETE },
199 { "undelete-subthread", OP_UNDELETE_SUBTHREAD },
200 { "undelete-thread", OP_UNDELETE_THREAD },
201#ifdef USE_NOTMUCH
202 { "vfolder-from-query", OP_MAIN_VFOLDER_FROM_QUERY },
203 { "vfolder-from-query-readonly", OP_MAIN_VFOLDER_FROM_QUERY_READONLY },
204#endif
205 { "view-attachments", OP_VIEW_ATTACHMENTS },
206 { "view-raw-message", OP_VIEW_RAW_MESSAGE },
207 { "what-key", OP_WHAT_KEY },
208 // Deprecated
209 { "buffy-list", OP_MAILBOX_LIST, MFF_DEPRECATED },
210 { "error-history", OP_SHOW_LOG_MESSAGES, MFF_DEPRECATED },
211 { NULL, 0 },
212};
213
217static const struct MenuOpSeq PagerDefaultBindings[] = { /* map: pager */
218 { OP_ATTACH_EDIT_TYPE, "\005" }, // <Ctrl-E>
219 { OP_BOUNCE_MESSAGE, "b" },
220 { OP_CHECK_TRADITIONAL, "\033P" }, // <Alt-P>
221 { OP_COPY_MESSAGE, "C" },
222 { OP_CREATE_ALIAS, "a" },
223 { OP_DECODE_COPY, "\033C" }, // <Alt-C>
224 { OP_DECODE_SAVE, "\033s" }, // <Alt-s>
225 { OP_DELETE, "d" },
226 { OP_DELETE_SUBTHREAD, "\033d" }, // <Alt-d>
227 { OP_DELETE_THREAD, "\004" }, // <Ctrl-D>
228 { OP_DISPLAY_ADDRESS, "@" },
229 { OP_DISPLAY_HEADERS, "h" },
230 { OP_EDIT_LABEL, "Y" },
231 { OP_EDIT_OR_VIEW_RAW_MESSAGE, "e" },
232 { OP_ENTER_COMMAND, ":" },
233 { OP_EXIT, "q" },
234 { OP_EXIT, "x" },
235 { OP_EXTRACT_KEYS, "\013" }, // <Ctrl-K>
236 { OP_FLAG_MESSAGE, "F" },
237 { OP_FORGET_PASSPHRASE, "\006" }, // <Ctrl-F>
238 { OP_FORWARD_MESSAGE, "f" },
239 { OP_GROUP_REPLY, "g" },
240 { OP_HELP, "?" },
241 { OP_JUMP_1, "1" },
242 { OP_JUMP_2, "2" },
243 { OP_JUMP_3, "3" },
244 { OP_JUMP_4, "4" },
245 { OP_JUMP_5, "5" },
246 { OP_JUMP_6, "6" },
247 { OP_JUMP_7, "7" },
248 { OP_JUMP_8, "8" },
249 { OP_JUMP_9, "9" },
250 { OP_LIST_REPLY, "L" },
251 { OP_MAIL, "m" },
252 { OP_MAILBOX_LIST, "." },
253 { OP_MAIL_KEY, "\033k" }, // <Alt-k>
254 { OP_MAIN_BREAK_THREAD, "#" },
255 { OP_MAIN_CHANGE_FOLDER, "c" },
256 { OP_MAIN_CHANGE_FOLDER_READONLY, "\033c" }, // <Alt-c>
257 { OP_MAIN_CLEAR_FLAG, "W" },
258 { OP_MAIN_LINK_THREADS, "&" },
259 { OP_MAIN_NEXT_NEW_THEN_UNREAD, "\t" }, // <Tab>
260 { OP_MAIN_NEXT_SUBTHREAD, "\033n" }, // <Alt-n>
261 { OP_MAIN_NEXT_THREAD, "\016" }, // <Ctrl-N>
262 { OP_MAIN_NEXT_UNDELETED, "<down>" },
263 { OP_MAIN_NEXT_UNDELETED, "<right>" },
264 { OP_MAIN_NEXT_UNDELETED, "j" },
265 { OP_MAIN_PARENT_MESSAGE, "P" },
266 { OP_MAIN_PREV_SUBTHREAD, "\033p" }, // <Alt-p>
267 { OP_MAIN_PREV_THREAD, "\020" }, // <Ctrl-P>
268 { OP_MAIN_PREV_UNDELETED, "<left>" },
269 { OP_MAIN_PREV_UNDELETED, "<up>" },
270 { OP_MAIN_PREV_UNDELETED, "k" },
271 { OP_MAIN_READ_SUBTHREAD, "\033r" }, // <Alt-r>
272 { OP_MAIN_READ_THREAD, "\022" }, // <Ctrl-R>
273 { OP_MAIN_SET_FLAG, "w" },
274 { OP_MAIN_SYNC_FOLDER, "$" },
275 { OP_NEXT_ENTRY, "J" },
276 { OP_NEXT_LINE, "<keypadenter>" },
277 { OP_NEXT_LINE, "\n" }, // <Enter>
278 { OP_NEXT_LINE, "\r" }, // <Return>
279 { OP_NEXT_PAGE, " " }, // <Space>
280 { OP_NEXT_PAGE, "<pagedown>" },
281 { OP_PAGER_BOTTOM, "<end>" },
282 { OP_PAGER_HIDE_QUOTED, "T" },
283 { OP_PAGER_SKIP_HEADERS, "H" },
284 { OP_PAGER_SKIP_QUOTED, "S" },
285 { OP_PAGER_TOP, "<home>" },
286 { OP_PAGER_TOP, "^" },
287 { OP_PIPE, "|" },
288 { OP_PREV_ENTRY, "K" },
289 { OP_PREV_LINE, "<backspace>" },
290 { OP_PREV_PAGE, "-" },
291 { OP_PREV_PAGE, "<pageup>" },
292 { OP_PRINT, "p" },
293 { OP_QUIT, "Q" },
294 { OP_RECALL_MESSAGE, "R" },
295 { OP_REDRAW, "\014" }, // <Ctrl-L>
296 { OP_REPLY, "r" },
297 { OP_RESEND, "\033e" }, // <Alt-e>
298 { OP_SAVE, "s" },
299 { OP_SEARCH, "/" },
300 { OP_SEARCH_NEXT, "n" },
301 { OP_SEARCH_REVERSE, "\033/" }, // <Alt-/>
302 { OP_SEARCH_TOGGLE, "\\" }, // <Backslash>
303 { OP_SHELL_ESCAPE, "!" },
304 { OP_SORT, "o" },
305 { OP_SORT_REVERSE, "O" },
306 { OP_TAG, "t" },
307 { OP_TOGGLE_NEW, "N" },
308 { OP_TOGGLE_WRITE, "%" },
309 { OP_UNDELETE, "u" },
310 { OP_UNDELETE_SUBTHREAD, "\033u" }, // <Alt-u>
311 { OP_UNDELETE_THREAD, "\025" }, // <Ctrl-U>
312 { OP_VERSION, "V" },
313 { OP_VIEW_ATTACHMENTS, "v" },
314 { 0, NULL },
315};
316// clang-format on
317
321void pager_init_keys(struct SubMenu *sm_generic)
322{
323 struct MenuDefinition *md = NULL;
324 struct SubMenu *sm_pager = NULL;
325 struct SubMenu *sm_sidebar = sidebar_get_submenu();
326
327 sm_pager = km_register_submenu(OpPager);
328 md = km_register_menu(MENU_PAGER, "pager");
329 km_menu_add_submenu(md, sm_pager);
330 km_menu_add_submenu(md, sm_sidebar);
332
333 MdPager = md;
334}
335
344static inline bool assert_pager_mode(bool test)
345{
346 if (test)
347 return true;
348
351 return false;
352}
353
362static int up_n_lines(int nlines, struct Line *info, int cur, bool hiding)
363{
364 while ((cur > 0) && (nlines > 0))
365 {
366 cur--;
367 if (!hiding || !COLOR_QUOTED(info[cur].cid))
368 nlines--;
369 }
370
371 return cur;
372}
373
381bool jump_to_bottom(struct PagerPrivateData *priv, struct PagerView *pview)
382{
383 if (!(priv->lines[priv->cur_line].offset < (priv->st.st_size - 1)))
384 {
385 return false;
386 }
387
388 int line_num = priv->cur_line;
389 /* make sure the types are defined to the end of file */
390 while (display_line(priv->fp, &priv->bytes_read, &priv->lines, line_num,
391 &priv->lines_used, &priv->lines_max,
392 priv->has_types | (pview->flags & MUTT_PAGER_NOWRAP),
393 &priv->quote_list, &priv->q_level, &priv->force_redraw,
394 &priv->search_re, priv->pview->win_pager, &priv->ansi_list) == 0)
395 {
396 line_num++;
397 }
398 priv->top_line = up_n_lines(priv->pview->win_pager->state.rows, priv->lines,
399 priv->lines_used, priv->hide_quoted);
401 return true;
402}
403
404// -----------------------------------------------------------------------------
405
409static int op_pager_bottom(struct IndexSharedData *shared,
410 struct PagerPrivateData *priv, const struct KeyEvent *event)
411{
412 if (!jump_to_bottom(priv, priv->pview))
413 mutt_message(_("Bottom of message is shown"));
414
415 return FR_SUCCESS;
416}
417
421static int op_pager_half_down(struct IndexSharedData *shared,
422 struct PagerPrivateData *priv, const struct KeyEvent *event)
423{
424 const bool c_pager_stop = cs_subset_bool(NeoMutt->sub, "pager_stop");
425 if (priv->lines[priv->cur_line].offset < (priv->st.st_size - 1))
426 {
427 priv->top_line = up_n_lines(priv->pview->win_pager->state.rows / 2,
428 priv->lines, priv->cur_line, priv->hide_quoted);
430 }
431 else if (c_pager_stop)
432 {
433 /* emulate "less -q" and don't go on to the next message. */
434 mutt_message(_("Bottom of message is shown"));
435 }
436 else
437 {
438 /* end of the current message, so display the next message. */
440 }
441 return FR_SUCCESS;
442}
443
447static int op_pager_half_up(struct IndexSharedData *shared,
448 struct PagerPrivateData *priv, const struct KeyEvent *event)
449{
450 if (priv->top_line)
451 {
452 priv->top_line = up_n_lines(priv->pview->win_pager->state.rows / 2 +
453 (priv->pview->win_pager->state.rows % 2),
454 priv->lines, priv->top_line, priv->hide_quoted);
456 }
457 else
458 {
459 mutt_message(_("Top of message is shown"));
460 }
461 return FR_SUCCESS;
462}
463
467static int op_pager_hide_quoted(struct IndexSharedData *shared,
468 struct PagerPrivateData *priv, const struct KeyEvent *event)
469{
470 if (!priv->has_types)
471 return FR_NO_ACTION;
472
473 priv->hide_quoted ^= MUTT_HIDE;
474 if (priv->hide_quoted && COLOR_QUOTED(priv->lines[priv->top_line].cid))
475 {
476 priv->top_line = up_n_lines(1, priv->lines, priv->top_line, priv->hide_quoted);
477 }
478 else
479 {
481 }
483 return FR_SUCCESS;
484}
485
489static int op_pager_next_line(struct IndexSharedData *shared,
490 struct PagerPrivateData *priv, const struct KeyEvent *event)
491{
492 if (priv->lines[priv->cur_line].offset < (priv->st.st_size - 1))
493 {
494 priv->top_line++;
495 if (priv->hide_quoted)
496 {
497 while ((priv->top_line < priv->lines_used) &&
498 COLOR_QUOTED(priv->lines[priv->top_line].cid))
499 {
500 priv->top_line++;
501 }
502 }
504 }
505 else
506 {
507 mutt_message(_("Bottom of message is shown"));
508 }
509 return FR_SUCCESS;
510}
511
515static int op_pager_next_page(struct IndexSharedData *shared,
516 struct PagerPrivateData *priv, const struct KeyEvent *event)
517{
518 const bool c_pager_stop = cs_subset_bool(NeoMutt->sub, "pager_stop");
519 if (priv->lines[priv->cur_line].offset < (priv->st.st_size - 1))
520 {
521 const short c_pager_context = cs_subset_number(NeoMutt->sub, "pager_context");
522 priv->top_line = up_n_lines(c_pager_context, priv->lines, priv->cur_line, priv->hide_quoted);
524 }
525 else if (c_pager_stop)
526 {
527 /* emulate "less -q" and don't go on to the next message. */
528 mutt_message(_("Bottom of message is shown"));
529 }
530 else
531 {
532 /* end of the current message, so display the next message. */
534 }
535 return FR_SUCCESS;
536}
537
541static int op_pager_prev_line(struct IndexSharedData *shared,
542 struct PagerPrivateData *priv, const struct KeyEvent *event)
543{
544 if (priv->top_line)
545 {
546 priv->top_line = up_n_lines(1, priv->lines, priv->top_line, priv->hide_quoted);
548 }
549 else
550 {
551 mutt_message(_("Top of message is shown"));
552 }
553 return FR_SUCCESS;
554}
555
559static int op_pager_prev_page(struct IndexSharedData *shared,
560 struct PagerPrivateData *priv, const struct KeyEvent *event)
561{
562 if (priv->top_line == 0)
563 {
564 mutt_message(_("Top of message is shown"));
565 }
566 else
567 {
568 const short c_pager_context = cs_subset_number(NeoMutt->sub, "pager_context");
569 priv->top_line = up_n_lines(priv->pview->win_pager->state.rows - c_pager_context,
570 priv->lines, priv->top_line, priv->hide_quoted);
572 }
573 return FR_SUCCESS;
574}
575
583static int op_pager_search(struct IndexSharedData *shared,
584 struct PagerPrivateData *priv, const struct KeyEvent *event)
585{
586 struct PagerView *pview = priv->pview;
587
588 int rc = FR_NO_ACTION;
589 struct Buffer *buf = buf_pool_get();
590
591 buf_strcpy(buf, priv->search_str);
592 const int op = event->op;
593 if (mw_get_field(((op == OP_SEARCH) || (op == OP_SEARCH_NEXT)) ? _("Search for: ") : _("Reverse search for: "),
595 {
596 goto done;
597 }
598
599 if (mutt_str_equal(buf_string(buf), priv->search_str))
600 {
601 if (priv->search_compiled)
602 {
603 struct KeyEvent event_s = { 0, OP_NULL };
604
605 /* do an implicit search-next */
606 if (op == OP_SEARCH)
607 event_s.op = OP_SEARCH_NEXT;
608 else
609 event_s.op = OP_SEARCH_OPPOSITE;
610
611 priv->wrapped = false;
612 op_pager_search_next(shared, priv, &event_s);
613 }
614 }
615
616 if (buf_is_empty(buf))
617 goto done;
618
619 mutt_str_copy(priv->search_str, buf_string(buf), sizeof(priv->search_str));
620
621 /* leave search_back alone if op == OP_SEARCH_NEXT */
622 if (op == OP_SEARCH)
623 priv->search_back = false;
624 else if (op == OP_SEARCH_REVERSE)
625 priv->search_back = true;
626
627 if (priv->search_compiled)
628 {
629 regfree(&priv->search_re);
630 for (size_t i = 0; i < priv->lines_used; i++)
631 {
632 FREE(&(priv->lines[i].search));
633 priv->lines[i].search_arr_size = -1;
634 }
635 }
636
637 uint16_t rflags = mutt_mb_is_lower(priv->search_str) ? REG_ICASE : 0;
638 int err = REG_COMP(&priv->search_re, priv->search_str, REG_NEWLINE | rflags);
639 if (err != 0)
640 {
641 regerror(err, &priv->search_re, buf->data, buf->dsize);
642 mutt_error("%s", buf_string(buf));
643 for (size_t i = 0; i < priv->lines_max; i++)
644 {
645 /* cleanup */
646 FREE(&(priv->lines[i].search));
647 priv->lines[i].search_arr_size = -1;
648 }
649 priv->search_flag = 0;
650 priv->search_compiled = false;
651 }
652 else
653 {
654 priv->search_compiled = true;
655 /* update the search pointers */
656 int line_num = 0;
657 while (display_line(priv->fp, &priv->bytes_read, &priv->lines, line_num,
658 &priv->lines_used, &priv->lines_max,
659 MUTT_SEARCH | (pview->flags & MUTT_PAGER_NOWRAP) | priv->has_types,
660 &priv->quote_list, &priv->q_level, &priv->force_redraw,
661 &priv->search_re, priv->pview->win_pager, &priv->ansi_list) == 0)
662 {
663 line_num++;
664 }
665
666 if (priv->search_back)
667 {
668 /* searching backward */
669 int i;
670 for (i = priv->top_line; i >= 0; i--)
671 {
672 if ((!priv->hide_quoted || !COLOR_QUOTED(priv->lines[i].cid)) &&
673 !priv->lines[i].cont_line && (priv->lines[i].search_arr_size > 0))
674 {
675 break;
676 }
677 }
678
679 if (i >= 0)
680 priv->top_line = i;
681 }
682 else
683 {
684 /* searching forward */
685 int i;
686 for (i = priv->top_line; i < priv->lines_used; i++)
687 {
688 if ((!priv->hide_quoted || !COLOR_QUOTED(priv->lines[i].cid)) &&
689 !priv->lines[i].cont_line && (priv->lines[i].search_arr_size > 0))
690 {
691 break;
692 }
693 }
694
695 if (i < priv->lines_used)
696 priv->top_line = i;
697 }
698
699 if (priv->lines[priv->top_line].search_arr_size == 0)
700 {
701 priv->search_flag = 0;
702 mutt_error(_("Not found"));
703 }
704 else
705 {
706 const short c_search_context = cs_subset_number(NeoMutt->sub, "search_context");
707 priv->search_flag = MUTT_SEARCH;
708 /* give some context for search results */
709 if (c_search_context < priv->pview->win_pager->state.rows)
710 priv->searchctx = c_search_context;
711 else
712 priv->searchctx = 0;
713 if (priv->top_line - priv->searchctx > 0)
714 priv->top_line -= priv->searchctx;
715 }
716 }
719 rc = FR_SUCCESS;
720
721done:
722 buf_pool_release(&buf);
723 return rc;
724}
725
733static int op_pager_search_next(struct IndexSharedData *shared,
734 struct PagerPrivateData *priv, const struct KeyEvent *event)
735{
736 if (priv->search_compiled)
737 {
738 const short c_search_context = cs_subset_number(NeoMutt->sub, "search_context");
739 priv->wrapped = false;
740
741 if (c_search_context < priv->pview->win_pager->state.rows)
742 priv->searchctx = c_search_context;
743 else
744 priv->searchctx = 0;
745
746 const int op = event->op;
747
748 search_next:
749 if ((!priv->search_back && (op == OP_SEARCH_NEXT)) ||
750 (priv->search_back && (op == OP_SEARCH_OPPOSITE)))
751 {
752 /* searching forward */
753 int i;
754 for (i = priv->wrapped ? 0 : priv->top_line + priv->searchctx + 1;
755 i < priv->lines_used; i++)
756 {
757 if ((!priv->hide_quoted || !COLOR_QUOTED(priv->lines[i].cid)) &&
758 !priv->lines[i].cont_line && (priv->lines[i].search_arr_size > 0))
759 {
760 break;
761 }
762 }
763
764 const bool c_wrap_search = cs_subset_bool(NeoMutt->sub, "wrap_search");
765 if (i < priv->lines_used)
766 {
767 priv->top_line = i;
768 }
769 else if (priv->wrapped || !c_wrap_search)
770 {
771 mutt_error(_("Not found"));
772 }
773 else
774 {
775 mutt_message(_("Search wrapped to top"));
776 priv->wrapped = true;
777 goto search_next;
778 }
779 }
780 else
781 {
782 /* searching backward */
783 int i;
784 for (i = priv->wrapped ? priv->lines_used : priv->top_line + priv->searchctx - 1;
785 i >= 0; i--)
786 {
787 if ((!priv->hide_quoted ||
788 (priv->has_types && !COLOR_QUOTED(priv->lines[i].cid))) &&
789 !priv->lines[i].cont_line && (priv->lines[i].search_arr_size > 0))
790 {
791 break;
792 }
793 }
794
795 const bool c_wrap_search = cs_subset_bool(NeoMutt->sub, "wrap_search");
796 if (i >= 0)
797 {
798 priv->top_line = i;
799 }
800 else if (priv->wrapped || !c_wrap_search)
801 {
802 mutt_error(_("Not found"));
803 }
804 else
805 {
806 mutt_message(_("Search wrapped to bottom"));
807 priv->wrapped = true;
808 goto search_next;
809 }
810 }
811
812 if (priv->lines[priv->top_line].search_arr_size > 0)
813 {
814 priv->search_flag = MUTT_SEARCH;
815 /* give some context for search results */
816 if (priv->top_line - priv->searchctx > 0)
817 priv->top_line -= priv->searchctx;
818 }
819
821 return FR_SUCCESS;
822 }
823
824 /* no previous search pattern */
825 return op_pager_search(shared, priv, event);
826}
827
831static int op_pager_skip_headers(struct IndexSharedData *shared,
832 struct PagerPrivateData *priv, const struct KeyEvent *event)
833{
834 struct PagerView *pview = priv->pview;
835
836 if (!priv->has_types)
837 return FR_NO_ACTION;
838
839 int rc = 0;
840 int new_topline = 0;
841
842 while (((new_topline < priv->lines_used) ||
843 (0 == (rc = display_line(priv->fp, &priv->bytes_read, &priv->lines,
844 new_topline, &priv->lines_used, &priv->lines_max,
845 MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP), &priv->quote_list,
846 &priv->q_level, &priv->force_redraw, &priv->search_re,
847 priv->pview->win_pager, &priv->ansi_list)))) &&
848 color_is_header(priv->lines[new_topline].cid))
849 {
850 new_topline++;
851 }
852
853 if (rc < 0)
854 {
855 /* L10N: Displayed if <skip-headers> is invoked in the pager, but
856 there is no text past the headers.
857 (I don't think this is actually possible in Mutt's code, but
858 display some kind of message in case it somehow occurs.) */
859 mutt_warning(_("No text past headers"));
860 return FR_NO_ACTION;
861 }
862 priv->top_line = new_topline;
864 return FR_SUCCESS;
865}
866
870static int op_pager_skip_quoted(struct IndexSharedData *shared,
871 struct PagerPrivateData *priv, const struct KeyEvent *event)
872{
873 struct PagerView *pview = priv->pview;
874
875 if (!priv->has_types)
876 return FR_NO_ACTION;
877
878 const short c_pager_skip_quoted_context = cs_subset_number(NeoMutt->sub, "pager_skip_quoted_context");
879 int rc = 0;
880 int new_topline = priv->top_line;
881 int num_quoted = 0;
882
883 /* In a header? Skip all the email headers, and done */
884 if (color_is_header(priv->lines[new_topline].cid))
885 {
886 while (((new_topline < priv->lines_used) ||
887 (0 == (rc = display_line(priv->fp, &priv->bytes_read, &priv->lines,
888 new_topline, &priv->lines_used, &priv->lines_max,
889 MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP), &priv->quote_list,
890 &priv->q_level, &priv->force_redraw, &priv->search_re,
891 priv->pview->win_pager, &priv->ansi_list)))) &&
892 color_is_header(priv->lines[new_topline].cid))
893 {
894 new_topline++;
895 }
896 priv->top_line = new_topline;
898 return FR_SUCCESS;
899 }
900
901 /* Already in the body? Skip past previous "context" quoted lines */
902 if (c_pager_skip_quoted_context > 0)
903 {
904 while (((new_topline < priv->lines_used) ||
905 (0 == (rc = display_line(priv->fp, &priv->bytes_read, &priv->lines,
906 new_topline, &priv->lines_used, &priv->lines_max,
907 MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP), &priv->quote_list,
908 &priv->q_level, &priv->force_redraw, &priv->search_re,
909 priv->pview->win_pager, &priv->ansi_list)))) &&
910 COLOR_QUOTED(priv->lines[new_topline].cid))
911 {
912 new_topline++;
913 num_quoted++;
914 }
915
916 if (rc < 0)
917 {
918 mutt_error(_("No more unquoted text after quoted text"));
919 return FR_NO_ACTION;
920 }
921 }
922
923 if (num_quoted <= c_pager_skip_quoted_context)
924 {
925 num_quoted = 0;
926
927 while (((new_topline < priv->lines_used) ||
928 (0 == (rc = display_line(priv->fp, &priv->bytes_read, &priv->lines,
929 new_topline, &priv->lines_used, &priv->lines_max,
930 MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP), &priv->quote_list,
931 &priv->q_level, &priv->force_redraw, &priv->search_re,
932 priv->pview->win_pager, &priv->ansi_list)))) &&
933 !COLOR_QUOTED(priv->lines[new_topline].cid))
934 {
935 new_topline++;
936 }
937
938 if (rc < 0)
939 {
940 mutt_error(_("No more quoted text"));
941 return FR_NO_ACTION;
942 }
943
944 while (((new_topline < priv->lines_used) ||
945 (0 == (rc = display_line(priv->fp, &priv->bytes_read, &priv->lines,
946 new_topline, &priv->lines_used, &priv->lines_max,
947 MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP), &priv->quote_list,
948 &priv->q_level, &priv->force_redraw, &priv->search_re,
949 priv->pview->win_pager, &priv->ansi_list)))) &&
950 COLOR_QUOTED(priv->lines[new_topline].cid))
951 {
952 new_topline++;
953 num_quoted++;
954 }
955
956 if (rc < 0)
957 {
958 mutt_error(_("No more unquoted text after quoted text"));
959 return FR_NO_ACTION;
960 }
961 }
962 priv->top_line = new_topline - MIN(c_pager_skip_quoted_context, num_quoted);
964 return FR_SUCCESS;
965}
966
970static int op_pager_top(struct IndexSharedData *shared,
971 struct PagerPrivateData *priv, const struct KeyEvent *event)
972{
973 if (priv->top_line == 0)
974 {
975 mutt_message(_("Top of message is shown"));
976 }
977 else
978 {
979 priv->top_line = 0;
981 }
982
983 return FR_SUCCESS;
984}
985
986// -----------------------------------------------------------------------------
987
991static int op_exit(struct IndexSharedData *shared,
992 struct PagerPrivateData *priv, const struct KeyEvent *event)
993{
994 priv->rc = -1;
995 priv->loop = PAGER_LOOP_QUIT;
996 return FR_DONE;
997}
998
1002static int op_help(struct IndexSharedData *shared,
1003 struct PagerPrivateData *priv, const struct KeyEvent *event)
1004{
1005 if (priv->pview->mode == PAGER_MODE_HELP)
1006 {
1007 /* don't let the user enter the help-menu from the help screen! */
1008 mutt_error(_("Help is currently being shown"));
1009 return FR_ERROR;
1010 }
1013 return FR_SUCCESS;
1014}
1015
1019static int op_save(struct IndexSharedData *shared,
1020 struct PagerPrivateData *priv, const struct KeyEvent *event)
1021{
1022 struct PagerView *pview = priv->pview;
1023 if (pview->mode != PAGER_MODE_OTHER)
1024 return FR_UNKNOWN;
1025
1026 if (!priv->fp)
1027 return FR_UNKNOWN;
1028
1029 int rc = FR_ERROR;
1030 FILE *fp_save = NULL;
1031 struct Buffer *buf = buf_pool_get();
1032
1033 // Save the current read position
1034 long pos = ftell(priv->fp);
1035 rewind(priv->fp);
1036
1037 struct FileCompletionData cdata = { false, NULL, NULL, NULL, NULL };
1038 if ((mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
1039 &CompleteFileOps, &cdata) != 0) ||
1040 buf_is_empty(buf))
1041 {
1042 rc = FR_SUCCESS;
1043 goto done;
1044 }
1045
1046 expand_path(buf, false);
1047 fp_save = mutt_file_fopen(buf_string(buf), "a+");
1048 if (!fp_save)
1049 {
1050 mutt_perror("%s", buf_string(buf));
1051 goto done;
1052 }
1053
1054 int bytes = mutt_file_copy_stream(priv->fp, fp_save);
1055 if (bytes == -1)
1056 {
1057 mutt_perror("%s", buf_string(buf));
1058 goto done;
1059 }
1060
1061 mutt_message(_("Saved to: %s"), buf_string(buf));
1062 rc = FR_SUCCESS;
1063
1064done:
1065 // Restore the read position (rewound at start of function)
1066 if (pos >= 0)
1067 (void) mutt_file_seek(priv->fp, pos, SEEK_SET);
1068
1069 mutt_file_fclose(&fp_save);
1070 buf_pool_release(&buf);
1071
1072 return rc;
1073}
1074
1078static int op_search_toggle(struct IndexSharedData *shared,
1079 struct PagerPrivateData *priv, const struct KeyEvent *event)
1080{
1081 if (priv->search_compiled)
1082 {
1083 priv->search_flag ^= MUTT_SEARCH;
1085 }
1086 return FR_SUCCESS;
1087}
1088
1092static int op_view_attachments(struct IndexSharedData *shared,
1093 struct PagerPrivateData *priv, const struct KeyEvent *event)
1094{
1095 struct PagerView *pview = priv->pview;
1096
1097 // This needs to be delegated
1098 if (pview->flags & MUTT_PAGER_ATTACHMENT)
1099 return FR_UNKNOWN;
1100
1101 if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
1102 return FR_NOT_IMPL;
1103 dlg_attach(NeoMutt->sub, shared->mailbox_view, shared->email,
1104 pview->pdata->fp, shared->attach_msg);
1105 if (shared->email->attach_del)
1106 shared->mailbox->changed = true;
1108 return FR_SUCCESS;
1109}
1110
1111// -----------------------------------------------------------------------------
1112
1116static const struct PagerFunction PagerFunctions[] = {
1117 // clang-format off
1118 { OP_EXIT, op_exit },
1119 { OP_HALF_DOWN, op_pager_half_down },
1120 { OP_HALF_UP, op_pager_half_up },
1121 { OP_HELP, op_help },
1122 { OP_NEXT_LINE, op_pager_next_line },
1123 { OP_NEXT_PAGE, op_pager_next_page },
1124 { OP_PAGER_BOTTOM, op_pager_bottom },
1125 { OP_PAGER_HIDE_QUOTED, op_pager_hide_quoted },
1126 { OP_PAGER_SKIP_HEADERS, op_pager_skip_headers },
1127 { OP_PAGER_SKIP_QUOTED, op_pager_skip_quoted },
1128 { OP_PAGER_TOP, op_pager_top },
1129 { OP_PREV_LINE, op_pager_prev_line },
1130 { OP_PREV_PAGE, op_pager_prev_page },
1131 { OP_SAVE, op_save },
1132 { OP_SEARCH, op_pager_search },
1133 { OP_SEARCH_REVERSE, op_pager_search },
1134 { OP_SEARCH_NEXT, op_pager_search_next },
1135 { OP_SEARCH_OPPOSITE, op_pager_search_next },
1136 { OP_SEARCH_TOGGLE, op_search_toggle },
1137 { OP_VIEW_ATTACHMENTS, op_view_attachments },
1138 { 0, NULL },
1139 // clang-format on
1140};
1141
1145int pager_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
1146{
1147 if (!win || !event)
1148 {
1150 return FR_ERROR;
1151 }
1152
1153 struct PagerPrivateData *priv = win->parent->wdata;
1154 if (!priv)
1155 return FR_ERROR;
1156
1157 struct MuttWindow *dlg = dialog_find(win);
1158 if (!dlg || !dlg->wdata)
1159 return FR_ERROR;
1160
1161 const int op = event->op;
1162 int rc = FR_UNKNOWN;
1163 for (size_t i = 0; PagerFunctions[i].op != OP_NULL; i++)
1164 {
1165 const struct PagerFunction *fn = &PagerFunctions[i];
1166 if (fn->op == op)
1167 {
1168 struct IndexSharedData *shared = dlg->wdata;
1169 rc = fn->function(shared, priv, event);
1170 break;
1171 }
1172 }
1173
1174 if (rc == FR_UNKNOWN) // Not our function
1175 return rc;
1176
1177 const char *result = dispatcher_get_retval_name(rc);
1178 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
1179
1180 return rc;
1181}
GUI display the mailboxes in a side panel.
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition complete.c:152
Select a Mailbox from a list.
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
Color and attribute parsing.
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition helpers.c:143
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_DONE
Exit the Dialog.
Definition dispatcher.h:36
@ FR_UNKNOWN
Unknown function.
Definition dispatcher.h:34
@ FR_ERROR
Valid function - error occurred.
Definition dispatcher.h:39
@ FR_NOT_IMPL
Invalid function - feature not enabled.
Definition dispatcher.h:37
@ FR_NO_ACTION
Valid function - no action performed.
Definition dispatcher.h:38
bool color_is_header(enum ColorId cid)
Colour is for an Email header.
Definition display.c:487
int display_line(FILE *fp, LOFF_T *bytes_read, struct Line **lines, int line_num, int *lines_used, int *lines_max, PagerFlags flags, struct QuoteStyle **quote_list, int *q_level, bool *force_redraw, regex_t *search_re, struct MuttWindow *win_pager, struct AttrColorList *ansi_list)
Print a line on screen.
Definition display.c:1053
Pager Display.
void pager_queue_redraw(struct PagerPrivateData *priv, PagerRedrawFlags redraw)
Queue a request for a redraw.
Definition dlg_pager.c:125
Edit a string.
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition wdata.h:43
Structs that make up an email.
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:224
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:648
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition get.c:65
#define MFF_DEPRECATED
Redraw the pager.
Definition get.h:44
static int op_exit(struct AliasMenuData *mdata, const struct KeyEvent *event)
exit this menu - Implements alias_function_t -
Definition functions.c:234
int pager_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
Perform a Pager function - Implements function_dispatcher_t -.
Definition functions.c:1145
static int op_help(struct EnterWindowData *wdata, const struct KeyEvent *event)
Display Help - Implements enter_function_t -.
Definition functions.c:452
void dlg_attach(struct ConfigSubset *sub, struct MailboxView *mv, struct Email *e, FILE *fp, bool attach_msg)
Show the attachments in a Menu -.
Definition dlg_attach.c:207
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition window.c:463
static int op_view_attachments(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Show MIME attachments - Implements index_function_t -.
Definition functions.c:2651
static int op_save(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Make decrypted copy - Implements index_function_t -.
Definition functions.c:2375
#define mutt_warning(...)
Definition logging2.h:92
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define mutt_perror(...)
Definition logging2.h:95
static int op_pager_search(struct IndexSharedData *shared, struct PagerPrivateData *priv, const struct KeyEvent *event)
Search for a regular expression - Implements pager_function_t -.
Definition functions.c:583
static int op_pager_hide_quoted(struct IndexSharedData *shared, struct PagerPrivateData *priv, const struct KeyEvent *event)
Toggle display of quoted text - Implements pager_function_t -.
Definition functions.c:467
static int op_pager_skip_quoted(struct IndexSharedData *shared, struct PagerPrivateData *priv, const struct KeyEvent *event)
Skip beyond quoted text - Implements pager_function_t -.
Definition functions.c:870
static int op_pager_bottom(struct IndexSharedData *shared, struct PagerPrivateData *priv, const struct KeyEvent *event)
Jump to the bottom of the message - Implements pager_function_t -.
Definition functions.c:409
static int op_pager_skip_headers(struct IndexSharedData *shared, struct PagerPrivateData *priv, const struct KeyEvent *event)
Jump to first line after headers - Implements pager_function_t -.
Definition functions.c:831
static int op_pager_half_up(struct IndexSharedData *shared, struct PagerPrivateData *priv, const struct KeyEvent *event)
Scroll up 1/2 page - Implements pager_function_t -.
Definition functions.c:447
static int op_pager_prev_page(struct IndexSharedData *shared, struct PagerPrivateData *priv, const struct KeyEvent *event)
Move to the previous page - Implements pager_function_t -.
Definition functions.c:559
static int op_pager_search_next(struct IndexSharedData *shared, struct PagerPrivateData *priv, const struct KeyEvent *event)
Search for next match - Implements pager_function_t -.
Definition functions.c:733
static int op_pager_next_page(struct IndexSharedData *shared, struct PagerPrivateData *priv, const struct KeyEvent *event)
Move to the next page - Implements pager_function_t -.
Definition functions.c:515
static int op_pager_next_line(struct IndexSharedData *shared, struct PagerPrivateData *priv, const struct KeyEvent *event)
Scroll down one line - Implements pager_function_t -.
Definition functions.c:489
static int op_pager_prev_line(struct IndexSharedData *shared, struct PagerPrivateData *priv, const struct KeyEvent *event)
Scroll up one line - Implements pager_function_t -.
Definition functions.c:541
static int op_pager_top(struct IndexSharedData *shared, struct PagerPrivateData *priv, const struct KeyEvent *event)
Jump to the top of the message - Implements pager_function_t -.
Definition functions.c:970
static int op_pager_half_down(struct IndexSharedData *shared, struct PagerPrivateData *priv, const struct KeyEvent *event)
Scroll down 1/2 page - Implements pager_function_t -.
Definition functions.c:421
static int op_search_toggle(struct IndexSharedData *shared, struct PagerPrivateData *priv, const struct KeyEvent *event)
Toggle search pattern coloring - Implements pager_function_t -.
Definition functions.c:1078
Convenience wrapper for the gui headers.
void mutt_help(const struct MenuDefinition *md)
Display the Help Page.
Definition help.c:147
Read/write command history from/to a file.
@ HC_FILE
Files.
Definition lib.h:58
@ HC_PATTERN
Patterns.
Definition lib.h:59
bool index_next_undeleted(struct MuttWindow *win_index)
Select the next undeleted Email (if possible)
Definition functions.c:398
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
void km_menu_add_bindings(struct MenuDefinition *md, const struct MenuOpSeq bindings[])
Add Keybindings to a Menu.
Definition init.c:136
Manage keymappings.
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
Definition mbyte.c:355
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MIN(a, b)
Return the minimum of two values.
Definition memory.h:40
GUI present the user with a selectable list.
Convenience wrapper for the library headers.
#define N_(a)
Definition message.h:32
#define _(a)
Definition message.h:28
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
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:665
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition string.c:586
Many unsorted constants and some structs.
void expand_path(struct Buffer *buf, bool regex)
Create the canonical path.
Definition muttlib.c:122
Some miscellaneous functions.
@ NT_PAGER
Pager data has changed, NotifyPager, PagerPrivateData.
Definition notify_type.h:53
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition opcodes.c:48
struct MenuDefinition * MdPager
Pager Menu Definition.
Definition functions.c:64
void pager_init_keys(struct SubMenu *sm_generic)
Initialise the Pager Keybindings - Implements ::init_keys_api.
Definition functions.c:321
static int up_n_lines(int nlines, struct Line *info, int cur, bool hiding)
Reposition the pager's view up by n lines.
Definition functions.c:362
static const char * Not_available_in_this_menu
Error message for unavailable functions.
Definition functions.c:57
static const struct MenuOpSeq PagerDefaultBindings[]
Key bindings for the Pager Menu.
Definition functions.c:217
static const struct MenuFuncOp OpPager[]
Functions for the Pager Menu.
Definition functions.c:70
bool jump_to_bottom(struct PagerPrivateData *priv, struct PagerView *pview)
Make sure the bottom line is displayed.
Definition functions.c:381
static bool assert_pager_mode(bool test)
Check that pager is in correct mode.
Definition functions.c:344
static const struct PagerFunction PagerFunctions[]
All the NeoMutt functions that the Pager supports.
Definition functions.c:1116
Pager functions.
GUI display a file/email/help in a viewport with paging.
@ PAGER_LOOP_QUIT
Quit the Pager.
Definition lib.h:153
#define NT_PAGER_VIEW
Pager View has changed.
Definition lib.h:187
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition lib.h:73
#define MUTT_HIDE
Don't show quoted text.
Definition lib.h:65
#define MUTT_TYPES
Compute line's type.
Definition lib.h:67
#define MUTT_SEARCH
Resolve search patterns.
Definition lib.h:66
@ PAGER_MODE_OTHER
Pager is invoked via 3rd path. Non-email content is likely to be shown.
Definition lib.h:142
@ PAGER_MODE_HELP
Pager is invoked via 3rd path to show help.
Definition lib.h:141
@ PAGER_MODE_EMAIL
Pager is invoked via 1st path. The mime part is selected automatically.
Definition lib.h:138
#define PAGER_REDRAW_PAGER
Redraw the pager.
Definition lib.h:191
#define MUTT_PAGER_ATTACHMENT
Attachments may exist.
Definition lib.h:72
Private state data for the Pager.
const struct CompleteOps CompletePatternOps
Auto-Completion of Patterns.
Definition complete.c:98
Match patterns to emails.
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
#define COLOR_QUOTED(cid)
Definition quoted.h:28
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition regex3.h:49
struct SubMenu * sidebar_get_submenu(void)
Get the Sidebar SubMenu.
Definition functions.c:106
GUI display the mailboxes in a side panel.
#define NONULL(x)
Definition string2.h:44
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
bool attach_del
Has an attachment marked for deletion.
Definition email.h:99
Input for the file completion function.
Definition curs_lib.h:39
Data shared between Index, Pager and Sidebar.
Definition shared_data.h:37
struct Email * email
Currently selected Email.
Definition shared_data.h:42
struct Mailbox * mailbox
Current Mailbox.
Definition shared_data.h:41
bool attach_msg
Are we in "attach message" mode?
Definition shared_data.h:46
struct MailboxView * mailbox_view
Current Mailbox view.
Definition shared_data.h:40
An event such as a keypress.
Definition get.h:50
int op
Function opcode, e.g. OP_HELP.
Definition get.h:52
A line of text in the pager.
Definition display.h:50
short search_arr_size
Number of items in search array.
Definition display.h:59
struct TextSyntax * search
Array of search text in the line.
Definition display.h:60
bool cont_line
Continuation of a previous line (wrapped by NeoMutt)
Definition display.h:53
short cid
Default line colour, e.g. MT_COLOR_SIGNATURE.
Definition display.h:52
LOFF_T offset
Offset into Email file (PagerPrivateData->fp)
Definition display.h:51
bool changed
Mailbox has been modified.
Definition mailbox.h:109
Functions for a Dialog or Window.
Definition menu.h:80
Mapping between a function and an operation.
Definition menu.h:38
Mapping between an operation and a key sequence.
Definition menu.h:48
struct WindowState state
Current state of the Window.
void * wdata
Private data.
struct MuttWindow * parent
Parent Window.
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
FILE * fp
Source stream.
Definition lib.h:163
A NeoMutt function.
Definition functions.h:57
pager_function_t function
Function to call.
Definition functions.h:59
int op
Op code, e.g. OP_MAIN_LIMIT.
Definition functions.h:58
Private state data for the Pager.
PagerFlags hide_quoted
Set to MUTT_HIDE when quoted email is hidden <toggle-quoted>
int rc
Return code from functions.
int q_level
Number of unique quoting levels.
int cur_line
Current line (last line visible on screen)
bool wrapped
Has the search/next wrapped around?
int lines_used
Size of lines array (used entries)
char search_str[256]
Current search string.
int lines_max
Capacity of lines array (total entries)
bool force_redraw
Repaint is needed.
enum PagerLoopMode loop
What the Event Loop should do next, e.g. PAGER_LOOP_CONTINUE.
struct Line * lines
Array of text lines in pager.
int has_types
Set to MUTT_TYPES for PAGER_MODE_EMAIL or MUTT_SHOWCOLOR.
struct Notify * notify
Notifications: NotifyPager, PagerPrivateData.
LOFF_T bytes_read
Number of bytes read from file.
int top_line
First visible line on screen.
struct stat st
Stats about Email file.
bool search_back
Search backwards.
struct QuoteStyle * quote_list
Tree of quoting levels.
struct PagerView * pview
Object to view in the pager.
struct AttrColorList ansi_list
List of ANSI colours used in the Pager.
int searchctx
Space to show around search matches.
regex_t search_re
Compiled search string.
FILE * fp
File containing decrypted/decoded/weeded Email.
PagerFlags search_flag
Set to MUTT_SEARCH when search results are visible <search-toggle>
bool search_compiled
Search regex is in use.
Paged view into some data.
Definition lib.h:172
struct MuttWindow * win_index
Index Window.
Definition lib.h:178
struct PagerData * pdata
Data that pager displays. NOTNULL.
Definition lib.h:173
enum PagerMode mode
Pager mode.
Definition lib.h:174
PagerFlags flags
Additional settings to tweak pager's function.
Definition lib.h:175
struct MuttWindow * win_pager
Pager Window.
Definition lib.h:180
Collection of related functions.
Definition menu.h:68
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition mutt_window.h:61
@ MENU_PAGER
Pager pager (email viewer)
Definition type.h:45