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