NeoMutt  2024-12-12-14-g7b49f7
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 || !COLOR_QUOTED(info[cur].cid))
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 && COLOR_QUOTED(priv->lines[priv->top_line].cid))
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 COLOR_QUOTED(priv->lines[priv->top_line].cid))
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 || !COLOR_QUOTED(priv->lines[i].cid)) &&
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 || !COLOR_QUOTED(priv->lines[i].cid)) &&
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 || !COLOR_QUOTED(priv->lines[i].cid)) &&
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 ||
779 (priv->has_types && !COLOR_QUOTED(priv->lines[i].cid))) &&
780 !priv->lines[i].cont_line && (priv->lines[i].search_arr_size > 0))
781 {
782 break;
783 }
784 }
785
786 const bool c_wrap_search = cs_subset_bool(NeoMutt->sub, "wrap_search");
787 if (i >= 0)
788 {
789 priv->top_line = i;
790 }
791 else if (priv->wrapped || !c_wrap_search)
792 {
793 mutt_error(_("Not found"));
794 }
795 else
796 {
797 mutt_message(_("Search wrapped to bottom"));
798 priv->wrapped = true;
799 goto search_next;
800 }
801 }
802
803 if (priv->lines[priv->top_line].search_arr_size > 0)
804 {
805 priv->search_flag = MUTT_SEARCH;
806 /* give some context for search results */
807 if (priv->top_line - priv->searchctx > 0)
808 priv->top_line -= priv->searchctx;
809 }
810
812 return FR_SUCCESS;
813 }
814
815 /* no previous search pattern */
816 return op_pager_search(shared, priv, op);
817}
818
822static int op_pager_skip_headers(struct IndexSharedData *shared,
823 struct PagerPrivateData *priv, int op)
824{
825 struct PagerView *pview = priv->pview;
826
827 if (!priv->has_types)
828 return FR_NO_ACTION;
829
830 int rc = 0;
831 int new_topline = 0;
832
833 while (((new_topline < priv->lines_used) ||
834 (0 == (rc = display_line(priv->fp, &priv->bytes_read, &priv->lines,
835 new_topline, &priv->lines_used, &priv->lines_max,
836 MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP), &priv->quote_list,
837 &priv->q_level, &priv->force_redraw, &priv->search_re,
838 priv->pview->win_pager, &priv->ansi_list)))) &&
839 color_is_header(priv->lines[new_topline].cid))
840 {
841 new_topline++;
842 }
843
844 if (rc < 0)
845 {
846 /* L10N: Displayed if <skip-headers> is invoked in the pager, but
847 there is no text past the headers.
848 (I don't think this is actually possible in Mutt's code, but
849 display some kind of message in case it somehow occurs.) */
850 mutt_warning(_("No text past headers"));
851 return FR_NO_ACTION;
852 }
853 priv->top_line = new_topline;
855 return FR_SUCCESS;
856}
857
861static int op_pager_skip_quoted(struct IndexSharedData *shared,
862 struct PagerPrivateData *priv, int op)
863{
864 struct PagerView *pview = priv->pview;
865
866 if (!priv->has_types)
867 return FR_NO_ACTION;
868
869 const short c_pager_skip_quoted_context = cs_subset_number(NeoMutt->sub, "pager_skip_quoted_context");
870 int rc = 0;
871 int new_topline = priv->top_line;
872 int num_quoted = 0;
873
874 /* In a header? Skip all the email headers, and done */
875 if (color_is_header(priv->lines[new_topline].cid))
876 {
877 while (((new_topline < priv->lines_used) ||
878 (0 == (rc = display_line(priv->fp, &priv->bytes_read, &priv->lines,
879 new_topline, &priv->lines_used, &priv->lines_max,
880 MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP), &priv->quote_list,
881 &priv->q_level, &priv->force_redraw, &priv->search_re,
882 priv->pview->win_pager, &priv->ansi_list)))) &&
883 color_is_header(priv->lines[new_topline].cid))
884 {
885 new_topline++;
886 }
887 priv->top_line = new_topline;
889 return FR_SUCCESS;
890 }
891
892 /* Already in the body? Skip past previous "context" quoted lines */
893 if (c_pager_skip_quoted_context > 0)
894 {
895 while (((new_topline < priv->lines_used) ||
896 (0 == (rc = display_line(priv->fp, &priv->bytes_read, &priv->lines,
897 new_topline, &priv->lines_used, &priv->lines_max,
898 MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP), &priv->quote_list,
899 &priv->q_level, &priv->force_redraw, &priv->search_re,
900 priv->pview->win_pager, &priv->ansi_list)))) &&
901 COLOR_QUOTED(priv->lines[new_topline].cid))
902 {
903 new_topline++;
904 num_quoted++;
905 }
906
907 if (rc < 0)
908 {
909 mutt_error(_("No more unquoted text after quoted text"));
910 return FR_NO_ACTION;
911 }
912 }
913
914 if (num_quoted <= c_pager_skip_quoted_context)
915 {
916 num_quoted = 0;
917
918 while (((new_topline < priv->lines_used) ||
919 (0 == (rc = display_line(priv->fp, &priv->bytes_read, &priv->lines,
920 new_topline, &priv->lines_used, &priv->lines_max,
921 MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP), &priv->quote_list,
922 &priv->q_level, &priv->force_redraw, &priv->search_re,
923 priv->pview->win_pager, &priv->ansi_list)))) &&
924 !COLOR_QUOTED(priv->lines[new_topline].cid))
925 {
926 new_topline++;
927 }
928
929 if (rc < 0)
930 {
931 mutt_error(_("No more quoted text"));
932 return FR_NO_ACTION;
933 }
934
935 while (((new_topline < priv->lines_used) ||
936 (0 == (rc = display_line(priv->fp, &priv->bytes_read, &priv->lines,
937 new_topline, &priv->lines_used, &priv->lines_max,
938 MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP), &priv->quote_list,
939 &priv->q_level, &priv->force_redraw, &priv->search_re,
940 priv->pview->win_pager, &priv->ansi_list)))) &&
941 COLOR_QUOTED(priv->lines[new_topline].cid))
942 {
943 new_topline++;
944 num_quoted++;
945 }
946
947 if (rc < 0)
948 {
949 mutt_error(_("No more unquoted text after quoted text"));
950 return FR_NO_ACTION;
951 }
952 }
953 priv->top_line = new_topline - MIN(c_pager_skip_quoted_context, num_quoted);
955 return FR_SUCCESS;
956}
957
961static int op_pager_top(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
962{
963 if (priv->top_line)
964 priv->top_line = 0;
965 else
966 mutt_message(_("Top of message is shown"));
967 return FR_SUCCESS;
968}
969
970// -----------------------------------------------------------------------------
971
975static int op_exit(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
976{
977 priv->rc = -1;
978 priv->loop = PAGER_LOOP_QUIT;
979 return FR_DONE;
980}
981
985static int op_help(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
986{
987 if (priv->pview->mode == PAGER_MODE_HELP)
988 {
989 /* don't let the user enter the help-menu from the help screen! */
990 mutt_error(_("Help is currently being shown"));
991 return FR_ERROR;
992 }
995 return FR_SUCCESS;
996}
997
1001static int op_save(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
1002{
1003 struct PagerView *pview = priv->pview;
1004 if (pview->mode != PAGER_MODE_OTHER)
1005 return FR_UNKNOWN;
1006
1007 if (!priv->fp)
1008 return FR_UNKNOWN;
1009
1010 int rc = FR_ERROR;
1011 FILE *fp_save = NULL;
1012 struct Buffer *buf = buf_pool_get();
1013
1014 // Save the current read position
1015 long pos = ftell(priv->fp);
1016 rewind(priv->fp);
1017
1018 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
1019 if ((mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
1020 &CompleteFileOps, &cdata) != 0) ||
1021 buf_is_empty(buf))
1022 {
1023 rc = FR_SUCCESS;
1024 goto done;
1025 }
1026
1027 buf_expand_path(buf);
1028 fp_save = mutt_file_fopen(buf_string(buf), "a+");
1029 if (!fp_save)
1030 {
1031 mutt_perror("%s", buf_string(buf));
1032 goto done;
1033 }
1034
1035 int bytes = mutt_file_copy_stream(priv->fp, fp_save);
1036 if (bytes == -1)
1037 {
1038 mutt_perror("%s", buf_string(buf));
1039 goto done;
1040 }
1041
1042 // Restore the read position
1043 if (pos >= 0)
1044 mutt_file_seek(priv->fp, pos, SEEK_CUR);
1045
1046 mutt_message(_("Saved to: %s"), buf_string(buf));
1047 rc = FR_SUCCESS;
1048
1049done:
1050 mutt_file_fclose(&fp_save);
1051 buf_pool_release(&buf);
1052
1053 return rc;
1054}
1055
1059static int op_search_toggle(struct IndexSharedData *shared,
1060 struct PagerPrivateData *priv, int op)
1061{
1062 if (priv->search_compiled)
1063 {
1064 priv->search_flag ^= MUTT_SEARCH;
1066 }
1067 return FR_SUCCESS;
1068}
1069
1073static int op_view_attachments(struct IndexSharedData *shared,
1074 struct PagerPrivateData *priv, int op)
1075{
1076 struct PagerView *pview = priv->pview;
1077
1078 // This needs to be delegated
1079 if (pview->flags & MUTT_PAGER_ATTACHMENT)
1080 return FR_UNKNOWN;
1081
1082 if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
1083 return FR_NOT_IMPL;
1084 dlg_attachment(NeoMutt->sub, shared->mailbox_view, shared->email,
1085 pview->pdata->fp, shared->attach_msg);
1086 if (shared->email->attach_del)
1087 shared->mailbox->changed = true;
1089 return FR_SUCCESS;
1090}
1091
1092// -----------------------------------------------------------------------------
1093
1097static const struct PagerFunction PagerFunctions[] = {
1098 // clang-format off
1099 { OP_EXIT, op_exit },
1100 { OP_HALF_DOWN, op_pager_half_down },
1101 { OP_HALF_UP, op_pager_half_up },
1102 { OP_HELP, op_help },
1103 { OP_NEXT_LINE, op_pager_next_line },
1104 { OP_NEXT_PAGE, op_pager_next_page },
1105 { OP_PAGER_BOTTOM, op_pager_bottom },
1106 { OP_PAGER_HIDE_QUOTED, op_pager_hide_quoted },
1107 { OP_PAGER_SKIP_HEADERS, op_pager_skip_headers },
1108 { OP_PAGER_SKIP_QUOTED, op_pager_skip_quoted },
1109 { OP_PAGER_TOP, op_pager_top },
1110 { OP_PREV_LINE, op_pager_prev_line },
1111 { OP_PREV_PAGE, op_pager_prev_page },
1112 { OP_SAVE, op_save },
1113 { OP_SEARCH, op_pager_search },
1114 { OP_SEARCH_REVERSE, op_pager_search },
1115 { OP_SEARCH_NEXT, op_pager_search_next },
1116 { OP_SEARCH_OPPOSITE, op_pager_search_next },
1117 { OP_SEARCH_TOGGLE, op_search_toggle },
1118 { OP_VIEW_ATTACHMENTS, op_view_attachments },
1119 { 0, NULL },
1120 // clang-format on
1121};
1122
1127{
1128 if (!win)
1129 {
1131 return FR_ERROR;
1132 }
1133
1134 struct PagerPrivateData *priv = win->parent->wdata;
1135 if (!priv)
1136 return FR_ERROR;
1137
1138 struct MuttWindow *dlg = dialog_find(win);
1139 if (!dlg || !dlg->wdata)
1140 return FR_ERROR;
1141
1142 int rc = FR_UNKNOWN;
1143 for (size_t i = 0; PagerFunctions[i].op != OP_NULL; i++)
1144 {
1145 const struct PagerFunction *fn = &PagerFunctions[i];
1146 if (fn->op == op)
1147 {
1148 struct IndexSharedData *shared = dlg->wdata;
1149 rc = fn->function(shared, priv, op);
1150 break;
1151 }
1152 }
1153
1154 if (rc == FR_UNKNOWN) // Not our function
1155 return rc;
1156
1157 const char *result = dispatcher_get_retval_name(rc);
1158 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
1159
1160 return rc;
1161}
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.
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
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:1052
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:201
int pager_function_dispatcher(struct MuttWindow *win, int op)
Perform a Pager function - Implements function_dispatcher_t -.
Definition: functions.c:1126
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:208
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:2477
static int op_save(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Make decrypted copy - Implements index_function_t -.
Definition: functions.c:2211
#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:861
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:822
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:1059
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:961
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:56
@ HC_PATTERN
Patterns.
Definition: lib.h:57
bool index_next_undeleted(struct MuttWindow *win_index)
Select the next undeleted Email (if possible)
Definition: functions.c:390
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:1097
@ 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:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
Prototypes for many functions.
#define COLOR_QUOTED(cid)
Definition: quoted.h:39
#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: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: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:127
void * wdata
Private data.
Definition: mutt_window.h:145
struct MuttWindow * parent
Parent Window.
Definition: mutt_window.h:135
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:62
@ MENU_PAGER
Pager pager (email viewer)
Definition: type.h:52