Add Nano tool - user-friendly text editor
[tomato.git] / release / src / router / nano / src / help.c
blob0eede72dbc85c6940c7fabeac69e6467a6912e7e
1 /* $Id: help.c 4453 2009-12-02 03:36:22Z astyanax $ */
2 /**************************************************************************
3 * help.c *
4 * *
5 * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, *
6 * 2009 Free Software Foundation, Inc. *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 3, or (at your option) *
10 * any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, but *
13 * WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
15 * General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
20 * 02110-1301, USA. *
21 * *
22 **************************************************************************/
24 #include "proto.h"
26 #include <stdio.h>
27 #include <string.h>
28 #include <ctype.h>
30 #ifndef DISABLE_HELP
32 static char *help_text = NULL;
33 /* The text displayed in the help window. */
35 /* Our main help browser function. refresh_func is the function we will
36 * call to refresh the edit window. */
37 void do_help(void (*refresh_func)(void))
39 int kbinput = ERR;
40 bool meta_key, func_key, old_no_help = ISSET(NO_HELP);
41 bool abort = FALSE;
42 /* Whether we should abort the help browser. */
43 size_t line = 0;
44 /* The line number in help_text of the first displayed help
45 * line. This variable is zero-based. */
46 size_t last_line = 0;
47 /* The line number in help_text of the last help line. This
48 * variable is zero-based. */
49 #ifndef DISABLE_MOUSE
50 /* The current shortcut list. */
51 int oldmenu = currmenu;
52 #endif
53 const char *ptr;
54 /* The current line of the help text. */
55 size_t old_line = (size_t)-1;
56 /* The line we were on before the current line. */
57 const sc *s;
58 const subnfunc *f;
60 curs_set(0);
61 blank_edit();
62 wattroff(bottomwin, reverse_attr);
63 blank_statusbar();
65 /* Set help_text as the string to display. */
66 help_init();
68 assert(help_text != NULL);
70 #ifndef DISABLE_MOUSE
71 /* Set currmenu to allow clicking on the help screen's shortcut
72 * list, after help_init() is called. */
73 currmenu = MHELP;
74 #endif
76 if (ISSET(NO_HELP)) {
77 /* Make sure that the help screen's shortcut list will actually
78 * be displayed. */
79 UNSET(NO_HELP);
80 window_init();
83 bottombars(MHELP);
84 wnoutrefresh(bottomwin);
86 /* Get the last line of the help text. */
87 ptr = help_text;
89 for (; *ptr != '\0'; last_line++) {
90 ptr += help_line_len(ptr);
91 if (*ptr == '\n')
92 ptr++;
94 if (last_line > 0)
95 last_line--;
97 while (!abort) {
98 size_t i;
100 /* Display the help text if we don't have a key, or if the help
101 * text has moved. */
102 if (kbinput == ERR || line != old_line) {
103 blank_edit();
105 ptr = help_text;
107 /* Calculate where in the text we should be, based on the
108 * page. */
109 for (i = 0; i < line; i++) {
110 ptr += help_line_len(ptr);
111 if (*ptr == '\n')
112 ptr++;
115 for (i = 0; i < editwinrows && *ptr != '\0'; i++) {
116 size_t j = help_line_len(ptr);
118 mvwaddnstr(edit, i, 0, ptr, j);
119 ptr += j;
120 if (*ptr == '\n')
121 ptr++;
125 wnoutrefresh(edit);
127 old_line = line;
129 kbinput = get_kbinput(edit, &meta_key, &func_key);
131 #ifndef DISABLE_MOUSE
132 if (kbinput == KEY_MOUSE) {
133 int mouse_x, mouse_y;
134 get_mouseinput(&mouse_x, &mouse_y, TRUE);
135 continue;
136 /* Redraw the screen. */
138 #endif
140 parse_help_input(&kbinput, &meta_key, &func_key);
141 s = get_shortcut(MHELP, &kbinput, &meta_key, &func_key);
142 if (!s)
143 continue;
144 f = sctofunc((sc *) s);
145 if (!f)
146 continue;
148 if (f->scfunc == TOTAL_REFRESH) {
149 total_redraw();
150 break;
151 } else if (f->scfunc == DO_PAGE_UP) {
152 if (line > editwinrows - 2)
153 line -= editwinrows - 2;
154 else
155 line = 0;
156 } else if (f->scfunc == DO_PAGE_DOWN) {
157 if (line + (editwinrows - 1) < last_line)
158 line += editwinrows - 2;
159 } else if (f->scfunc == DO_UP_VOID) {
160 if (line > 0)
161 line--;
162 } else if (f->scfunc == DO_DOWN_VOID) {
163 if (line + (editwinrows - 1) < last_line)
164 line++;
165 } else if (f->scfunc == DO_FIRST_LINE) {
166 if (meta_key)
167 line = 0;
168 break;
169 } else if (f->scfunc == DO_LAST_LINE) {
170 if (meta_key) {
171 if (line + (editwinrows - 1) < last_line)
172 line = last_line - (editwinrows - 1);
174 break;
175 /* Abort the help browser. */
176 } else if (f->scfunc == DO_EXIT) {
177 abort = TRUE;
178 break;
182 #ifndef DISABLE_MOUSE
183 currmenu = oldmenu;
184 #endif
186 if (old_no_help) {
187 blank_bottombars();
188 wnoutrefresh(bottomwin);
189 SET(NO_HELP);
190 window_init();
191 } else
192 bottombars(currmenu);
194 curs_set(1);
195 refresh_func();
197 /* The help_init() at the beginning allocated help_text. Since
198 * help_text has now been written to the screen, we don't need it
199 * anymore. */
200 free(help_text);
201 help_text = NULL;
204 #ifndef DISABLE_BROWSER
205 /* Start the help browser for the file browser. */
206 void do_browser_help(void)
208 do_help(&browser_refresh);
210 #endif
212 /* This function allocates help_text, and stores the help string in it.
213 * help_text should be NULL initially. */
214 void help_init(void)
216 size_t allocsize = 0; /* Space needed for help_text. */
217 const char *htx[3]; /* Untranslated help message. We break
218 * it up into three chunks in case the
219 * full string is too long for the
220 * compiler to handle. */
221 char *ptr;
222 const subnfunc *f;
223 const sc *s;
224 int scsfound = 0;
226 #ifndef NANO_TINY
227 #ifdef ENABLE_NANORC
228 bool old_whitespace = ISSET(WHITESPACE_DISPLAY);
230 UNSET(WHITESPACE_DISPLAY);
231 #endif
232 #endif
234 /* First, set up the initial help text for the current function. */
235 if (currmenu == MWHEREIS || currmenu == MREPLACE || currmenu == MREPLACE2) {
236 htx[0] = N_("Search Command Help Text\n\n "
237 "Enter the words or characters you would like to "
238 "search for, and then press Enter. If there is a "
239 "match for the text you entered, the screen will be "
240 "updated to the location of the nearest match for the "
241 "search string.\n\n The previous search string will be "
242 "shown in brackets after the search prompt. Hitting "
243 "Enter without entering any text will perform the "
244 "previous search. ");
245 htx[1] = N_("If you have selected text with the mark and then "
246 "search to replace, only matches in the selected text "
247 "will be replaced.\n\n The following function keys are "
248 "available in Search mode:\n\n");
249 htx[2] = NULL;
250 } else if (currmenu == MGOTOLINE) {
251 htx[0] = N_("Go To Line Help Text\n\n "
252 "Enter the line number that you wish to go to and hit "
253 "Enter. If there are fewer lines of text than the "
254 "number you entered, you will be brought to the last "
255 "line of the file.\n\n The following function keys are "
256 "available in Go To Line mode:\n\n");
257 htx[1] = NULL;
258 htx[2] = NULL;
259 } else if (currmenu == MINSERTFILE) {
260 htx[0] = N_("Insert File Help Text\n\n "
261 "Type in the name of a file to be inserted into the "
262 "current file buffer at the current cursor "
263 "location.\n\n If you have compiled nano with multiple "
264 "file buffer support, and enable multiple file buffers "
265 "with the -F or --multibuffer command line flags, the "
266 "Meta-F toggle, or a nanorc file, inserting a file "
267 "will cause it to be loaded into a separate buffer "
268 "(use Meta-< and > to switch between file buffers). ");
269 htx[1] = N_("If you need another blank buffer, do not enter "
270 "any filename, or type in a nonexistent filename at "
271 "the prompt and press Enter.\n\n The following "
272 "function keys are available in Insert File mode:\n\n");
273 htx[2] = NULL;
274 } else if (currmenu == MWRITEFILE) {
275 htx[0] = N_("Write File Help Text\n\n "
276 "Type the name that you wish to save the current file "
277 "as and press Enter to save the file.\n\n If you have "
278 "selected text with the mark, you will be prompted to "
279 "save only the selected portion to a separate file. To "
280 "reduce the chance of overwriting the current file with "
281 "just a portion of it, the current filename is not the "
282 "default in this mode.\n\n The following function keys "
283 "are available in Write File mode:\n\n");
284 htx[1] = NULL;
285 htx[2] = NULL;
287 #ifndef DISABLE_BROWSER
288 else if (currmenu == MBROWSER) {
289 htx[0] = N_("File Browser Help Text\n\n "
290 "The file browser is used to visually browse the "
291 "directory structure to select a file for reading "
292 "or writing. You may use the arrow keys or Page Up/"
293 "Down to browse through the files, and S or Enter to "
294 "choose the selected file or enter the selected "
295 "directory. To move up one level, select the "
296 "directory called \"..\" at the top of the file "
297 "list.\n\n The following function keys are available "
298 "in the file browser:\n\n");
299 htx[1] = NULL;
300 htx[2] = NULL;
301 } else if (currmenu == MWHEREISFILE) {
302 htx[0] = N_("Browser Search Command Help Text\n\n "
303 "Enter the words or characters you would like to "
304 "search for, and then press Enter. If there is a "
305 "match for the text you entered, the screen will be "
306 "updated to the location of the nearest match for the "
307 "search string.\n\n The previous search string will be "
308 "shown in brackets after the search prompt. Hitting "
309 "Enter without entering any text will perform the "
310 "previous search.\n\n");
311 htx[1] = N_(" The following function keys are available in "
312 "Browser Search mode:\n\n");
313 htx[2] = NULL;
314 } else if (currmenu == MGOTODIR) {
315 htx[0] = N_("Browser Go To Directory Help Text\n\n "
316 "Enter the name of the directory you would like to "
317 "browse to.\n\n If tab completion has not been "
318 "disabled, you can use the Tab key to (attempt to) "
319 "automatically complete the directory name.\n\n The "
320 "following function keys are available in Browser Go "
321 "To Directory mode:\n\n");
322 htx[1] = NULL;
323 htx[2] = NULL;
325 #endif /* !DISABLE_BROWSER */
326 #ifndef DISABLE_SPELLER
327 else if (currmenu == MSPELL) {
328 htx[0] = N_("Spell Check Help Text\n\n "
329 "The spell checker checks the spelling of all text in "
330 "the current file. When an unknown word is "
331 "encountered, it is highlighted and a replacement can "
332 "be edited. It will then prompt to replace every "
333 "instance of the given misspelled word in the current "
334 "file, or, if you have selected text with the mark, in "
335 "the selected text.\n\n The following function keys "
336 "are available in Spell Check mode:\n\n");
337 htx[1] = NULL;
338 htx[2] = NULL;
340 #endif /* !DISABLE_SPELLER */
341 #ifndef NANO_TINY
342 else if (currmenu == MEXTCMD) {
343 htx[0] = N_("Execute Command Help Text\n\n "
344 "This mode allows you to insert the output of a "
345 "command run by the shell into the current buffer (or "
346 "a new buffer in multiple file buffer mode). If you "
347 "need another blank buffer, do not enter any "
348 "command.\n\n The following function keys are "
349 "available in Execute Command mode:\n\n");
350 htx[1] = NULL;
351 htx[2] = NULL;
353 #endif /* !NANO_TINY */
354 else {
355 /* Default to the main help list. */
356 htx[0] = N_("Main nano help text\n\n "
357 "The nano editor is designed to emulate the "
358 "functionality and ease-of-use of the UW Pico text "
359 "editor. There are four main sections of the editor. "
360 "The top line shows the program version, the current "
361 "filename being edited, and whether or not the file "
362 "has been modified. Next is the main editor window "
363 "showing the file being edited. The status line is "
364 "the third line from the bottom and shows important "
365 "messages. ");
366 htx[1] = N_("The bottom two lines show the most commonly used "
367 "shortcuts in the editor.\n\n The notation for "
368 "shortcuts is as follows: Control-key sequences are "
369 "notated with a caret (^) symbol and can be entered "
370 "either by using the Control (Ctrl) key or pressing "
371 "the Escape (Esc) key twice. Escape-key sequences are "
372 "notated with the Meta (M-) symbol and can be entered "
373 "using either the Esc, Alt, or Meta key depending on "
374 "your keyboard setup. ");
375 htx[2] = N_("Also, pressing Esc twice and then typing a "
376 "three-digit decimal number from 000 to 255 will enter "
377 "the character with the corresponding value. The "
378 "following keystrokes are available in the main editor "
379 "window. Alternative keys are shown in "
380 "parentheses:\n\n");
383 htx[0] = _(htx[0]);
384 if (htx[1] != NULL)
385 htx[1] = _(htx[1]);
386 if (htx[2] != NULL)
387 htx[2] = _(htx[2]);
389 allocsize += strlen(htx[0]);
390 if (htx[1] != NULL)
391 allocsize += strlen(htx[1]);
392 if (htx[2] != NULL)
393 allocsize += strlen(htx[2]);
395 /* Count the shortcut help text. Each entry has up to three keys,
396 * which fill 24 columns, plus translated text, plus one or two
397 * \n's. */
398 for (f = allfuncs; f != NULL; f = f->next)
399 if (f->menus & currmenu)
400 allocsize += (24 * mb_cur_max()) + strlen(f->help) + 2;
402 #ifndef NANO_TINY
403 /* If we're on the main list, we also count the toggle help text.
404 * Each entry has "M-%c\t\t\t", which fills 24 columns, plus a
405 * space, plus translated text, plus one or two '\n's. */
406 if (currmenu == MMAIN) {
407 size_t endis_len = strlen(_("enable/disable"));
409 for (s = sclist; s != NULL; s = s->next)
410 if (s->scfunc == DO_TOGGLE)
411 allocsize += strlen(_(flagtostr(s->toggle))) + endis_len + 9;
414 #endif
416 /* help_text has been freed and set to NULL unless the user resized
417 * while in the help screen. */
418 if (help_text != NULL)
419 free(help_text);
421 /* Allocate space for the help text. */
422 help_text = charalloc(allocsize + 1);
424 /* Now add the text we want. */
425 strcpy(help_text, htx[0]);
426 if (htx[1] != NULL)
427 strcat(help_text, htx[1]);
428 if (htx[2] != NULL)
429 strcat(help_text, htx[2]);
431 ptr = help_text + strlen(help_text);
433 /* Now add our shortcut info. */
434 for (f = allfuncs; f != NULL; f = f->next) {
436 if ((f->menus & currmenu) == 0)
437 continue;
439 if (!f->desc || !strcmp(f->desc, ""))
440 continue;
442 /* Lets just try and use the first 3 shortcuts
443 from the new struct... */
444 for (s = sclist, scsfound = 0; s != NULL; s = s->next) {
446 if (scsfound == 3)
447 continue;
449 if (s->type == RAW)
450 continue;
452 if ((s->menu & currmenu) == 0)
453 continue;
455 if (s->scfunc == f->scfunc) {
456 scsfound++;
458 if (scsfound == 1)
459 ptr += sprintf(ptr, "%s", s->keystr);
460 else
461 ptr += sprintf(ptr, "(%s)", s->keystr);
462 *(ptr++) = '\t';
465 /* Pad with tabs if we didnt find 3 */
466 for (; scsfound < 3; scsfound++) {
467 *(ptr++) = '\t';
470 /* The shortcut's help text. */
471 ptr += sprintf(ptr, "%s\n", _(f->help));
473 if (f->blank_after)
474 ptr += sprintf(ptr, "\n");
477 #ifndef NANO_TINY
478 /* And the toggles... */
479 if (currmenu == MMAIN)
480 for (s = sclist; s != NULL; s = s->next)
481 if (s->scfunc == DO_TOGGLE)
482 ptr += sprintf(ptr, "(%s)\t\t\t%s %s\n",
483 s->keystr, _(flagtostr(s->toggle)), _("enable/disable"));
486 #ifdef ENABLE_NANORC
487 if (old_whitespace)
488 SET(WHITESPACE_DISPLAY);
489 #endif
490 #endif
492 /* If all went well, we didn't overwrite the allocated space for
493 * help_text. */
494 assert(strlen(help_text) <= allocsize + 1);
497 /* Determine the shortcut key corresponding to the values of kbinput
498 * (the key itself), meta_key (whether the key is a meta sequence), and
499 * func_key (whether the key is a function key), if any. In the
500 * process, convert certain non-shortcut keys into their corresponding
501 * shortcut keys. */
502 void parse_help_input(int *kbinput, bool *meta_key, bool *func_key)
504 get_shortcut(MHELP, kbinput, meta_key, func_key);
506 if (!*meta_key) {
507 switch (*kbinput) {
508 /* For consistency with the file browser. */
509 case ' ':
510 *kbinput = sc_seq_or(DO_PAGE_UP, 0);
511 break;
512 case '-':
513 *kbinput = sc_seq_or(DO_PAGE_DOWN, 0);;
514 break;
515 /* Cancel is equivalent to Exit here. */
516 case 'E':
517 case 'e':
518 *kbinput = sc_seq_or(DO_EXIT, 0);;
519 break;
524 /* Calculate the next line of help_text, starting at ptr. */
525 size_t help_line_len(const char *ptr)
527 int help_cols = (COLS > 24) ? COLS - 1 : 24;
529 /* Try to break the line at (COLS - 1) columns if we have more than
530 * 24 columns, and at 24 columns otherwise. */
531 ssize_t wrap_loc = break_line(ptr, help_cols, TRUE);
532 size_t retval = (wrap_loc < 0) ? 0 : wrap_loc;
533 size_t retval_save = retval;
535 /* Get the length of the entire line up to a null or a newline. */
536 while (*(ptr + retval) != '\0' && *(ptr + retval) != '\n')
537 retval += move_mbright(ptr + retval, 0);
539 /* If the entire line doesn't go more than one column beyond where
540 * we tried to break it, we should display it as-is. Otherwise, we
541 * should display it only up to the break. */
542 if (strnlenpt(ptr, retval) > help_cols + 1)
543 retval = retval_save;
545 return retval;
548 #endif /* !DISABLE_HELP */
550 /* Start the help browser for the edit window. */
551 void do_help_void(void)
554 #ifndef DISABLE_HELP
555 /* Start the help browser for the edit window. */
556 do_help(&edit_refresh);
557 #else
558 if (currmenu == MMAIN)
559 nano_disabled_msg();
560 else
561 beep();
562 #endif