nano

nano with my custom patches
git clone git://bsandro.tech/nano
Log | Files | Refs | README | LICENSE

help.c (19976B)


      1 /**************************************************************************
      2  *   help.c  --  This file is part of GNU nano.                           *
      3  *                                                                        *
      4  *   Copyright (C) 2000-2011, 2013-2025 Free Software Foundation, Inc.    *
      5  *   Copyright (C) 2017 Rishabh Dave                                      *
      6  *   Copyright (C) 2014-2019 Benno Schulenberg                            *
      7  *                                                                        *
      8  *   GNU nano is free software: you can redistribute it and/or modify     *
      9  *   it under the terms of the GNU General Public License as published    *
     10  *   by the Free Software Foundation, either version 3 of the License,    *
     11  *   or (at your option) any later version.                               *
     12  *                                                                        *
     13  *   GNU nano is distributed in the hope that it will be useful,          *
     14  *   but WITHOUT ANY WARRANTY; without even the implied warranty          *
     15  *   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.              *
     16  *   See the GNU General Public License for more details.                 *
     17  *                                                                        *
     18  *   You should have received a copy of the GNU General Public License    *
     19  *   along with this program.  If not, see https://gnu.org/licenses/.     *
     20  *                                                                        *
     21  **************************************************************************/
     22 
     23 #include "prototypes.h"
     24 
     25 #ifdef ENABLE_HELP
     26 
     27 #include <errno.h>
     28 #include <string.h>
     29 
     30 static char *help_text = NULL;
     31 		/* The text displayed in the help window. */
     32 static const char *start_of_body = NULL;
     33 		/* The point in the help text just after the title. */
     34 static char *end_of_intro = NULL;
     35 		/* The point in the help text where the shortcut descriptions begin. */
     36 static size_t location;
     37 		/* The offset (in bytes) of the topleft of the shown help text. */
     38 
     39 /* Allocate space for the help text for the current menu,
     40  * and concatenate the different pieces of text into it. */
     41 void help_init(void)
     42 {
     43 	size_t allocsize = 0;
     44 		/* Space needed for help_text. */
     45 	const char *htx[3];
     46 		/* Untranslated help introduction.  We break it up into three chunks
     47 		 * in case the full string is too long for the compiler to handle. */
     48 	const funcstruct *f;
     49 	const keystruct *s;
     50 	char *ptr;
     51 
     52 	/* First, set up the initial help text for the current function. */
     53 	if (currmenu & (MWHEREIS|MREPLACE)) {
     54 		htx[0] = N_("Search Command Help Text\n\n "
     55 				"Enter the words or characters you would like to "
     56 				"search for, and then press Enter.  If there is a "
     57 				"match for the text you entered, the screen will be "
     58 				"updated to the location of the nearest match for the "
     59 				"search string.\n\n The previous search string will be "
     60 				"shown in brackets after the search prompt.  Hitting "
     61 				"Enter without entering any text will perform the "
     62 				"previous search.  ");
     63 		htx[1] = N_("If you have selected text with the mark and then "
     64 				"search to replace, only matches in the selected text "
     65 				"will be replaced.\n\n The following function keys are "
     66 				"available in Search mode:\n\n");
     67 		htx[2] = NULL;
     68 	} else if (currmenu == MREPLACEWITH) {
     69 		htx[0] = N_("=== Replacement ===\n\n "
     70 				"Type the characters that should replace what you "
     71 				"typed at the previous prompt, and press Enter.\n\n");
     72 		htx[1] = N_(" The following function keys "
     73 				"are available at this prompt:\n\n");
     74 		htx[2] = NULL;
     75 	} else if (currmenu == MGOTOLINE) {
     76 		htx[0] = N_("Go To Line Help Text\n\n "
     77 				"Enter the line number that you wish to go to and hit "
     78 				"Enter.  If there are fewer lines of text than the "
     79 				"number you entered, you will be brought to the last "
     80 				"line of the file.\n\n The following function keys are "
     81 				"available in Go To Line mode:\n\n");
     82 		htx[1] = NULL;
     83 		htx[2] = NULL;
     84 	} else if (currmenu == MINSERTFILE) {
     85 		htx[0] = N_("Insert File Help Text\n\n "
     86 				"Type in the name of a file to be inserted into the "
     87 				"current file buffer at the current cursor "
     88 				"location.\n\n If you have compiled nano with multiple "
     89 				"file buffer support, and enable multiple file buffers "
     90 				"with the -F or --multibuffer command line flags, the "
     91 				"Meta-F toggle, or a nanorc file, inserting a file "
     92 				"will cause it to be loaded into a separate buffer "
     93 				"(use Meta-< and > to switch between file buffers).  ");
     94 		htx[1] = N_("If you need another blank buffer, do not enter "
     95 				"any filename, or type in a nonexistent filename at "
     96 				"the prompt and press Enter.\n\n The following "
     97 				"function keys are available in Insert File mode:\n\n");
     98 		htx[2] = NULL;
     99 	} else if (currmenu == MWRITEFILE) {
    100 		htx[0] = N_("Write File Help Text\n\n "
    101 				"Type the name that you wish to save the current file "
    102 				"as and press Enter to save the file.\n\n If you have "
    103 				"selected text with the mark, you will be prompted to "
    104 				"save only the selected portion to a separate file.  To "
    105 				"reduce the chance of overwriting the current file with "
    106 				"just a portion of it, the current filename is not the "
    107 				"default in this mode.\n\n The following function keys "
    108 				"are available in Write File mode:\n\n");
    109 		htx[1] = NULL;
    110 		htx[2] = NULL;
    111 	}
    112 #ifdef ENABLE_BROWSER
    113 	else if (currmenu == MBROWSER) {
    114 		htx[0] = N_("File Browser Help Text\n\n "
    115 				"The file browser is used to visually browse the "
    116 				"directory structure to select a file for reading "
    117 				"or writing.  You may use the arrow keys or Page Up/"
    118 				"Down to browse through the files, and S or Enter to "
    119 				"choose the selected file or enter the selected "
    120 				"directory.  To move up one level, select the "
    121 				"directory called \"..\" at the top of the file "
    122 				"list.\n\n The following function keys are available "
    123 				"in the file browser:\n\n");
    124 		htx[1] = NULL;
    125 		htx[2] = NULL;
    126 	} else if (currmenu == MWHEREISFILE) {
    127 		htx[0] = N_("Browser Search Command Help Text\n\n "
    128 				"Enter the words or characters you would like to "
    129 				"search for, and then press Enter.  If there is a "
    130 				"match for the text you entered, the screen will be "
    131 				"updated to the location of the nearest match for the "
    132 				"search string.\n\n The previous search string will be "
    133 				"shown in brackets after the search prompt.  Hitting "
    134 				"Enter without entering any text will perform the "
    135 				"previous search.\n\n");
    136 		htx[1] = N_(" The following function keys "
    137 				"are available at this prompt:\n\n");
    138 		htx[2] = NULL;
    139 	} else if (currmenu == MGOTODIR) {
    140 		htx[0] = N_("Browser Go To Directory Help Text\n\n "
    141 				"Enter the name of the directory you would like to "
    142 				"browse to.\n\n If tab completion has not been "
    143 				"disabled, you can use the Tab key to (attempt to) "
    144 				"automatically complete the directory name.\n\n The "
    145 				"following function keys are available in Browser Go "
    146 				"To Directory mode:\n\n");
    147 		htx[1] = NULL;
    148 		htx[2] = NULL;
    149 	}
    150 #endif /* ENABLE_BROWSER */
    151 #ifdef ENABLE_SPELLER
    152 	else if (currmenu == MSPELL) {
    153 		htx[0] = N_("Spell Check Help Text\n\n "
    154 				"The spell checker checks the spelling of all text in "
    155 				"the current file.  When an unknown word is "
    156 				"encountered, it is highlighted and a replacement can "
    157 				"be edited.  It will then prompt to replace every "
    158 				"instance of the given misspelled word in the current "
    159 				"file, or, if you have selected text with the mark, in "
    160 				"the selected text.\n\n The following function keys "
    161 				"are available in Spell Check mode:\n\n");
    162 		htx[1] = NULL;
    163 		htx[2] = NULL;
    164 	}
    165 #endif /* ENABLE_SPELLER */
    166 #ifndef NANO_TINY
    167 	else if (currmenu == MEXECUTE) {
    168 		htx[0] = N_("Execute Command Help Text\n\n "
    169 				"This mode allows you to insert the output of a "
    170 				"command run by the shell into the current buffer (or "
    171 				"into a new buffer).  If the command is preceded by '|' "
    172 				"(the pipe symbol), the current contents of the buffer "
    173 				"(or marked region) will be piped to the command.  ");
    174 		htx[1] = N_("If you just need another blank buffer, do not enter any "
    175 				"command.\n\n You can also pick one of four tools, or cut a "
    176 				"large piece of the buffer, or put the editor to sleep.\n\n");
    177 		htx[2] = N_(" The following function keys "
    178 				"are available at this prompt:\n\n");
    179 	} else if (currmenu == MLINTER) {
    180 		htx[0] = N_("=== Linter ===\n\n "
    181 				"In this mode, the status bar shows an error message or "
    182 				"warning, and the cursor is put at the corresponding "
    183 				"position in the file.  With PageUp and PageDown you "
    184 				"can switch to earlier and later messages.\n\n");
    185 		htx[1] = N_(" The following function keys are "
    186 				"available in Linter mode:\n\n");
    187 		htx[2] = NULL;
    188 	}
    189 #endif /* !NANO_TINY */
    190 	else {
    191 		/* Default to the main help list. */
    192 		htx[0] = N_("Main nano help text\n\n "
    193 				"The nano editor is designed to emulate the "
    194 				"functionality and ease-of-use of the UW Pico text "
    195 				"editor.  There are four main sections of the editor.  "
    196 				"The top line shows the program version, the current "
    197 				"filename being edited, and whether or not the file "
    198 				"has been modified.  Next is the main editor window "
    199 				"showing the file being edited.  The status line is "
    200 				"the third line from the bottom and shows important "
    201 				"messages.  ");
    202 		htx[1] = N_("The bottom two lines show the most commonly used "
    203 				"shortcuts in the editor.\n\n Shortcuts are written as "
    204 				"follows: Control-key sequences are notated with a '^' "
    205 				"and can be entered either by using the Ctrl key or "
    206 				"pressing the Esc key twice.  Meta-key sequences are "
    207 				"notated with 'M-' and can be entered using either the "
    208 				"Alt, Cmd, or Esc key, depending on your keyboard setup.  ");
    209 		htx[2] = N_("Also, pressing Esc twice and then typing a "
    210 				"three-digit decimal number from 000 to 255 will enter "
    211 				"the character with the corresponding value.  The "
    212 				"following keystrokes are available in the main editor "
    213 				"window.  Alternative keys are shown in "
    214 				"parentheses:\n\n");
    215 	}
    216 
    217 	htx[0] = _(htx[0]);
    218 	if (htx[1] != NULL)
    219 		htx[1] = _(htx[1]);
    220 	if (htx[2] != NULL)
    221 		htx[2] = _(htx[2]);
    222 
    223 	allocsize += strlen(htx[0]);
    224 	if (htx[1] != NULL)
    225 		allocsize += strlen(htx[1]);
    226 	if (htx[2] != NULL)
    227 		allocsize += strlen(htx[2]);
    228 
    229 	/* Calculate the length of the descriptions of the shortcuts.
    230 	 * Each entry has one or two keystrokes, which fill 17 cells,
    231 	 * plus translated text, plus one or two \n's. */
    232 	for (f = allfuncs; f != NULL; f = f->next)
    233 		if (f->menus & currmenu)
    234 			allocsize += strlen(_(f->phrase)) + 21;
    235 
    236 #ifndef NANO_TINY
    237 	/* If we're on the main list, we also count the toggle help text.
    238 	 * Each entry has "M-%c\t\t ", six chars which fill 17 cells, plus
    239 	 * two translated texts, plus a space, plus one or two '\n's. */
    240 	if (currmenu == MMAIN) {
    241 		size_t onoff_len = strlen(_("enable/disable"));
    242 
    243 		for (s = sclist; s != NULL; s = s->next)
    244 			if (s->func == do_toggle)
    245 				allocsize += strlen(_(epithet_of_flag(s->toggle))) + onoff_len + 9;
    246 	}
    247 #endif
    248 
    249 	/* Allocate memory for the help text. */
    250 	help_text = nmalloc(allocsize + 1);
    251 
    252 	/* Now add the text we want. */
    253 	strcpy(help_text, htx[0]);
    254 	if (htx[1] != NULL)
    255 		strcat(help_text, htx[1]);
    256 	if (htx[2] != NULL)
    257 		strcat(help_text, htx[2]);
    258 
    259 	/* Remember this end-of-introduction, start-of-shortcuts. */
    260 	end_of_intro = help_text + strlen(help_text);
    261 	ptr = end_of_intro;
    262 
    263 	/* Now add the shortcuts and their descriptions. */
    264 	for (f = allfuncs; f != NULL; f = f->next) {
    265 		int tally = 0;
    266 
    267 		if ((f->menus & currmenu) == 0)
    268 			continue;
    269 
    270 		/* Show the first two shortcuts (if any) for each function. */
    271 		for (s = sclist; s != NULL; s = s->next) {
    272 			if ((s->menus & currmenu) && s->func == f->func && s->keystr[0]) {
    273 				/* Make the first column 7 cells wide and the second 10. */
    274 				if (++tally == 1) {
    275 					sprintf(ptr, "%s                ", s->keystr);
    276 					/* Unicode arrows take three bytes instead of one. */
    277 					ptr += (strstr(s->keystr, "\xE2") != NULL ? 9 : 7);
    278 				} else {
    279 					sprintf(ptr, "(%s)       ", s->keystr);
    280 					ptr += (strstr(s->keystr, "\xE2") != NULL ? 12 : 10);
    281 					break;
    282 				}
    283 			}
    284 		}
    285 
    286 		if (tally == 0)
    287 			ptr += sprintf(ptr, "\t\t ");
    288 		else if (tally == 1)
    289 			ptr += 10;
    290 
    291 		/* The shortcut's description. */
    292 		ptr += sprintf(ptr, "%s\n", _(f->phrase));
    293 
    294 		if (f->blank_after)
    295 			ptr += sprintf(ptr, "\n");
    296 	}
    297 
    298 #ifndef NANO_TINY
    299 	/* And the toggles... */
    300 	if (currmenu == MMAIN) {
    301 		int maximum = 0, counter = 0;
    302 
    303 		/* First see how many toggles there are. */
    304 		for (s = sclist; s != NULL; s = s->next)
    305 			maximum = (s->toggle && s->ordinal > maximum) ? s->ordinal : maximum;
    306 
    307 		/* Now show them in the original order. */
    308 		while (counter < maximum) {
    309 			counter++;
    310 			for (s = sclist; s != NULL; s = s->next)
    311 				if (s->toggle && s->ordinal == counter) {
    312 					ptr += sprintf(ptr, "%s\t\t %s %s\n", (s->menus & MMAIN ? s->keystr : ""),
    313 								_(epithet_of_flag(s->toggle)), _("enable/disable"));
    314 					/* Add a blank like between two groups. */
    315 					if (s->toggle == NO_SYNTAX)
    316 						ptr += sprintf(ptr, "\n");
    317 					break;
    318 				}
    319 		}
    320 	}
    321 #endif
    322 }
    323 
    324 /* Hard-wrap the concatenated help text, and write it into a new buffer. */
    325 void wrap_help_text_into_buffer(void)
    326 {
    327 	/* Avoid overtight and overwide paragraphs in the introductory text. */
    328 	size_t wrapping_point = ((COLS < 40) ? 40 : (COLS > 74) ? 74 : COLS) - sidebar;
    329 	const char *ptr = start_of_body;
    330 	size_t sum = 0;
    331 
    332 	make_new_buffer();
    333 
    334 	/* Ensure there is a blank line at the top of the text, for esthetics. */
    335 	if ((ISSET(MINIBAR) || !ISSET(EMPTY_LINE)) && LINES > 6) {
    336 		openfile->current->data = mallocstrcpy(openfile->current->data, " ");
    337 		openfile->current->next = make_new_node(openfile->current);
    338 		openfile->current = openfile->current->next;
    339 	}
    340 
    341 	/* Copy the help text into the just-created new buffer. */
    342 	while (*ptr != '\0') {
    343 		int length, shim;
    344 		char *oneline;
    345 
    346 		if (ptr == end_of_intro)
    347 			wrapping_point = ((COLS < 40) ? 40 : COLS) - sidebar;
    348 
    349 		if (ptr < end_of_intro || *(ptr - 1) == '\n') {
    350 			length = break_line(ptr, wrapping_point, TRUE);
    351 			oneline = nmalloc(length + 1);
    352 			shim = (*(ptr + length - 1) == ' ') ? 0 : 1;
    353 			snprintf(oneline, length + shim, "%s", ptr);
    354 		} else {
    355 			length = break_line(ptr, ((COLS < 40) ? 22 : COLS - 18) - sidebar, TRUE);
    356 			oneline = nmalloc(length + 5);
    357 			snprintf(oneline, length + 5, "\t\t  %s", ptr);
    358 		}
    359 
    360 		free(openfile->current->data);
    361 		openfile->current->data = oneline;
    362 
    363 		ptr += length;
    364 		if (*ptr != '\n')
    365 			ptr--;
    366 
    367 		/* Create a new line, and then one more for each extra \n. */
    368 		do {
    369 			openfile->current->next = make_new_node(openfile->current);
    370 			openfile->current = openfile->current->next;
    371 			openfile->current->data = copy_of("");
    372 		} while (*(++ptr) == '\n');
    373 	}
    374 
    375 	openfile->filebot = openfile->current;
    376 	openfile->current = openfile->filetop;
    377 
    378 	remove_magicline();
    379 #ifdef ENABLE_COLOR
    380 	find_and_prime_applicable_syntax();
    381 #endif
    382 	prepare_for_display();
    383 
    384 	/* Move to the position in the file where we were before. */
    385 	while (TRUE) {
    386 		sum += strlen(openfile->current->data);
    387 		if (sum > location)
    388 			break;
    389 		openfile->current = openfile->current->next;
    390 	}
    391 
    392 	openfile->edittop = openfile->current;
    393 }
    394 
    395 /* Assemble a help text, display it, and allow scrolling through it. */
    396 void show_help(void)
    397 {
    398 	int kbinput = ERR;
    399 	functionptrtype function;
    400 		/* The function of the key the user typed in. */
    401 	int oldmenu = currmenu;
    402 		/* The menu we were called from. */
    403 #ifdef ENABLE_LINENUMBERS
    404 	int was_margin = margin;
    405 #endif
    406 	ssize_t was_tabsize = tabsize;
    407 #ifdef ENABLE_COLOR
    408 	char *was_syntax = syntaxstr;
    409 #endif
    410 	char *saved_answer = (answer != NULL) ? copy_of(answer) : NULL;
    411 		/* The current answer when the user invokes help at the prompt. */
    412 	unsigned stash[sizeof(flags) / sizeof(flags[0])];
    413 		/* A storage place for the current flag settings. */
    414 	linestruct *line;
    415 	int length;
    416 
    417 	/* Save the settings of all flags. */
    418 	memcpy(stash, flags, sizeof(flags));
    419 
    420 	/* Ensure that the help screen's shortcut list can be displayed. */
    421 	if (ISSET(NO_HELP) || ISSET(ZERO)) {
    422 		UNSET(NO_HELP);
    423 		UNSET(ZERO);
    424 		window_init();
    425 	} else
    426 		blank_statusbar();
    427 
    428 	/* When searching, do it forward, case insensitive, and without regexes. */
    429 	UNSET(BACKWARDS_SEARCH);
    430 	UNSET(CASE_SENSITIVE);
    431 	UNSET(USE_REGEXP);
    432 
    433 	UNSET(WHITESPACE_DISPLAY);
    434 
    435 #ifdef ENABLE_LINENUMBERS
    436 	editwincols = COLS - sidebar;
    437 	margin = 0;
    438 #endif
    439 	tabsize = 8;
    440 #ifdef ENABLE_COLOR
    441 	syntaxstr = "nanohelp";
    442 #endif
    443 	curs_set(0);
    444 
    445 	/* Compose the help text from all the relevant pieces. */
    446 	help_init();
    447 
    448 	inhelp = TRUE;
    449 	location = 0;
    450 	didfind = 0;
    451 
    452 	bottombars(MHELP);
    453 
    454 	/* Extract the title from the head of the help text. */
    455 	length = break_line(help_text, HIGHEST_POSITIVE, TRUE);
    456 	title = measured_copy(help_text, length);
    457 
    458 	titlebar(title);
    459 
    460 	/* Skip over the title to point at the start of the body text. */
    461 	start_of_body = help_text + length;
    462 	while (*start_of_body == '\n')
    463 		start_of_body++;
    464 
    465 	wrap_help_text_into_buffer();
    466 	edit_refresh();
    467 
    468 	while (TRUE) {
    469 		lastmessage = VACUUM;
    470 		focusing = TRUE;
    471 
    472 		/* Show the cursor when we searched and found something. */
    473 		kbinput = get_kbinput(midwin, didfind == 1 || ISSET(SHOW_CURSOR));
    474 
    475 		didfind = 0;
    476 
    477 #ifndef NANO_TINY
    478 		spotlighted = FALSE;
    479 #endif
    480 		function = interpret(kbinput);
    481 
    482 		if (ISSET(SHOW_CURSOR) && (function == do_left || function == do_right ||
    483 									function == do_up || function == do_down)) {
    484 			function();
    485 		} else if (function == do_up || function == do_scroll_up) {
    486 			do_scroll_up();
    487 		} else if (function == do_down || function == do_scroll_down) {
    488 			if (openfile->edittop->lineno + editwinrows - 1 < openfile->filebot->lineno)
    489 				do_scroll_down();
    490 		} else if (function == do_page_up || function == do_page_down ||
    491 					function == to_first_line || function == to_last_line) {
    492 			function();
    493 		} else if (function == do_search_backward || function == do_search_forward ||
    494 					function == do_findprevious || function == do_findnext) {
    495 			function();
    496 			bottombars(MHELP);
    497 #ifdef ENABLE_NANORC
    498 		} else if (function == (functionptrtype)implant) {
    499 			implant(first_sc_for(MHELP, function)->expansion);
    500 #endif
    501 #ifdef ENABLE_MOUSE
    502 		} else if (kbinput == KEY_MOUSE) {
    503 			int dummy_row, dummy_col;
    504 			get_mouseinput(&dummy_row, &dummy_col, TRUE);
    505 #endif
    506 #ifndef NANO_TINY
    507 		} else if (kbinput == START_OF_PASTE) {
    508 			while (get_kbinput(midwin, BLIND) != END_OF_PASTE)
    509 				;
    510 			statusline(AHEM, _("Paste is ignored"));
    511 		} else if (kbinput == THE_WINDOW_RESIZED) {
    512 			;  /* Nothing to do. */
    513 #endif
    514 		} else if (function == full_refresh) {
    515 			full_refresh();
    516 		} else if (function == do_exit) {
    517 			break;
    518 		} else
    519 			unbound_key(kbinput);
    520 
    521 		edit_refresh();
    522 
    523 		location = 0;
    524 		line = openfile->filetop;
    525 
    526 		/* Count how far (in bytes) edittop is into the file. */
    527 		while (line != openfile->edittop) {
    528 			location += strlen(line->data);
    529 			line = line->next;
    530 		}
    531 	}
    532 
    533 	/* Discard the help-text buffer. */
    534 	close_buffer();
    535 
    536 	/* Restore the settings of all flags. */
    537 	memcpy(flags, stash, sizeof(flags));
    538 
    539 #ifdef ENABLE_LINENUMBERS
    540 	margin = was_margin;
    541 	editwincols = COLS - margin - sidebar;
    542 #endif
    543 	tabsize = was_tabsize;
    544 #ifdef ENABLE_COLOR
    545 	syntaxstr = was_syntax;
    546 	have_palette = FALSE;
    547 #endif
    548 
    549 	free(title);
    550 	title = NULL;
    551 	free(answer);
    552 	answer = saved_answer;
    553 	free(help_text);
    554 	inhelp = FALSE;
    555 
    556 	curs_set(0);
    557 
    558 	if (ISSET(NO_HELP) || ISSET(ZERO))
    559 		window_init();
    560 	else
    561 		blank_statusbar();
    562 
    563 	bottombars(oldmenu);
    564 
    565 #ifdef ENABLE_BROWSER
    566 	if (oldmenu & (MBROWSER|MWHEREISFILE|MGOTODIR))
    567 		browser_refresh();
    568 	else
    569 #endif
    570 	{
    571 		titlebar(NULL);
    572 		edit_refresh();
    573 	}
    574 }
    575 
    576 #endif /* ENABLE_HELP */
    577 
    578 /* Start the help viewer, or indicate that there is no help. */
    579 void do_help(void)
    580 {
    581 #ifdef ENABLE_HELP
    582 	show_help();
    583 #else
    584 	if (currmenu & (MMAIN|MBROWSER))
    585 		statusbar(_("^W = Ctrl+W    M-W = Alt+W"));
    586 	else
    587 		beep();
    588 #endif
    589 }