NeoMutt  2019-11-11
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, enum MenuType menu)
 Find a keybinding for an operation. More...
 
void mutt_make_help (char *buf, size_t buflen, const char *txt, enum MenuType menu, int op)
 Create one entry for the help bar. More...
 
char * mutt_compile_help (char *buf, size_t buflen, enum MenuType 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, int wraplen)
 Write a formatted line to a file. More...
 
static void dump_menu (FILE *fp, enum MenuType menu, int wraplen)
 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, int wraplen)
 Write out all the operations with no key bindings. More...
 
void mutt_help (enum MenuType menu, int wraplen)
 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_HELP_MESSAGE

#define DEFINE_HELP_MESSAGE (   opcode,
  help_string 
)    help_string,

Function Documentation

◆ help_lookup_function()

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

Find a keybinding for an operation.

Parameters
opOperation, e.g. OP_DELETE
menuCurrent Menu, e.g. MENU_PAGER
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:117
Pager pager (email viewer)
Definition: keymap.h:78
const char * name
name of the function
Definition: keymap.h:116
const struct Binding OpGeneric[]
Key bindings for the generic menu.
Definition: functions.h:54
const struct Binding * km_get_table(enum MenuType menu)
Lookup a menu&#39;s keybindings.
Definition: keymap.c:1223
Mapping between a user key and a function.
Definition: keymap.h:114
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_make_help()

void mutt_make_help ( char *  buf,
size_t  buflen,
const char *  txt,
enum MenuType  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, e.g. MENU_PAGER
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:117
struct Keymap * km_find_func(enum MenuType menu, int func)
Find a function&#39;s mapping in a Menu.
Definition: keymap.c:856
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: keymap.c:828
Generic selection list.
Definition: keymap.h:76
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_compile_help()

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

Create the text for the help menu.

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

Definition at line 115 of file help.c.

117 {
118  char *pbuf = buf;
119 
120  for (int i = 0; items[i].name && buflen > 2; i++)
121  {
122  if (i)
123  {
124  *pbuf++ = ' ';
125  *pbuf++ = ' ';
126  buflen -= 2;
127  }
128  mutt_make_help(pbuf, buflen, _(items[i].name), menu, items[i].value);
129  const size_t len = mutt_str_strlen(pbuf);
130  pbuf += len;
131  buflen -= len;
132  }
133  return buf;
134 }
#define _(a)
Definition: message.h:28
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
const char * name
Definition: pgpmicalg.c:45
void mutt_make_help(char *buf, size_t buflen, const char *txt, enum MenuType menu, int op)
Create one entry for the help bar.
Definition: help.c:92
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:

◆ print_macro()

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 145 of file help.c.

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

◆ get_wrapped_width()

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 216 of file help.c.

217 {
218  wchar_t wc;
219  size_t k;
220  size_t m, n;
221  size_t len = mutt_str_strlen(t);
222  const char *s = t;
223  mbstate_t mbstate;
224 
225  memset(&mbstate, 0, sizeof(mbstate));
226  for (m = wid, n = 0; len && (k = mbrtowc(&wc, s, len, &mbstate)) && (n <= wid);
227  s += k, len -= k)
228  {
229  if (*s == ' ')
230  m = n;
231  if ((k == (size_t)(-1)) || (k == (size_t)(-2)))
232  {
233  if (k == (size_t)(-1))
234  memset(&mbstate, 0, sizeof(mbstate));
235  k = (k == (size_t)(-1)) ? 1 : len;
236  wc = ReplacementChar;
237  }
238  if (!IsWPrint(wc))
239  wc = '?';
240  n += wcwidth(wc);
241  }
242  if (n > wid)
243  n = m;
244  else
245  n = wid;
246  return n;
247 }
#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:666
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:

◆ pad()

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 257 of file help.c.

258 {
259  if (col < i)
260  {
261  char fmt[32] = { 0 };
262  snprintf(fmt, sizeof(fmt), "%%-%ds", i - col);
263  fprintf(fp, fmt, "");
264  return i;
265  }
266  fputc(' ', fp);
267  return col + 1;
268 }
+ Here is the caller graph for this function:

◆ format_line()

static void format_line ( FILE *  fp,
int  ismacro,
const char *  t1,
const char *  t2,
const char *  t3,
int  wraplen 
)
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
wraplenWidth to wrap to

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 286 of file help.c.

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

◆ dump_menu()

static void dump_menu ( FILE *  fp,
enum MenuType  menu,
int  wraplen 
)
static

Write all the key bindings to a file.

Parameters
fpFile to write to
menuCurrent Menu, e.g. MENU_PAGER
wraplenWidth to wrap to

Definition at line 376 of file help.c.

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

◆ is_bound()

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 412 of file help.c.

413 {
414  for (; map; map = map->next)
415  if (map->op == op)
416  return true;
417  return false;
418 }
int op
function id number
Definition: keymap.h:117
short op
operation to perform
Definition: keymap.h:51
struct Keymap * next
next key in map
Definition: keymap.h:50
+ Here is the caller graph for this function:

◆ dump_unbound()

static void dump_unbound ( FILE *  fp,
const struct Binding funcs,
struct Keymap map,
struct Keymap aux,
int  wraplen 
)
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
wraplenWidth to wrap to

Definition at line 428 of file help.c.

430 {
431  for (int i = 0; funcs[i].name; i++)
432  {
433  if (!is_bound(map, funcs[i].op) && (!aux || !is_bound(aux, funcs[i].op)))
434  format_line(fp, 0, funcs[i].name, "", _(HelpStrings[funcs[i].op]), wraplen);
435  }
436 }
int op
function id number
Definition: keymap.h:117
#define _(a)
Definition: message.h:28
static void format_line(FILE *fp, int ismacro, const char *t1, const char *t2, const char *t3, int wraplen)
Write a formatted line to a file.
Definition: help.c:286
const char * name
Definition: pgpmicalg.c:45
const char * name
name of the function
Definition: keymap.h:116
static bool is_bound(struct Keymap *map, int op)
Does a function have a keybinding?
Definition: help.c:412
static const char * HelpStrings[]
Definition: help.c:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_help()

void mutt_help ( enum MenuType  menu,
int  wraplen 
)

Display the help menu.

Parameters
menuCurrent Menu
wraplenWidth to wrap to

Definition at line 443 of file help.c.

444 {
445  char buf[128];
446  FILE *fp = NULL;
447 
448  /* We don't use the buffer pool because of the extended lifetime of t */
449  struct Buffer t = mutt_buffer_make(PATH_MAX);
450  mutt_buffer_mktemp(&t);
451 
452  const struct Binding *funcs = km_get_table(menu);
453  const char *desc = mutt_map_get_name(menu, Menus);
454  if (!desc)
455  desc = _("<UNKNOWN>");
456 
457  do
458  {
459  fp = mutt_file_fopen(mutt_b2s(&t), "w");
460  if (!fp)
461  {
462  mutt_perror(mutt_b2s(&t));
463  goto cleanup;
464  }
465 
466  dump_menu(fp, menu, wraplen);
467  if ((menu != MENU_EDITOR) && (menu != MENU_PAGER))
468  {
469  fprintf(fp, "\n%s\n\n", _("Generic bindings:"));
470  dump_menu(fp, MENU_GENERIC, wraplen);
471  }
472 
473  fprintf(fp, "\n%s\n\n", _("Unbound functions:"));
474  if (funcs)
475  dump_unbound(fp, funcs, Keymaps[menu], NULL, wraplen);
476  if (menu != MENU_PAGER)
477  dump_unbound(fp, OpGeneric, Keymaps[MENU_GENERIC], Keymaps[menu], wraplen);
478 
479  mutt_file_fclose(&fp);
480 
481  snprintf(buf, sizeof(buf), _("Help for %s"), desc);
482  } while (mutt_do_pager(buf, mutt_b2s(&t),
484  NULL) == OP_REFORMAT_WINCH);
485 
486 cleanup:
488 }
static void dump_unbound(FILE *fp, const struct Binding *funcs, struct Keymap *map, struct Keymap *aux, int wraplen)
Write out all the operations with no key bindings.
Definition: help.c:428
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:79
#define mutt_perror(...)
Definition: logging.h:85
struct Keymap * Keymaps[MENU_MAX]
Array of Keymap keybindings, one for each Menu.
Definition: keymap.c:149
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
String manipulation buffer.
Definition: buffer.h:33
#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:78
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:152
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
#define MUTT_PAGER_NSKIP
Preserve whitespace with smartwrap.
Definition: pager.h:52
#define mutt_b2s(buf)
Definition: buffer.h:41
const struct Mapping Menus[]
Menu name lookup table.
Definition: keymap.c:62
#define PATH_MAX
Definition: mutt.h:50
const struct Binding OpGeneric[]
Key bindings for the generic menu.
Definition: functions.h:54
static void dump_menu(FILE *fp, enum MenuType menu, int wraplen)
Write all the key bindings to a file.
Definition: help.c:376
#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:631
const struct Binding * km_get_table(enum MenuType menu)
Lookup a menu&#39;s keybindings.
Definition: keymap.c:1223
Text entry area.
Definition: keymap.h:74
#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:585
Mapping between a user key and a function.
Definition: keymap.h:114
Generic selection list.
Definition: keymap.h:76
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ HelpStrings

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

Definition at line 45 of file help.c.