]> git.wh0rd.org Git - nano.git/commitdiff
overhaul the high-level input routines for the statusbar to make them
authorDavid Lawrence Ramsey <pooka109@gmail.com>
Sat, 1 Jan 2005 07:28:15 +0000 (07:28 +0000)
committerDavid Lawrence Ramsey <pooka109@gmail.com>
Sat, 1 Jan 2005 07:28:15 +0000 (07:28 +0000)
more flexible, among other things, and add UTF-8 support to them in the
process; also update the copyright years of the modified files

git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@2210 35c25a1d-7b9e-4130-9fde-d3aeb78583b8

ChangeLog
src/files.c
src/global.c
src/nano.c
src/proto.h
src/winio.c

index 8137dd21ea170b630eef4fef504f0d0ded98099f..7a9d139e2f4e3efd1852324e17d554be40b8f047 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -45,19 +45,38 @@ CVS code -
          do_mouse() and moved to nano.c), do_verbatim_input(),
          do_tab(), main(), and get_ascii_kbinput() (renamed to
          get_word_kbinput()).  The wide version of ncurses is required
-         in order for output to work properly. (DLR; buffered
-         input/output based on ideas from mutt 1.4.2.1; double-Escape
-         input of Unicode characters suggested by Michael Piefel)
+         in order for wide/multibyte input and output to work properly.
+         (DLR; buffered input/output based on ideas from mutt 1.4.2.1;
+         double-Escape input of Unicode characters suggested by Michael
+         Piefel)
        - More steps toward wide character/multibyte character support.
          Movement and cursor display in the edit window should now work
          properly with files containing multibyte characters, and text
-         display of such files should work properly some of the time.
-         New functions control_rep(), parse_char(), move_left(),
+         display of such files should now work properly as well.  New
+         functions control_rep(), parse_char(), move_left(),
          move_right(), and display_string_len(); changes to do_left(),
          do_right(), do_delete(), breakable(), break_line(),
          do_output(), get_buffer(), unget_input(), actual_x(),
          strnlenpt(), display_string(), titlebar(), statusbar(),
          onekey(), and do_credits(). (David Benbennick and DLR)
+       - Overhaul the high-level input routines for the statusbar to
+         make them read the shortcut lists for functions instead of
+         manually running them, to make nanogetstr() less complex, and
+         to increase flexibility.  Note that currshortcut is now used
+         regardless of #ifdefs.  Changes to shortcut_init() and
+         nanogetstr(); new functions do_statusbar_input(),
+         do_statusbar_mouse(), do_statusbar_home(), do_statusbar_end(),
+         do_statusbar_right(), do_statusbar_left(),
+         do_statusbar_backspace(), do_statusbar_delete(),
+         do_statusbar_cut_text(), and do_statusbar_output(). (DLR)
+       - Even more steps toward wide character/multibyte character
+         support.  Movement and (most) cursor display at the statusbar
+         prompt should now work properly with a string containing
+         multibyte characters, and text display of such strings should
+         now (mostly) work properly as well.  Changes to
+         do_statusbar_right(), do_statusbar_left(),
+         do_statusbar_backspace(), and do_statusbar_delete(). (David
+         Benbennick and DLR)
 - cut.c:
   do_cut_text()
        - If keep_cutbuffer is FALSE, only blow away the text in the
@@ -100,6 +119,9 @@ CVS code -
          loop if there are no more paragraphs after the current one and
          the paragraph search left us on the magicline, so as to avoid
          a segfault. (DLR)
+  do_input()
+       - Add finished parameter, used to indicate when we run or try to
+         run a function associated with a shortcut. (DLR)
   main()
        - Try to automatically detect whether UTF-8 support is needed by
          setting the NO_UTF8 flag if setlocale() returns a string that
index 7e6228d6702e3cac856ea829575798b6fc5f213e..7598640bae981e7d6c2eda9dfb1c82d478f685c6 100644 (file)
@@ -2,7 +2,7 @@
 /**************************************************************************
  *   files.c                                                              *
  *                                                                        *
- *   Copyright (C) 1999-2004 Chris Allegretta                             *
+ *   Copyright (C) 1999-2005 Chris Allegretta                             *
  *   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)  *
@@ -1738,9 +1738,7 @@ int do_writeout(bool exiting)
     static bool did_cred = FALSE;
 #endif
 
-#if !defined(DISABLE_BROWSER) || !defined(DISABLE_MOUSE)
     currshortcut = writefile_list;
-#endif
 
     if (exiting && filename[0] != '\0' && ISSET(TEMP_FILE)) {
        retval = write_file(filename, FALSE, 0, FALSE);
@@ -2541,9 +2539,7 @@ char *do_browser(const char *inpath)
 
        check_statusblank();
 
-#if !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
        currshortcut = browser_list;
-#endif
 
        editline = 0;
        col = 0;
index 4c4d2ec2ecf25f6fd4d261a5f06ed9b5f32f78fa..0db515ee7d7ab254a15cf2bae2779e4ada4e6b1f 100644 (file)
@@ -2,7 +2,7 @@
 /**************************************************************************
  *   global.c                                                             *
  *                                                                        *
- *   Copyright (C) 1999-2004 Chris Allegretta                             *
+ *   Copyright (C) 1999-2005 Chris Allegretta                             *
  *   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)  *
@@ -159,9 +159,7 @@ syntaxtype *syntaxes = NULL;
 char *syntaxstr = NULL;
 #endif
 
-#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
 const shortcut *currshortcut;  /* Current shortcut list we're using */
-#endif
 
 #ifndef NANO_SMALL
 toggle *toggles = NULL;
@@ -614,12 +612,12 @@ void shortcut_init(bool unjustify)
     /* Translators: try to keep this string under 10 characters long */
     sc_init_one(&whereis_list, NANO_TOOTHERSEARCH_KEY, replace_msg,
        IFHELP(nano_replace_msg, NANO_NO_KEY), NANO_REPLACE_FKEY,
-       NANO_NO_KEY, VIEW, do_replace);
+       NANO_NO_KEY, VIEW, 0);
 
     /* Translators: try to keep this string under 10 characters long */
     sc_init_one(&whereis_list, NANO_TOGOTOLINE_KEY, go_to_line_msg,
        IFHELP(nano_gotoline_msg, NANO_NO_KEY), NANO_GOTOLINE_FKEY,
-       NANO_NO_KEY, VIEW, do_gotoline_void);
+       NANO_NO_KEY, VIEW, 0);
 
 #ifndef DISABLE_JUSTIFY
     /* Translators: try to keep this string under 10 characters long */
@@ -691,11 +689,11 @@ void shortcut_init(bool unjustify)
     /* Translators: try to keep this string under 12 characters long */
     sc_init_one(&replace_list, NANO_TOOTHERSEARCH_KEY, N_("No Replace"),
        IFHELP(nano_whereis_msg, NANO_NO_KEY), NANO_REPLACE_FKEY,
-       NANO_NO_KEY, VIEW, do_search);
+       NANO_NO_KEY, VIEW, 0);
 
     sc_init_one(&replace_list, NANO_TOGOTOLINE_KEY, go_to_line_msg,
        IFHELP(nano_gotoline_msg, NANO_NO_KEY), NANO_GOTOLINE_FKEY,
-       NANO_NO_KEY, VIEW, do_gotoline_void);
+       NANO_NO_KEY, VIEW, 0);
 
 #ifndef NANO_SMALL
     sc_init_one(&replace_list, NANO_NO_KEY, case_sens_msg,
@@ -773,7 +771,7 @@ void shortcut_init(bool unjustify)
 
     sc_init_one(&gotoline_list, NANO_TOOTHERWHEREIS_KEY,
        N_("Go To Text"), IFHELP(nano_whereis_msg, NANO_NO_KEY),
-       NANO_NO_KEY, NANO_NO_KEY, VIEW, do_search);
+       NANO_NO_KEY, NANO_NO_KEY, VIEW, 0);
 
 #ifndef DISABLE_HELP
     free_shortcutage(&help_list);
index 755fbefd09f38231b6fcf33598307821827c70dd..559ac14bfc9e09527460454707450824be463279 100644 (file)
@@ -2,7 +2,7 @@
 /**************************************************************************
  *   nano.c                                                               *
  *                                                                        *
- *   Copyright (C) 1999-2004 Chris Allegretta                             *
+ *   Copyright (C) 1999-2005 Chris Allegretta                             *
  *   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)  *
@@ -2718,7 +2718,7 @@ void do_justify(bool full_justify)
     size_t mark_beginx_save = mark_beginx;
 #endif
     int kbinput;
-    bool meta_key, func_key, s_or_t;
+    bool meta_key, func_key, s_or_t, finished;
 
     /* If we're justifying the entire file, start at the beginning. */
     if (full_justify)
@@ -2984,7 +2984,7 @@ void do_justify(bool full_justify)
 
     /* Now get a keystroke and see if it's unjustify.  If not, put back
      * the keystroke and return. */
-    kbinput = do_input(&meta_key, &func_key, &s_or_t, FALSE);
+    kbinput = do_input(&meta_key, &func_key, &s_or_t, &finished, FALSE);
 
     if (!meta_key && !func_key && s_or_t &&
        kbinput == NANO_UNJUSTIFY_KEY) {
@@ -3386,7 +3386,7 @@ void terminal_init(void)
 }
 
 int do_input(bool *meta_key, bool *func_key, bool *s_or_t, bool
-       allow_funcs)
+       *finished, bool allow_funcs)
 {
     int input;
        /* The character we read in. */
@@ -3402,6 +3402,7 @@ int do_input(bool *meta_key, bool *func_key, bool *s_or_t, bool
 #endif
 
     *s_or_t = FALSE;
+    *finished = FALSE;
 
     /* Read in a character. */
     input = get_kbinput(edit, meta_key, func_key);
@@ -3477,7 +3478,8 @@ int do_input(bool *meta_key, bool *func_key, bool *s_or_t, bool
 
        if (have_shortcut) {
            switch (input) {
-               /* Handle the "universal" edit window shortcuts. */
+               /* Handle the "universal" statusbar prompt shortcuts,
+                * setting ran_s_or_t to TRUE to indicate it. */
                case NANO_XON_KEY:
                    statusbar(_("XON ignored, mumble mumble."));
                    break;
@@ -3490,21 +3492,23 @@ int do_input(bool *meta_key, bool *func_key, bool *s_or_t, bool
                        do_suspend(0);
                    break;
 #endif
-               /* Handle the normal edit window shortcuts. */
+               /* Handle the normal edit window shortcuts, setting
+                * finished to TRUE to indicate that we're done after
+                * running or trying to run their associated
+                * functions. */
                default:
                    /* Blow away the text in the cutbuffer if we aren't
                     * cutting text. */
                    if (s->func != do_cut_text)
                        cutbuffer_reset();
 
-                   /* Run the function associated with this shortcut,
-                    * if there is one. */
                    if (s->func != NULL) {
                        if (ISSET(VIEW_MODE) && !s->viewok)
                            print_view_warning();
                        else
                            s->func();
                    }
+                   *finished = TRUE;
                    break;
            }
        }
@@ -3577,9 +3581,6 @@ bool do_mouse(void)
            edit_refresh();
        }
     }
-    /* FIXME: If we clicked on a location in the statusbar, the cursor
-     * should move to the location we clicked on.  This functionality
-     * should be in do_statusbar_mouse() when it's written. */
 
     return retval;
 }
@@ -4225,6 +4226,9 @@ int main(int argc, char **argv)
                /* Whether we got a function key. */
        bool s_or_t;
                /* Whether we got a shortcut or toggle. */
+       bool ran_s_or_t;
+               /* Whether we ran a function associated with a
+                * shortcut. */
 
        /* Make sure the cursor is in the edit window. */
        reset_cursor();
@@ -4234,12 +4238,10 @@ int main(int argc, char **argv)
        if (ISSET(CONSTUPDATE))
            do_cursorpos(TRUE);
 
-#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
        currshortcut = main_list;
-#endif
 
        /* Read in and interpret characters. */
-       do_input(&meta_key, &func_key, &s_or_t, TRUE);
+       do_input(&meta_key, &func_key, &s_or_t, &ran_s_or_t, TRUE);
     }
     assert(FALSE);
 }
index cb2d0f14120dd222799965d9c575cd563a07b9ae..2441932400f97d480ac62ab002d7a7a1dc1bf91d 100644 (file)
@@ -2,7 +2,7 @@
 /**************************************************************************
  *   proto.h                                                              *
  *                                                                        *
- *   Copyright (C) 1999-2004 Chris Allegretta                             *
+ *   Copyright (C) 1999-2005 Chris Allegretta                             *
  *   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)  *
@@ -122,9 +122,7 @@ extern shortcut *spell_list;
 extern shortcut *browser_list, *gotodir_list;
 #endif
 
-#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
 extern const shortcut *currshortcut;
-#endif
 
 #ifdef HAVE_REGEX_H
 extern regex_t search_regexp;
@@ -391,7 +389,7 @@ void disable_flow_control(void);
 void enable_flow_control(void);
 void terminal_init(void);
 int do_input(bool *meta_key, bool *func_key, bool *s_or_t, bool
-       allow_funcs);
+       *finished, bool allow_funcs);
 #ifndef DISABLE_MOUSE
 bool do_mouse(void);
 #endif
@@ -569,6 +567,19 @@ const shortcut *get_shortcut(const shortcut *s_list, int *kbinput, bool
 #ifndef NANO_SMALL
 const toggle *get_toggle(int kbinput, bool meta_key);
 #endif
+int do_statusbar_input(bool *meta_key, bool *func_key, bool *s_or_t,
+       bool *finished, bool allow_funcs);
+#ifndef DISABLE_MOUSE
+bool do_statusbar_mouse(void);
+#endif
+void do_statusbar_home(void);
+void do_statusbar_end(void);
+void do_statusbar_right(void);
+void do_statusbar_left(void);
+void do_statusbar_backspace(void);
+void do_statusbar_delete(void);
+void do_statusbar_cut_text(void);
+void do_statusbar_output(int *kbinput, size_t kbinput_len);
 size_t xplustabs(void);
 size_t actual_x(const char *str, size_t xplus);
 size_t strnlenpt(const char *buf, size_t size);
index d116b89960a6727a93a9487cdcb046c8bd3c3077..4cc6c77e0a997f4412eea9b008149771382550a9 100644 (file)
@@ -2,7 +2,7 @@
 /**************************************************************************
  *   winio.c                                                              *
  *                                                                        *
- *   Copyright (C) 1999-2004 Chris Allegretta                             *
+ *   Copyright (C) 1999-2005 Chris Allegretta                             *
  *   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)  *
@@ -46,6 +46,10 @@ static size_t key_buffer_len = 0;
 static int statusblank = 0;    /* The number of keystrokes left after
                                 * we call statusbar(), before we
                                 * actually blank the statusbar. */
+static size_t statusbar_x = (size_t)-1;
+                               /* The cursor position in answer. */
+static size_t statusbar_xend = 0;
+                               /* The length of answer. */
 static bool resetstatuspos = FALSE;
                                /* Should we reset the cursor position
                                 * at the statusbar prompt? */
@@ -1609,6 +1613,271 @@ const toggle *get_toggle(int kbinput, bool meta_key)
 }
 #endif /* !NANO_SMALL */
 
+int do_statusbar_input(bool *meta_key, bool *func_key, bool *s_or_t,
+       bool *finished, bool allow_funcs)
+{
+    int input;
+       /* The character we read in. */
+    static int *kbinput = NULL;
+       /* The input buffer. */
+    static size_t kbinput_len = 0;
+       /* The length of the input buffer. */
+    const shortcut *s;
+    bool have_shortcut;
+
+    *s_or_t = FALSE;
+    *finished = FALSE;
+
+    /* Read in a character. */
+    input = get_kbinput(bottomwin, meta_key, func_key);
+
+#ifndef DISABLE_MOUSE
+    /* If we got a mouse click and it was on a shortcut, read in the
+     * shortcut character. */
+    if (allow_funcs && func_key && input == KEY_MOUSE) {
+       if (do_mouse())
+           input = get_kbinput(bottomwin, meta_key, func_key);
+       else
+           input = ERR;
+    }
+#endif
+
+    /* Check for a shortcut in the current list. */
+    s = get_shortcut(currshortcut, &input, meta_key, func_key);
+
+    /* If we got a shortcut from the current list, or a "universal"
+     * statusbar prompt shortcut, set have_shortcut to TRUE. */
+    have_shortcut = (s != NULL || input == NANO_REFRESH_KEY ||
+       input == NANO_HOME_KEY || input == NANO_END_KEY ||
+       input == NANO_FORWARD_KEY || input == NANO_BACK_KEY ||
+       input == NANO_BACKSPACE_KEY || input == NANO_DELETE_KEY ||
+       input == NANO_CUT_KEY);
+
+    /* Set s_or_t to TRUE if we got a shortcut. */
+    *s_or_t = have_shortcut;
+
+    if (allow_funcs) {
+       if (input != ERR && *s_or_t == FALSE && !is_cntrl_char(input)) {
+           /* If we're using restricted mode, the filename isn't blank,
+            * and we're at the "Write File" prompt, disable text
+            * input. */
+           if (!ISSET(RESTRICTED) || filename[0] == '\0' ||
+               currshortcut != writefile_list) {
+               kbinput_len++;
+               kbinput = (int *)nrealloc(kbinput, kbinput_len *
+                       sizeof(int));
+               kbinput[kbinput_len - 1] = input;
+           }
+       }
+
+       /* If we got a shortcut, or if there aren't any other characters
+        * waiting after the one we read in, we need to display all the
+        * characters in the input buffer if it isn't empty. */
+        if (*s_or_t == TRUE || get_buffer_len() == 0) {
+           if (kbinput != NULL) {
+               /* Display all the characters in the input buffer at
+                * once. */
+               do_statusbar_output(kbinput, kbinput_len);
+
+               /* Empty the input buffer. */
+               kbinput_len = 0;
+               free(kbinput);
+               kbinput = NULL;
+           }
+       }
+
+       if (have_shortcut) {
+           switch (input) {
+               /* Handle the "universal" statusbar prompt shortcuts. */
+               case NANO_REFRESH_KEY:
+                   total_refresh();
+                   break;
+               case NANO_HOME_KEY:
+                   do_statusbar_home();
+                   break;
+               case NANO_END_KEY:
+                   do_statusbar_end();
+                   break;
+               case NANO_FORWARD_KEY:
+                   do_statusbar_right();
+                   break;
+               case NANO_BACK_KEY:
+                   do_statusbar_left();
+                   break;
+               case NANO_BACKSPACE_KEY:
+                   /* If we're using restricted mode, the filename
+                    * isn't blank, and we're at the "Write File"
+                    * prompt, disable Backspace. */
+                   if (!ISSET(RESTRICTED) || filename[0] == '\0' ||
+                       currshortcut != writefile_list)
+                       do_statusbar_backspace();
+                   break;
+               case NANO_DELETE_KEY:
+                   /* If we're using restricted mode, the filename
+                    * isn't blank, and we're at the "Write File"
+                    * prompt, disable Delete. */
+                   if (!ISSET(RESTRICTED) || filename[0] == '\0' ||
+                       currshortcut != writefile_list)
+                       do_statusbar_delete();
+                   break;
+               case NANO_CUT_KEY:
+                   /* If we're using restricted mode, the filename
+                    * isn't blank, and we're at the "Write File"
+                    * prompt, disable Cut. */
+                   if (!ISSET(RESTRICTED) || filename[0] == '\0' ||
+                       currshortcut != writefile_list)
+                       do_statusbar_cut_text();
+                   break;
+               /* Handle the normal statusbar prompt shortcuts, setting
+                * finished to TRUE to indicate that we're done after
+                * running or trying to run their associated
+                * functions. */
+               default:
+                   if (s->func != NULL) {
+                       if (ISSET(VIEW_MODE) && !s->viewok)
+                           print_view_warning();
+                       else
+                           s->func();
+                   }
+                   *finished = TRUE;
+           }
+       }
+    }
+
+    return input;
+}
+
+#ifndef DISABLE_MOUSE
+bool do_statusbar_mouse(void)
+{
+    /* FIXME: If we clicked on a location in the statusbar, the cursor
+     * should move to the location we clicked on.  This functionality
+     * should be in this function. */
+    int mouse_x, mouse_y;
+    return get_mouseinput(&mouse_x, &mouse_y, TRUE);
+}
+#endif
+
+void do_statusbar_home(void)
+{
+#ifndef NANO_SMALL
+    if (ISSET(SMART_HOME)) {
+       size_t statusbar_x_save = statusbar_x;
+       for (statusbar_x = 0; isblank(answer[statusbar_x]) &&
+               statusbar_x < statusbar_xend; statusbar_x++)
+           ;
+       if (statusbar_x == statusbar_x_save ||
+               statusbar_x == statusbar_xend)
+           statusbar_x = 0;
+    } else
+#endif
+       statusbar_x = 0;
+}
+
+void do_statusbar_end(void)
+{
+    statusbar_x = statusbar_xend;
+}
+
+void do_statusbar_right(void)
+{
+    if (statusbar_x < statusbar_xend)
+       statusbar_x = move_right(answer, statusbar_x);
+}
+
+void do_statusbar_left(void)
+{
+    if (statusbar_x > 0)
+       statusbar_x = move_left(answer, statusbar_x);
+}
+
+void do_statusbar_backspace(void)
+{
+    if (statusbar_x > 0) {
+       do_statusbar_left();
+       do_statusbar_delete();
+    }
+}
+
+void do_statusbar_delete(void)
+{
+    if (statusbar_x < statusbar_xend) {
+       int char_len = parse_char(answer + statusbar_x, NULL, NULL
+#ifdef NANO_WIDE
+               , NULL
+#endif
+               );
+
+       charmove(answer + statusbar_x, answer + statusbar_x + char_len,
+               statusbar_xend - statusbar_x - char_len + 1);
+       statusbar_xend -= char_len;
+    }
+}
+
+void do_statusbar_cut_text(void)
+{
+    null_at(&answer, 0);
+    statusbar_x = 0;
+    statusbar_xend = 0;
+}
+
+void do_statusbar_output(int *kbinput, size_t kbinput_len)
+{
+    size_t i;
+
+    char *key =
+#ifdef NANO_WIDE
+       !ISSET(NO_UTF8) ? charalloc(MB_CUR_MAX) :
+#endif
+       charalloc(1);
+
+    assert(answer != NULL);
+
+    for (i = 0; i < kbinput_len; i++) {
+       int key_len;
+
+       /* Null to newline, if needed. */
+       if (kbinput[i] == '\0')
+           kbinput[i] = '\n';
+       /* Newline to Enter, if needed. */
+       else if (kbinput[i] == '\n')
+           /* FIXME: We need to indicate when this happens, so that we
+            * can break out of the statusbar prompt properly. */
+           return;
+
+#ifdef NANO_WIDE
+       /* Change the wide character to its multibyte value.  If it's
+        * invalid, go on to the next character. */
+       if (!ISSET(NO_UTF8)) {
+           key_len = wctomb(key, (wchar_t)kbinput[i]);
+
+           if (key_len == -1)
+               continue;
+       /* Interpret the character as a single-byte sequence. */
+       } else {
+#endif
+           key_len = 1;
+           key[0] = (unsigned char)kbinput[i];
+#ifdef NANO_WIDE
+       }
+#endif
+
+       /* More dangerousness fun =) */
+       answer = charealloc(answer, statusbar_xend + key_len + 1);
+
+       assert(statusbar_x <= statusbar_xend);
+
+       charmove(&answer[statusbar_x + key_len], &answer[statusbar_x],
+               statusbar_xend - statusbar_x + key_len);
+       charcpy(&answer[statusbar_x], key, key_len);
+       statusbar_xend += key_len;
+
+       do_statusbar_right();
+    }
+
+    free(key);
+}
+
 /* Return the placewewant associated with current_x.  That is, xplustabs
  * is the zero-based column position of the cursor.  Value is no smaller
  * than current_x. */
@@ -2101,14 +2370,9 @@ int nanogetstr(bool allow_tabs, const char *buf, const char *def,
                )
 {
     int kbinput;
-    bool meta_key, func_key;
-    static size_t x = (size_t)-1;
-       /* the cursor position in 'answer' */
-    size_t xend;
-       /* length of 'answer', the status bar text */
+    bool meta_key, func_key, s_or_t, finished;
     bool tabbed = FALSE;
        /* used by input_tab() */
-    const shortcut *t;
 
 #ifndef NANO_SMALL
    /* for history */
@@ -2125,32 +2389,30 @@ int nanogetstr(bool allow_tabs, const char *buf, const char *def,
        answer or restored from answer to currentbuf. */
     int use_cb = 0;
 #endif
-    xend = strlen(def);
+    statusbar_xend = strlen(def);
 
-    /* Only put x at the end of the string if it's uninitialized, if it
-       would be past the end of the string as it is, or if
-       resetstatuspos is TRUE.  Otherwise, leave it alone.  This is so
-       the cursor position stays at the same place if a prompt-changing
-       toggle is pressed. */
-    if (x == (size_t)-1 || x > xend || resetstatuspos)
-       x = xend;
+    /* Only put statusbar_x at the end of the string if it's
+     * uninitialized, if it would be past the end of the string as it
+     * is, or if resetstatuspos is TRUE.  Otherwise, leave it alone.
+     * This is so the cursor position stays at the same place if a
+     * prompt-changing toggle is pressed. */
+    if (statusbar_x == (size_t)-1 || statusbar_x > statusbar_xend ||
+               resetstatuspos)
+       statusbar_x = statusbar_xend;
 
-    answer = charealloc(answer, xend + 1);
-    if (xend > 0)
+    answer = charealloc(answer, statusbar_xend + 1);
+    if (statusbar_xend > 0)
        strcpy(answer, def);
     else
        answer[0] = '\0';
 
-#if !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
     currshortcut = s;
-#endif
 
     /* Get the input! */
 
-    nanoget_repaint(buf, answer, x);
+    nanoget_repaint(buf, answer, statusbar_x);
 
-    /* Make sure any editor screen updates are displayed before getting
-       input */
+    /* Refresh the edit window before getting input. */
     wnoutrefresh(edit);
     wrefresh(bottomwin);
 
@@ -2159,105 +2421,22 @@ int nanogetstr(bool allow_tabs, const char *buf, const char *def,
      * to files not specified on the command line.  In this case,
      * disable all keys that would change the text if the filename isn't
      * blank and we're at the "Write File" prompt. */
-    while ((kbinput = get_kbinput(bottomwin, &meta_key, &func_key)) !=
-       NANO_CANCEL_KEY && kbinput != NANO_ENTER_KEY) {
-       for (t = s; t != NULL; t = t->next) {
-#ifdef DEBUG
-           fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput, kbinput);
-#endif
+    while ((kbinput = do_statusbar_input(&meta_key, &func_key,
+       &s_or_t, &finished, TRUE)) != NANO_CANCEL_KEY &&
+       kbinput != NANO_ENTER_KEY) {
 
-           /* Temporary hack to interpret NANO_HELP_FKEY correctly. */
-           if (kbinput == t->funcval)
-               kbinput = t->ctrlval;
-
-           if (kbinput == t->ctrlval && is_cntrl_char(kbinput)) {
-
-#ifndef DISABLE_HELP
-               /* Have to do this here, it would be too late to do it
-                  in statusq() */
-               if (kbinput == NANO_HELP_KEY) {
-                   do_help();
-                   break;
-               }
-#endif
-#ifndef NANO_SMALL
-               /* Have to handle these here too, for the time being */
-               if (kbinput == NANO_PREVLINE_KEY || kbinput == NANO_NEXTLINE_KEY)
-                   break;
-#endif
+       /* If we have a shortcut with an associated function, break out
+        * if we're finished after running the function. */
+       if (finished)
+           break;
 
-               return t->ctrlval;
-           }
-       }
-       assert(x <= xend && xend == strlen(answer));
+       assert(statusbar_x <= statusbar_xend &&
+               statusbar_xend == strlen(answer));
 
        if (kbinput != '\t')
            tabbed = FALSE;
 
        switch (kbinput) {
-#ifndef DISABLE_MOUSE
-       case KEY_MOUSE:
-           {
-               int mouse_x, mouse_y;
-               get_mouseinput(&mouse_x, &mouse_y, TRUE);
-           }
-           break;
-#endif
-       case NANO_REFRESH_KEY:
-           total_refresh();
-           break;
-       case NANO_HOME_KEY:
-#ifndef NANO_SMALL
-           if (ISSET(SMART_HOME)) {
-               size_t old_x = x;
-
-               for (x = 0; isblank(answer[x]) && x < xend; x++)
-                   ;
-
-               if (x == old_x || x == xend)
-                   x = 0;
-           } else
-#endif
-               x = 0;
-           break;
-       case NANO_END_KEY:
-           x = xend;
-           break;
-       case NANO_FORWARD_KEY:
-           if (x < xend)
-               x++;
-           break;
-       case NANO_DELETE_KEY:
-           /* If we're using restricted mode, the filename isn't blank,
-            * and we're at the "Write File" prompt, disable Delete. */
-           if (!ISSET(RESTRICTED) || filename[0] == '\0' || s != writefile_list) {
-               if (x < xend) {
-                   charmove(answer + x, answer + x + 1, xend - x);
-                   xend--;
-               }
-           }
-           break;
-       case NANO_CUT_KEY:
-           /* If we're using restricted mode, the filename isn't blank,
-            * and we're at the "Write File" prompt, disable Cut. */
-           if (!ISSET(RESTRICTED) || filename[0] == '\0' || s != writefile_list) {
-               null_at(&answer, 0);
-               xend = 0;
-               x = 0;
-           }
-           break;
-       case NANO_BACKSPACE_KEY:
-           /* If we're using restricted mode, the filename isn't blank,
-            * and we're at the "Write File" prompt, disable
-            * Backspace. */
-           if (!ISSET(RESTRICTED) || filename[0] == '\0' || s != writefile_list) {
-               if (x > 0) {
-                   charmove(answer + x - 1, answer + x, xend - x + 1);
-                   x--;
-                   xend--;
-               }
-           }
-           break;
        case NANO_TAB_KEY:
 #ifndef NANO_SMALL
            /* tab history completion */
@@ -2269,8 +2448,8 @@ int nanogetstr(bool allow_tabs, const char *buf, const char *def,
 
                if (history_list->len > 0) {
                    complete = get_history_completion(history_list, answer);
-                   xend = strlen(complete);
-                   x = xend;
+                   statusbar_x = strlen(complete);
+                   statusbar_xend = statusbar_x;
                    answer = mallocstrcpy(answer, complete);
                }
            }
@@ -2282,18 +2461,15 @@ int nanogetstr(bool allow_tabs, const char *buf, const char *def,
            if (allow_tabs) {
                int shift = 0;
 
-               answer = input_tab(answer, x, &tabbed, &shift, list);
-               xend = strlen(answer);
-               x += shift;
-               if (x > xend)
-                   x = xend;
+               answer = input_tab(answer, statusbar_x, &tabbed, &shift,
+                       list);
+               statusbar_xend = strlen(answer);
+               statusbar_x += shift;
+               if (statusbar_x > statusbar_xend)
+                   statusbar_x = statusbar_xend;
            }
 #endif
            break;
-       case NANO_BACK_KEY:
-           if (x > 0)
-               x--;
-           break;
        case NANO_PREVLINE_KEY:
 #ifndef NANO_SMALL
            if (history_list != NULL) {
@@ -2321,7 +2497,7 @@ int nanogetstr(bool allow_tabs, const char *buf, const char *def,
                    answer = mallocstrcpy(answer, currentbuf);
                    free(currentbuf);
                    currentbuf = NULL;
-                   xend = strlen(answer);
+                   statusbar_xend = strlen(answer);
                    use_cb = 0;
 
                /* else get older search from the history list and save
@@ -2329,12 +2505,12 @@ int nanogetstr(bool allow_tabs, const char *buf, const char *def,
                   answer */
                } else if ((history = get_history_older(history_list)) != NULL) {
                    answer = mallocstrcpy(answer, history);
-                   xend = strlen(history);
+                   statusbar_xend = strlen(history);
                } else {
                    answer = mallocstrcpy(answer, "");
-                   xend = 0;
+                   statusbar_xend = 0;
                }
-               x = xend;
+               statusbar_x = statusbar_xend;
            }
 #endif
            break;
@@ -2346,7 +2522,7 @@ int nanogetstr(bool allow_tabs, const char *buf, const char *def,
                   in answer */
                if ((history = get_history_newer(history_list)) != NULL) {
                    answer = mallocstrcpy(answer, history);
-                   xend = strlen(history);
+                   statusbar_xend = strlen(history);
 
                /* if there is no newer search, we're here */
                
@@ -2360,7 +2536,7 @@ int nanogetstr(bool allow_tabs, const char *buf, const char *def,
                    answer = mallocstrcpy(answer, currentbuf);
                    free(currentbuf);
                    currentbuf = NULL;
-                   xend = strlen(answer);
+                   statusbar_xend = strlen(answer);
                    use_cb = 1;
 
                /* otherwise, if currentbuf is NULL and use_cb isn't 2, 
@@ -2374,53 +2550,24 @@ int nanogetstr(bool allow_tabs, const char *buf, const char *def,
                        currentbuf = mallocstrcpy(currentbuf, answer);
                        answer = mallocstrcpy(answer, "");
                    }
-                   xend = 0;
+                   statusbar_xend = 0;
                    use_cb = 2;
                }
-               x = xend;
+               statusbar_x = statusbar_xend;
            }
 #endif
            break;
-           default:
-
-               for (t = s; t != NULL; t = t->next) {
-#ifdef DEBUG
-                   fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput,
-                           kbinput);
-#endif
-                   if (meta_key && (kbinput == t->metaval || kbinput == t->miscval))
-                       /* We hit a meta key.  Do like above.  We don't
-                        * just put back the letter and let it get
-                        * caught above cause that screws the
-                        * keypad... */
-                       return kbinput;
-               }
-
-           /* If we're using restricted mode, the filename isn't blank,
-            * and we're at the "Write File" prompt, act as though the
-            * unhandled character we got is a control character and
-            * throw it away. */
-           if (is_cntrl_char(kbinput) || (ISSET(RESTRICTED) && filename[0] != '\0' && s == writefile_list))
-               break;
-           answer = charealloc(answer, xend + 2);
-           charmove(answer + x + 1, answer + x, xend - x + 1);
-           xend++;
-           answer[x] = kbinput;
-           x++;
-
-#ifdef DEBUG
-           fprintf(stderr, "input \'%c\' (%d)\n", kbinput, kbinput);
-#endif
-       } /* switch (kbinput) */
+       }
 #ifndef NANO_SMALL
        last_kbinput = kbinput;
 #endif
-       nanoget_repaint(buf, answer, x);
+       nanoget_repaint(buf, answer, statusbar_x);
        wrefresh(bottomwin);
-    } /* while (kbinput ...) */
+    }
 
-    /* We finished putting in an answer; reset x */
-    x = (size_t)-1;
+    /* We finished putting in an answer, so reset statusbar_x. */
+    if (kbinput == NANO_CANCEL_KEY || kbinput == NANO_ENTER_KEY)
+       statusbar_x = (size_t)-1;
 
     return kbinput;
 }
@@ -2464,36 +2611,6 @@ int statusq(bool allow_tabs, const shortcut *s, const char *def,
     resetstatuspos = FALSE;
 
     switch (ret) {
-       case NANO_FIRSTLINE_KEY:
-       case NANO_FIRSTLINE_FKEY:
-           do_first_line();
-           resetstatuspos = TRUE;
-           break;
-       case NANO_LASTLINE_KEY:
-       case NANO_LASTLINE_FKEY:
-           do_last_line();
-           resetstatuspos = TRUE;
-           break;
-#ifndef DISABLE_JUSTIFY
-       case NANO_PARABEGIN_KEY:
-       case NANO_PARABEGIN_ALTKEY1:
-       case NANO_PARABEGIN_ALTKEY2:
-           do_para_begin();
-           resetstatuspos = TRUE;
-           break;
-       case NANO_PARAEND_KEY:
-       case NANO_PARAEND_ALTKEY1:
-       case NANO_PARAEND_ALTKEY2:
-           do_para_end();
-           resetstatuspos = TRUE;
-           break;
-       case NANO_FULLJUSTIFY_KEY:
-       case NANO_FULLJUSTIFY_ALTKEY:
-           if (!ISSET(VIEW_MODE))
-               do_full_justify();
-           resetstatuspos = TRUE;
-           break;
-#endif
        case NANO_CANCEL_KEY:
            ret = -1;
            resetstatuspos = TRUE;