NeoMutt  2025-01-09-41-g086358
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
help.c
Go to the documentation of this file.
1
34#include "config.h"
35#include <limits.h>
36#include <stdbool.h>
37#include <stddef.h>
38#include <stdio.h>
39#include <string.h>
40#include <wchar.h>
41#include "mutt/lib.h"
42#include "config/lib.h"
43#include "core/lib.h"
44#include "gui/lib.h"
45#include "index/lib.h"
46#include "key/lib.h"
47#include "menu/lib.h"
48#include "pager/lib.h"
49#include "protos.h"
50
55{
56 const char *first;
57 const char *second;
58 const char *third;
59};
60ARRAY_HEAD(HelpLineArray, struct HelpLine);
61
69static const struct MenuFuncOp *help_lookup_function(int op, enum MenuType menu)
70{
71 if ((menu != MENU_PAGER) && (menu != MENU_GENERIC))
72 {
73 /* first look in the generic map for the function */
74 for (int i = 0; OpGeneric[i].name; i++)
75 if (OpGeneric[i].op == op)
76 return &OpGeneric[i];
77 }
78
79 const struct MenuFuncOp *funcs = km_get_table(menu);
80 if (funcs)
81 {
82 for (int i = 0; funcs[i].name; i++)
83 if (funcs[i].op == op)
84 return &funcs[i];
85 }
86
87 return NULL;
88}
89
93static int help_sort_alpha(const void *a, const void *b, void *sdata)
94{
95 const struct HelpLine *x = (const struct HelpLine *) a;
96 const struct HelpLine *y = (const struct HelpLine *) b;
97
98 return mutt_str_cmp(x->first, y->first);
99}
100
108static void escape_macro(const char *macro, struct Buffer *buf)
109{
110 wchar_t wc = 0;
111 size_t k;
112 size_t len = mutt_str_len(macro);
113 mbstate_t mbstate1 = { 0 };
114 mbstate_t mbstate2 = { 0 };
115
116 for (; (len > 0) && (k = mbrtowc(&wc, macro, MB_LEN_MAX, &mbstate1)); macro += k, len -= k)
117 {
118 if ((k == ICONV_ILLEGAL_SEQ) || (k == ICONV_BUF_TOO_SMALL))
119 {
120 if (k == ICONV_ILLEGAL_SEQ)
121 memset(&mbstate1, 0, sizeof(mbstate1));
122 k = (k == ICONV_ILLEGAL_SEQ) ? 1 : len;
123 wc = ReplacementChar;
124 }
125
126 const int w = wcwidth(wc);
127 if (IsWPrint(wc) && (w >= 0))
128 {
129 char tmp[MB_LEN_MAX * 2] = { 0 };
130 if (wcrtomb(tmp, wc, &mbstate2) != ICONV_ILLEGAL_SEQ)
131 {
132 buf_addstr(buf, tmp);
133 }
134 }
135 else if ((wc < 0x20) || (wc == 0x7f))
136 {
137 if (wc == '\033') // Escape
138 buf_addstr(buf, "\\e");
139 else if (wc == '\n')
140 buf_addstr(buf, "\\n");
141 else if (wc == '\r')
142 buf_addstr(buf, "\\r");
143 else if (wc == '\t')
144 buf_addstr(buf, "\\t");
145 else
146 buf_add_printf(buf, "^%c", (char) ((wc + '@') & 0x7f));
147 }
148 else
149 {
150 buf_addch(buf, '?');
151 }
152 }
153}
154
164static void dump_menu(enum MenuType menu, struct HelpLineArray *hla_menu,
165 struct HelpLineArray *hla_macro)
166{
167 struct Keymap *map = NULL;
168 struct Buffer *buf = buf_pool_get();
169
170 STAILQ_FOREACH(map, &Keymaps[menu], entries)
171 {
172 if (map->op == OP_NULL)
173 continue;
174
175 buf_reset(buf);
176 km_expand_key(map, buf);
177
178 struct HelpLine hl = { 0 };
179
180 hl.first = buf_strdup(buf);
181
182 if (map->op == OP_MACRO)
183 {
184 hl.second = map->macro;
185 hl.third = map->desc;
186 ARRAY_ADD(hla_macro, hl);
187 }
188 else
189 {
190 const struct MenuFuncOp *funcs = help_lookup_function(map->op, menu);
191 ASSERT(funcs);
192 hl.second = funcs->name;
193 hl.third = _(opcodes_get_description(funcs->op));
194 ARRAY_ADD(hla_menu, hl);
195 }
196 }
197
198 buf_pool_release(&buf);
199}
200
210static void dump_bound(enum MenuType menu, FILE *fp)
211{
212 struct HelpLineArray hla_gen = ARRAY_HEAD_INITIALIZER;
213 struct HelpLineArray hla_macro = ARRAY_HEAD_INITIALIZER;
214 struct HelpLineArray hla_menu = ARRAY_HEAD_INITIALIZER;
215
216 dump_menu(menu, &hla_menu, &hla_macro);
217 if ((menu != MENU_EDITOR) && (menu != MENU_PAGER) && (menu != MENU_GENERIC))
218 {
219 dump_menu(MENU_GENERIC, &hla_gen, &hla_macro);
220 }
221
222 struct HelpLine *hl = NULL;
223 int w1 = 0;
224 int w2 = 0;
225 ARRAY_FOREACH(hl, &hla_menu)
226 {
227 w1 = MAX(w1, mutt_str_len(hl->first));
228 w2 = MAX(w2, mutt_str_len(hl->second));
229 }
230
231 ARRAY_FOREACH(hl, &hla_gen)
232 {
233 w1 = MAX(w1, mutt_str_len(hl->first));
234 w2 = MAX(w2, mutt_str_len(hl->second));
235 }
236
237 ARRAY_FOREACH(hl, &hla_macro)
238 {
239 w1 = MAX(w1, mutt_str_len(hl->first));
240 }
241
242 const char *desc = mutt_map_get_name(menu, MenuNames);
243 fprintf(fp, _("%s bindings:"), desc);
244 fputs("\n\n", fp);
245
246 ARRAY_FOREACH(hl, &hla_menu)
247 {
248 fprintf(fp, "%*s ", -w1, hl->first);
249 fprintf(fp, "%*s %s\n", -w2, hl->second, hl->third);
250 }
251
252 if (!ARRAY_EMPTY(&hla_gen))
253 {
254 fprintf(fp, "\n%s\n\n", _("Generic bindings:"));
255 ARRAY_FOREACH(hl, &hla_gen)
256 {
257 fprintf(fp, "%*s ", -w1, hl->first);
258 fprintf(fp, "%*s %s\n", -w2, hl->second, hl->third);
259 }
260 }
261
262 if (!ARRAY_EMPTY(&hla_macro))
263 {
264 fprintf(fp, "\n%s\n\n", _("macros:"));
265 struct Buffer *macro = buf_pool_get();
266 ARRAY_FOREACH(hl, &hla_macro)
267 {
268 fprintf(fp, "%*s ", -w1, hl->first);
269
270 buf_reset(macro);
271 escape_macro(hl->second, macro);
272
273 if (hl->third) // there's a description
274 {
275 // Two lines, description then macro
276 fprintf(fp, "%s\n", hl->third);
277 fprintf(fp, "%s\n\n", buf_string(macro));
278 }
279 else
280 {
281 fprintf(fp, "%s\n", buf_string(macro));
282 }
283 }
284 buf_pool_release(&macro);
285 }
286
287 ARRAY_FOREACH(hl, &hla_gen)
288 {
289 FREE(&hl->first);
290 }
291
292 ARRAY_FOREACH(hl, &hla_menu)
293 {
294 FREE(&hl->first);
295 }
296
297 ARRAY_FOREACH(hl, &hla_macro)
298 {
299 FREE(&hl->first);
300 }
301
302 ARRAY_FREE(&hla_gen);
303 ARRAY_FREE(&hla_macro);
304 ARRAY_FREE(&hla_menu);
305}
306
313static bool is_bound(struct KeymapList *km_list, int op)
314{
315 struct Keymap *map = NULL;
316 STAILQ_FOREACH(map, km_list, entries)
317 {
318 if (map->op == op)
319 return true;
320 }
321 return false;
322}
323
333static void dump_unbound_menu(const struct MenuFuncOp *funcs, struct KeymapList *km_list,
334 struct KeymapList *aux, struct HelpLineArray *hla)
335{
336 for (int i = 0; funcs[i].name; i++)
337 {
338 if (!is_bound(km_list, funcs[i].op) && (!aux || !is_bound(aux, funcs[i].op)))
339 {
340 struct HelpLine hl = { 0 };
341 hl.first = funcs[i].name;
342 hl.second = _(opcodes_get_description(funcs[i].op));
343 ARRAY_ADD(hla, hl);
344 }
345 }
346}
347
355static void dump_unbound(enum MenuType menu, FILE *fp)
356{
357 fprintf(fp, "\n%s\n\n", _("Unbound functions:"));
358
359 struct HelpLineArray hla = ARRAY_HEAD_INITIALIZER;
360
361 const struct MenuFuncOp *funcs = km_get_table(menu);
362 if (funcs)
363 dump_unbound_menu(funcs, &Keymaps[menu], NULL, &hla);
364
365 if ((menu != MENU_EDITOR) && (menu != MENU_PAGER) && (menu != MENU_GENERIC))
367
368 struct HelpLine *hl = NULL;
369 int w1 = 0;
370 ARRAY_FOREACH(hl, &hla)
371 {
372 w1 = MAX(w1, mutt_str_len(hl->first));
373 }
374
375 ARRAY_SORT(&hla, help_sort_alpha, NULL);
376 ARRAY_FOREACH(hl, &hla)
377 {
378 fprintf(fp, "%*s %s\n", -w1, hl->first, hl->second);
379 }
380
381 ARRAY_FREE(&hla);
382}
383
391static void show_flag_if_present(FILE *fp, const struct MbTable *table, int index, char *desc)
392{
393 const char *flag = mbtable_get_nth_wchar(table, index);
394 if ((strlen(flag) < 1) || (*flag == ' '))
395 return;
396
397 const int cols = mutt_strwidth(flag);
398
399 fprintf(fp, " %s%*s %s\n", flag, 4 - cols, "", desc);
400}
401
412static void dump_message_flags(enum MenuType menu, FILE *fp)
413{
414 if (menu != MENU_INDEX)
415 return;
416
417 fprintf(fp, "\n%s\n\n", _("Message flags:"));
418
419 const struct MbTable *c_flag_chars = cs_subset_mbtable(NeoMutt->sub, "flag_chars");
420 const struct MbTable *c_crypt_chars = cs_subset_mbtable(NeoMutt->sub, "crypt_chars");
421 const struct MbTable *c_to_chars = cs_subset_mbtable(NeoMutt->sub, "to_chars");
422
423 fputs("$flag_chars:\n", fp);
424 show_flag_if_present(fp, c_flag_chars, FLAG_CHAR_TAGGED, _("message is tagged"));
425 show_flag_if_present(fp, c_flag_chars, FLAG_CHAR_IMPORTANT, _("message is flagged"));
426 show_flag_if_present(fp, c_flag_chars, FLAG_CHAR_DELETED, _("message is deleted"));
427 show_flag_if_present(fp, c_flag_chars, FLAG_CHAR_DELETED_ATTACH, _("attachment is deleted"));
428 show_flag_if_present(fp, c_flag_chars, FLAG_CHAR_REPLIED, _("message has been replied to"));
429 show_flag_if_present(fp, c_flag_chars, FLAG_CHAR_OLD, _("message has been read"));
430 show_flag_if_present(fp, c_flag_chars, FLAG_CHAR_NEW, _("message is new"));
431 show_flag_if_present(fp, c_flag_chars, FLAG_CHAR_OLD_THREAD, _("thread has been read"));
433 _("thread has at least one new message"));
434 show_flag_if_present(fp, c_flag_chars, FLAG_CHAR_SEMPTY,
435 _("message has been read (%S expando)"));
436 show_flag_if_present(fp, c_flag_chars, FLAG_CHAR_ZEMPTY,
437 _("message has been read (%Z expando)"));
438
439 fputs("\n$crypt_chars:\n", fp);
441 _("message signed with a verified key"));
443 _("message is PGP-encrypted"));
444 show_flag_if_present(fp, c_crypt_chars, FLAG_CHAR_CRYPT_SIGNED, _("message is signed"));
446 _("message contains a PGP key"));
448 _("message has no cryptography information"));
449
450 fputs("\n$to_chars:\n", fp);
452 _("message is not To: you"));
454 _("message is To: you and only you"));
455 show_flag_if_present(fp, c_to_chars, FLAG_CHAR_TO_TO, _("message is To: you"));
456 show_flag_if_present(fp, c_to_chars, FLAG_CHAR_TO_CC, _("message is Cc: to you"));
457 show_flag_if_present(fp, c_to_chars, FLAG_CHAR_TO_ORIGINATOR, _("message is From: you"));
459 _("message is sent to a subscribed mailing list"));
461 _("you are in the Reply-To: list"));
462 fputs("\n", fp);
463}
464
469void mutt_help(enum MenuType menu)
470{
471 char banner[128] = { 0 };
472 FILE *fp = NULL;
473
474 struct Buffer *tempfile = buf_pool_get();
475 buf_mktemp(tempfile);
476
477 struct PagerData pdata = { 0 };
478 struct PagerView pview = { &pdata };
479
480 pview.mode = PAGER_MODE_HELP;
482
483 fp = mutt_file_fopen(buf_string(tempfile), "w");
484 if (!fp)
485 {
486 mutt_perror("%s", buf_string(tempfile));
487 goto cleanup;
488 }
489
490 dump_bound(menu, fp);
491 dump_unbound(menu, fp);
492 dump_message_flags(menu, fp);
493
494 mutt_file_fclose(&fp);
495
496 const char *desc = mutt_map_get_name(menu, MenuNames);
497 snprintf(banner, sizeof(banner), _("Help for %s"), desc);
498 pdata.fname = buf_string(tempfile);
499 pview.banner = banner;
500
501 mutt_do_pager(&pview, NULL);
502
503cleanup:
504 buf_pool_release(&tempfile);
505}
#define ARRAY_SORT(head, fn, sdata)
Sort an array.
Definition: array.h:279
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:156
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:212
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition: array.h:74
#define ARRAY_HEAD(name, type)
Define a named struct for arrays of elements of a certain type.
Definition: array.h:47
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:204
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:58
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:204
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:226
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:571
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
struct MbTable * cs_subset_mbtable(const struct ConfigSubset *sub, const char *name)
Get a Multibyte table config item by name.
Definition: helpers.c:119
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:444
int mutt_do_pager(struct PagerView *pview, struct Email *e)
Display some page-able text to the user (help or attachment)
Definition: do_pager.c:122
@ FLAG_CHAR_TO_ORIGINATOR
Character denoting that the user is originator.
Definition: expando_index.h:71
@ FLAG_CHAR_TO_UNIQUE
Character denoting that the user is unique recipient.
Definition: expando_index.h:68
@ FLAG_CHAR_TO_NOT_IN_THE_LIST
Character denoting that the user is not in list.
Definition: expando_index.h:67
@ FLAG_CHAR_TO_TO
Character denoting that the user is in the TO list.
Definition: expando_index.h:69
@ FLAG_CHAR_TO_CC
Character denoting that the user is in the CC list.
Definition: expando_index.h:70
@ FLAG_CHAR_TO_REPLY_TO
Character denoting that the user is in the Reply-To list.
Definition: expando_index.h:73
@ FLAG_CHAR_TO_SUBSCRIBED_LIST
Character denoting that the message is sent to a subscribed mailing list.
Definition: expando_index.h:72
@ FLAG_CHAR_CRYPT_CONTAINS_KEY
Character denoting a message contains a PGP key.
Definition: expando_index.h:58
@ FLAG_CHAR_CRYPT_SIGNED
Character denoting a message is signed.
Definition: expando_index.h:57
@ FLAG_CHAR_CRYPT_NO_CRYPTO
Character denoting a message has no cryptography information.
Definition: expando_index.h:59
@ FLAG_CHAR_CRYPT_GOOD_SIGN
Character denoting a message signed with a verified key.
Definition: expando_index.h:55
@ FLAG_CHAR_CRYPT_ENCRYPTED
Character denoting a message is PGP-encrypted.
Definition: expando_index.h:56
@ FLAG_CHAR_OLD
Character denoting an email that has been read.
Definition: expando_index.h:42
@ FLAG_CHAR_REPLIED
Character denoting an email that has been replied to.
Definition: expando_index.h:41
@ FLAG_CHAR_OLD_THREAD
Character denoting a thread of emails that has been read.
Definition: expando_index.h:44
@ FLAG_CHAR_ZEMPTY
Character denoting a read email, $index_format Z expando.
Definition: expando_index.h:47
@ FLAG_CHAR_TAGGED
Character denoting a tagged email.
Definition: expando_index.h:37
@ FLAG_CHAR_NEW
Character denoting an unread email.
Definition: expando_index.h:43
@ FLAG_CHAR_DELETED
Character denoting a deleted email.
Definition: expando_index.h:39
@ FLAG_CHAR_NEW_THREAD
Character denoting a thread containing at least one new email.
Definition: expando_index.h:45
@ FLAG_CHAR_DELETED_ATTACH
Character denoting a deleted attachment.
Definition: expando_index.h:40
@ FLAG_CHAR_SEMPTY
Character denoting a read email, $index_format S expando.
Definition: expando_index.h:46
@ FLAG_CHAR_IMPORTANT
Character denoting a important (flagged) email.
Definition: expando_index.h:38
#define mutt_file_fclose(FP)
Definition: file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:138
#define mutt_perror(...)
Definition: logging2.h:93
static int help_sort_alpha(const void *a, const void *b, void *sdata)
Compare two Help Lines by their first entry - Implements sort_t -.
Definition: help.c:93
const struct MenuFuncOp OpGeneric[]
Functions for the Generic Menu.
Definition: functions.c:68
Convenience wrapper for the gui headers.
static void dump_message_flags(enum MenuType menu, FILE *fp)
Write out all the message flags.
Definition: help.c:412
static bool is_bound(struct KeymapList *km_list, int op)
Does a function have a keybinding?
Definition: help.c:313
static void dump_unbound(enum MenuType menu, FILE *fp)
Dump the unbound keys to a file.
Definition: help.c:355
static void dump_unbound_menu(const struct MenuFuncOp *funcs, struct KeymapList *km_list, struct KeymapList *aux, struct HelpLineArray *hla)
Write the operations with no key bindings to a HelpLine Array.
Definition: help.c:333
static void dump_menu(enum MenuType menu, struct HelpLineArray *hla_menu, struct HelpLineArray *hla_macro)
Write all the key bindings to a HelpLine Array.
Definition: help.c:164
static void escape_macro(const char *macro, struct Buffer *buf)
Escape any special characters in a macro.
Definition: help.c:108
static void show_flag_if_present(FILE *fp, const struct MbTable *table, int index, char *desc)
Write out a message flag if exists.
Definition: help.c:391
static void dump_bound(enum MenuType menu, FILE *fp)
Dump the bound keys to a file.
Definition: help.c:210
static const struct MenuFuncOp * help_lookup_function(int op, enum MenuType menu)
Find a keybinding for an operation.
Definition: help.c:69
void mutt_help(enum MenuType menu)
Display the help menu.
Definition: help.c:469
GUI manage the main index (list of emails)
struct KeymapList Keymaps[MENU_MAX]
Array of key mappings, one for each MenuType.
Definition: lib.c:124
const struct MenuFuncOp * km_get_table(enum MenuType mtype)
Lookup a Menu's functions.
Definition: lib.c:499
bool km_expand_key(struct Keymap *map, struct Buffer *buf)
Get the key string bound to a Keymap.
Definition: lib.c:451
Manage keymappings.
const char * mutt_map_get_name(int val, const struct Mapping *map)
Lookup a string for a constant.
Definition: mapping.c:42
const char * mbtable_get_nth_wchar(const struct MbTable *table, int index)
Extract one char from a multi-byte table.
Definition: mbtable.c:331
#define IsWPrint(wc)
Definition: mbyte.h:41
#define FREE(x)
Definition: memory.h:55
#define MAX(a, b)
Definition: memory.h:31
GUI present the user with a selectable list.
wchar_t ReplacementChar
When a Unicode character can't be displayed, use this instead.
Definition: charset.c:61
#define ICONV_BUF_TOO_SMALL
Error value for iconv() - Buffer too small.
Definition: charset.h:98
#define ICONV_ILLEGAL_SEQ
Error value for iconv() - Illegal sequence.
Definition: charset.h:96
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
int mutt_str_cmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:399
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:496
const char * opcodes_get_description(int op)
Get the description of an opcode.
Definition: opcodes.c:70
GUI display a file/email/help in a viewport with paging.
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition: lib.h:71
#define MUTT_PAGER_STRIPES
Striped highlighting.
Definition: lib.h:74
#define MUTT_PAGER_MARKER
Use markers if option is set.
Definition: lib.h:69
@ PAGER_MODE_HELP
Pager is invoked via 3rd path to show help.
Definition: lib.h:139
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
Prototypes for many functions.
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:390
#define ASSERT(COND)
Definition: signal2.h:58
String manipulation buffer.
Definition: buffer.h:36
One line of Help text.
Definition: help.c:55
const char * second
Second column.
Definition: help.c:57
const char * third
Third column.
Definition: help.c:58
const char * first
First column.
Definition: help.c:56
A keyboard mapping.
Definition: lib.h:66
char * macro
Macro expansion (op == OP_MACRO)
Definition: lib.h:67
char * desc
Description of a macro for the help menu.
Definition: lib.h:68
short op
Operation to perform.
Definition: lib.h:69
Multibyte character table.
Definition: mbtable.h:36
Mapping between a function and an operation.
Definition: lib.h:102
const char * name
Name of the function.
Definition: lib.h:103
int op
Operation, e.g. OP_DELETE.
Definition: lib.h:104
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
Data to be displayed by PagerView.
Definition: lib.h:159
const char * fname
Name of the file to read.
Definition: lib.h:163
Paged view into some data.
Definition: lib.h:170
struct PagerData * pdata
Data that pager displays. NOTNULL.
Definition: lib.h:171
enum PagerMode mode
Pager mode.
Definition: lib.h:172
PagerFlags flags
Additional settings to tweak pager's function.
Definition: lib.h:173
const char * banner
Title to display in status bar.
Definition: lib.h:174
#define buf_mktemp(buf)
Definition: tmp.h:33
const struct Mapping MenuNames[]
Menu name lookup table.
Definition: type.c:37
MenuType
Types of GUI selections.
Definition: type.h:36
@ MENU_INDEX
Index panel (list of emails)
Definition: type.h:51
@ MENU_GENERIC
Generic selection list.
Definition: type.h:46
@ MENU_PAGER
Pager pager (email viewer)
Definition: type.h:52
@ MENU_EDITOR
Text entry area.
Definition: type.h:44