Logo Search packages:      
Sourcecode: nano version File versions  Download package

help.c

/* $Id: help.c,v 1.8 2005/12/08 02:47:10 dolorous Exp $ */
/**************************************************************************
 *   help.c                                                               *
 *                                                                        *
 *   Copyright (C) 2000-2004 Chris Allegretta                             *
 *   Copyright (C) 2005 David Lawrence Ramsey                             *
 *   This program is free software; you can redistribute it and/or modify *
 *   it under the terms of the GNU General Public License as published by *
 *   the Free Software Foundation; either version 2, or (at your option)  *
 *   any later version.                                                   *
 *                                                                        *
 *   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, write to the Free Software          *
 *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA            *
 *   02110-1301, USA.                                                     *
 *                                                                        *
 **************************************************************************/

#include "proto.h"

#include <stdio.h>
#include <string.h>
#include <ctype.h>

#ifndef DISABLE_HELP

static char *help_text = NULL;
      /* The text displayed in the help window. */

/* Our dynamic, shortcut-list-compliant help function. */
void do_help(void)
{
    int line = 0;
      /* The line number in help_text of the first displayed help
       * line.  This variable is zero-based. */
    bool no_more = FALSE;
      /* no_more means the end of the help text is shown, so don't go
       * down any more. */
    int kbinput = ERR;
    bool meta_key, func_key;

    bool old_no_help = ISSET(NO_HELP);
#ifndef DISABLE_MOUSE
    const shortcut *oldshortcut = currshortcut;
      /* We will set currshortcut to allow clicking on the help
       * screen's shortcut list. */
#endif

    curs_set(0);
    blank_edit();
    wattroff(bottomwin, A_REVERSE);
    blank_statusbar();

    /* Set help_text as the string to display. */
    help_init();

    assert(help_text != NULL);

#ifndef DISABLE_MOUSE
    /* Set currshortcut to allow clicking on the help screen's shortcut
     * list, after help_init() is called. */
    currshortcut = help_list;
#endif

    if (ISSET(NO_HELP)) {
      /* Make sure that the help screen's shortcut list will actually
       * be displayed. */
      UNSET(NO_HELP);
      window_init();
    }

    bottombars(help_list);

    do {
      int i;
      int old_line = line;
          /* We redisplay the help only if it moved. */
      const char *ptr = help_text;

      switch (kbinput) {
#ifndef DISABLE_MOUSE
          case KEY_MOUSE:
            {
                int mouse_x, mouse_y;
                get_mouseinput(&mouse_x, &mouse_y, TRUE);
            }
            break;
#endif
          case NANO_PREVPAGE_KEY:
          case NANO_PREVPAGE_FKEY:
            if (line > 0) {
                line -= editwinrows - 2;
                if (line < 0)
                  line = 0;
            }
            break;
          case NANO_NEXTPAGE_KEY:
          case NANO_NEXTPAGE_FKEY:
            if (!no_more)
                line += editwinrows - 2;
            break;
          case NANO_PREVLINE_KEY:
            if (line > 0)
                line--;
            break;
          case NANO_NEXTLINE_KEY:
            if (!no_more)
                line++;
            break;
      }

      if (kbinput == NANO_REFRESH_KEY)
          /* Redraw the screen. */
          total_redraw();
      else {
          if (kbinput != ERR && line == old_line)
            goto skip_redisplay;

          blank_edit();
      }

      /* Calculate where in the text we should be, based on the
       * page. */
      for (i = 0; i < line; i++) {
          ptr += help_line_len(ptr);
          if (*ptr == '\n')
            ptr++;
      }

      for (i = 0; i < editwinrows && *ptr != '\0'; i++) {
          size_t j = help_line_len(ptr);

          mvwaddnstr(edit, i, 0, ptr, j);
          ptr += j;
          if (*ptr == '\n')
            ptr++;
      }
      no_more = (*ptr == '\0');

  skip_redisplay:
      kbinput = get_kbinput(edit, &meta_key, &func_key);
    } while (kbinput != NANO_EXIT_KEY && kbinput != NANO_EXIT_FKEY);

#ifndef DISABLE_MOUSE
    currshortcut = oldshortcut;
#endif

    if (old_no_help) {
      blank_bottombars();
      wnoutrefresh(bottomwin);
      SET(NO_HELP);
      window_init();
    } else
      bottombars(currshortcut);

    curs_set(1);
    edit_refresh();

    /* The help_init() at the beginning allocated help_text.  Since 
     * help_text has now been written to the screen, we don't need it
     * anymore. */
    free(help_text);
    help_text = NULL;
}

/* This function allocates help_text, and stores the help string in it. 
 * help_text should be NULL initially. */
void help_init(void)
{
    size_t allocsize = 0;     /* Space needed for help_text. */
    const char *htx[3];       /* Untranslated help message.  We break
                         * it up into three chunks in case the
                         * full string is too long for the
                         * compiler to handle. */
    char *ptr;
    const shortcut *s;
#ifndef NANO_TINY
    const toggle *t;
#ifdef ENABLE_NANORC
    bool old_whitespace = ISSET(WHITESPACE_DISPLAY);

    UNSET(WHITESPACE_DISPLAY);
#endif
#endif

    /* First, set up the initial help text for the current function. */
    if (currshortcut == whereis_list || currshortcut == replace_list ||
      currshortcut == replace_list_2) {
      htx[0] = N_("Search Command Help Text\n\n "
            "Enter the words or characters you would like to "
            "search for, and then press Enter.  If there is a "
            "match for the text you entered, the screen will be "
            "updated to the location of the nearest match for the "
            "search string.\n\n The previous search string will be "
            "shown in brackets after the search prompt.  Hitting "
            "Enter without entering any text will perform the "
            "previous search.  ");
      htx[1] = N_("If you have selected text with the mark and then "
            "search to replace, only matches in the selected text "
            "will be replaced.\n\n The following function keys are "
            "available in Search mode:\n\n");
      htx[2] = NULL;
    } else if (currshortcut == gotoline_list) {
      htx[0] = N_("Go To Line Help Text\n\n "
            "Enter the line number that you wish to go to and hit "
            "Enter.  If there are fewer lines of text than the "
            "number you entered, you will be brought to the last "
            "line of the file.\n\n The following function keys are "
            "available in Go To Line mode:\n\n");
      htx[1] = NULL;
      htx[2] = NULL;
    } else if (currshortcut == insertfile_list) {
      htx[0] = N_("Insert File Help Text\n\n "
            "Type in the name of a file to be inserted into the "
            "current file buffer at the current cursor "
            "location.\n\n If you have compiled nano with multiple "
            "file buffer support, and enable multiple file buffers "
            "with the -F or --multibuffer command line flags, the "
            "Meta-F toggle, or a nanorc file, inserting a file "
            "will cause it to be loaded into a separate buffer "
            "(use Meta-< and > to switch between file buffers).  ");
      htx[1] = N_("If you need another blank buffer, do not enter "
            "any filename, or type in a nonexistent filename at "
            "the prompt and press Enter.\n\n The following "
            "function keys are available in Insert File mode:\n\n");
      htx[2] = NULL;
    } else if (currshortcut == writefile_list) {
      htx[0] = N_("Write File Help Text\n\n "
            "Type the name that you wish to save the current file "
            "as and press Enter to save the file.\n\n If you have "
            "selected text with the mark, you will be prompted to "
            "save only the selected portion to a separate file.  To "
            "reduce the chance of overwriting the current file with "
            "just a portion of it, the current filename is not the "
            "default in this mode.\n\n The following function keys "
            "are available in Write File mode:\n\n");
      htx[1] = NULL;
      htx[2] = NULL;
    }
#ifndef DISABLE_BROWSER
    else if (currshortcut == browser_list) {
      htx[0] = N_("File Browser Help Text\n\n "
            "The file browser is used to visually browse the "
            "directory structure to select a file for reading "
            "or writing.  You may use the arrow keys or Page Up/"
            "Down to browse through the files, and S or Enter to "
            "choose the selected file or enter the selected "
            "directory.  To move up one level, select the "
            "directory called \"..\" at the top of the file "
            "list.\n\n The following function keys are available "
            "in the file browser:\n\n");
      htx[1] = NULL;
      htx[2] = NULL;
    } else if (currshortcut == gotodir_list) {
      htx[0] = N_("Browser Go To Directory Help Text\n\n "
            "Enter the name of the directory you would like to "
            "browse to.\n\n If tab completion has not been "
            "disabled, you can use the Tab key to (attempt to) "
            "automatically complete the directory name.\n\n The "
            "following function keys are available in Browser Go "
            "To Directory mode:\n\n");
      htx[1] = NULL;
      htx[2] = NULL;
    }
#endif
#ifndef DISABLE_SPELLER
    else if (currshortcut == spell_list) {
      htx[0] = N_("Spell Check Help Text\n\n "
            "The spell checker checks the spelling of all text in "
            "the current file.  When an unknown word is "
            "encountered, it is highlighted and a replacement can "
            "be edited.  It will then prompt to replace every "
            "instance of the given misspelled word in the current "
            "file, or, if you have selected text with the mark, in "
            "the selected text.\n\n The following other functions "
            "are available in Spell Check mode:\n\n");
      htx[1] = NULL;
      htx[2] = NULL;
    }
#endif
#ifndef NANO_TINY
    else if (currshortcut == extcmd_list) {
      htx[0] = N_("Execute Command Help Text\n\n "
            "This menu allows you to insert the output of a "
            "command run by the shell into the current buffer (or "
            "a new buffer in multiple file buffer mode). If you "
            "need another blank buffer, do not enter any "
            "command.\n\n The following keys are available in "
            "Execute Command mode:\n\n");
      htx[1] = NULL;
      htx[2] = NULL;
    }
#endif
    else {
      /* Default to the main help list. */
      htx[0] = N_(" nano help text\n\n "
            "The nano editor is designed to emulate the "
            "functionality and ease-of-use of the UW Pico text "
            "editor.  There are four main sections of the editor.  "
            "The top line shows the program version, the current "
            "filename being edited, and whether or not the file "
            "has been modified.  Next is the main editor window "
            "showing the file being edited.  The status line is "
            "the third line from the bottom and shows important "
            "messages.  The bottom two lines show the most "
            "commonly used shortcuts in the editor.\n\n ");
      htx[1] = N_("The notation for shortcuts is as follows: "
            "Control-key sequences are notated with a caret (^) "
            "symbol and can be entered either by using the Control "
            "(Ctrl) key or pressing the Escape (Esc) key twice.  "
            "Escape-key sequences are notated with the Meta (M) "
            "symbol and can be entered using either the Esc, Alt, "
            "or Meta key depending on your keyboard setup.  ");
      htx[2] = N_("Also, pressing Esc twice and then typing a "
            "three-digit decimal number from 000 to 255 will enter "
            "the character with the corresponding value.  The "
            "following keystrokes are available in the main editor "
            "window.  Alternative keys are shown in "
            "parentheses:\n\n");
    }

    htx[0] = _(htx[0]);
    if (htx[1] != NULL)
      htx[1] = _(htx[1]);
    if (htx[2] != NULL)
      htx[2] = _(htx[2]);

    allocsize += strlen(htx[0]);
    if (htx[1] != NULL)
      allocsize += strlen(htx[1]);
    if (htx[2] != NULL)
      allocsize += strlen(htx[2]);

    /* The space needed for the shortcut lists, at most COLS characters,
     * plus '\n'. */
    allocsize += (COLS < 24 ? (24 * mb_cur_max()) :
      ((COLS + 1) * mb_cur_max())) * length_of_list(currshortcut);

#ifndef NANO_TINY
    /* If we're on the main list, we also count the toggle help text.
     * Each line has "M-%c\t\t\t", which fills 24 columns, plus a space,
     * plus translated text, plus '\n'. */
    if (currshortcut == main_list) {
      size_t endis_len = strlen(_("enable/disable"));

      for (t = toggles; t != NULL; t = t->next)
          allocsize += 8 + strlen(t->desc) + endis_len;
    }
#endif

    /* help_text has been freed and set to NULL unless the user resized
     * while in the help screen. */
    if (help_text != NULL)
      free(help_text);

    /* Allocate space for the help text. */
    help_text = charalloc(allocsize + 1);

    /* Now add the text we want. */
    strcpy(help_text, htx[0]);
    if (htx[1] != NULL)
      strcat(help_text, htx[1]);
    if (htx[2] != NULL)
      strcat(help_text, htx[2]);

    ptr = help_text + strlen(help_text);

    /* Now add our shortcut info.  Assume that each shortcut has, at the
     * very least, an equivalent control key, an equivalent primary meta
     * key sequence, or both.  Also assume that the meta key values are
     * not control characters.  We can display a maximum of 3 shortcut
     * entries. */
    for (s = currshortcut; s != NULL; s = s->next) {
      int entries = 0;

      /* Control key. */
      if (s->ctrlval != NANO_NO_KEY) {
          entries++;
          /* Yucky sentinel values that we can't handle a better
           * way. */
          if (s->ctrlval == NANO_CONTROL_SPACE) {
            char *space_ptr = display_string(_("Space"), 0, 6,
                  FALSE);

            ptr += sprintf(ptr, "^%s", space_ptr);

            free(space_ptr);
          } else if (s->ctrlval == NANO_CONTROL_8)
            ptr += sprintf(ptr, "^?");
          /* Normal values. */
          else
            ptr += sprintf(ptr, "^%c", s->ctrlval + 64);
          *(ptr++) = '\t';
      }

      /* Function key. */
      if (s->funcval != NANO_NO_KEY) {
          entries++;
          /* If this is the first entry, put it in the middle. */
          if (entries == 1) {
            entries++;
            *(ptr++) = '\t';
          }
          ptr += sprintf(ptr, "(F%d)", s->funcval - KEY_F0);
          *(ptr++) = '\t';
      }

      /* Primary meta key sequence.  If it's the first entry, don't
       * put parentheses around it. */
      if (s->metaval != NANO_NO_KEY) {
          entries++;
          /* If this is the last entry, put it at the end. */
          if (entries == 2 && s->miscval == NANO_NO_KEY) {
            entries++;
            *(ptr++) = '\t';
          }
          /* Yucky sentinel values that we can't handle a better
           * way. */
          if (s->metaval == NANO_ALT_SPACE && entries == 1) {
            char *space_ptr = display_string(_("Space"), 0, 5,
                  FALSE);

            ptr += sprintf(ptr, "M-%s", space_ptr);

            free(space_ptr);
          } else
            /* Normal values. */
            ptr += sprintf(ptr, (entries == 1) ? "M-%c" : "(M-%c)",
                  toupper(s->metaval));
          *(ptr++) = '\t';
      }

      /* Miscellaneous meta key sequence. */
      if (entries < 3 && s->miscval != NANO_NO_KEY) {
          entries++;
          /* If this is the last entry, put it at the end. */
          if (entries == 2) {
            entries++;
            *(ptr++) = '\t';
          }
          ptr += sprintf(ptr, "(M-%c)", toupper(s->miscval));
          *(ptr++) = '\t';
      }

      /* Make sure all the help text starts at the same place. */
      while (entries < 3) {
          entries++;
          *(ptr++) = '\t';
      }

      assert(s->help != NULL);

      if (COLS > 24) {
          char *help_ptr = display_string(s->help, 0, COLS - 24,
            FALSE);

          ptr += sprintf(ptr, help_ptr);

          free(help_ptr);
      }

      ptr += sprintf(ptr, "\n");
    }

#ifndef NANO_TINY
    /* And the toggles... */
    if (currshortcut == main_list) {
      for (t = toggles; t != NULL; t = t->next) {

          assert(t->desc != NULL);

          ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val),
            t->desc, _("enable/disable"));
      }
    }

#ifdef ENABLE_NANORC
    if (old_whitespace)
      SET(WHITESPACE_DISPLAY);
#endif
#endif

    /* If all went well, we didn't overwrite the allocated space for
     * help_text. */
    assert(strlen(help_text) <= allocsize + 1);
}

/* Calculate the next line of help_text, starting at ptr. */
size_t help_line_len(const char *ptr)
{
    int help_cols = (COLS > 24) ? COLS - 8 : 24;

    /* Try to break the line at (COLS - 8) columns if we have more than
     * 24 columns, and at 24 columns otherwise. */
    size_t retval = break_line(ptr, help_cols, TRUE);
    size_t retval_save = retval;

    /* Get the length of the entire line up to a null or a newline. */
    while (*(ptr + retval) != '\0' && *(ptr + retval) != '\n')
      retval += move_mbright(ptr + retval, 0);

    /* If the entire line doesn't go more than 8 columns beyond where we
     * tried to break it, we should display it as-is.  Otherwise, we
     * should display it only up to the break. */
    if (strnlenpt(ptr, retval) > help_cols + 8)
      retval = retval_save;

    return retval;
}

#endif /* !DISABLE_HELP */

Generated by  Doxygen 1.6.0   Back to index