NeoMutt  2020-09-25
Teaching an old dog new tricks
DOXYGEN
menu.c
Go to the documentation of this file.
1 
29 #include "config.h"
30 #include <stdbool.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <wchar.h>
34 #include "mutt/lib.h"
35 #include "config/lib.h"
36 #include "email/lib.h"
37 #include "core/lib.h"
38 #include "gui/lib.h"
39 #include "mutt.h"
40 #include "pattern/lib.h"
41 #include "commands.h"
42 #include "context.h"
43 #include "keymap.h"
44 #include "mutt_globals.h"
45 #include "mutt_logging.h"
46 #include "mutt_menu.h"
47 #include "mutt_thread.h"
48 #include "muttlib.h"
49 #include "opcodes.h"
50 #include "options.h"
51 #include "protos.h"
52 
53 /* These Config Variables are only used in menu.c */
57 
59 
60 /* These are used to track the active menus, for redraw operations. */
61 ARRAY_HEAD(, struct Menu *) MenuStack = ARRAY_HEAD_INITIALIZER;
62 
63 #define DIRECTION ((neg * 2) + 1)
64 
65 #define MUTT_SEARCH_UP 1
66 #define MUTT_SEARCH_DOWN 2
67 
77 static int get_color(int index, unsigned char *s)
78 {
79  struct ColorLineList *color = NULL;
80  struct ColorLine *np = NULL;
81  struct Email *e = mutt_get_virt_email(Context->mailbox, index);
82  int type = *s;
83 
84  switch (type)
85  {
87  color = &Colors->index_author_list;
88  break;
90  color = &Colors->index_flags_list;
91  break;
93  color = &Colors->index_subject_list;
94  break;
95  case MT_COLOR_INDEX_TAG:
96  STAILQ_FOREACH(np, &Colors->index_tag_list, entries)
97  {
98  if (mutt_strn_equal((const char *) (s + 1), np->pattern, strlen(np->pattern)))
99  return np->pair;
100  const char *transform = mutt_hash_find(TagTransforms, np->pattern);
101  if (transform && mutt_strn_equal((const char *) (s + 1), transform, strlen(transform)))
102  {
103  return np->pair;
104  }
105  }
106  return 0;
107  default:
108  return Colors->defs[type];
109  }
110 
111  STAILQ_FOREACH(np, color, entries)
112  {
115  return np->pair;
116  }
117 
118  return 0;
119 }
120 
128 static void print_enriched_string(int index, int attr, unsigned char *s, bool do_color)
129 {
130  wchar_t wc;
131  size_t k;
132  size_t n = mutt_str_len((char *) s);
133  mbstate_t mbstate;
134 
135  memset(&mbstate, 0, sizeof(mbstate));
136  while (*s)
137  {
138  if (*s < MUTT_TREE_MAX)
139  {
140  if (do_color)
141 #if defined(HAVE_COLOR) && defined(HAVE_USE_DEFAULT_COLORS)
142  /* Combining tree fg color and another bg color requires
143  * having use_default_colors, because the other bg color
144  * may be undefined. */
146 #else
148 #endif
149 
150  while (*s && (*s < MUTT_TREE_MAX))
151  {
152  switch (*s)
153  {
154  case MUTT_TREE_LLCORNER:
155  if (C_AsciiChars)
156  mutt_window_addch('`');
157 #ifdef WACS_LLCORNER
158  else
159  add_wch(WACS_LLCORNER);
160 #else
161  else if (CharsetIsUtf8)
162  mutt_window_addstr("\342\224\224"); /* WACS_LLCORNER */
163  else
164  mutt_window_addch(ACS_LLCORNER);
165 #endif
166  break;
167  case MUTT_TREE_ULCORNER:
168  if (C_AsciiChars)
169  mutt_window_addch(',');
170 #ifdef WACS_ULCORNER
171  else
172  add_wch(WACS_ULCORNER);
173 #else
174  else if (CharsetIsUtf8)
175  mutt_window_addstr("\342\224\214"); /* WACS_ULCORNER */
176  else
177  mutt_window_addch(ACS_ULCORNER);
178 #endif
179  break;
180  case MUTT_TREE_LTEE:
181  if (C_AsciiChars)
182  mutt_window_addch('|');
183 #ifdef WACS_LTEE
184  else
185  add_wch(WACS_LTEE);
186 #else
187  else if (CharsetIsUtf8)
188  mutt_window_addstr("\342\224\234"); /* WACS_LTEE */
189  else
190  mutt_window_addch(ACS_LTEE);
191 #endif
192  break;
193  case MUTT_TREE_HLINE:
194  if (C_AsciiChars)
195  mutt_window_addch('-');
196 #ifdef WACS_HLINE
197  else
198  add_wch(WACS_HLINE);
199 #else
200  else if (CharsetIsUtf8)
201  mutt_window_addstr("\342\224\200"); /* WACS_HLINE */
202  else
203  mutt_window_addch(ACS_HLINE);
204 #endif
205  break;
206  case MUTT_TREE_VLINE:
207  if (C_AsciiChars)
208  mutt_window_addch('|');
209 #ifdef WACS_VLINE
210  else
211  add_wch(WACS_VLINE);
212 #else
213  else if (CharsetIsUtf8)
214  mutt_window_addstr("\342\224\202"); /* WACS_VLINE */
215  else
216  mutt_window_addch(ACS_VLINE);
217 #endif
218  break;
219  case MUTT_TREE_TTEE:
220  if (C_AsciiChars)
221  mutt_window_addch('-');
222 #ifdef WACS_TTEE
223  else
224  add_wch(WACS_TTEE);
225 #else
226  else if (CharsetIsUtf8)
227  mutt_window_addstr("\342\224\254"); /* WACS_TTEE */
228  else
229  mutt_window_addch(ACS_TTEE);
230 #endif
231  break;
232  case MUTT_TREE_BTEE:
233  if (C_AsciiChars)
234  mutt_window_addch('-');
235 #ifdef WACS_BTEE
236  else
237  add_wch(WACS_BTEE);
238 #else
239  else if (CharsetIsUtf8)
240  mutt_window_addstr("\342\224\264"); /* WACS_BTEE */
241  else
242  mutt_window_addch(ACS_BTEE);
243 #endif
244  break;
245  case MUTT_TREE_SPACE:
246  mutt_window_addch(' ');
247  break;
248  case MUTT_TREE_RARROW:
249  mutt_window_addch('>');
250  break;
251  case MUTT_TREE_STAR:
252  mutt_window_addch('*'); /* fake thread indicator */
253  break;
254  case MUTT_TREE_HIDDEN:
255  mutt_window_addch('&');
256  break;
257  case MUTT_TREE_EQUALS:
258  mutt_window_addch('=');
259  break;
260  case MUTT_TREE_MISSING:
261  mutt_window_addch('?');
262  break;
263  }
264  s++;
265  n--;
266  }
267  if (do_color)
268  mutt_curses_set_attr(attr);
269  }
270  else if (*s == MUTT_SPECIAL_INDEX)
271  {
272  s++;
273  if (do_color)
274  {
275  if (*s == MT_COLOR_INDEX)
276  {
277  attrset(attr);
278  }
279  else
280  {
281  if (get_color(index, s) == 0)
282  {
283  attron(attr);
284  }
285  else
286  {
287  attron(get_color(index, s));
288  }
289  }
290  }
291  s++;
292  n -= 2;
293  }
294  else if ((k = mbrtowc(&wc, (char *) s, n, &mbstate)) > 0)
295  {
296  mutt_window_addnstr((char *) s, k);
297  s += k;
298  n -= k;
299  }
300  else
301  break;
302  }
303 }
304 
312 static void make_entry(char *buf, size_t buflen, struct Menu *menu, int i)
313 {
314  if (!ARRAY_EMPTY(&menu->dialog))
315  {
316  mutt_str_copy(buf, NONULL(*ARRAY_GET(&menu->dialog, i)), buflen);
317  menu->current = -1; /* hide menubar */
318  }
319  else
320  menu->make_entry(buf, buflen, menu, i);
321 }
322 
331 static void menu_pad_string(struct Menu *menu, char *buf, size_t buflen)
332 {
333  char *scratch = mutt_str_dup(buf);
334  int shift = C_ArrowCursor ? mutt_strwidth(C_ArrowString) + 1 : 0;
335  int cols = menu->win_index->state.cols - shift;
336 
337  mutt_simple_format(buf, buflen, cols, cols, JUSTIFY_LEFT, ' ', scratch,
338  mutt_str_len(scratch), true);
339  buf[buflen - 1] = '\0';
340  FREE(&scratch);
341 }
342 
347 void menu_redraw_full(struct Menu *menu)
348 {
350  /* clear() doesn't optimize screen redraws */
351  mutt_window_move_abs(0, 0);
353 
354  window_redraw(RootWindow, true);
355  menu->pagelen = menu->win_index->state.rows;
356 
357  mutt_show_error();
358 
360 }
361 
366 void menu_redraw_status(struct Menu *menu)
367 {
368  char buf[256];
369 
370  snprintf(buf, sizeof(buf), "-- NeoMutt: %s", menu->title);
372  mutt_window_move(menu->win_ibar, 0, 0);
373  mutt_paddstr(menu->win_ibar->state.cols, buf);
375  menu->redraw &= ~REDRAW_STATUS;
376 }
377 
382 void menu_redraw_index(struct Menu *menu)
383 {
384  char buf[1024];
385  bool do_color;
386  int attr;
387 
388  for (int i = menu->top; i < menu->top + menu->pagelen; i++)
389  {
390  if (i < menu->max)
391  {
392  attr = menu->color(i);
393 
394  make_entry(buf, sizeof(buf), menu, i);
395  menu_pad_string(menu, buf, sizeof(buf));
396 
397  mutt_curses_set_attr(attr);
398  mutt_window_move(menu->win_index, 0, i - menu->top);
399  do_color = true;
400 
401  if (i == menu->current)
402  {
404  if (C_ArrowCursor)
405  {
407  mutt_curses_set_attr(attr);
408  mutt_window_addch(' ');
409  }
410  else
411  do_color = false;
412  }
413  else if (C_ArrowCursor)
414  /* Print space chars to match the screen width of C_ArrowString */
416 
417  print_enriched_string(i, attr, (unsigned char *) buf, do_color);
418  }
419  else
420  {
422  mutt_window_clearline(menu->win_index, i - menu->top);
423  }
424  }
426  menu->redraw = 0;
427 }
428 
433 void menu_redraw_motion(struct Menu *menu)
434 {
435  char buf[1024];
436 
437  if (!ARRAY_EMPTY(&menu->dialog))
438  {
439  menu->redraw &= ~REDRAW_MOTION;
440  return;
441  }
442 
443  /* Note: menu->color() for the index can end up retrieving a message
444  * over imap (if matching against ~h for instance). This can
445  * generate status messages. So we want to call it *before* we
446  * position the cursor for drawing. */
447  const int old_color = menu->color(menu->oldcurrent);
448  mutt_window_move(menu->win_index, 0, menu->oldcurrent - menu->top);
449  mutt_curses_set_attr(old_color);
450 
451  if (C_ArrowCursor)
452  {
453  /* clear the arrow */
454  /* Print space chars to match the screen width of C_ArrowString */
456 
457  if (menu->redraw & REDRAW_MOTION_RESYNC)
458  {
459  make_entry(buf, sizeof(buf), menu, menu->oldcurrent);
460  menu_pad_string(menu, buf, sizeof(buf));
462  menu->oldcurrent - menu->top);
463  print_enriched_string(menu->oldcurrent, old_color, (unsigned char *) buf, true);
464  }
465 
466  /* now draw it in the new location */
468  mutt_window_mvaddstr(menu->win_index, 0, menu->current - menu->top, C_ArrowString);
469  }
470  else
471  {
472  /* erase the current indicator */
473  make_entry(buf, sizeof(buf), menu, menu->oldcurrent);
474  menu_pad_string(menu, buf, sizeof(buf));
475  print_enriched_string(menu->oldcurrent, old_color, (unsigned char *) buf, true);
476 
477  /* now draw the new one to reflect the change */
478  const int cur_color = menu->color(menu->current);
479  make_entry(buf, sizeof(buf), menu, menu->current);
480  menu_pad_string(menu, buf, sizeof(buf));
482  mutt_window_move(menu->win_index, 0, menu->current - menu->top);
483  print_enriched_string(menu->current, cur_color, (unsigned char *) buf, false);
484  }
485  menu->redraw &= REDRAW_STATUS;
487 }
488 
493 void menu_redraw_current(struct Menu *menu)
494 {
495  char buf[1024];
496  int attr = menu->color(menu->current);
497 
498  mutt_window_move(menu->win_index, 0, menu->current - menu->top);
499  make_entry(buf, sizeof(buf), menu, menu->current);
500  menu_pad_string(menu, buf, sizeof(buf));
501 
503  if (C_ArrowCursor)
504  {
506  mutt_curses_set_attr(attr);
507  mutt_window_addch(' ');
508  menu_pad_string(menu, buf, sizeof(buf));
509  print_enriched_string(menu->current, attr, (unsigned char *) buf, true);
510  }
511  else
512  print_enriched_string(menu->current, attr, (unsigned char *) buf, false);
513  menu->redraw &= REDRAW_STATUS;
515 }
516 
521 static void menu_redraw_prompt(struct Menu *menu)
522 {
523  if (!menu || ARRAY_EMPTY(&menu->dialog))
524  return;
525 
526  if (OptMsgErr)
527  {
528  mutt_sleep(1);
529  OptMsgErr = false;
530  }
531 
532  if (ErrorBufMessage)
534 
537 }
538 
543 void menu_check_recenter(struct Menu *menu)
544 {
545  int c = MIN(C_MenuContext, menu->pagelen / 2);
546  int old_top = menu->top;
547 
548  if (!C_MenuMoveOff && (menu->max <= menu->pagelen)) /* less entries than lines */
549  {
550  if (menu->top != 0)
551  {
552  menu->top = 0;
553  menu->redraw |= REDRAW_INDEX;
554  }
555  }
556  else
557  {
558  if (C_MenuScroll || (menu->pagelen <= 0) || (c < C_MenuContext))
559  {
560  if (menu->current < menu->top + c)
561  menu->top = menu->current - c;
562  else if (menu->current >= menu->top + menu->pagelen - c)
563  menu->top = menu->current - menu->pagelen + c + 1;
564  }
565  else
566  {
567  if (menu->current < menu->top + c)
568  {
569  menu->top -= (menu->pagelen - c) * ((menu->top + menu->pagelen - 1 - menu->current) /
570  (menu->pagelen - c)) -
571  c;
572  }
573  else if ((menu->current >= menu->top + menu->pagelen - c))
574  {
575  menu->top +=
576  (menu->pagelen - c) * ((menu->current - menu->top) / (menu->pagelen - c)) - c;
577  }
578  }
579  }
580 
581  if (!C_MenuMoveOff) /* make entries stick to bottom */
582  menu->top = MIN(menu->top, menu->max - menu->pagelen);
583  menu->top = MAX(menu->top, 0);
584 
585  if (menu->top != old_top)
586  menu->redraw |= REDRAW_INDEX;
587 }
588 
595 static void menu_jump(struct Menu *menu)
596 {
597  int n;
598 
599  if (menu->max)
600  {
602  char buf[128];
603  buf[0] = '\0';
604  if ((mutt_get_field(_("Jump to: "), buf, sizeof(buf), MUTT_COMP_NO_FLAGS) == 0) && buf[0])
605  {
606  if ((mutt_str_atoi(buf, &n) == 0) && (n > 0) && (n < menu->max + 1))
607  {
608  n--; /* msg numbers are 0-based */
609  menu->current = n;
610  menu->redraw = REDRAW_MOTION;
611  }
612  else
613  mutt_error(_("Invalid index number"));
614  }
615  }
616  else
617  mutt_error(_("No entries"));
618 }
619 
624 void menu_next_line(struct Menu *menu)
625 {
626  if (menu->max)
627  {
628  int c = MIN(C_MenuContext, menu->pagelen / 2);
629 
630  if ((menu->top + 1 < menu->max - c) &&
631  (C_MenuMoveOff ||
632  ((menu->max > menu->pagelen) && (menu->top < menu->max - menu->pagelen))))
633  {
634  menu->top++;
635  if ((menu->current < menu->top + c) && (menu->current < menu->max - 1))
636  menu->current++;
637  menu->redraw = REDRAW_INDEX;
638  }
639  else
640  mutt_message(_("You can't scroll down farther"));
641  }
642  else
643  mutt_error(_("No entries"));
644 }
645 
650 void menu_prev_line(struct Menu *menu)
651 {
652  if (menu->top > 0)
653  {
654  int c = MIN(C_MenuContext, menu->pagelen / 2);
655 
656  menu->top--;
657  if ((menu->current >= menu->top + menu->pagelen - c) && (menu->current > 1))
658  menu->current--;
659  menu->redraw = REDRAW_INDEX;
660  }
661  else
662  mutt_message(_("You can't scroll up farther"));
663 }
664 
675 static void menu_length_jump(struct Menu *menu, int jumplen)
676 {
677  const int neg = (jumplen >= 0) ? 0 : -1;
678  const int c = MIN(C_MenuContext, menu->pagelen / 2);
679 
680  if (menu->max)
681  {
682  /* possible to scroll? */
683  int tmp;
684  if (DIRECTION * menu->top <
685  (tmp = (neg ? 0 : (menu->max /* -1 */) - (menu->pagelen /* -1 */))))
686  {
687  menu->top += jumplen;
688 
689  /* jumped too long? */
690  if ((neg || !C_MenuMoveOff) && (DIRECTION * menu->top > tmp))
691  menu->top = tmp;
692 
693  /* need to move the cursor? */
694  if ((DIRECTION *
695  (tmp = (menu->current - (menu->top + (neg ? (menu->pagelen - 1) - c : c))))) < 0)
696  {
697  menu->current -= tmp;
698  }
699 
700  menu->redraw = REDRAW_INDEX;
701  }
702  else if ((menu->current != (neg ? 0 : menu->max - 1)) && ARRAY_EMPTY(&menu->dialog))
703  {
704  menu->current += jumplen;
705  menu->redraw = REDRAW_MOTION;
706  }
707  else
708  {
709  mutt_message(neg ? _("You are on the first page") : _("You are on the last page"));
710  }
711 
712  menu->current = MIN(menu->current, menu->max - 1);
713  menu->current = MAX(menu->current, 0);
714  }
715  else
716  mutt_error(_("No entries"));
717 }
718 
723 void menu_next_page(struct Menu *menu)
724 {
725  menu_length_jump(menu, MAX(menu->pagelen /* - MenuOverlap */, 0));
726 }
727 
732 void menu_prev_page(struct Menu *menu)
733 {
734  menu_length_jump(menu, 0 - MAX(menu->pagelen /* - MenuOverlap */, 0));
735 }
736 
741 void menu_half_down(struct Menu *menu)
742 {
743  menu_length_jump(menu, menu->pagelen / 2);
744 }
745 
750 void menu_half_up(struct Menu *menu)
751 {
752  menu_length_jump(menu, 0 - menu->pagelen / 2);
753 }
754 
759 void menu_top_page(struct Menu *menu)
760 {
761  if (menu->current == menu->top)
762  return;
763 
764  menu->current = menu->top;
765  menu->redraw = REDRAW_MOTION;
766 }
767 
772 void menu_bottom_page(struct Menu *menu)
773 {
774  if (menu->max)
775  {
776  menu->current = menu->top + menu->pagelen - 1;
777  if (menu->current > menu->max - 1)
778  menu->current = menu->max - 1;
779  menu->redraw = REDRAW_MOTION;
780  }
781  else
782  mutt_error(_("No entries"));
783 }
784 
789 void menu_middle_page(struct Menu *menu)
790 {
791  if (menu->max)
792  {
793  int i = menu->top + menu->pagelen;
794  if (i > menu->max - 1)
795  i = menu->max - 1;
796  menu->current = menu->top + (i - menu->top) / 2;
797  menu->redraw = REDRAW_MOTION;
798  }
799  else
800  mutt_error(_("No entries"));
801 }
802 
807 void menu_first_entry(struct Menu *menu)
808 {
809  if (menu->max)
810  {
811  menu->current = 0;
812  menu->redraw = REDRAW_MOTION;
813  }
814  else
815  mutt_error(_("No entries"));
816 }
817 
822 void menu_last_entry(struct Menu *menu)
823 {
824  if (menu->max)
825  {
826  menu->current = menu->max - 1;
827  menu->redraw = REDRAW_MOTION;
828  }
829  else
830  mutt_error(_("No entries"));
831 }
832 
837 void menu_current_top(struct Menu *menu)
838 {
839  if (menu->max)
840  {
841  menu->top = menu->current;
842  menu->redraw = REDRAW_INDEX;
843  }
844  else
845  mutt_error(_("No entries"));
846 }
847 
852 void menu_current_middle(struct Menu *menu)
853 {
854  if (menu->max)
855  {
856  menu->top = menu->current - menu->pagelen / 2;
857  if (menu->top < 0)
858  menu->top = 0;
859  menu->redraw = REDRAW_INDEX;
860  }
861  else
862  mutt_error(_("No entries"));
863 }
864 
869 void menu_current_bottom(struct Menu *menu)
870 {
871  if (menu->max)
872  {
873  menu->top = menu->current - menu->pagelen + 1;
874  if (menu->top < 0)
875  menu->top = 0;
876  menu->redraw = REDRAW_INDEX;
877  }
878  else
879  mutt_error(_("No entries"));
880 }
881 
886 static void menu_next_entry(struct Menu *menu)
887 {
888  if (menu->current < menu->max - 1)
889  {
890  menu->current++;
891  menu->redraw = REDRAW_MOTION;
892  }
893  else
894  mutt_message(_("You are on the last entry"));
895 }
896 
901 static void menu_prev_entry(struct Menu *menu)
902 {
903  if (menu->current)
904  {
905  menu->current--;
906  menu->redraw = REDRAW_MOTION;
907  }
908  else
909  mutt_message(_("You are on the first entry"));
910 }
911 
915 static int default_color(int line)
916 {
917  return Colors->defs[MT_COLOR_NORMAL];
918 }
919 
923 static int generic_search(struct Menu *menu, regex_t *rx, int line)
924 {
925  char buf[1024];
926 
927  make_entry(buf, sizeof(buf), menu, line);
928  return regexec(rx, buf, 0, NULL, 0);
929 }
930 
934 void mutt_menu_init(void)
935 {
936  for (int i = 0; i < MENU_MAX; i++)
937  SearchBuffers[i] = NULL;
938 }
939 
946 {
947  struct Menu *menu = mutt_mem_calloc(1, sizeof(struct Menu));
948 
949  menu->type = type;
950  menu->current = 0;
951  menu->top = 0;
952  menu->redraw = REDRAW_FULL;
953  menu->color = default_color;
954  menu->search = generic_search;
955  menu->custom_search = false;
956 
957  return menu;
958 }
959 
964 void mutt_menu_free(struct Menu **ptr)
965 {
966  if (!ptr || !*ptr)
967  return;
968 
969  struct Menu *m = *ptr;
970  char **line = NULL;
971  ARRAY_FOREACH(line, &m->dialog)
972  {
973  FREE(line);
974  }
975  ARRAY_FREE(&m->dialog);
976 
977  FREE(ptr);
978 }
979 
985 void mutt_menu_add_dialog_row(struct Menu *menu, const char *row)
986 {
987  ARRAY_SET(&menu->dialog, menu->max, mutt_str_dup(row));
988  menu->max++;
989 }
990 
995 static struct Menu *get_current_menu(void)
996 {
997  struct Menu **mp = ARRAY_LAST(&MenuStack);
998  return mp ? *mp : NULL;
999 }
1000 
1007 void mutt_menu_push_current(struct Menu *menu)
1008 {
1009  ARRAY_ADD(&MenuStack, menu);
1010  CurrentMenu = menu->type;
1011 }
1012 
1019 void mutt_menu_pop_current(struct Menu *menu)
1020 {
1021  struct Menu *prev_menu = NULL;
1022 
1023  if (ARRAY_EMPTY(&MenuStack) || (*ARRAY_LAST(&MenuStack) != menu))
1024  {
1025  mutt_debug(LL_DEBUG1, "called with inactive menu\n");
1026  return;
1027  }
1028  ARRAY_SHRINK(&MenuStack, 1);
1029 
1030  prev_menu = get_current_menu();
1031  if (prev_menu)
1032  {
1033  CurrentMenu = prev_menu->type;
1034  prev_menu->redraw = REDRAW_FULL;
1035  }
1036  else
1037  {
1039  /* Clearing when NeoMutt exits would be an annoying change in behavior for
1040  * those who have disabled alternative screens. The option is currently
1041  * set by autocrypt initialization which mixes menus and prompts outside of
1042  * the normal menu system state. */
1044  {
1045  mutt_window_move_abs(0, 0);
1047  }
1048  }
1049 }
1050 
1056 {
1057  struct Menu *current_menu = get_current_menu();
1058  if (current_menu)
1059  current_menu->redraw |= redraw;
1060 }
1061 
1066 {
1067  struct Menu *current_menu = get_current_menu();
1068  if (current_menu)
1069  current_menu->redraw = REDRAW_FULL;
1070 }
1071 
1080 {
1081  if (CurrentMenu == menu)
1083 }
1084 
1092 {
1093  if (CurrentMenu == menu)
1095 }
1096 
1101 {
1102  struct Menu *current_menu = get_current_menu();
1103  if (current_menu)
1104  {
1105  if (menu_redraw(current_menu) == OP_REDRAW)
1106  {
1107  /* On a REDRAW_FULL with a non-customized redraw, menu_redraw()
1108  * will return OP_REDRAW to give the calling menu-loop a chance to
1109  * customize output. */
1110  menu_redraw(current_menu);
1111  }
1112  }
1113 }
1114 
1122 static int search(struct Menu *menu, int op)
1123 {
1124  int rc = 0, wrap = 0;
1125  int search_dir;
1126  regex_t re;
1127  char buf[128];
1128  char *search_buf = ((menu->type < MENU_MAX)) ? SearchBuffers[menu->type] : NULL;
1129 
1130  if (!(search_buf && *search_buf) || ((op != OP_SEARCH_NEXT) && (op != OP_SEARCH_OPPOSITE)))
1131  {
1132  mutt_str_copy(buf, search_buf && (search_buf[0] != '\0') ? search_buf : "",
1133  sizeof(buf));
1134  if ((mutt_get_field(((op == OP_SEARCH) || (op == OP_SEARCH_NEXT)) ?
1135  _("Search for: ") :
1136  _("Reverse search for: "),
1137  buf, sizeof(buf), MUTT_CLEAR) != 0) ||
1138  (buf[0] == '\0'))
1139  {
1140  return -1;
1141  }
1142  if (menu->type < MENU_MAX)
1143  {
1144  mutt_str_replace(&SearchBuffers[menu->type], buf);
1145  search_buf = SearchBuffers[menu->type];
1146  }
1147  menu->search_dir =
1148  ((op == OP_SEARCH) || (op == OP_SEARCH_NEXT)) ? MUTT_SEARCH_DOWN : MUTT_SEARCH_UP;
1149  }
1150 
1151  search_dir = (menu->search_dir == MUTT_SEARCH_UP) ? -1 : 1;
1152  if (op == OP_SEARCH_OPPOSITE)
1153  search_dir = -search_dir;
1154 
1155  if (search_buf)
1156  {
1157  int flags = mutt_mb_is_lower(search_buf) ? REG_ICASE : 0;
1158  rc = REG_COMP(&re, search_buf, REG_NOSUB | flags);
1159  }
1160 
1161  if (rc != 0)
1162  {
1163  regerror(rc, &re, buf, sizeof(buf));
1164  mutt_error("%s", buf);
1165  return -1;
1166  }
1167 
1168  rc = menu->current + search_dir;
1169 search_next:
1170  if (wrap)
1171  mutt_message(_("Search wrapped to top"));
1172  while ((rc >= 0) && (rc < menu->max))
1173  {
1174  if (menu->search(menu, &re, rc) == 0)
1175  {
1176  regfree(&re);
1177  return rc;
1178  }
1179 
1180  rc += search_dir;
1181  }
1182 
1183  if (C_WrapSearch && (wrap++ == 0))
1184  {
1185  rc = (search_dir == 1) ? 0 : menu->max - 1;
1186  goto search_next;
1187  }
1188  regfree(&re);
1189  mutt_error(_("Not found"));
1190  return -1;
1191 }
1192 
1198 static int menu_dialog_translate_op(int i)
1199 {
1200  switch (i)
1201  {
1202  case OP_NEXT_ENTRY:
1203  return OP_NEXT_LINE;
1204  case OP_PREV_ENTRY:
1205  return OP_PREV_LINE;
1206  case OP_CURRENT_TOP:
1207  case OP_FIRST_ENTRY:
1208  return OP_TOP_PAGE;
1209  case OP_CURRENT_BOTTOM:
1210  case OP_LAST_ENTRY:
1211  return OP_BOTTOM_PAGE;
1212  case OP_CURRENT_MIDDLE:
1213  return OP_MIDDLE_PAGE;
1214  }
1215 
1216  return i;
1217 }
1218 
1226 static int menu_dialog_dokey(struct Menu *menu, int *ip)
1227 {
1228  struct KeyEvent ch;
1229  char *p = NULL;
1230 
1231  do
1232  {
1233  ch = mutt_getch();
1234  } while (ch.ch == -2);
1235 
1236  if (ch.ch < 0)
1237  {
1238  *ip = -1;
1239  return 0;
1240  }
1241 
1242  if (ch.ch && (p = strchr(menu->keys, ch.ch)))
1243  {
1244  *ip = OP_MAX + (p - menu->keys + 1);
1245  return 0;
1246  }
1247  else
1248  {
1249  if (ch.op == OP_NULL)
1250  mutt_unget_event(ch.ch, 0);
1251  else
1252  mutt_unget_event(0, ch.op);
1253  return -1;
1254  }
1255 }
1256 
1263 int menu_redraw(struct Menu *menu)
1264 {
1265  if (menu->custom_redraw)
1266  {
1267  menu->custom_redraw(menu);
1268  return OP_NULL;
1269  }
1270 
1271  /* See if all or part of the screen needs to be updated. */
1272  if (menu->redraw & REDRAW_FULL)
1273  {
1274  menu_redraw_full(menu);
1275  /* allow the caller to do any local configuration */
1276  return OP_REDRAW;
1277  }
1278 
1279  if (ARRAY_EMPTY(&menu->dialog))
1280  menu_check_recenter(menu);
1281 
1282  if (menu->redraw & REDRAW_STATUS)
1283  menu_redraw_status(menu);
1284  if (menu->redraw & REDRAW_INDEX)
1285  menu_redraw_index(menu);
1286  else if (menu->redraw & (REDRAW_MOTION | REDRAW_MOTION_RESYNC))
1287  menu_redraw_motion(menu);
1288  else if (menu->redraw == REDRAW_CURRENT)
1289  menu_redraw_current(menu);
1290 
1291  if (!ARRAY_EMPTY(&menu->dialog))
1292  menu_redraw_prompt(menu);
1293 
1294  return OP_NULL;
1295 }
1296 
1302 int mutt_menu_loop(struct Menu *menu)
1303 {
1304  static int last_position = -1;
1305  int i = OP_NULL;
1306 
1307  if (menu->max && menu->is_mailbox_list)
1308  {
1309  if (last_position > (menu->max - 1))
1310  last_position = -1;
1311  else if (last_position >= 0)
1312  menu->current = last_position;
1313  }
1314 
1315  while (true)
1316  {
1317  /* Clear the tag prefix unless we just started it. Don't clear
1318  * the prefix on a timeout (i==-2), but do clear on an abort (i==-1) */
1319  if (menu->tagprefix && (i != OP_TAG_PREFIX) && (i != OP_TAG_PREFIX_COND) && (i != -2))
1320  menu->tagprefix = false;
1321 
1323 
1324  if (menu_redraw(menu) == OP_REDRAW)
1325  return OP_REDRAW;
1326 
1327  /* give visual indication that the next command is a tag- command */
1328  if (menu->tagprefix)
1329  {
1330  mutt_window_mvaddstr(MessageWindow, 0, 0, "tag-");
1332  }
1333 
1334  menu->oldcurrent = menu->current;
1335 
1336  /* move the cursor out of the way */
1337  if (C_ArrowCursor)
1338  mutt_window_move(menu->win_index, 2, menu->current - menu->top);
1339  else if (C_BrailleFriendly)
1340  mutt_window_move(menu->win_index, 0, menu->current - menu->top);
1341  else
1342  {
1343  mutt_window_move(menu->win_index, menu->win_index->state.cols - 1,
1344  menu->current - menu->top);
1345  }
1346 
1347  mutt_refresh();
1348 
1349  /* try to catch dialog keys before ops */
1350  if (!ARRAY_EMPTY(&menu->dialog) && (menu_dialog_dokey(menu, &i) == 0))
1351  return i;
1352 
1353  i = km_dokey(menu->type);
1354  if ((i == OP_TAG_PREFIX) || (i == OP_TAG_PREFIX_COND))
1355  {
1356  if (menu->tagprefix)
1357  {
1358  menu->tagprefix = false;
1360  continue;
1361  }
1362 
1363  if (menu->tagged)
1364  {
1365  menu->tagprefix = true;
1366  continue;
1367  }
1368  else if (i == OP_TAG_PREFIX)
1369  {
1370  mutt_error(_("No tagged entries"));
1371  i = -1;
1372  }
1373  else /* None tagged, OP_TAG_PREFIX_COND */
1374  {
1376  mutt_message(_("Nothing to do"));
1377  i = -1;
1378  }
1379  }
1380  else if (menu->tagged && C_AutoTag)
1381  menu->tagprefix = true;
1382 
1384 
1385  if (SigWinch)
1386  {
1387  SigWinch = 0;
1389  clearok(stdscr, true); /* force complete redraw */
1390  }
1391 
1392  if (i < 0)
1393  {
1394  if (menu->tagprefix)
1396  continue;
1397  }
1398 
1399  if (ARRAY_EMPTY(&menu->dialog))
1400  mutt_clear_error();
1401 
1402  /* Convert menubar movement to scrolling */
1403  if (!ARRAY_EMPTY(&menu->dialog))
1404  i = menu_dialog_translate_op(i);
1405 
1406  switch (i)
1407  {
1408  case OP_NEXT_ENTRY:
1409  menu_next_entry(menu);
1410  break;
1411  case OP_PREV_ENTRY:
1412  menu_prev_entry(menu);
1413  break;
1414  case OP_HALF_DOWN:
1415  menu_half_down(menu);
1416  break;
1417  case OP_HALF_UP:
1418  menu_half_up(menu);
1419  break;
1420  case OP_NEXT_PAGE:
1421  menu_next_page(menu);
1422  break;
1423  case OP_PREV_PAGE:
1424  menu_prev_page(menu);
1425  break;
1426  case OP_NEXT_LINE:
1427  menu_next_line(menu);
1428  break;
1429  case OP_PREV_LINE:
1430  menu_prev_line(menu);
1431  break;
1432  case OP_FIRST_ENTRY:
1433  menu_first_entry(menu);
1434  break;
1435  case OP_LAST_ENTRY:
1436  menu_last_entry(menu);
1437  break;
1438  case OP_TOP_PAGE:
1439  menu_top_page(menu);
1440  break;
1441  case OP_MIDDLE_PAGE:
1442  menu_middle_page(menu);
1443  break;
1444  case OP_BOTTOM_PAGE:
1445  menu_bottom_page(menu);
1446  break;
1447  case OP_CURRENT_TOP:
1448  menu_current_top(menu);
1449  break;
1450  case OP_CURRENT_MIDDLE:
1451  menu_current_middle(menu);
1452  break;
1453  case OP_CURRENT_BOTTOM:
1454  menu_current_bottom(menu);
1455  break;
1456  case OP_SEARCH:
1457  case OP_SEARCH_REVERSE:
1458  case OP_SEARCH_NEXT:
1459  case OP_SEARCH_OPPOSITE:
1460  if (menu->custom_search)
1461  return i;
1462  else if (menu->search && ARRAY_EMPTY(&menu->dialog)) /* Searching dialogs won't work */
1463  {
1464  menu->oldcurrent = menu->current;
1465  menu->current = search(menu, i);
1466  if (menu->current != -1)
1467  menu->redraw = REDRAW_MOTION;
1468  else
1469  menu->current = menu->oldcurrent;
1470  }
1471  else
1472  mutt_error(_("Search is not implemented for this menu"));
1473  break;
1474 
1475  case OP_JUMP:
1476  if (!ARRAY_EMPTY(&menu->dialog))
1477  mutt_error(_("Jumping is not implemented for dialogs"));
1478  else
1479  menu_jump(menu);
1480  break;
1481 
1482  case OP_ENTER_COMMAND:
1484  window_set_focus(menu->win_index);
1485  window_redraw(RootWindow, false);
1486  break;
1487 
1488  case OP_TAG:
1489  if (menu->tag && ARRAY_EMPTY(&menu->dialog))
1490  {
1491  if (menu->tagprefix && !C_AutoTag)
1492  {
1493  for (i = 0; i < menu->max; i++)
1494  menu->tagged += menu->tag(menu, i, 0);
1495  menu->redraw |= REDRAW_INDEX;
1496  }
1497  else if (menu->max)
1498  {
1499  int j = menu->tag(menu, menu->current, -1);
1500  menu->tagged += j;
1501  if (j && C_Resolve && (menu->current < menu->max - 1))
1502  {
1503  menu->current++;
1504  menu->redraw |= REDRAW_MOTION_RESYNC;
1505  }
1506  else
1507  menu->redraw |= REDRAW_CURRENT;
1508  }
1509  else
1510  mutt_error(_("No entries"));
1511  }
1512  else
1513  mutt_error(_("Tagging is not supported"));
1514  break;
1515 
1516  case OP_SHELL_ESCAPE:
1518  break;
1519 
1520  case OP_WHAT_KEY:
1521  mutt_what_key();
1522  break;
1523 
1524  case OP_CHECK_STATS:
1525  mutt_check_stats();
1526  break;
1527 
1528  case OP_REDRAW:
1529  clearok(stdscr, true);
1530  menu->redraw = REDRAW_FULL;
1531  break;
1532 
1533  case OP_HELP:
1534  mutt_help(menu->type, menu->win_index->state.cols);
1535  menu->redraw = REDRAW_FULL;
1536  break;
1537 
1538  case OP_NULL:
1539  km_error_key(menu->type);
1540  break;
1541 
1542  case OP_END_COND:
1543  break;
1544 
1545  default:
1546  if (menu->is_mailbox_list)
1547  last_position = menu->current;
1548  return i;
1549  }
1550  }
1551  /* not reached */
1552 }
1553 
1558 {
1559  if (!nc->event_data)
1560  return -1;
1561  if (nc->event_type != NT_CONFIG)
1562  return 0;
1563 
1564  struct EventColor *ev_c = nc->event_data;
1565 
1566  int c = ev_c->color;
1567 
1568  bool simple = (c == MT_COLOR_INDEX_COLLAPSED) || (c == MT_COLOR_INDEX_DATE) ||
1569  (c == MT_COLOR_INDEX_LABEL) || (c == MT_COLOR_INDEX_NUMBER) ||
1570  (c == MT_COLOR_INDEX_SIZE) || (c == MT_COLOR_INDEX_TAGS);
1571  bool lists = (c == MT_COLOR_ATTACH_HEADERS) || (c == MT_COLOR_BODY) ||
1572  (c == MT_COLOR_HEADER) || (c == MT_COLOR_INDEX) ||
1573  (c == MT_COLOR_INDEX_AUTHOR) || (c == MT_COLOR_INDEX_FLAGS) ||
1574  (c == MT_COLOR_INDEX_SUBJECT) || (c == MT_COLOR_INDEX_TAG);
1575 
1576  // The changes aren't relevant to the index menu
1577  if (!simple && !lists)
1578  return 0;
1579 
1580  // Colour deleted from a list
1581  if ((nc->event_subtype == NT_COLOR_RESET) && lists && Context && Context->mailbox)
1582  {
1583  struct Mailbox *m = Context->mailbox;
1584  // Force re-caching of index colors
1585  for (int i = 0; i < m->msg_count; i++)
1586  {
1587  struct Email *e = m->emails[i];
1588  if (!e)
1589  break;
1590  e->pair = 0;
1591  }
1592  }
1593 
1595  return 0;
1596 }
1597 
1602 {
1603  if (!nc->event_data)
1604  return -1;
1605  if (nc->event_type != NT_CONFIG)
1606  return 0;
1607 
1608  struct EventConfig *ec = nc->event_data;
1609 
1610  const struct ConfigDef *cdef = ec->he->data;
1611  ConfigRedrawFlags flags = cdef->type & R_REDRAW_MASK;
1612 
1613  if (flags == R_REDRAW_NO_FLAGS)
1614  return 0;
1615 
1616  if (flags & R_INDEX)
1618  if (flags & R_PAGER)
1620  if (flags & R_PAGER_FLOW)
1621  {
1624  }
1625 
1626  if (flags & R_RESORT_SUB)
1627  OptSortSubthreads = true;
1628  if (flags & R_RESORT)
1629  OptNeedResort = true;
1630  if (flags & R_RESORT_INIT)
1631  OptResortInit = true;
1632  if (flags & R_TREE)
1633  OptRedrawTree = true;
1634 
1635  if (flags & R_REFLOW)
1636  mutt_window_reflow(NULL);
1637  if (flags & R_MENU)
1639 
1640  return 0;
1641 }
int km_dokey(enum MenuType menu)
Determine what a keypress should do.
Definition: keymap.c:658
void * mutt_hash_find(const struct HashTable *table, const char *strkey)
Find the HashElem data in a Hash Table element using a key.
Definition: hash.c:354
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
Convenience wrapper for the gui headers.
struct ColorLineList index_tag_list
List of colours applied to tags in the index.
Definition: color.h:140
MIME attachment test (takes a pattern)
Definition: color.h:62
The "current" mailbox.
Definition: context.h:38
#define R_PAGER
Redraw the pager menu.
Definition: types.h:66
Star character (for threads)
Definition: mutt_thread.h:63
Index: index number.
Definition: color.h:109
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:45
Manage keymappings.
#define NONULL(x)
Definition: string2.h:37
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
int msg_count
Total number of messages.
Definition: mailbox.h:91
Ampersand character (for threads)
Definition: mutt_thread.h:64
int mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition: string.c:252
Left justify the text.
Definition: curs_lib.h:47
The envelope/body of an email.
Definition: email.h:37
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:62
Index: tags field (g, J)
Definition: color.h:111
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:394
#define MIN(a, b)
Definition: memory.h:31
GUI selectable list of items.
Definition: mutt_menu.h:52
Data passed to a notification function.
Definition: observer.h:39
#define R_PAGER_FLOW
Reflow line_info and redraw the pager menu.
Definition: types.h:67
void window_set_focus(struct MuttWindow *win)
Set the Window focus.
Definition: mutt_window.c:773
Structs that make up an email.
An Event that happened to a Colour.
Definition: color.h:159
The "currently-open" mailbox.
MenuType
Types of GUI selections.
Definition: keymap.h:72
#define mutt_message(...)
Definition: logging.h:83
Pager: highlight body of message (takes a pattern)
Definition: color.h:63
int oldcurrent
For driver use only.
Definition: mutt_menu.h:76
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:57
#define REDRAW_FLOW
Used by pager to reflow text.
Definition: mutt_menu.h:47
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:198
int * defs
Array of all fixed colours, see enum ColorId.
Definition: color.h:131
char * prompt
Prompt for user, similar to mutt_multi_choice.
Definition: mutt_menu.h:71
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:254
struct PatternList * color_pattern
Compiled pattern to speed up index color calculation.
Definition: color.h:40
void mutt_resize_screen(void)
Update NeoMutt&#39;s opinion about the window size (CURSES)
Definition: resize.c:101
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:206
NeoMutt Logging.
WHERE bool OptNeedResort
(pseudo) used to force a re-sort
Definition: options.h:43
struct ColorLineList index_flags_list
List of colours applied to the flags in the index.
Definition: color.h:137
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:105
void mutt_check_stats(void)
Forcibly update mailbox stats.
Definition: commands.c:1428
A config-change event.
Definition: subset.h:70
char * pattern
Pattern to match.
Definition: color.h:39
int pair
Colour pair index.
Definition: color.h:43
void mutt_enter_command(void)
enter a neomutt command
Definition: commands.c:872
struct ColorLineList index_subject_list
List of colours applied to the subject in the index.
Definition: color.h:139
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
void mutt_unget_event(int ch, int op)
Return a keystroke to the input buffer.
Definition: curs_lib.c:834
#define _(a)
Definition: message.h:28
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:53
int op
function op
Definition: keymap.h:66
int ch
raw key pressed
Definition: keymap.h:65
void mutt_window_move_abs(int col, int row)
Move the cursor to an absolute screen position.
Definition: mutt_window.c:549
WHERE bool C_BrailleFriendly
Config: Move the cursor to the beginning of the line.
Definition: mutt_globals.h:140
Index panel (list of emails)
Definition: keymap.h:80
#define ARRAY_SHRINK(head, num)
Mark a number of slots at the end of the array as unused.
Definition: array.h:168
int mutt_window_mvaddstr(struct MuttWindow *win, int col, int row, const char *str)
Move the cursor and write a fixed string to a Window.
Definition: mutt_window.c:406
Config item definition.
Definition: set.h:61
WHERE bool C_AutoTag
Config: Automatically apply actions to all tagged messages.
Definition: mutt_globals.h:137
Index: number of messages in collapsed thread.
Definition: color.h:106
All user-callable functions.
#define R_RESORT
Resort the mailbox.
Definition: types.h:68
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:91
Lower left corner.
Definition: mutt_thread.h:56
Convenience wrapper for the config headers.
void mutt_paddstr(int n, const char *s)
Display a string on screen, padded if necessary.
Definition: curs_lib.c:1266
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:392
int event_subtype
Send: Event subtype, e.g. NT_ACCOUNT_ADD.
Definition: observer.h:43
#define R_TREE
Redraw the thread tree.
Definition: types.h:71
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:42
Some miscellaneous functions.
#define MAX(a, b)
Definition: memory.h:30
Pager pager (email viewer)
Definition: keymap.h:81
Index: author field (takes a pattern)
Definition: color.h:101
int mutt_window_addnstr(const char *str, int num)
Write a partial string to a Window.
Definition: mutt_window.c:514
#define R_REDRAW_NO_FLAGS
No refresh/resort flags.
Definition: types.h:64
WHERE enum MenuType CurrentMenu
Current Menu, e.g. MENU_PAGER.
Definition: mutt_globals.h:77
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1446
struct HashElem * he
Config item that changed.
Definition: subset.h:74
void mutt_curses_set_cursor(enum MuttCursorState state)
Set the cursor state.
Definition: mutt_curses.c:78
enum MenuType type
Menu definition for keymap entries.
Definition: mutt_menu.h:59
struct Mailbox * mailbox
Definition: context.h:50
Many unsorted constants and some structs.
Top T-piece.
Definition: mutt_thread.h:66
Message headers (takes a pattern)
Definition: color.h:72
void mutt_flush_macro_to_endcond(void)
Drop a macro from the input buffer.
Definition: curs_lib.c:890
#define ARRAY_LAST(head)
Convenience method to get the last element.
Definition: array.h:140
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
struct MuttWindow * win_ibar
Definition: mutt_menu.h:64
const char * title
Title of this menu.
Definition: mutt_menu.h:54
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:232
WHERE bool OptMenuPopClearScreen
(pseudo) clear the screen when popping the last menu
Definition: options.h:40
void mutt_what_key(void)
Ask the user to press a key.
Definition: keymap.c:1676
Display a normal cursor.
Definition: mutt_curses.h:81
int LastKey
contains the last key the user pressed
Definition: keymap.c:146
Index: tag field (g, takes a pattern)
Definition: color.h:104
Convenience wrapper for the core headers.
void mutt_shell_escape(void)
invoke a command in a subshell
Definition: commands.c:844
Index: tree-drawing characters.
Definition: color.h:96
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:54
void mutt_window_clrtobot(void)
Clear to the bottom of the Window.
Definition: mutt_window.c:243
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
#define REDRAW_MOTION
Redraw after moving the menu list.
Definition: mutt_menu.h:41
Vertical line.
Definition: mutt_thread.h:60
Plain text.
Definition: color.h:77
#define R_MENU
Redraw all menus.
Definition: types.h:74
#define REDRAW_MOTION_RESYNC
Redraw any changing the menu selection.
Definition: mutt_menu.h:42
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:57
#define R_RESORT_SUB
Resort subthreads.
Definition: types.h:69
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:108
Index: date field.
Definition: color.h:107
Prototypes for many functions.
#define R_REFLOW
Reflow window layout and full redraw.
Definition: types.h:72
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:120
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:44
struct MuttWindow * MessageWindow
Message Window, ":set", etc.
Definition: mutt_window.c:47
#define SLIST_FIRST(head)
Definition: queue.h:228
struct MuttWindow * RootWindow
Parent of all Windows.
Definition: mutt_window.c:45
Index: size field.
Definition: color.h:110
Create/manipulate threading in emails.
void km_error_key(enum MenuType menu)
Handle an unbound key sequence.
Definition: keymap.c:1137
int(* color)(int line)
Calculate the colour for a line of the menu.
Definition: mutt_menu.h:115
Status bar (takes a pattern)
Definition: color.h:94
A mailbox.
Definition: mailbox.h:81
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:1359
Right arrow.
Definition: mutt_thread.h:62
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:58
int top
Entry that is the top of the current page.
Definition: mutt_menu.h:75
bool tagprefix
Definition: mutt_menu.h:61
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition: array.h:70
Manage where the email is piped to external commands.
struct ColorLineList index_author_list
List of colours applied to the author in the index.
Definition: color.h:136
Match patterns to emails.
Bottom T-piece.
Definition: mutt_thread.h:67
bool is_mailbox_list
Definition: mutt_menu.h:62
Color has been reset/removed.
Definition: color.h:172
Selected item in list.
Definition: color.h:73
enum ColorId color
Definition: color.h:161
GUI present the user with a selectable list.
Left T-piece.
Definition: mutt_thread.h:58
struct HashTable * TagTransforms
Lookup table of alternative tag names.
Definition: tags.c:38
uint32_t ConfigRedrawFlags
Flags for redraw/resort, e.g. R_INDEX.
Definition: types.h:63
int search_dir
Direction of search.
Definition: mutt_menu.h:77
void(* custom_redraw)(struct Menu *menu)
Redraw the menu.
Definition: mutt_menu.h:121
An event such as a keypress.
Definition: keymap.h:63
Upper left corner.
Definition: mutt_thread.h:57
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
int(* tag)(struct Menu *menu, int sel, int act)
Tag some menu items.
Definition: mutt_menu.h:107
bool custom_search
The menu implements its own non-Menusearch()-compatible search, trickle OP_SEARCH*.
Definition: mutt_menu.h:79
struct KeyEvent mutt_getch(void)
Read a character from the input buffer.
Definition: curs_lib.c:189
int pagelen
Number of entries per screen.
Definition: mutt_menu.h:60
char * keys
Keys used in the prompt.
Definition: mutt_menu.h:72
WHERE bool OptRedrawTree
(pseudo) redraw the thread tree
Definition: options.h:50
Definition: color.h:129
WHERE bool OptResortInit
(pseudo) used to force the next resort to be from scratch
Definition: options.h:51
int tagged
Number of tagged entries.
Definition: mutt_menu.h:78
bool CharsetIsUtf8
Is the user&#39;s current character set utf-8?
Definition: charset.c:63
WHERE bool C_WrapSearch
Config: Wrap around when the search hits the end.
Definition: mutt_globals.h:169
void * event_data
Data from notify_send()
Definition: observer.h:44
int max
Number of entries in the menu.
Definition: mutt_menu.h:57
WHERE bool C_ArrowCursor
Config: Use an arrow &#39;->&#39; instead of highlighting in the index.
Definition: mutt_globals.h:131
WHERE bool C_AsciiChars
Config: Use plain ASCII characters, when drawing email threads.
Definition: mutt_globals.h:133
bool mutt_strn_equal(const char *a, const char *b, size_t l)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:593
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:58
#define ARRAY_SET(head, idx, elem)
Set an element in the array.
Definition: array.h:119
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:37
void * data
User-supplied data.
Definition: hash.h:47
int mutt_pattern_exec(struct Pattern *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: exec.c:738
int mutt_window_printf(const char *fmt,...)
Write a formatted string to a Window.
Definition: mutt_window.c:560
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
int mutt_window_addch(int ch)
Write one character to a Window.
Definition: mutt_window.c:502
Index: label field.
Definition: color.h:108
unsigned int type
Variable type, e.g. DT_STRING.
Definition: set.h:64
Horizontal line.
Definition: mutt_thread.h:59
Index: subject field (takes a pattern)
Definition: color.h:103
Log at debug level 1.
Definition: logging.h:40
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:716
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:40
void mutt_help(enum MenuType menu, int wraplen)
Display the help menu.
Definition: help.c:386
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
void mutt_window_reflow(struct MuttWindow *win)
Resize a Window and its children.
Definition: mutt_window.c:443
#define mutt_error(...)
Definition: logging.h:84
int index
The absolute (unsorted) message number.
Definition: email.h:86
Colour indicator.
Definition: mutt_thread.h:71
#define FREE(x)
Definition: memory.h:40
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:152
WHERE bool OptMsgErr
(pseudo) used by mutt_error/mutt_message
Definition: options.h:41
Hide the cursor.
Definition: mutt_curses.h:80
#define R_RESORT_INIT
Resort from scratch.
Definition: types.h:70
WHERE bool OptSortSubthreads
(pseudo) used when $sort_aux changes
Definition: options.h:54
void window_redraw(struct MuttWindow *win, bool force)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:757
void mutt_show_error(void)
Show the user an error message.
Definition: curs_lib.c:557
int mutt_window_addstr(const char *str)
Write a string to a Window.
Definition: mutt_window.c:532
Hundreds of global variables to back the user variables.
Handling of global boolean variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
WHERE bool ErrorBufMessage
true if the last message was an error
Definition: mutt_globals.h:44
int mutt_color_combine(struct Colors *c, uint32_t fg_attr, uint32_t bg_attr)
Combine two colours.
Definition: color.c:576
Index: default colour (takes a pattern)
Definition: color.h:100
Blank space.
Definition: mutt_thread.h:61
int current
Current entry.
Definition: mutt_menu.h:56
struct MuttWindow * win_index
Definition: mutt_menu.h:63
Convenience wrapper for the library headers.
void mutt_curses_set_attr(int attr)
Set the attributes for text.
Definition: mutt_curses.c:40
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
Definition: mbyte.c:358
WHERE SIG_ATOMIC_VOLATILE_T SigWinch
true after SIGWINCH is received
Definition: mutt_globals.h:75
int(* search)(struct Menu *menu, regex_t *rx, int line)
Search a menu for a item matching a regex.
Definition: mutt_menu.h:98
Question mark.
Definition: mutt_thread.h:68
void(* make_entry)(char *buf, size_t buflen, struct Menu *menu, int line)
Format a item for a menu.
Definition: mutt_menu.h:88
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: lib.h:94
int pair
Color-pair to use when displaying in the index.
Definition: email.h:80
WHERE char * C_ArrowString
Config: Use an custom string for arrow_cursor.
Definition: mutt_globals.h:132
#define REDRAW_CURRENT
Redraw the current line of the menu.
Definition: mutt_menu.h:43
Index: flags field (takes a pattern)
Definition: color.h:102
A regular expression and a color to highlight a line.
Definition: color.h:35
WHERE bool C_Resolve
Config: Move to the next email whenever a command modifies an email.
Definition: mutt_globals.h:154
#define R_REDRAW_MASK
Mask for the Redraw Flags.
Definition: types.h:76
void mutt_simple_format(char *buf, size_t buflen, int min_width, int max_width, enum FormatJustify justify, char pad_char, const char *s, size_t n, bool arboreal)
Format a string, like snprintf()
Definition: curs_lib.c:1093
Equals (for threads)
Definition: mutt_thread.h:65
#define R_INDEX
Redraw the index menu (MENU_MAIN)
Definition: types.h:65
uint16_t MuttRedrawFlags
Flags, e.g. REDRAW_INDEX.
Definition: mutt_menu.h:38