NeoMutt  2022-04-29-145-g9b6a0e
Teaching an old dog new tricks
DOXYGEN
curs_lib.c
Go to the documentation of this file.
1 
30 #include "config.h"
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <limits.h>
34 #include <stdbool.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <termios.h>
39 #include <unistd.h>
40 #include <wchar.h>
41 #include "mutt/lib.h"
42 #include "config/lib.h"
43 #include "core/lib.h"
44 #include "mutt.h"
45 #include "curs_lib.h"
46 #include "browser/lib.h"
47 #include "color/lib.h"
48 #include "enter/lib.h"
49 #include "question/lib.h"
50 #include "keymap.h"
51 #include "msgwin.h"
52 #include "mutt_curses.h"
53 #include "mutt_globals.h"
54 #include "mutt_logging.h"
55 #include "mutt_thread.h"
56 #include "mutt_window.h"
57 #include "opcodes.h"
58 #include "options.h"
59 #include "protos.h"
60 #ifdef HAVE_ISWBLANK
61 #include <wctype.h>
62 #endif
63 #ifdef USE_INOTIFY
64 #include "monitor.h"
65 #endif
66 
67 /* not possible to unget more than one char under some curses libs, so roll our
68  * own input buffering routines. */
69 
70 ARRAY_HEAD(KeyEventArray, struct KeyEvent);
71 
72 /* These are used for macros and exec/push commands.
73  * They can be temporarily ignored by setting OptIgnoreMacroEvents */
74 static struct KeyEventArray MacroEvents = ARRAY_HEAD_INITIALIZER;
75 
76 /* These are used in all other "normal" situations, and are not
77  * ignored when setting OptIgnoreMacroEvents */
78 static struct KeyEventArray UngetKeyEvents = ARRAY_HEAD_INITIALIZER;
79 
85 static struct KeyEvent *array_pop(struct KeyEventArray *a)
86 {
87  if (ARRAY_EMPTY(a))
88  {
89  return NULL;
90  }
91 
92  struct KeyEvent *event = ARRAY_LAST(a);
93  ARRAY_SHRINK(a, 1);
94  return event;
95 }
96 
103 static void array_add(struct KeyEventArray *a, int ch, int op)
104 {
105  struct KeyEvent event = { .ch = ch, .op = op };
106  ARRAY_ADD(a, event);
107 }
108 
113 static void array_to_endcond(struct KeyEventArray *a)
114 {
115  while (!ARRAY_EMPTY(a))
116  {
117  if (array_pop(a)->op == OP_END_COND)
118  {
119  return;
120  }
121  }
122 }
123 
125 
130 void mutt_beep(bool force)
131 {
132  const bool c_beep = cs_subset_bool(NeoMutt->sub, "beep");
133  if (force || c_beep)
134  beep();
135 }
136 
140 void mutt_refresh(void)
141 {
142  /* don't refresh when we are waiting for a child. */
143  if (OptKeepQuiet)
144  return;
145 
146  /* don't refresh in the middle of macros unless necessary */
148  return;
149 
150  /* else */
151  refresh();
152 }
153 
163 {
164  // Forcibly switch to the alternate screen.
165  // Using encryption can leave ncurses confused about which mode it's in.
166  fputs("\033[?1049h", stdout);
167  fflush(stdout);
168  keypad(stdscr, true);
169  clearok(stdscr, true);
170  window_redraw(NULL);
171 }
172 
181 static void set_timeout(int delay)
182 {
183  MuttGetchTimeout = delay;
184  timeout(delay);
185 }
186 
197 struct KeyEvent mutt_getch_timeout(int delay)
198 {
199  set_timeout(delay);
200  struct KeyEvent event = mutt_getch();
201  set_timeout(-1);
202  return event;
203 }
204 
205 #ifdef USE_INOTIFY
211 static int mutt_monitor_getch(void)
212 {
213  /* ncurses has its own internal buffer, so before we perform a poll,
214  * we need to make sure there isn't a character waiting */
215  timeout(0);
216  int ch = getch();
217  timeout(MuttGetchTimeout);
218  if (ch == ERR)
219  {
220  if (mutt_monitor_poll() != 0)
221  ch = ERR;
222  else
223  ch = getch();
224  }
225  return ch;
226 }
227 #endif /* USE_INOTIFY */
228 
242 struct KeyEvent mutt_getch(void)
243 {
244  int ch;
245  const struct KeyEvent err = { 0, OP_ABORT };
246  const struct KeyEvent timeout = { 0, OP_TIMEOUT };
247 
248  struct KeyEvent *key = array_pop(&UngetKeyEvents);
249  if (key)
250  {
251  return *key;
252  }
253 
254  if (!OptIgnoreMacroEvents && (key = array_pop(&MacroEvents)))
255  {
256  return *key;
257  }
258 
259  SigInt = false;
260 
262 #ifdef KEY_RESIZE
263  /* ncurses 4.2 sends this when the screen is resized */
264  ch = KEY_RESIZE;
265  while (ch == KEY_RESIZE)
266 #endif
267 #ifdef USE_INOTIFY
269 #else
270  ch = getch();
271 #endif
273 
274  if (SigInt)
275  {
276  mutt_query_exit();
277  return err;
278  }
279 
280  /* either timeout, a sigwinch (if timeout is set), the terminal
281  * has been lost, or curses was never initialized */
282  if (ch == ERR)
283  {
284  if (!isatty(0))
285  {
286  mutt_exit(1);
287  }
288 
289  return OptNoCurses ? err : timeout;
290  }
291 
292  const bool c_meta_key = cs_subset_bool(NeoMutt->sub, "meta_key");
293  if ((ch & 0x80) && c_meta_key)
294  {
295  /* send ALT-x as ESC-x */
296  ch &= ~0x80;
297  mutt_unget_ch(ch);
298  ch = '\033';
299  return (struct KeyEvent){ .ch = '\033' /* Escape */, .op = OP_NULL };
300  }
301 
302  if (ch == AbortKey)
303  return err;
304 
305  return (struct KeyEvent){ .ch = ch, .op = OP_NULL };
306 }
307 
313 void mutt_edit_file(const char *editor, const char *file)
314 {
315  struct Buffer *cmd = mutt_buffer_pool_get();
316 
317  mutt_endwin();
318  mutt_buffer_file_expand_fmt_quote(cmd, editor, file);
319  if (mutt_system(mutt_buffer_string(cmd)) != 0)
320  {
321  mutt_error(_("Error running \"%s\""), mutt_buffer_string(cmd));
322  }
323  /* the terminal may have been resized while the editor owned it */
325  keypad(stdscr, true);
326  clearok(stdscr, true);
327 
329 }
330 
336 void mutt_query_exit(void)
337 {
338  mutt_flushinp();
340  const short c_timeout = cs_subset_number(NeoMutt->sub, "timeout");
341  if (c_timeout)
342  set_timeout(-1); /* restore blocking operation */
343  if (mutt_yesorno(_("Exit NeoMutt?"), MUTT_YES) == MUTT_YES)
344  {
345  mutt_exit(1);
346  }
348  mutt_curses_set_cursor(cursor);
349  SigInt = false;
350 }
351 
355 void mutt_endwin(void)
356 {
357  if (OptNoCurses)
358  return;
359 
360  int e = errno;
361 
362  /* at least in some situations (screen + xterm under SuSE11/12) endwin()
363  * doesn't properly flush the screen without an explicit call. */
364  mutt_refresh();
365  endwin();
366 
367  errno = e;
368 }
369 
374 void mutt_perror_debug(const char *s)
375 {
376  char *p = strerror(errno);
377 
378  mutt_debug(LL_DEBUG1, "%s: %s (errno = %d)\n", s, p ? p : "unknown error", errno);
379  mutt_error("%s: %s (errno = %d)", s, p ? p : _("unknown error"), errno);
380 }
381 
388 int mutt_any_key_to_continue(const char *s)
389 {
390  struct termios term;
391  struct termios old;
392 
393  int fd = open("/dev/tty", O_RDONLY);
394  if (fd < 0)
395  return EOF;
396 
397  tcgetattr(fd, &old); // Save the current tty settings
398 
399  term = old;
400  term.c_lflag &= ~(ICANON | ECHO); // Canonical (not line-buffered), don't echo the characters
401  term.c_cc[VMIN] = 1; // Wait for at least one character
402  term.c_cc[VTIME] = 255; // Wait for 25.5s
403  tcsetattr(fd, TCSANOW, &term);
404 
405  if (s)
406  fputs(s, stdout);
407  else
408  fputs(_("Press any key to continue..."), stdout);
409  fflush(stdout);
410 
411  char ch = '\0';
412  // Wait for a character. This might timeout, so loop.
413  while (read(fd, &ch, 1) == 0)
414  ; // do nothing
415 
416  // Change the tty settings to be non-blocking
417  term.c_cc[VMIN] = 0; // Returning with zero characters is acceptable
418  term.c_cc[VTIME] = 0; // Don't wait
419  tcsetattr(fd, TCSANOW, &term);
420 
421  char buf[64];
422  while (read(fd, buf, sizeof(buf)) > 0)
423  ; // Mop up any remaining chars
424 
425  tcsetattr(fd, TCSANOW, &old); // Restore the previous tty settings
426  close(fd);
427 
428  fputs("\r\n", stdout);
430  return (ch >= 0) ? ch : EOF;
431 }
432 
446 int mutt_buffer_enter_fname(const char *prompt, struct Buffer *fname,
447  bool mailbox, struct Mailbox *m, bool multiple,
448  char ***files, int *numfiles, SelectFileFlags flags)
449 {
450  struct MuttWindow *win = msgwin_get_window();
451  if (!win)
452  return -1;
453 
454  struct KeyEvent ch = { OP_NULL, OP_NULL };
455  struct MuttWindow *old_focus = window_set_focus(win);
456 
458  mutt_window_mvaddstr(win, 0, 0, prompt);
459  mutt_window_addstr(win, _(" ('?' for list): "));
461  if (!mutt_buffer_is_empty(fname))
464  mutt_refresh();
465 
467  do
468  {
469  ch = mutt_getch();
470  } while (ch.op == OP_TIMEOUT);
471  mutt_curses_set_cursor(cursor);
472 
473  mutt_window_move(win, 0, 0);
475  mutt_refresh();
476  window_set_focus(old_focus);
477 
478  if (ch.ch < 0)
479  {
480  return -1;
481  }
482  else if (ch.ch == '?')
483  {
484  mutt_buffer_reset(fname);
485 
486  if (flags == MUTT_SEL_NO_FLAGS)
487  flags = MUTT_SEL_FOLDER;
488  if (multiple)
489  flags |= MUTT_SEL_MULTI;
490  if (mailbox)
491  flags |= MUTT_SEL_MAILBOX;
492  mutt_buffer_select_file(fname, flags, m, files, numfiles);
493  }
494  else
495  {
496  char *pc = mutt_mem_malloc(mutt_str_len(prompt) + 3);
497 
498  sprintf(pc, "%s: ", prompt);
499  if (ch.op == OP_NULL)
500  mutt_unget_ch(ch.ch);
501  else
502  mutt_unget_op(ch.op);
503 
504  mutt_buffer_alloc(fname, 1024);
506  multiple, m, files, numfiles) != 0)
507  {
508  mutt_buffer_reset(fname);
509  }
510  FREE(&pc);
511  }
512 
513  return 0;
514 }
515 
522 void mutt_unget_ch(int ch)
523 {
524  array_add(&UngetKeyEvents, ch, OP_NULL);
525 }
526 
533 void mutt_unget_op(int op)
534 {
535  array_add(&UngetKeyEvents, 0, op);
536 }
537 
544 void mutt_unget_string(const char *s)
545 {
546  const char *p = s + mutt_str_len(s) - 1;
547 
548  while (p >= s)
549  {
550  mutt_unget_ch((unsigned char) *p--);
551  }
552 }
553 
562 void mutt_push_macro_event(int ch, int op)
563 {
564  array_add(&MacroEvents, ch, op);
565 }
566 
574 {
576 }
577 
586 {
588 }
589 
593 void mutt_flushinp(void)
594 {
597  flushinp();
598 }
599 
607 int mutt_addwch(struct MuttWindow *win, wchar_t wc)
608 {
609  char buf[MB_LEN_MAX * 2];
610  mbstate_t mbstate = { 0 };
611  size_t n1, n2;
612 
613  if (((n1 = wcrtomb(buf, wc, &mbstate)) == (size_t) (-1)) ||
614  ((n2 = wcrtomb(buf + n1, 0, &mbstate)) == (size_t) (-1)))
615  {
616  return -1; /* ERR */
617  }
618  else
619  {
620  return mutt_window_addstr(win, buf);
621  }
622 }
623 
640 void mutt_simple_format(char *buf, size_t buflen, int min_width, int max_width,
641  enum FormatJustify justify, char pad_char,
642  const char *s, size_t n, bool arboreal)
643 {
644  wchar_t wc = 0;
645  int w;
646  size_t k, k2;
647  char scratch[MB_LEN_MAX];
648  mbstate_t mbstate1 = { 0 };
649  mbstate_t mbstate2 = { 0 };
650  bool escaped = false;
651 
652  buflen--;
653  char *p = buf;
654  for (; n && (k = mbrtowc(&wc, s, n, &mbstate1)); s += k, n -= k)
655  {
656  if ((k == (size_t) (-1)) || (k == (size_t) (-2)))
657  {
658  if ((k == (size_t) (-1)) && (errno == EILSEQ))
659  memset(&mbstate1, 0, sizeof(mbstate1));
660 
661  k = (k == (size_t) (-1)) ? 1 : n;
662  wc = ReplacementChar;
663  }
664  if (escaped)
665  {
666  escaped = false;
667  w = 0;
668  }
669  else if (arboreal && (wc == MUTT_SPECIAL_INDEX))
670  {
671  escaped = true;
672  w = 0;
673  }
674  else if (arboreal && (wc < MUTT_TREE_MAX))
675  {
676  w = 1; /* hack */
677  }
678  else
679  {
680 #ifdef HAVE_ISWBLANK
681  if (iswblank(wc))
682  wc = ' ';
683  else
684 #endif
685  if (!IsWPrint(wc))
686  wc = '?';
687  w = wcwidth(wc);
688  }
689  if (w >= 0)
690  {
691  if ((w > max_width) || ((k2 = wcrtomb(scratch, wc, &mbstate2)) > buflen))
692  continue;
693  min_width -= w;
694  max_width -= w;
695  strncpy(p, scratch, k2);
696  p += k2;
697  buflen -= k2;
698  }
699  }
700  w = ((int) buflen < min_width) ? buflen : min_width;
701  if (w <= 0)
702  *p = '\0';
703  else if (justify == JUSTIFY_RIGHT) /* right justify */
704  {
705  p[w] = '\0';
706  while (--p >= buf)
707  p[w] = *p;
708  while (--w >= 0)
709  buf[w] = pad_char;
710  }
711  else if (justify == JUSTIFY_CENTER) /* center */
712  {
713  char *savedp = p;
714  int half = (w + 1) / 2; /* half of cushion space */
715 
716  p[w] = '\0';
717 
718  /* move str to center of buffer */
719  while (--p >= buf)
720  p[half] = *p;
721 
722  /* fill rhs */
723  p = savedp + half;
724  while (--w >= half)
725  *p++ = pad_char;
726 
727  /* fill lhs */
728  while (half--)
729  buf[half] = pad_char;
730  }
731  else /* left justify */
732  {
733  while (--w >= 0)
734  *p++ = pad_char;
735  *p = '\0';
736  }
737 }
738 
753 void mutt_format_s_x(char *buf, size_t buflen, const char *prec, const char *s, bool arboreal)
754 {
755  enum FormatJustify justify = JUSTIFY_RIGHT;
756  char *p = NULL;
757  int min_width;
758  int max_width = INT_MAX;
759 
760  if (*prec == '-')
761  {
762  prec++;
763  justify = JUSTIFY_LEFT;
764  }
765  else if (*prec == '=')
766  {
767  prec++;
768  justify = JUSTIFY_CENTER;
769  }
770  min_width = strtol(prec, &p, 10);
771  if (*p == '.')
772  {
773  prec = p + 1;
774  max_width = strtol(prec, &p, 10);
775  if (p <= prec)
776  max_width = INT_MAX;
777  }
778 
779  mutt_simple_format(buf, buflen, min_width, max_width, justify, ' ', s,
780  mutt_str_len(s), arboreal);
781 }
782 
790 void mutt_format_s(char *buf, size_t buflen, const char *prec, const char *s)
791 {
792  mutt_format_s_x(buf, buflen, prec, s, false);
793 }
794 
802 void mutt_format_s_tree(char *buf, size_t buflen, const char *prec, const char *s)
803 {
804  mutt_format_s_x(buf, buflen, prec, s, true);
805 }
806 
813 void mutt_paddstr(struct MuttWindow *win, int n, const char *s)
814 {
815  wchar_t wc = 0;
816  size_t k;
817  size_t len = mutt_str_len(s);
818  mbstate_t mbstate = { 0 };
819 
820  for (; len && (k = mbrtowc(&wc, s, len, &mbstate)); s += k, len -= k)
821  {
822  if ((k == (size_t) (-1)) || (k == (size_t) (-2)))
823  {
824  if (k == (size_t) (-1))
825  memset(&mbstate, 0, sizeof(mbstate));
826  k = (k == (size_t) (-1)) ? 1 : len;
827  wc = ReplacementChar;
828  }
829  if (!IsWPrint(wc))
830  wc = '?';
831  const int w = wcwidth(wc);
832  if (w >= 0)
833  {
834  if (w > n)
835  break;
836  mutt_window_addnstr(win, (char *) s, k);
837  n -= w;
838  }
839  }
840  while (n-- > 0)
841  mutt_window_addch(win, ' ');
842 }
843 
855 size_t mutt_wstr_trunc(const char *src, size_t maxlen, size_t maxwid, size_t *width)
856 {
857  wchar_t wc = 0;
858  size_t n, w = 0, l = 0, cl;
859  int cw;
860  mbstate_t mbstate = { 0 };
861 
862  if (!src)
863  goto out;
864 
865  n = mutt_str_len(src);
866 
867  for (w = 0; n && (cl = mbrtowc(&wc, src, n, &mbstate)); src += cl, n -= cl)
868  {
869  if ((cl == (size_t) (-1)) || (cl == (size_t) (-2)))
870  {
871  if (cl == (size_t) (-1))
872  memset(&mbstate, 0, sizeof(mbstate));
873  cl = (cl == (size_t) (-1)) ? 1 : n;
874  wc = ReplacementChar;
875  }
876  cw = wcwidth(wc);
877  /* hack because MUTT_TREE symbols aren't turned into characters
878  * until rendered by print_enriched_string() */
879  if ((cw < 0) && (src[0] == MUTT_SPECIAL_INDEX))
880  {
881  cl = 2; /* skip the index coloring sequence */
882  cw = 0;
883  }
884  else if ((cw < 0) && (cl == 1) && (src[0] != '\0') && (src[0] < MUTT_TREE_MAX))
885  cw = 1;
886  else if (cw < 0)
887  cw = 0; /* unprintable wchar */
888  if ((cl + l > maxlen) || (cw + w > maxwid))
889  break;
890  l += cl;
891  w += cw;
892  }
893 out:
894  if (width)
895  *width = w;
896  return l;
897 }
898 
904 size_t mutt_strwidth(const char *s)
905 {
906  if (!s)
907  return 0;
908  return mutt_strnwidth(s, mutt_str_len(s));
909 }
910 
917 size_t mutt_strnwidth(const char *s, size_t n)
918 {
919  if (!s)
920  return 0;
921 
922  wchar_t wc = 0;
923  int w;
924  size_t k;
925  mbstate_t mbstate = { 0 };
926 
927  for (w = 0; n && (k = mbrtowc(&wc, s, n, &mbstate)); s += k, n -= k)
928  {
929  if (*s == MUTT_SPECIAL_INDEX)
930  {
931  s += 2; /* skip the index coloring sequence */
932  k = 0;
933  continue;
934  }
935 
936  if ((k == (size_t) (-1)) || (k == (size_t) (-2)))
937  {
938  if (k == (size_t) (-1))
939  memset(&mbstate, 0, sizeof(mbstate));
940  k = (k == (size_t) (-1)) ? 1 : n;
941  wc = ReplacementChar;
942  }
943  if (!IsWPrint(wc))
944  wc = '?';
945  w += wcwidth(wc);
946  }
947  return w;
948 }
#define ARRAY_SHRINK(head, num)
Mark a number of slots at the end of the array as unused.
Definition: array.h:171
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:155
#define ARRAY_LAST(head)
Convenience method to get the last element.
Definition: array.h:143
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition: array.h:73
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:86
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:57
Select a Mailbox from a list.
#define MUTT_SEL_MAILBOX
Select a mailbox.
Definition: lib.h:56
#define MUTT_SEL_FOLDER
Select a local directory.
Definition: lib.h:58
#define MUTT_SEL_MULTI
Multi-selection is enabled.
Definition: lib.h:57
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition: lib.h:55
uint8_t SelectFileFlags
Flags for mutt_select_file(), e.g. MUTT_SEL_MAILBOX.
Definition: lib.h:54
void mutt_buffer_select_file(struct Buffer *file, SelectFileFlags flags, struct Mailbox *m, char ***files, int *numfiles)
Let the user select a file.
Definition: browser.c:1085
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:250
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:81
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
Color and attribute parsing.
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:53
@ MT_COLOR_PROMPT
Question/user input.
Definition: color.h:56
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:313
size_t mutt_strnwidth(const char *s, size_t n)
Measure a string's width in screen cells.
Definition: curs_lib.c:917
static struct KeyEventArray MacroEvents
Definition: curs_lib.c:74
struct KeyEvent mutt_getch_timeout(int delay)
Get an event with a timeout.
Definition: curs_lib.c:197
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:593
static struct KeyEventArray UngetKeyEvents
Definition: curs_lib.c:78
size_t mutt_wstr_trunc(const char *src, size_t maxlen, size_t maxwid, size_t *width)
Work out how to truncate a widechar string.
Definition: curs_lib.c:855
static void array_add(struct KeyEventArray *a, int ch, int op)
Add an event to the end of the array.
Definition: curs_lib.c:103
static void array_to_endcond(struct KeyEventArray *a)
Clear the array until an OP_END_COND.
Definition: curs_lib.c:113
struct KeyEvent mutt_getch(void)
Read a character from the input buffer.
Definition: curs_lib.c:242
void mutt_unget_string(const char *s)
Return a string to the input buffer.
Definition: curs_lib.c:544
void mutt_push_macro_event(int ch, int op)
Add the character/operation to the macro buffer.
Definition: curs_lib.c:562
int mutt_buffer_enter_fname(const char *prompt, struct Buffer *fname, bool mailbox, struct Mailbox *m, bool multiple, char ***files, int *numfiles, SelectFileFlags flags)
Ask the user to select a file.
Definition: curs_lib.c:446
void mutt_paddstr(struct MuttWindow *win, int n, const char *s)
Display a string on screen, padded if necessary.
Definition: curs_lib.c:813
void mutt_format_s_x(char *buf, size_t buflen, const char *prec, const char *s, bool arboreal)
Format a string like snprintf()
Definition: curs_lib.c:753
void mutt_unget_op(int op)
Return an operation to the input buffer.
Definition: curs_lib.c:533
void mutt_format_s_tree(char *buf, size_t buflen, const char *prec, const char *s)
Format a simple string with tree characters.
Definition: curs_lib.c:802
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:140
static void set_timeout(int delay)
Set the getch() timeout.
Definition: curs_lib.c:181
static struct KeyEvent * array_pop(struct KeyEventArray *a)
Remove an event from the array.
Definition: curs_lib.c:85
void mutt_flush_unget_to_endcond(void)
Clear entries from UngetKeyEvents.
Definition: curs_lib.c:585
int mutt_addwch(struct MuttWindow *win, wchar_t wc)
Addwch would be provided by an up-to-date curses library.
Definition: curs_lib.c:607
void mutt_flush_macro_to_endcond(void)
Drop a macro from the input buffer.
Definition: curs_lib.c:573
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:640
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:388
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition: curs_lib.c:162
static int mutt_monitor_getch(void)
Get a character and poll the filesystem monitor.
Definition: curs_lib.c:211
void mutt_query_exit(void)
Ask the user if they want to leave NeoMutt.
Definition: curs_lib.c:336
ARRAY_HEAD(KeyEventArray, struct KeyEvent)
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:355
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:130
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:904
void mutt_unget_ch(int ch)
Return a keystroke to the input buffer.
Definition: curs_lib.c:522
void mutt_perror_debug(const char *s)
Show the user an 'errno' message.
Definition: curs_lib.c:374
void mutt_format_s(char *buf, size_t buflen, const char *prec, const char *s)
Format a simple string.
Definition: curs_lib.c:790
int MuttGetchTimeout
Timeout in ms for mutt_getch()
Definition: curs_lib.c:124
GUI miscellaneous curses (window drawing) routines.
FormatJustify
Alignment for mutt_simple_format()
Definition: curs_lib.h:41
@ JUSTIFY_RIGHT
Right justify the text.
Definition: curs_lib.h:44
@ JUSTIFY_LEFT
Left justify the text.
Definition: curs_lib.h:42
@ JUSTIFY_CENTER
Centre the text.
Definition: curs_lib.h:43
Enter a string.
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: window.c:180
void mutt_buffer_file_expand_fmt_quote(struct Buffer *dest, const char *fmt, const char *src)
Replace s in a string with a filename.
Definition: file.c:1488
#define mutt_error(...)
Definition: logging.h:87
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
keycode_t AbortKey
code of key to abort prompts, normally Ctrl-G
Definition: keymap.c:124
Manage keymappings.
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:248
#define IsWPrint(wc)
Definition: mbyte.h:39
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:43
int mutt_monitor_poll(void)
Check for filesystem changes.
Definition: monitor.c:399
Monitor files for changes.
struct MuttWindow * msgwin_get_window(void)
Get the Message Window pointer.
Definition: msgwin.c:258
Message Window.
wchar_t ReplacementChar
When a Unicode character can't be displayed, use this instead.
Definition: charset.c:57
#define EILSEQ
Definition: charset.c:51
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:544
Many unsorted constants and some structs.
#define MUTT_COMP_FILE
File completion (in browser)
Definition: mutt.h:55
#define MUTT_COMP_FILE_MBOX
File completion, plus incoming folders (in browser)
Definition: mutt.h:56
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:62
enum MuttCursorState mutt_curses_set_cursor(enum MuttCursorState state)
Set the cursor state.
Definition: mutt_curses.c:96
struct AttrColor * mutt_curses_set_normal_backed_color_by_id(enum ColorId cid)
Set the colour and attributes by the colour id.
Definition: mutt_curses.c:65
struct AttrColor * mutt_curses_set_color_by_id(enum ColorId cid)
Set the colour and attributes by the colour id.
Definition: mutt_curses.c:81
Define wrapper functions around Curses.
void mutt_resize_screen(void)
Update NeoMutt's opinion about the window size (CURSES)
Definition: resize.c:73
MuttCursorState
Cursor states for mutt_curses_set_cursor()
Definition: mutt_curses.h:52
@ MUTT_CURSOR_VISIBLE
Display a normal cursor.
Definition: mutt_curses.h:54
Hundreds of global variables to back the user variables.
SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: mutt_globals.h:69
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
NeoMutt Logging.
Create/manipulate threading in emails.
@ MUTT_TREE_MAX
Definition: mutt_thread.h:57
@ MUTT_SPECIAL_INDEX
Colour indicator.
Definition: mutt_thread.h:59
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:604
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:293
struct MuttWindow * window_set_focus(struct MuttWindow *win)
Set the Window focus.
Definition: mutt_window.c:659
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:307
int mutt_window_addstr(struct MuttWindow *win, const char *str)
Write a string to a Window.
Definition: mutt_window.c:409
int mutt_window_addnstr(struct MuttWindow *win, const char *str, int num)
Write a partial string to a Window.
Definition: mutt_window.c:394
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:242
int mutt_window_addch(struct MuttWindow *win, int ch)
Write one character to a Window.
Definition: mutt_window.c:381
Window management.
All user-callable functions.
#define OP_TIMEOUT
Definition: opcodes.h:32
#define OP_ABORT
Definition: opcodes.h:33
Handling of global boolean variables.
bool OptKeepQuiet
(pseudo) shut up the message and refresh functions while we are executing an external program
Definition: options.h:44
bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:53
bool OptForceRefresh
(pseudo) refresh even during macros
Definition: options.h:42
bool OptIgnoreMacroEvents
(pseudo) don't process macro/push/exec events while set
Definition: options.h:43
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
Prototypes for many functions.
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
Ask the user a question.
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:194
void mutt_sig_allow_interrupt(bool allow)
Allow/disallow Ctrl-C (SIGINT)
Definition: signal.c:238
String manipulation buffer.
Definition: buffer.h:34
An event such as a keypress.
Definition: keymap.h:65
int op
Function opcode, e.g. OP_HELP.
Definition: keymap.h:67
int ch
Raw key pressed.
Definition: keymap.h:66
A mailbox.
Definition: mailbox.h:79
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39