NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
question.c File Reference

Ask the user a question. More...

#include "config.h"
#include <ctype.h>
#include <langinfo.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "gui/lib.h"
#include "keymap.h"
#include "mutt_globals.h"
#include "mutt_logging.h"
+ Include dependency graph for question.c:

Go to the source code of this file.

Functions

int mutt_multi_choice (const char *prompt, const char *letters)
 Offer the user a multiple choice question. More...
 
enum QuadOption mutt_yesorno (const char *msg, enum QuadOption def)
 Ask the user a Yes/No question. More...
 
enum QuadOption query_quadoption (enum QuadOption opt, const char *prompt)
 Ask the user a quad-question. More...
 

Detailed Description

Ask the user a question.

Authors
  • Richard Russon

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file question.c.

Function Documentation

◆ mutt_multi_choice()

int mutt_multi_choice ( const char *  prompt,
const char *  letters 
)

Offer the user a multiple choice question.

Parameters
promptMessage prompt
lettersAllowable selection keys
Return values
>=00-based user selection
-1Selection aborted

Definition at line 49 of file question.c.

50 {
51  struct MuttWindow *win = msgwin_get_window();
52  if (!win)
53  return -1;
54 
55  struct KeyEvent ch;
56  int choice;
57  bool redraw = true;
58  int prompt_lines = 1;
59 
60  const bool opt_cols = ((mutt_color(MT_COLOR_OPTIONS) != 0) &&
62 
63  struct MuttWindow *old_focus = window_set_focus(win);
64  window_redraw(NULL);
65  while (true)
66  {
67  if (redraw || SigWinch)
68  {
69  redraw = false;
70  if (SigWinch)
71  {
72  SigWinch = false;
74  clearok(stdscr, true);
75  window_redraw(NULL);
76  }
77  if (win->state.cols)
78  {
79  int width = mutt_strwidth(prompt) + 2; // + '?' + space
80  /* If we're going to colour the options,
81  * make an assumption about the modified prompt size. */
82  if (opt_cols)
83  width -= 2 * mutt_str_len(letters);
84 
85  prompt_lines = (width + win->state.cols - 1) / win->state.cols;
86  prompt_lines = MAX(1, MIN(3, prompt_lines));
87  }
88  if (prompt_lines != win->state.rows)
89  {
90  msgwin_set_height(prompt_lines);
91  window_redraw(NULL);
92  }
93 
94  mutt_window_move(win, 0, 0);
95 
96  if (opt_cols)
97  {
98  char *cur = NULL;
99 
100  while ((cur = strchr(prompt, '(')))
101  {
102  // write the part between prompt and cur using MT_COLOR_PROMPT
104  mutt_window_addnstr(win, prompt, cur - prompt);
105 
106  if (isalnum(cur[1]) && (cur[2] == ')'))
107  {
108  // we have a single letter within parentheses
110  mutt_window_addch(win, cur[1]);
111  prompt = cur + 3;
112  }
113  else
114  {
115  // we have a parenthesis followed by something else
116  mutt_window_addch(win, cur[0]);
117  prompt = cur + 1;
118  }
119  }
120  }
121 
123  mutt_window_addstr(win, prompt);
125 
126  mutt_window_addch(win, ' ');
128  }
129 
130  mutt_refresh();
131  /* SigWinch is not processed unless timeout is set */
132  mutt_getch_timeout(30 * 1000);
133  ch = mutt_getch();
134  mutt_getch_timeout(-1);
135  if (ch.ch == -2) // Timeout
136  continue;
137  /* (ch.ch == 0) is technically possible. Treat the same as < 0 (abort) */
138  if ((ch.ch <= 0) || CI_is_return(ch.ch))
139  {
140  choice = -1;
141  break;
142  }
143  else
144  {
145  char *p = strchr(letters, ch.ch);
146  if (p)
147  {
148  choice = p - letters + 1;
149  break;
150  }
151  else if ((ch.ch <= '9') && (ch.ch > '0'))
152  {
153  choice = ch.ch - '0';
154  if (choice <= mutt_str_len(letters))
155  break;
156  }
157  }
158  mutt_beep(false);
159  }
160  if (win->state.rows == 1)
161  {
162  mutt_window_clearline(win, 0);
163  }
164  else
165  {
167  window_redraw(NULL);
168  }
169  window_set_focus(old_focus);
170  mutt_refresh();
171  return choice;
172 }
#define CI_is_return(ch)
Definition: mutt_curses.h:71
#define MIN(a, b)
Definition: memory.h:31
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:56
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:259
void mutt_resize_screen(void)
Update NeoMutt&#39;s opinion about the window size (CURSES)
Definition: resize.c:101
struct MuttWindow * window_set_focus(struct MuttWindow *win)
Set the Window focus.
Definition: mutt_window.c:680
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:632
int ch
raw key pressed
Definition: keymap.h:66
void msgwin_set_height(short height)
Resize the Message Window.
Definition: msgwin.c:276
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:310
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:105
#define MAX(a, b)
Definition: memory.h:30
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:247
struct MuttWindow * msgwin_get_window(void)
Get the Message Window pointer.
Definition: msgwin.c:253
int mutt_window_addstr(struct MuttWindow *win, const char *str)
Write a string to a Window.
Definition: mutt_window.c:434
Plain text.
Definition: color.h:58
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:115
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:983
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:61
An event such as a keypress.
Definition: keymap.h:64
struct KeyEvent mutt_getch(void)
Read a character from the input buffer.
Definition: curs_lib.c:196
int mutt_color(enum ColorId id)
Return the color of an object.
Definition: color.c:1427
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
void mutt_getch_timeout(int delay)
Set the getch() timeout.
Definition: curs_lib.c:153
int mutt_window_addnstr(struct MuttWindow *win, const char *str, int num)
Write a partial string to a Window.
Definition: mutt_window.c:415
Options in prompt.
Definition: color.h:59
WHERE SIG_ATOMIC_VOLATILE_T SigWinch
true after SIGWINCH is received
Definition: mutt_globals.h:68
Question/user input.
Definition: color.h:61
int mutt_window_addch(struct MuttWindow *win, int ch)
Write one character to a Window.
Definition: mutt_window.c:402
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_yesorno()

enum QuadOption mutt_yesorno ( const char *  msg,
enum QuadOption  def 
)

Ask the user a Yes/No question.

Parameters
msgPrompt
defDefault answer, MUTT_YES or MUTT_NO (see QuadOption)
Return values
numSelection made, see QuadOption

Definition at line 180 of file question.c.

181 {
182  struct MuttWindow *win = msgwin_get_window();
183  if (!win)
184  return MUTT_ABORT;
185 
186  struct KeyEvent ch;
187  char *answer_string = NULL;
188  int answer_string_wid, msg_wid;
189  size_t trunc_msg_len;
190  bool redraw = true;
191  int prompt_lines = 1;
192  char answer[2] = { 0 };
193 
194  char *yes = N_("yes");
195  char *no = N_("no");
196  char *trans_yes = _(yes);
197  char *trans_no = _(no);
198 
199  char *expr = NULL;
200  regex_t reyes;
201  regex_t reno;
202 
203  bool reyes_ok = (expr = nl_langinfo(YESEXPR)) && (expr[0] == '^') &&
204  (REG_COMP(&reyes, expr, REG_NOSUB) == 0);
205  bool reno_ok = (expr = nl_langinfo(NOEXPR)) && (expr[0] == '^') &&
206  (REG_COMP(&reno, expr, REG_NOSUB) == 0);
207 
208  if ((yes != trans_yes) && (no != trans_no) && reyes_ok && reno_ok)
209  {
210  // If all parts of the translation succeeded...
211  yes = trans_yes;
212  no = trans_no;
213  }
214  else
215  {
216  // otherwise, fallback to English
217  if (reyes_ok)
218  {
219  regfree(&reyes);
220  reyes_ok = false;
221  }
222  if (reno_ok)
223  {
224  regfree(&reno);
225  reno_ok = false;
226  }
227  }
228 
229  /* In order to prevent the default answer to the question to wrapped
230  * around the screen in the event the question is wider than the screen,
231  * ensure there is enough room for the answer and truncate the question
232  * to fit. */
233  mutt_str_asprintf(&answer_string, " ([%s]/%s): ", (def == MUTT_YES) ? yes : no,
234  (def == MUTT_YES) ? no : yes);
235  answer_string_wid = mutt_strwidth(answer_string);
236  msg_wid = mutt_strwidth(msg);
237 
238  struct MuttWindow *old_focus = window_set_focus(win);
239  window_redraw(NULL);
240  while (true)
241  {
242  if (redraw || SigWinch)
243  {
244  redraw = false;
245  if (SigWinch)
246  {
247  SigWinch = false;
249  clearok(stdscr, true);
250  window_redraw(NULL);
251  }
252  if (win->state.cols)
253  {
254  prompt_lines =
255  (msg_wid + answer_string_wid + win->state.cols - 1) / win->state.cols;
256  prompt_lines = MAX(1, MIN(3, prompt_lines));
257  }
258  if (prompt_lines != win->state.rows)
259  {
260  msgwin_set_height(prompt_lines);
261  window_redraw(NULL);
262  }
263 
264  /* maxlen here is sort of arbitrary, so pick a reasonable upper bound */
265  trunc_msg_len = mutt_wstr_trunc(
266  msg, (size_t) 4 * prompt_lines * win->state.cols,
267  ((size_t) prompt_lines * win->state.cols) - answer_string_wid, NULL);
268 
269  mutt_window_move(win, 0, 0);
271  mutt_window_addnstr(win, msg, trunc_msg_len);
272  mutt_window_addstr(win, answer_string);
275  }
276 
277  mutt_refresh();
278  /* SigWinch is not processed unless timeout is set */
279  mutt_getch_timeout(30 * 1000);
280  ch = mutt_getch();
281  mutt_getch_timeout(-1);
282  if (ch.ch == -2) // Timeout
283  continue;
284  if (CI_is_return(ch.ch))
285  break;
286  if (ch.ch < 0)
287  {
288  def = MUTT_ABORT;
289  break;
290  }
291 
292  answer[0] = ch.ch;
293  if (reyes_ok ? (regexec(&reyes, answer, 0, 0, 0) == 0) : (tolower(ch.ch) == 'y'))
294  {
295  def = MUTT_YES;
296  break;
297  }
298  else if (reno_ok ? (regexec(&reno, answer, 0, 0, 0) == 0) : (tolower(ch.ch) == 'n'))
299  {
300  def = MUTT_NO;
301  break;
302  }
303  else
304  {
305  mutt_beep(false);
306  }
307  }
308  window_set_focus(old_focus);
309 
310  FREE(&answer_string);
311 
312  if (reyes_ok)
313  regfree(&reyes);
314  if (reno_ok)
315  regfree(&reno);
316 
317  if (win->state.rows == 1)
318  {
319  mutt_window_clearline(win, 0);
320  }
321  else
322  {
324  window_redraw(NULL);
325  }
326 
327  if (def == MUTT_ABORT)
328  {
329  /* when the users cancels with ^G, clear the message stored with
330  * mutt_message() so it isn't displayed when the screen is refreshed. */
332  }
333  else
334  {
335  mutt_window_addstr(win, (char *) ((def == MUTT_YES) ? yes : no));
336  mutt_refresh();
337  }
338  return def;
339 }
#define CI_is_return(ch)
Definition: mutt_curses.h:71
#define MIN(a, b)
Definition: memory.h:31
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:56
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:259
void mutt_resize_screen(void)
Update NeoMutt&#39;s opinion about the window size (CURSES)
Definition: resize.c:101
struct MuttWindow * window_set_focus(struct MuttWindow *win)
Set the Window focus.
Definition: mutt_window.c:680
#define _(a)
Definition: message.h:28
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:54
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:632
int ch
raw key pressed
Definition: keymap.h:66
void msgwin_set_height(short height)
Resize the Message Window.
Definition: msgwin.c:276
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:310
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:105
#define MAX(a, b)
Definition: memory.h:30
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:247
struct MuttWindow * msgwin_get_window(void)
Get the Message Window pointer.
Definition: msgwin.c:253
int mutt_window_addstr(struct MuttWindow *win, const char *str)
Write a string to a Window.
Definition: mutt_window.c:434
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:112
User aborted the question (with Ctrl-G)
Definition: quad.h:37
Plain text.
Definition: color.h:58
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:115
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:983
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:61
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:933
An event such as a keypress.
Definition: keymap.h:64
struct KeyEvent mutt_getch(void)
Read a character from the input buffer.
Definition: curs_lib.c:196
void mutt_getch_timeout(int delay)
Set the getch() timeout.
Definition: curs_lib.c:153
#define FREE(x)
Definition: memory.h:40
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
int mutt_window_addnstr(struct MuttWindow *win, const char *str, int num)
Write a partial string to a Window.
Definition: mutt_window.c:415
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1128
#define N_(a)
Definition: message.h:32
WHERE SIG_ATOMIC_VOLATILE_T SigWinch
true after SIGWINCH is received
Definition: mutt_globals.h:68
Question/user input.
Definition: color.h:61
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ query_quadoption()

enum QuadOption query_quadoption ( enum QuadOption  opt,
const char *  prompt 
)

Ask the user a quad-question.

Parameters
optOption to use
promptMessage to show to the user
Return values
QuadOptionResult, e.g. MUTT_NO

Definition at line 347 of file question.c.

348 {
349  switch (opt)
350  {
351  case MUTT_YES:
352  case MUTT_NO:
353  return opt;
354 
355  default:
356  opt = mutt_yesorno(prompt, (opt == MUTT_ASKYES) ? MUTT_YES : MUTT_NO);
358  return opt;
359  }
360 
361  /* not reached */
362 }
void msgwin_clear_text(void)
Clear the text in the Message Window.
Definition: msgwin.c:242
Ask the user, defaulting to &#39;Yes&#39;.
Definition: quad.h:41
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:180
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function: