NeoMutt  2020-06-26-89-g172cd3
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 "mutt.h"
#include "functions.h"
#include "keymap.h"
#include "mutt_globals.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.

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

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.

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

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

88 {
89  char tmp[128];
90 
91  if (km_expand_key(tmp, sizeof(tmp), km_find_func(menu, op)) ||
92  km_expand_key(tmp, sizeof(tmp), km_find_func(MENU_GENERIC, op)))
93  {
94  snprintf(buf, buflen, "%s:%s", tmp, txt);
95  }
96  else
97  {
98  buf[0] = '\0';
99  }
100 }
int op
function id number
Definition: keymap.h:121
struct Keymap * km_find_func(enum MenuType menu, int func)
Find a function&#39;s mapping in a Menu.
Definition: keymap.c:899
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: keymap.c:871
Generic selection list.
Definition: keymap.h:77
+ 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 110 of file help.c.

112 {
113  char *pbuf = buf;
114 
115  for (int i = 0; items[i].name && buflen > 2; i++)
116  {
117  if (i)
118  {
119  *pbuf++ = ' ';
120  *pbuf++ = ' ';
121  buflen -= 2;
122  }
123  mutt_make_help(pbuf, buflen, _(items[i].name), menu, items[i].value);
124  const size_t len = mutt_str_len(pbuf);
125  pbuf += len;
126  buflen -= len;
127  }
128  return buf;
129 }
#define _(a)
Definition: message.h:28
const char * name
name of the function
Definition: keymap.h:120
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:636
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:87
const char * name
Definition: mapping.h:33
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 140 of file help.c.

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

212 {
213  wchar_t wc;
214  size_t k;
215  size_t m, n;
216  size_t len = mutt_str_len(t);
217  const char *s = t;
218  mbstate_t mbstate;
219 
220  memset(&mbstate, 0, sizeof(mbstate));
221  for (m = wid, n = 0; len && (k = mbrtowc(&wc, s, len, &mbstate)) && (n <= wid);
222  s += k, len -= k)
223  {
224  if (*s == ' ')
225  m = n;
226  if ((k == (size_t)(-1)) || (k == (size_t)(-2)))
227  {
228  if (k == (size_t)(-1))
229  memset(&mbstate, 0, sizeof(mbstate));
230  k = (k == (size_t)(-1)) ? 1 : len;
231  wc = ReplacementChar;
232  }
233  if (!IsWPrint(wc))
234  wc = '?';
235  n += wcwidth(wc);
236  }
237  if (n > wid)
238  n = m;
239  else
240  n = wid;
241  return n;
242 }
#define IsWPrint(wc)
Definition: mbyte.h:40
wchar_t ReplacementChar
When a Unicode character can&#39;t be displayed, use this instead.
Definition: charset.c:58
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:636
int n
Definition: acutest.h:492
+ 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
num
  • i - Padding was added
  • col - Content was already wider than col

Definition at line 253 of file help.c.

254 {
255  if (col < i)
256  {
257  char fmt[32] = { 0 };
258  snprintf(fmt, sizeof(fmt), "%%-%ds", i - col);
259  fprintf(fp, fmt, "");
260  return i;
261  }
262  fputc(' ', fp);
263  return col + 1;
264 }
static int const char * fmt
Definition: acutest.h:488
+ 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 282 of file help.c.

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

373 {
374  struct Keymap *map = NULL;
375  const struct Binding *b = NULL;
376  char buf[128];
377 
378  /* browse through the keymap table */
379  for (map = Keymaps[menu]; map; map = map->next)
380  {
381  if (map->op != OP_NULL)
382  {
383  km_expand_key(buf, sizeof(buf), map);
384 
385  if (map->op == OP_MACRO)
386  {
387  if (map->desc)
388  format_line(fp, 1, buf, map->macro, map->desc, wraplen);
389  else
390  format_line(fp, -1, buf, "macro", map->macro, wraplen);
391  }
392  else
393  {
394  b = help_lookup_function(map->op, menu);
395  format_line(fp, 0, buf, b ? b->name : "UNKNOWN",
396  b ? _(OpStrings[b->op][1]) : _("ERROR: please report this bug"), wraplen);
397  }
398  }
399  }
400 }
int op
function id number
Definition: keymap.h:121
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:54
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:282
const char * name
name of the function
Definition: keymap.h:120
short op
operation to perform
Definition: keymap.h:52
const char * OpStrings[][2]
Definition: opcodes.c:28
struct Keymap * next
next key in map
Definition: keymap.h:51
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: keymap.c:871
char * macro
macro expansion (op == OP_MACRO)
Definition: keymap.h:49
char * desc
description of a macro for the help menu
Definition: keymap.h:50
A keyboard mapping.
Definition: keymap.h:47
Mapping between a user key and a function.
Definition: keymap.h:118
+ 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 408 of file help.c.

409 {
410  for (; map; map = map->next)
411  if (map->op == op)
412  return true;
413  return false;
414 }
int op
function id number
Definition: keymap.h:121
short op
operation to perform
Definition: keymap.h:52
struct Keymap * next
next key in map
Definition: keymap.h:51
+ 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 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, "", _(OpStrings[funcs[i].op][1]), wraplen);
431  }
432 }
int op
function id number
Definition: keymap.h:121
#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:282
const char * name
name of the function
Definition: keymap.h:120
const char * OpStrings[][2]
Definition: opcodes.c:28
static bool is_bound(struct Keymap *map, int op)
Does a function have a keybinding?
Definition: help.c:408
+ 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 439 of file help.c.

440 {
441  char buf[128];
442  FILE *fp = NULL;
443 
444  /* We don't use the buffer pool because of the extended lifetime of t */
445  struct Buffer t = mutt_buffer_make(PATH_MAX);
446  mutt_buffer_mktemp(&t);
447 
448  const struct Binding *funcs = km_get_table(menu);
449  const char *desc = mutt_map_get_name(menu, Menus);
450  if (!desc)
451  desc = _("<UNKNOWN>");
452 
453  do
454  {
455  fp = mutt_file_fopen(mutt_b2s(&t), "w");
456  if (!fp)
457  {
458  mutt_perror(mutt_b2s(&t));
459  goto cleanup;
460  }
461 
462  dump_menu(fp, menu, wraplen);
463  if ((menu != MENU_EDITOR) && (menu != MENU_PAGER))
464  {
465  fprintf(fp, "\n%s\n\n", _("Generic bindings:"));
466  dump_menu(fp, MENU_GENERIC, wraplen);
467  }
468 
469  fprintf(fp, "\n%s\n\n", _("Unbound functions:"));
470  if (funcs)
471  dump_unbound(fp, funcs, Keymaps[menu], NULL, wraplen);
472  if (menu != MENU_PAGER)
473  dump_unbound(fp, OpGeneric, Keymaps[MENU_GENERIC], Keymaps[menu], wraplen);
474 
475  mutt_file_fclose(&fp);
476 
477  snprintf(buf, sizeof(buf), _("Help for %s"), desc);
478  } while (mutt_do_pager(buf, mutt_b2s(&t),
480  NULL) == OP_REFORMAT_WINCH);
481 
482 cleanup:
484 }
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:424
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
#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:79
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:372
#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:688
const struct Binding * km_get_table(enum MenuType menu)
Lookup a menu&#39;s keybindings.
Definition: keymap.c:1265
Text entry area.
Definition: keymap.h:75
#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:118
Generic selection list.
Definition: keymap.h:77
+ Here is the call graph for this function:
+ Here is the caller graph for this function: