NeoMutt  2020-11-20
Teaching an old dog new tricks
DOXYGEN
help.c File Reference

Generate the help-page and GUI display it. 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 "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...
 
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 KeymapList *km_list, int op)
 Does a function have a keybinding? More...
 
static void dump_unbound (FILE *fp, const struct Binding *funcs, struct KeymapList *km_list, struct KeymapList *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-page and GUI display it.

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

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

86 {
87  int n = maxwidth;
88  wchar_t wc;
89  size_t k;
90  size_t len = mutt_str_len(*macro);
91  mbstate_t mbstate1, mbstate2;
92 
93  memset(&mbstate1, 0, sizeof(mbstate1));
94  memset(&mbstate2, 0, sizeof(mbstate2));
95  for (; len && (k = mbrtowc(&wc, *macro, len, &mbstate1)); *macro += k, len -= k)
96  {
97  if ((k == (size_t)(-1)) || (k == (size_t)(-2)))
98  {
99  if (k == (size_t)(-1))
100  memset(&mbstate1, 0, sizeof(mbstate1));
101  k = (k == (size_t)(-1)) ? 1 : len;
102  wc = ReplacementChar;
103  }
104  /* glibc-2.1.3's wcwidth() returns 1 for unprintable chars! */
105  const int w = wcwidth(wc);
106  if (IsWPrint(wc) && (w >= 0))
107  {
108  if (w > n)
109  break;
110  n -= w;
111  {
112  char buf[MB_LEN_MAX * 2];
113  size_t n1, n2;
114  if (((n1 = wcrtomb(buf, wc, &mbstate2)) != (size_t)(-1)) &&
115  ((n2 = wcrtomb(buf + n1, 0, &mbstate2)) != (size_t)(-1)))
116  {
117  fputs(buf, fp);
118  }
119  }
120  }
121  else if ((wc < 0x20) || (wc == 0x7f))
122  {
123  if (n < 2)
124  break;
125  n -= 2;
126  if (wc == '\033') // Escape
127  fprintf(fp, "\\e");
128  else if (wc == '\n')
129  fprintf(fp, "\\n");
130  else if (wc == '\r')
131  fprintf(fp, "\\r");
132  else if (wc == '\t')
133  fprintf(fp, "\\t");
134  else
135  fprintf(fp, "^%c", (char) ((wc + '@') & 0x7f));
136  }
137  else
138  {
139  if (n < 1)
140  break;
141  n -= 1;
142  fprintf(fp, "?");
143  }
144  }
145  return maxwidth - n;
146 }
#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:631
+ 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 156 of file help.c.

157 {
158  wchar_t wc;
159  size_t k;
160  size_t m, n;
161  size_t len = mutt_str_len(t);
162  const char *s = t;
163  mbstate_t mbstate;
164 
165  memset(&mbstate, 0, sizeof(mbstate));
166  for (m = wid, n = 0; len && (k = mbrtowc(&wc, s, len, &mbstate)) && (n <= wid);
167  s += k, len -= k)
168  {
169  if (*s == ' ')
170  m = n;
171  if ((k == (size_t)(-1)) || (k == (size_t)(-2)))
172  {
173  if (k == (size_t)(-1))
174  memset(&mbstate, 0, sizeof(mbstate));
175  k = (k == (size_t)(-1)) ? 1 : len;
176  wc = ReplacementChar;
177  }
178  if (!IsWPrint(wc))
179  wc = '?';
180  n += wcwidth(wc);
181  }
182  if (n > wid)
183  n = m;
184  else
185  n = wid;
186  return n;
187 }
#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:631
+ 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 198 of file help.c.

199 {
200  if (col < i)
201  {
202  char fmt[32] = { 0 };
203  snprintf(fmt, sizeof(fmt), "%%-%ds", i - col);
204  fprintf(fp, fmt, "");
205  return i;
206  }
207  fputc(' ', fp);
208  return col + 1;
209 }
+ 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 227 of file help.c.

229 {
230  int col;
231  int col_b;
232 
233  fputs(t1, fp);
234 
235  /* don't try to press string into one line with less than 40 characters. */
236  bool split = (wraplen < 40);
237  if (split)
238  {
239  col = 0;
240  col_b = 1024;
241  fputc('\n', fp);
242  }
243  else
244  {
245  const int col_a = (wraplen > 83) ? (wraplen - 32) >> 2 : 12;
246  col_b = (wraplen > 49) ? (wraplen - 10) >> 1 : 19;
247  col = pad(fp, mutt_strwidth(t1), col_a);
248  }
249 
250  if (ismacro > 0)
251  {
252  if (!C_Pager || mutt_str_equal(C_Pager, "builtin"))
253  fputs("_\010", fp); // Ctrl-H (backspace)
254  fputs("M ", fp);
255  col += 2;
256 
257  if (!split)
258  {
259  col += print_macro(fp, col_b - col - 4, &t2);
260  if (mutt_strwidth(t2) > col_b - col)
261  t2 = "...";
262  }
263  }
264 
265  col += print_macro(fp, col_b - col - 1, &t2);
266  if (split)
267  fputc('\n', fp);
268  else
269  col = pad(fp, col, col_b);
270 
271  if (split)
272  {
273  print_macro(fp, 1024, &t3);
274  fputc('\n', fp);
275  }
276  else
277  {
278  while (*t3)
279  {
280  int n = wraplen - col;
281 
282  if (ismacro >= 0)
283  {
284  SKIPWS(t3);
285  n = get_wrapped_width(t3, n);
286  }
287 
288  n = print_macro(fp, n, &t3);
289 
290  if (*t3)
291  {
292  if (mutt_str_equal(C_Pager, "builtin"))
293  {
294  n += col - wraplen;
295  if (C_Markers)
296  n++;
297  }
298  else
299  {
300  fputc('\n', fp);
301  n = 0;
302  }
303  col = pad(fp, n, col_b);
304  }
305  }
306  }
307 
308  fputc('\n', fp);
309 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:871
static int print_macro(FILE *fp, int maxwidth, const char **macro)
Print a macro string to a file.
Definition: help.c:85
static int get_wrapped_width(const char *t, size_t wid)
Wrap a string at a sensible place.
Definition: help.c:156
#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:1359
WHERE bool C_Markers
Config: Display a &#39;+&#39; at the beginning of wrapped lines in the pager.
Definition: mutt_globals.h:151
WHERE char * C_Pager
Config: External command for viewing messages, or &#39;builtin&#39; to use NeoMutt&#39;s.
Definition: mutt_globals.h:99
static int pad(FILE *fp, int col, int i)
Write some padding to a file.
Definition: help.c:198
+ 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 317 of file help.c.

318 {
319  struct Keymap *map = NULL;
320  const struct Binding *b = NULL;
321  char buf[128];
322 
323  STAILQ_FOREACH(map, &Keymaps[menu], entries)
324  {
325  if (map->op != OP_NULL)
326  {
327  km_expand_key(buf, sizeof(buf), map);
328 
329  if (map->op == OP_MACRO)
330  {
331  if (map->desc)
332  format_line(fp, 1, buf, map->macro, map->desc, wraplen);
333  else
334  format_line(fp, -1, buf, "macro", map->macro, wraplen);
335  }
336  else
337  {
338  b = help_lookup_function(map->op, menu);
339  format_line(fp, 0, buf, b ? b->name : "UNKNOWN",
340  b ? _(OpStrings[b->op][1]) : _("ERROR: please report this bug"), wraplen);
341  }
342  }
343  }
344 }
struct KeymapList Keymaps[MENU_MAX]
Array of Keymap keybindings, one for each Menu.
Definition: keymap.c:149
int op
function id number
Definition: keymap.h:123
#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:53
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:227
const char * name
name of the function
Definition: keymap.h:122
short op
operation to perform
Definition: keymap.h:51
const char * OpStrings[][2]
Definition: opcodes.c:28
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: keymap.c:911
char * macro
macro expansion (op == OP_MACRO)
Definition: keymap.h:49
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
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:120
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ is_bound()

static bool is_bound ( struct KeymapList *  km_list,
int  op 
)
static

Does a function have a keybinding?

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

Definition at line 352 of file help.c.

353 {
354  struct Keymap *map = NULL;
355  STAILQ_FOREACH(map, km_list, entries)
356  {
357  if (map->op == op)
358  return true;
359  }
360  return false;
361 }
short op
operation to perform
Definition: keymap.h:51
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
A keyboard mapping.
Definition: keymap.h:47
+ Here is the caller graph for this function:

◆ dump_unbound()

static void dump_unbound ( FILE *  fp,
const struct Binding funcs,
struct KeymapList *  km_list,
struct KeymapList *  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
km_listFirst key map to consider
auxSecond key map to consider
wraplenWidth to wrap to

Definition at line 371 of file help.c.

373 {
374  for (int i = 0; funcs[i].name; i++)
375  {
376  if (!is_bound(km_list, funcs[i].op) && (!aux || !is_bound(aux, funcs[i].op)))
377  format_line(fp, 0, funcs[i].name, "", _(OpStrings[funcs[i].op][1]), wraplen);
378  }
379 }
#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:227
const char * name
name of the function
Definition: keymap.h:122
short op
operation to perform
Definition: keymap.h:51
const char * OpStrings[][2]
Definition: opcodes.c:28
static bool is_bound(struct KeymapList *km_list, int op)
Does a function have a keybinding?
Definition: help.c:352
+ 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 386 of file help.c.

387 {
388  char buf[128];
389  FILE *fp = NULL;
390 
391  /* We don't use the buffer pool because of the extended lifetime of t */
392  struct Buffer t = mutt_buffer_make(PATH_MAX);
393  mutt_buffer_mktemp(&t);
394 
395  const struct Binding *funcs = km_get_table(menu);
396  const char *desc = mutt_map_get_name(menu, Menus);
397  if (!desc)
398  desc = _("<UNKNOWN>");
399 
400  do
401  {
402  fp = mutt_file_fopen(mutt_b2s(&t), "w");
403  if (!fp)
404  {
405  mutt_perror(mutt_b2s(&t));
406  goto cleanup;
407  }
408 
409  dump_menu(fp, menu, wraplen);
410  if ((menu != MENU_EDITOR) && (menu != MENU_PAGER))
411  {
412  fprintf(fp, "\n%s\n\n", _("Generic bindings:"));
413  dump_menu(fp, MENU_GENERIC, wraplen);
414  }
415 
416  fprintf(fp, "\n%s\n\n", _("Unbound functions:"));
417  if (funcs)
418  dump_unbound(fp, funcs, &Keymaps[menu], NULL, wraplen);
419  if (menu != MENU_PAGER)
420  dump_unbound(fp, OpGeneric, &Keymaps[MENU_GENERIC], &Keymaps[menu], wraplen);
421 
422  mutt_file_fclose(&fp);
423 
424  snprintf(buf, sizeof(buf), _("Help for %s"), desc);
425  } while (mutt_do_pager(buf, mutt_b2s(&t),
427  NULL) == OP_REFORMAT_WINCH);
428 
429 cleanup:
431 }
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
static void dump_unbound(FILE *fp, const struct Binding *funcs, struct KeymapList *km_list, struct KeymapList *aux, int wraplen)
Write out all the operations with no key bindings.
Definition: help.c:371
#define mutt_perror(...)
Definition: logging.h:85
struct KeymapList 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:81
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:53
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:317
#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:690
const struct Binding * km_get_table(enum MenuType menu)
Lookup a menu&#39;s keybindings.
Definition: keymap.c:1306
Text entry area.
Definition: keymap.h:77
#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:120
Generic selection list.
Definition: keymap.h:79
+ Here is the call graph for this function:
+ Here is the caller graph for this function: