NeoMutt  2020-03-20-65-g141838
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/lib.h"
#include "gui/lib.h"
#include "functions.h"
#include "globals.h"
#include "keymap.h"
#include "muttlib.h"
#include "opcodes.h"
#include "pager.h"
#include "protos.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 60 of file help.c.

61 {
62  const struct Binding *map = NULL;
63 
64  if (menu != MENU_PAGER)
65  {
66  /* first look in the generic map for the function */
67  for (int i = 0; OpGeneric[i].name; i++)
68  if (OpGeneric[i].op == op)
69  return &OpGeneric[i];
70  }
71 
72  map = km_get_table(menu);
73  if (map)
74  {
75  for (int i = 0; map[i].name; i++)
76  if (map[i].op == op)
77  return &map[i];
78  }
79 
80  return NULL;
81 }
int op
function id number
Definition: keymap.h:120
Pager pager (email viewer)
Definition: keymap.h:78
const struct Binding OpGeneric[]
Key bindings for the generic menu.
Definition: functions.c:55
const char * name
name of the function
Definition: keymap.h:119
const struct Binding * km_get_table(enum MenuType menu)
Lookup a menu&#39;s keybindings.
Definition: keymap.c:1264
Mapping between a user key and a function.
Definition: keymap.h:117
+ 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 93 of file help.c.

94 {
95  char tmp[128];
96 
97  if (km_expand_key(tmp, sizeof(tmp), km_find_func(menu, op)) ||
98  km_expand_key(tmp, sizeof(tmp), km_find_func(MENU_GENERIC, op)))
99  {
100  snprintf(buf, buflen, "%s:%s", tmp, txt);
101  }
102  else
103  {
104  buf[0] = '\0';
105  }
106 }
int op
function id number
Definition: keymap.h:120
struct Keymap * km_find_func(enum MenuType menu, int func)
Find a function&#39;s mapping in a Menu.
Definition: keymap.c:898
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: keymap.c:870
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 116 of file help.c.

118 {
119  char *pbuf = buf;
120 
121  for (int i = 0; items[i].name && buflen > 2; i++)
122  {
123  if (i)
124  {
125  *pbuf++ = ' ';
126  *pbuf++ = ' ';
127  buflen -= 2;
128  }
129  mutt_make_help(pbuf, buflen, _(items[i].name), menu, items[i].value);
130  const size_t len = mutt_str_strlen(pbuf);
131  pbuf += len;
132  buflen -= len;
133  }
134  return buf;
135 }
#define _(a)
Definition: message.h:28
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:689
const char * name
Definition: pgpmicalg.c:46
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:93
const char * name
Definition: mapping.h:31
static unsigned char * pbuf
Cache PGP data packet.
Definition: pgppacket.c:38
+ 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 146 of file help.c.

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

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

259 {
260  if (col < i)
261  {
262  char fmt[32] = { 0 };
263  snprintf(fmt, sizeof(fmt), "%%-%ds", i - col);
264  fprintf(fp, fmt, "");
265  return i;
266  }
267  fputc(' ', fp);
268  return col + 1;
269 }
static int const char * fmt
Definition: acutest.h:473
+ 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 287 of file help.c.

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

378 {
379  struct Keymap *map = NULL;
380  const struct Binding *b = NULL;
381  char buf[128];
382 
383  /* browse through the keymap table */
384  for (map = Keymaps[menu]; map; map = map->next)
385  {
386  if (map->op != OP_NULL)
387  {
388  km_expand_key(buf, sizeof(buf), map);
389 
390  if (map->op == OP_MACRO)
391  {
392  if (map->desc)
393  format_line(fp, 1, buf, map->macro, map->desc, wraplen);
394  else
395  format_line(fp, -1, buf, "macro", map->macro, wraplen);
396  }
397  else
398  {
399  b = help_lookup_function(map->op, menu);
400  format_line(fp, 0, buf, b ? b->name : "UNKNOWN",
401  b ? _(HelpStrings[b->op]) : _("ERROR: please report this bug"), wraplen);
402  }
403  }
404  }
405 }
int op
function id number
Definition: keymap.h:120
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:60
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:287
const char * name
name of the function
Definition: keymap.h:119
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:870
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:46
Mapping between a user key and a function.
Definition: keymap.h:117
+ 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 413 of file help.c.

414 {
415  for (; map; map = map->next)
416  if (map->op == op)
417  return true;
418  return false;
419 }
int op
function id number
Definition: keymap.h:120
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 429 of file help.c.

431 {
432  for (int i = 0; funcs[i].name; i++)
433  {
434  if (!is_bound(map, funcs[i].op) && (!aux || !is_bound(aux, funcs[i].op)))
435  format_line(fp, 0, funcs[i].name, "", _(HelpStrings[funcs[i].op]), wraplen);
436  }
437 }
int op
function id number
Definition: keymap.h:120
#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:287
const char * name
Definition: pgpmicalg.c:46
const char * name
name of the function
Definition: keymap.h:119
static bool is_bound(struct Keymap *map, int op)
Does a function have a keybinding?
Definition: help.c:413
static const char * HelpStrings[]
Definition: help.c:46
+ 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 444 of file help.c.

445 {
446  char buf[128];
447  FILE *fp = NULL;
448 
449  /* We don't use the buffer pool because of the extended lifetime of t */
450  struct Buffer t = mutt_buffer_make(PATH_MAX);
451  mutt_buffer_mktemp(&t);
452 
453  const struct Binding *funcs = km_get_table(menu);
454  const char *desc = mutt_map_get_name(menu, Menus);
455  if (!desc)
456  desc = _("<UNKNOWN>");
457 
458  do
459  {
460  fp = mutt_file_fopen(mutt_b2s(&t), "w");
461  if (!fp)
462  {
463  mutt_perror(mutt_b2s(&t));
464  goto cleanup;
465  }
466 
467  dump_menu(fp, menu, wraplen);
468  if ((menu != MENU_EDITOR) && (menu != MENU_PAGER))
469  {
470  fprintf(fp, "\n%s\n\n", _("Generic bindings:"));
471  dump_menu(fp, MENU_GENERIC, wraplen);
472  }
473 
474  fprintf(fp, "\n%s\n\n", _("Unbound functions:"));
475  if (funcs)
476  dump_unbound(fp, funcs, Keymaps[menu], NULL, wraplen);
477  if (menu != MENU_PAGER)
478  dump_unbound(fp, OpGeneric, Keymaps[MENU_GENERIC], Keymaps[menu], wraplen);
479 
480  mutt_file_fclose(&fp);
481 
482  snprintf(buf, sizeof(buf), _("Help for %s"), desc);
483  } while (mutt_do_pager(buf, mutt_b2s(&t),
485  NULL) == OP_REFORMAT_WINCH);
486 
487 cleanup:
489 }
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:429
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:81
#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:153
const struct Binding OpGeneric[]
Key bindings for the generic menu.
Definition: functions.c:55
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:61
#define PATH_MAX
Definition: mutt.h:44
static void dump_menu(FILE *fp, enum MenuType menu, int wraplen)
Write all the key bindings to a file.
Definition: help.c:377
#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:666
const struct Binding * km_get_table(enum MenuType menu)
Lookup a menu&#39;s keybindings.
Definition: keymap.c:1264
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:588
Mapping between a user key and a function.
Definition: keymap.h:117
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 46 of file help.c.