NeoMutt  2018-07-16 +1783-b00bd9
Teaching an old dog new tricks
DOXYGEN
help.c File Reference

Generate the help-line and help-page and GUI display them. More...

#include "config.h"
#include <stddef.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include "mutt/mutt.h"
#include "curs_lib.h"
#include "globals.h"
#include "keymap.h"
#include "mutt_window.h"
#include "muttlib.h"
#include "opcodes.h"
#include "pager.h"
+ Include dependency graph for help.c:

Go to the source code of this file.

Macros

#define DEFINE_HELP_MESSAGE(opcode, help_string)   help_string,
 

Functions

static const struct Bindinghelp_lookup_function (int op, int menu)
 Find a keybinding for an operation. More...
 
void mutt_make_help (char *buf, size_t buflen, const char *txt, int menu, int op)
 Create one entry for the help bar. More...
 
char * mutt_compile_help (char *buf, size_t buflen, int menu, const struct Mapping *items)
 Create the text for the help menu. More...
 
static int print_macro (FILE *fp, int maxwidth, const char **macro)
 Print a macro string to a file. More...
 
static int get_wrapped_width (const char *t, size_t wid)
 Wrap a string at a sensible place. More...
 
static int pad (FILE *fp, int col, int i)
 Write some padding to a file. More...
 
static void format_line (FILE *fp, int ismacro, const char *t1, const char *t2, const char *t3)
 Write a formatted line to a file. More...
 
static void dump_menu (FILE *fp, int menu)
 Write all the key bindings to a file. More...
 
static bool is_bound (struct Keymap *map, int op)
 Does a function have a keybinding? More...
 
static void dump_unbound (FILE *fp, const struct Binding *funcs, struct Keymap *map, struct Keymap *aux)
 Write out all the operations with no key bindings. More...
 
void mutt_help (int menu)
 Display the help menu. More...
 

Variables

static const char * HelpStrings []
 

Detailed Description

Generate the help-line and help-page and GUI display them.

Authors
  • Michael R. Elkins

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 help.c.

Macro Definition Documentation

#define DEFINE_HELP_MESSAGE (   opcode,
  help_string 
)    help_string,

Function Documentation

static const struct Binding* help_lookup_function ( int  op,
int  menu 
)
static

Find a keybinding for an operation.

Parameters
opOperation, e.g. OP_DELETE
menuCurrent Menu
Return values
ptrKey binding
NULLIf none

Definition at line 59 of file help.c.

60 {
61  const struct Binding *map = NULL;
62 
63  if (menu != MENU_PAGER)
64  {
65  /* first look in the generic map for the function */
66  for (int i = 0; OpGeneric[i].name; i++)
67  if (OpGeneric[i].op == op)
68  return &OpGeneric[i];
69  }
70 
71  map = km_get_table(menu);
72  if (map)
73  {
74  for (int i = 0; map[i].name; i++)
75  if (map[i].op == op)
76  return &map[i];
77  }
78 
79  return NULL;
80 }
int op
function id number
Definition: keymap.h:105
Pager pager (email viewer)
Definition: keymap.h:77
const char * name
name of the function
Definition: keymap.h:104
const struct Binding * km_get_table(int menu)
Lookup a menu&#39;s keybindings.
Definition: keymap.c:1204
const struct Binding OpGeneric[]
Key bindings for the generic menu.
Definition: functions.h:52
Mapping between a user key and a function.
Definition: keymap.h:102

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void mutt_make_help ( char *  buf,
size_t  buflen,
const char *  txt,
int  menu,
int  op 
)

Create one entry for the help bar.

Parameters
bufBuffer for the result
buflenLength of buffer
txtText part, e.g. "delete"
menuCurrent Menu
opOperation, e.g. OP_DELETE

This will return something like: "d:delete"

Definition at line 92 of file help.c.

93 {
94  char tmp[128];
95 
96  if (km_expand_key(tmp, sizeof(tmp), km_find_func(menu, op)) ||
97  km_expand_key(tmp, sizeof(tmp), km_find_func(MENU_GENERIC, op)))
98  {
99  snprintf(buf, buflen, "%s:%s", tmp, txt);
100  }
101  else
102  {
103  buf[0] = '\0';
104  }
105 }
int op
function id number
Definition: keymap.h:105
struct Keymap * km_find_func(int menu, int func)
Find a function&#39;s mapping in a Menu.
Definition: keymap.c:797
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: keymap.c:769
Generic selection list.
Definition: keymap.h:75

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

char* mutt_compile_help ( char *  buf,
size_t  buflen,
int  menu,
const struct Mapping items 
)

Create the text for the help menu.

Parameters
bufBuffer for the result
buflenLength of buffer
menuCurrent Menu
itemsMap of functions to display in the help bar
Return values
ptrBuffer containing result

Definition at line 115 of file help.c.

116 {
117  char *pbuf = buf;
118 
119  for (int i = 0; items[i].name && buflen > 2; i++)
120  {
121  if (i)
122  {
123  *pbuf++ = ' ';
124  *pbuf++ = ' ';
125  buflen -= 2;
126  }
127  mutt_make_help(pbuf, buflen, _(items[i].name), menu, items[i].value);
128  const size_t len = mutt_str_strlen(pbuf);
129  pbuf += len;
130  buflen -= len;
131  }
132  return buf;
133 }
#define _(a)
Definition: message.h:28
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:669
void mutt_make_help(char *buf, size_t buflen, const char *txt, int menu, int op)
Create one entry for the help bar.
Definition: help.c:92
const char * name
Definition: pgpmicalg.c:45
const char * name
Definition: mapping.h:31
static unsigned char * pbuf
Cache PGP data packet.
Definition: pgppacket.c:37

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int print_macro ( FILE *  fp,
int  maxwidth,
const char **  macro 
)
static

Print a macro string to a file.

Parameters
[in]fpFile to write to
[in]maxwidthMaximum width in screen columns
[out]macroMacro string
Return values
numNumber of screen columns used

The macro pointer is move past the string we've printed

Definition at line 144 of file help.c.

145 {
146  int n = maxwidth;
147  wchar_t wc;
148  size_t k;
149  size_t len = mutt_str_strlen(*macro);
150  mbstate_t mbstate1, mbstate2;
151 
152  memset(&mbstate1, 0, sizeof(mbstate1));
153  memset(&mbstate2, 0, sizeof(mbstate2));
154  for (; len && (k = mbrtowc(&wc, *macro, len, &mbstate1)); *macro += k, len -= k)
155  {
156  if ((k == (size_t)(-1)) || (k == (size_t)(-2)))
157  {
158  if (k == (size_t)(-1))
159  memset(&mbstate1, 0, sizeof(mbstate1));
160  k = (k == (size_t)(-1)) ? 1 : len;
161  wc = ReplacementChar;
162  }
163  /* glibc-2.1.3's wcwidth() returns 1 for unprintable chars! */
164  const int w = wcwidth(wc);
165  if (IsWPrint(wc) && (w >= 0))
166  {
167  if (w > n)
168  break;
169  n -= w;
170  {
171  char buf[MB_LEN_MAX * 2];
172  size_t n1, n2;
173  if (((n1 = wcrtomb(buf, wc, &mbstate2)) != (size_t)(-1)) &&
174  ((n2 = wcrtomb(buf + n1, 0, &mbstate2)) != (size_t)(-1)))
175  {
176  fputs(buf, fp);
177  }
178  }
179  }
180  else if ((wc < 0x20) || (wc == 0x7f))
181  {
182  if (n < 2)
183  break;
184  n -= 2;
185  if (wc == '\033') // Escape
186  fprintf(fp, "\\e");
187  else if (wc == '\n')
188  fprintf(fp, "\\n");
189  else if (wc == '\r')
190  fprintf(fp, "\\r");
191  else if (wc == '\t')
192  fprintf(fp, "\\t");
193  else
194  fprintf(fp, "^%c", (char) ((wc + '@') & 0x7f));
195  }
196  else
197  {
198  if (n < 1)
199  break;
200  n -= 1;
201  fprintf(fp, "?");
202  }
203  }
204  return maxwidth - n;
205 }
#define IsWPrint(wc)
Definition: mbyte.h:39
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:669
wchar_t ReplacementChar
When a Unicode character can&#39;t be displayed, use this instead.
Definition: charset.c:59

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int get_wrapped_width ( const char *  t,
size_t  wid 
)
static

Wrap a string at a sensible place.

Parameters
tString to wrap
widMaximum width
Return values
numBreak after this many characters

If the string's too long, look for some whitespace to break at.

Definition at line 215 of file help.c.

216 {
217  wchar_t wc;
218  size_t k;
219  size_t m, n;
220  size_t len = mutt_str_strlen(t);
221  const char *s = t;
222  mbstate_t mbstate;
223 
224  memset(&mbstate, 0, sizeof(mbstate));
225  for (m = wid, n = 0; len && (k = mbrtowc(&wc, s, len, &mbstate)) && (n <= wid);
226  s += k, len -= k)
227  {
228  if (*s == ' ')
229  m = n;
230  if ((k == (size_t)(-1)) || (k == (size_t)(-2)))
231  {
232  if (k == (size_t)(-1))
233  memset(&mbstate, 0, sizeof(mbstate));
234  k = (k == (size_t)(-1)) ? 1 : len;
235  wc = ReplacementChar;
236  }
237  if (!IsWPrint(wc))
238  wc = '?';
239  n += wcwidth(wc);
240  }
241  if (n > wid)
242  n = m;
243  else
244  n = wid;
245  return n;
246 }
#define IsWPrint(wc)
Definition: mbyte.h:39
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:669
wchar_t ReplacementChar
When a Unicode character can&#39;t be displayed, use this instead.
Definition: charset.c:59

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int pad ( FILE *  fp,
int  col,
int  i 
)
static

Write some padding to a file.

Parameters
fpFile to write to
colCurrent screen column
iScreen column to pad until
Return values
numi - Padding was added
numcol - Content was already wider than col

Definition at line 256 of file help.c.

257 {
258  if (col < i)
259  {
260  char fmt[32] = "";
261  snprintf(fmt, sizeof(fmt), "%%-%ds", i - col);
262  fprintf(fp, fmt, "");
263  return i;
264  }
265  fputc(' ', fp);
266  return col + 1;
267 }

+ Here is the caller graph for this function:

static void format_line ( FILE *  fp,
int  ismacro,
const char *  t1,
const char *  t2,
const char *  t3 
)
static

Write a formatted line to a file.

Parameters
fpFile to write to
ismacroLayout mode, see below
t1Text part 1
t2Text part 2
t3Text part 3

Assemble the three columns of text.

ismacro can be:

  • 1 : Macro with a description
  • 0 : Non-macro
  • -1 : Macro with no description

Definition at line 284 of file help.c.

285 {
286  int col;
287  int col_b;
288 
289  fputs(t1, fp);
290 
291  /* don't try to press string into one line with less than 40 characters. */
292  bool split = (MuttIndexWindow->cols < 40);
293  if (split)
294  {
295  col = 0;
296  col_b = 1024;
297  fputc('\n', fp);
298  }
299  else
300  {
301  const int col_a =
302  (MuttIndexWindow->cols > 83) ? (MuttIndexWindow->cols - 32) >> 2 : 12;
303  col_b = (MuttIndexWindow->cols > 49) ? (MuttIndexWindow->cols - 10) >> 1 : 19;
304  col = pad(fp, mutt_strwidth(t1), col_a);
305  }
306 
307  if (ismacro > 0)
308  {
309  if (mutt_str_strcmp(C_Pager, "builtin") == 0)
310  fputs("_\010", fp); // Ctrl-H (backspace)
311  fputs("M ", fp);
312  col += 2;
313 
314  if (!split)
315  {
316  col += print_macro(fp, col_b - col - 4, &t2);
317  if (mutt_strwidth(t2) > col_b - col)
318  t2 = "...";
319  }
320  }
321 
322  col += print_macro(fp, col_b - col - 1, &t2);
323  if (split)
324  fputc('\n', fp);
325  else
326  col = pad(fp, col, col_b);
327 
328  if (split)
329  {
330  print_macro(fp, 1024, &t3);
331  fputc('\n', fp);
332  }
333  else
334  {
335  while (*t3)
336  {
337  int n = MuttIndexWindow->cols - col;
338 
339  if (ismacro >= 0)
340  {
341  SKIPWS(t3);
342  n = get_wrapped_width(t3, n);
343  }
344 
345  n = print_macro(fp, n, &t3);
346 
347  if (*t3)
348  {
349  if (mutt_str_strcmp(C_Pager, "builtin") != 0)
350  {
351  fputc('\n', fp);
352  n = 0;
353  }
354  else
355  {
356  n += col - MuttIndexWindow->cols;
357  if (C_Markers)
358  n++;
359  }
360  col = pad(fp, n, col_b);
361  }
362  }
363  }
364 
365  fputc('\n', fp);
366 }
static int print_macro(FILE *fp, int maxwidth, const char **macro)
Print a macro string to a file.
Definition: help.c:144
static int get_wrapped_width(const char *t, size_t wid)
Wrap a string at a sensible place.
Definition: help.c:215
#define SKIPWS(ch)
Definition: string2.h:46
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:1239
struct MuttWindow * MuttIndexWindow
Index Window.
Definition: mutt_window.c:39
WHERE char * C_Pager
Config: External command for viewing messages, or &#39;builtin&#39; to use NeoMutt&#39;s.
Definition: globals.h:130
WHERE bool C_Markers
Config: Display a &#39;+&#39; at the beginning of wrapped lines in the pager.
Definition: globals.h:239
static int pad(FILE *fp, int col, int i)
Write some padding to a file.
Definition: help.c:256
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:618

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void dump_menu ( FILE *  fp,
int  menu 
)
static

Write all the key bindings to a file.

Parameters
fpFile to write to
menuCurrent Menu

Definition at line 373 of file help.c.

374 {
375  struct Keymap *map = NULL;
376  const struct Binding *b = NULL;
377  char buf[128];
378 
379  /* browse through the keymap table */
380  for (map = Keymaps[menu]; map; map = map->next)
381  {
382  if (map->op != OP_NULL)
383  {
384  km_expand_key(buf, sizeof(buf), map);
385 
386  if (map->op == OP_MACRO)
387  {
388  if (map->desc)
389  format_line(fp, 1, buf, map->macro, map->desc);
390  else
391  format_line(fp, -1, buf, "macro", map->macro);
392  }
393  else
394  {
395  b = help_lookup_function(map->op, menu);
396  format_line(fp, 0, buf, b ? b->name : "UNKNOWN",
397  b ? _(HelpStrings[b->op]) : _("ERROR: please report this bug"));
398  }
399  }
400  }
401 }
static void format_line(FILE *fp, int ismacro, const char *t1, const char *t2, const char *t3)
Write a formatted line to a file.
Definition: help.c:284
int op
function id number
Definition: keymap.h:105
struct Keymap * Keymaps[MENU_MAX]
Array of Keymap keybindings, one for each Menu.
Definition: keymap.c:147
#define _(a)
Definition: message.h:28
const char * name
name of the function
Definition: keymap.h:104
short op
operation to perform
Definition: keymap.h:53
struct Keymap * next
next key in map
Definition: keymap.h:52
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: keymap.c:769
char * macro
macro expansion (op == OP_MACRO)
Definition: keymap.h:50
char * desc
description of a macro for the help menu
Definition: keymap.h:51
A keyboard mapping.
Definition: keymap.h:48
static const char * HelpStrings[]
Definition: help.c:45
static const struct Binding * help_lookup_function(int op, int menu)
Find a keybinding for an operation.
Definition: help.c:59
Mapping between a user key and a function.
Definition: keymap.h:102

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool is_bound ( struct Keymap map,
int  op 
)
static

Does a function have a keybinding?

Parameters
mapKeymap to examine
opOperation, e.g. OP_DELETE
Return values
trueIf a key is bound to that operation

Definition at line 409 of file help.c.

410 {
411  for (; map; map = map->next)
412  if (map->op == op)
413  return true;
414  return false;
415 }
int op
function id number
Definition: keymap.h:105
short op
operation to perform
Definition: keymap.h:53
struct Keymap * next
next key in map
Definition: keymap.h:52

+ Here is the caller graph for this function:

static void dump_unbound ( FILE *  fp,
const struct Binding funcs,
struct Keymap map,
struct Keymap aux 
)
static

Write out all the operations with no key bindings.

Parameters
fpFile to write to
funcsAll the bindings for the current menu
mapFirst key map to consider
auxSecond key map to consider

Definition at line 424 of file help.c.

426 {
427  for (int i = 0; funcs[i].name; i++)
428  {
429  if (!is_bound(map, funcs[i].op) && (!aux || !is_bound(aux, funcs[i].op)))
430  format_line(fp, 0, funcs[i].name, "", _(HelpStrings[funcs[i].op]));
431  }
432 }
static void format_line(FILE *fp, int ismacro, const char *t1, const char *t2, const char *t3)
Write a formatted line to a file.
Definition: help.c:284
int op
function id number
Definition: keymap.h:105
#define _(a)
Definition: message.h:28
const char * name
Definition: pgpmicalg.c:45
const char * name
name of the function
Definition: keymap.h:104
static bool is_bound(struct Keymap *map, int op)
Does a function have a keybinding?
Definition: help.c:409
static const char * HelpStrings[]
Definition: help.c:45

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void mutt_help ( int  menu)

Display the help menu.

Parameters
menuCurrent Menu

Definition at line 438 of file help.c.

439 {
440  char t[PATH_MAX];
441  char buf[128];
442  FILE *fp = NULL;
443 
444  mutt_mktemp(t, sizeof(t));
445 
446  const struct Binding *funcs = km_get_table(menu);
447  const char *desc = mutt_map_get_name(menu, Menus);
448  if (!desc)
449  desc = _("<UNKNOWN>");
450 
451  do
452  {
453  fp = mutt_file_fopen(t, "w");
454  if (!fp)
455  {
456  mutt_perror(t);
457  return;
458  }
459 
460  dump_menu(fp, menu);
461  if ((menu != MENU_EDITOR) && (menu != MENU_PAGER))
462  {
463  fprintf(fp, "\n%s\n\n", _("Generic bindings:"));
464  dump_menu(fp, MENU_GENERIC);
465  }
466 
467  fprintf(fp, "\n%s\n\n", _("Unbound functions:"));
468  if (funcs)
469  dump_unbound(fp, funcs, Keymaps[menu], NULL);
470  if (menu != MENU_PAGER)
472 
473  mutt_file_fclose(&fp);
474 
475  snprintf(buf, sizeof(buf), _("Help for %s"), desc);
477  NULL) == OP_REFORMAT_WINCH);
478 }
static void dump_menu(FILE *fp, int menu)
Write all the key bindings to a file.
Definition: help.c:373
#define mutt_perror(...)
Definition: logging.h:84
struct Keymap * Keymaps[MENU_MAX]
Array of Keymap keybindings, one for each Menu.
Definition: keymap.c:147
#define _(a)
Definition: message.h:28
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition: pager.h:56
Pager pager (email viewer)
Definition: keymap.h:77
const char * mutt_map_get_name(int val, const struct Mapping *map)
Lookup a string for a constant.
Definition: mapping.c:42
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
#define MUTT_PAGER_NSKIP
Preserve whitespace with smartwrap.
Definition: pager.h:52
const struct Mapping Menus[]
Menu name lookup table.
Definition: keymap.c:60
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:74
const struct Binding * km_get_table(int menu)
Lookup a menu&#39;s keybindings.
Definition: keymap.c:1204
static void dump_unbound(FILE *fp, const struct Binding *funcs, struct Keymap *map, struct Keymap *aux)
Write out all the operations with no key bindings.
Definition: help.c:424
#define PATH_MAX
Definition: mutt.h:49
const struct Binding OpGeneric[]
Key bindings for the generic menu.
Definition: functions.h:52
#define MUTT_PAGER_RETWINCH
Need reformatting on SIGWINCH.
Definition: pager.h:54
int mutt_do_pager(const char *banner, const char *tempfile, PagerFlags do_color, struct Pager *info)
Display some page-able text to the user.
Definition: curs_lib.c:570
Text entry area.
Definition: keymap.h:73
#define MUTT_PAGER_MARKER
Use markers if option is set.
Definition: pager.h:53
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:578
Mapping between a user key and a function.
Definition: keymap.h:102
Generic selection list.
Definition: keymap.h:75

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Variable Documentation

const char* HelpStrings[]
static
Initial value:
= {
#define DEFINE_HELP_MESSAGE(opcode, help_string)
NULL,
}

Definition at line 45 of file help.c.