]> git.wh0rd.org Git - nano.git/commitdiff
move functions specific to the statusbar prompt to their own source
authorDavid Lawrence Ramsey <pooka109@gmail.com>
Tue, 1 Nov 2005 17:37:44 +0000 (17:37 +0000)
committerDavid Lawrence Ramsey <pooka109@gmail.com>
Tue, 1 Nov 2005 17:37:44 +0000 (17:37 +0000)
file, prompt.c, and adjust related variables accordingly

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

ChangeLog
src/Makefile.am
src/prompt.c [new file with mode: 0644]
src/proto.h
src/winio.c

index 6f889dcba2b7bb4533825e670f856cd2c0ec77d6..afb744a19197356b0c511357a5bec3a00beded20 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -17,6 +17,17 @@ CVS code -
          get_page_start(). (DLR)
        - Move xplustabs(), actual_x(), strnlenpt(), and strlenpt() from
          winio.c to utils.c, as they're really utility functions. (DLR)
+       - Move functions specific to the statusbar prompt to their own
+         source file, and adjust related variables accordingly.  New
+         file prompt.c; changes to do_statusbar_input(),
+         do_statusbar_mouse(), do_statusbar_output(),
+         do_statusbar_home(), do_statusbar_end(), do_statusbar_right(),
+         do_statusbar_left(), do_statusbar_backspace(),
+         do_statusbar_delete(), do_statusbar_cut_text(),
+         do_statusbar_next_word(), do_statusbar_prev_word(),
+         do_statusbar_verbatim_input(), statusbar_xplustabs(),
+         get_statusbar_page_start(), nanoget_repaint(), nanogetstr(),
+         statusq(), and statusq_abort() (all moved to prompt.c). (DLR)
 - nano.h:
        - Readd MIN_EDITOR_COLS #define. (DLR)
 - winio.c:
@@ -28,6 +39,8 @@ CVS code -
 - doc/nanorc.sample:
        - Tweak the "c-file" regex for characters to properly accept
          '\"' and reject '"' and '''. (DLR)
+- src/Makefile.am:
+       - Add prompt.c to nano_SOURCES. (DLR)
 
 GNU nano 1.3.9 - 2005.10.23
 - General:
index f9621c26e2016ec637a5b5a611607c810b97892d..635771aa22fef1ab5117d4569b9977bd0fb27a80 100644 (file)
@@ -12,6 +12,7 @@ nano_SOURCES =        chars.c \
                move.c \
                nano.c \
                nano.h \
+               prompt.c \
                proto.h \
                rcfile.c \
                search.c \
diff --git a/src/prompt.c b/src/prompt.c
new file mode 100644 (file)
index 0000000..2c212b5
--- /dev/null
@@ -0,0 +1,877 @@
+/* $Id$ */
+/**************************************************************************
+ *   prompt.c                                                             *
+ *                                                                        *
+ *   Copyright (C) 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)  *
+ *   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.                                                     *
+ *                                                                        *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdarg.h>
+#include <string.h>
+#include "proto.h"
+
+static char *prompt = NULL;
+                               /* The prompt string for statusbar
+                                * questions. */
+static size_t statusbar_x = (size_t)-1;
+                               /* The cursor position in answer. */
+static bool resetstatuspos = FALSE;
+                               /* Should we reset the cursor position
+                                * at the statusbar prompt? */
+
+int do_statusbar_input(bool *meta_key, bool *func_key, bool *s_or_t,
+       bool *ran_func, 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;
+    *ran_func = 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 == TRUE && input == KEY_MOUSE) {
+       if (do_statusbar_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 ||
+#ifndef NANO_SMALL
+               input == NANO_NEXTWORD_KEY ||
+#endif
+               (*meta_key == TRUE && (
+#ifndef NANO_SMALL
+               input == NANO_PREVWORD_KEY ||
+#endif
+               input == NANO_VERBATIM_KEY)));
+
+    /* Set s_or_t to TRUE if we got a shortcut. */
+    *s_or_t = have_shortcut;
+
+    if (allow_funcs) {
+       /* If we got a character, and it isn't a shortcut or toggle,
+        * it's a normal text character.  Display the warning if we're
+        * in view mode, or add the character to the input buffer if
+        * we're not. */
+       if (input != ERR && *s_or_t == FALSE) {
+           /* 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) || openfile->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_key_buffer_len() == 0) {
+           if (kbinput != NULL) {
+
+               /* Display all the characters in the input buffer at
+                * once, filtering out control characters. */
+               char *output = charalloc(kbinput_len + 1);
+               size_t i;
+               bool got_enter;
+                       /* Whether we got the Enter key. */
+
+               for (i = 0; i < kbinput_len; i++)
+                   output[i] = (char)kbinput[i];
+               output[i] = '\0';
+
+               do_statusbar_output(output, kbinput_len, &got_enter,
+                       FALSE);
+
+               free(output);
+
+               /* 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) || openfile->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) || openfile->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) || openfile->filename[0] ==
+                       '\0' || currshortcut != writefile_list)
+                       do_statusbar_cut_text();
+                   break;
+#ifndef NANO_SMALL
+               case NANO_NEXTWORD_KEY:
+                   do_statusbar_next_word(FALSE);
+                   break;
+               case NANO_PREVWORD_KEY:
+                   if (*meta_key == TRUE)
+                       do_statusbar_prev_word(FALSE);
+                   break;
+#endif
+               case NANO_VERBATIM_KEY:
+                   if (*meta_key == TRUE) {
+                       /* If we're using restricted mode, the filename
+                        * isn't blank, and we're at the "Write File"
+                        * prompt, disable verbatim input. */
+                       if (!ISSET(RESTRICTED) ||
+                               openfile->filename[0] == '\0' ||
+                               currshortcut != writefile_list) {
+                           bool got_enter;
+                               /* Whether we got the Enter key. */
+
+                           do_statusbar_verbatim_input(&got_enter);
+
+                           /* If we got the Enter key, set input to the
+                            * key value for Enter, and set finished to
+                            * TRUE to indicate that we're done. */
+                           if (got_enter) {
+                               input = NANO_ENTER_KEY;
+                               *finished = TRUE;
+                           }
+                       }
+                       break;
+                   }
+               /* Handle the normal statusbar prompt shortcuts, setting
+                * ran_func to TRUE if we try to run their associated
+                * functions and setting finished to TRUE to indicate
+                * that we're done after trying to run their associated
+                * functions. */
+               default:
+                   if (s->func != NULL) {
+                       *ran_func = TRUE;
+                       if (!ISSET(VIEW_MODE) || s->viewok)
+                           s->func();
+                   }
+                   *finished = TRUE;
+           }
+       }
+    }
+
+    return input;
+}
+
+#ifndef DISABLE_MOUSE
+bool do_statusbar_mouse(void)
+{
+    int mouse_x, mouse_y;
+    bool retval = get_mouseinput(&mouse_x, &mouse_y, TRUE);
+
+    if (!retval) {
+       /* We can click in the statusbar window text to move the
+        * cursor. */
+       if (wenclose(bottomwin, mouse_y, mouse_x)) {
+           size_t start_col = strlenpt(prompt) + 1;
+
+           /* Subtract out the sizes of topwin and edit. */
+           mouse_y -= (2 - no_more_space()) + editwinrows;
+
+           /* Move to where the click occurred. */
+           if (mouse_x > start_col && mouse_y == 0) {
+               statusbar_x = actual_x(answer,
+                       get_statusbar_page_start(start_col, start_col +
+                       statusbar_xplustabs()) + mouse_x - start_col -
+                       1);
+               nanoget_repaint(answer, statusbar_x);
+           }
+       }
+    }
+
+    return retval;
+}
+#endif
+
+/* The user typed output_len multibyte characters.  Add them to the
+ * statusbar prompt, setting got_enter to TRUE if we get a newline, and
+ * filtering out all control characters if allow_cntrls is TRUE. */
+void do_statusbar_output(char *output, size_t output_len, bool
+       *got_enter, bool allow_cntrls)
+{
+    size_t answer_len, i = 0;
+    char *char_buf = charalloc(mb_cur_max());
+    int char_buf_len;
+
+    assert(answer != NULL);
+
+    answer_len = strlen(answer);
+    *got_enter = FALSE;
+
+    while (i < output_len) {
+       /* If allow_cntrls is FALSE, filter out nulls and newlines,
+        * since they're control characters. */
+       if (allow_cntrls) {
+           /* Null to newline, if needed. */
+           if (output[i] == '\0')
+               output[i] = '\n';
+           /* Newline to Enter, if needed. */
+           else if (output[i] == '\n') {
+               /* Set got_enter to TRUE to indicate that we got the
+                * Enter key, put back the rest of the characters in
+                * output so that they can be parsed and output again,
+                * and get out. */
+               *got_enter = TRUE;
+               unparse_kbinput(output + i, output_len - i);
+               return;
+           }
+       }
+
+       /* Interpret the next multibyte character. */
+       char_buf_len = parse_mbchar(output + i, char_buf, NULL);
+
+       i += char_buf_len;
+
+       /* If allow_cntrls is FALSE, filter out a control character. */
+       if (!allow_cntrls && is_cntrl_mbchar(output + i - char_buf_len))
+           continue;
+
+       /* More dangerousness fun =) */
+       answer = charealloc(answer, answer_len + (char_buf_len * 2));
+
+       assert(statusbar_x <= answer_len);
+
+       charmove(&answer[statusbar_x + char_buf_len],
+               &answer[statusbar_x], answer_len - statusbar_x +
+               char_buf_len);
+       strncpy(&answer[statusbar_x], char_buf, char_buf_len);
+       answer_len += char_buf_len;
+
+       statusbar_x += char_buf_len;
+    }
+
+    free(char_buf);
+}
+
+void do_statusbar_home(void)
+{
+#ifndef NANO_SMALL
+    if (ISSET(SMART_HOME)) {
+       size_t statusbar_x_save = statusbar_x;
+
+       statusbar_x = indent_length(answer);
+
+       if (statusbar_x == statusbar_x_save ||
+               statusbar_x == strlen(answer))
+           statusbar_x = 0;
+    } else
+#endif
+       statusbar_x = 0;
+}
+
+void do_statusbar_end(void)
+{
+    statusbar_x = strlen(answer);
+}
+
+void do_statusbar_right(void)
+{
+    if (statusbar_x < strlen(answer))
+       statusbar_x = move_mbright(answer, statusbar_x);
+}
+
+void do_statusbar_left(void)
+{
+    if (statusbar_x > 0)
+       statusbar_x = move_mbleft(answer, statusbar_x);
+}
+
+void do_statusbar_backspace(void)
+{
+    if (statusbar_x > 0) {
+       do_statusbar_left();
+       do_statusbar_delete();
+    }
+}
+
+void do_statusbar_delete(void)
+{
+    if (answer[statusbar_x] != '\0') {
+       int char_buf_len = parse_mbchar(answer + statusbar_x, NULL,
+               NULL);
+       size_t line_len = strlen(answer + statusbar_x);
+
+       assert(statusbar_x < strlen(answer));
+
+       charmove(answer + statusbar_x, answer + statusbar_x +
+               char_buf_len, strlen(answer) - statusbar_x -
+               char_buf_len + 1);
+
+       null_at(&answer, statusbar_x + line_len - char_buf_len);
+    }
+}
+
+/* Move text from the statusbar prompt into oblivion. */
+void do_statusbar_cut_text(void)
+{
+    assert(answer != NULL);
+
+#ifndef NANO_SMALL
+    if (ISSET(CUT_TO_END))
+       null_at(&answer, statusbar_x);
+    else {
+#endif
+       null_at(&answer, 0);
+       statusbar_x = 0;
+#ifndef NANO_SMALL
+    }
+#endif
+}
+
+#ifndef NANO_SMALL
+/* Move to the next word at the statusbar prompt.  If allow_punct is
+ * TRUE, treat punctuation as part of a word.  Return TRUE if we started
+ * on a word, and FALSE otherwise. */
+bool do_statusbar_next_word(bool allow_punct)
+{
+    char *char_mb;
+    int char_mb_len;
+    bool end_line = FALSE, started_on_word = FALSE;
+
+    assert(answer != NULL);
+
+    char_mb = charalloc(mb_cur_max());
+
+    /* Move forward until we find the character after the last letter of
+     * the current word. */
+    while (!end_line) {
+       char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL);
+
+       /* If we've found it, stop moving forward through the current
+        * line. */
+       if (!is_word_mbchar(char_mb, allow_punct))
+           break;
+
+       /* If we haven't found it, then we've started on a word, so set
+        * started_on_word to TRUE. */
+       started_on_word = TRUE;
+
+       if (answer[statusbar_x] == '\0')
+           end_line = TRUE;
+       else
+           statusbar_x += char_mb_len;
+    }
+
+    /* Move forward until we find the first letter of the next word. */
+    if (answer[statusbar_x] == '\0')
+       end_line = TRUE;
+    else
+       statusbar_x += char_mb_len;
+
+    while (!end_line) {
+       char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL);
+
+       /* If we've found it, stop moving forward through the current
+        * line. */
+       if (is_word_mbchar(char_mb, allow_punct))
+           break;
+
+       if (answer[statusbar_x] == '\0')
+           end_line = TRUE;
+       else
+           statusbar_x += char_mb_len;
+    }
+
+    free(char_mb);
+
+    /* Return whether we started on a word. */
+    return started_on_word;
+}
+
+/* Move to the previous word at the statusbar prompt.  If allow_punct is
+ * TRUE, treat punctuation as part of a word.  Return TRUE if we started
+ * on a word, and FALSE otherwise. */
+bool do_statusbar_prev_word(bool allow_punct)
+{
+    char *char_mb;
+    int char_mb_len;
+    bool begin_line = FALSE, started_on_word = FALSE;
+
+    assert(answer != NULL);
+
+    char_mb = charalloc(mb_cur_max());
+
+    /* Move backward until we find the character before the first letter
+     * of the current word. */
+    while (!begin_line) {
+       char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL);
+
+       /* If we've found it, stop moving backward through the current
+        * line. */
+       if (!is_word_mbchar(char_mb, allow_punct))
+           break;
+
+       /* If we haven't found it, then we've started on a word, so set
+        * started_on_word to TRUE. */
+       started_on_word = TRUE;
+
+       if (statusbar_x == 0)
+           begin_line = TRUE;
+       else
+           statusbar_x = move_mbleft(answer, statusbar_x);
+    }
+
+    /* Move backward until we find the last letter of the previous
+     * word. */
+    if (statusbar_x == 0)
+       begin_line = TRUE;
+    else
+       statusbar_x = move_mbleft(answer, statusbar_x);
+
+    while (!begin_line) {
+       char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL);
+
+       /* If we've found it, stop moving backward through the current
+        * line. */
+       if (is_word_mbchar(char_mb, allow_punct))
+           break;
+
+       if (statusbar_x == 0)
+           begin_line = TRUE;
+       else
+           statusbar_x = move_mbleft(answer, statusbar_x);
+    }
+
+    /* If we've found it, move backward until we find the character
+     * before the first letter of the previous word. */
+    if (!begin_line) {
+       if (statusbar_x == 0)
+           begin_line = TRUE;
+       else
+           statusbar_x = move_mbleft(answer, statusbar_x);
+
+       while (!begin_line) {
+           char_mb_len = parse_mbchar(answer + statusbar_x, char_mb,
+               NULL);
+
+           /* If we've found it, stop moving backward through the
+            * current line. */
+           if (!is_word_mbchar(char_mb, allow_punct))
+               break;
+
+           if (statusbar_x == 0)
+               begin_line = TRUE;
+           else
+               statusbar_x = move_mbleft(answer, statusbar_x);
+       }
+
+       /* If we've found it, move forward to the first letter of the
+        * previous word. */
+       if (!begin_line)
+           statusbar_x += char_mb_len;
+    }
+
+    free(char_mb);
+
+    /* Return whether we started on a word. */
+    return started_on_word;
+}
+#endif /* !NANO_SMALL */
+
+void do_statusbar_verbatim_input(bool *got_enter)
+{
+    int *kbinput;
+    size_t kbinput_len, i;
+    char *output;
+
+    *got_enter = FALSE;
+
+    /* Read in all the verbatim characters. */
+    kbinput = get_verbatim_kbinput(bottomwin, &kbinput_len);
+
+    /* Display all the verbatim characters at once, not filtering out
+     * control characters. */
+    output = charalloc(kbinput_len + 1);
+
+    for (i = 0; i < kbinput_len; i++)
+       output[i] = (char)kbinput[i];
+    output[i] = '\0';
+
+    do_statusbar_output(output, kbinput_len, got_enter, TRUE);
+
+    free(output);
+}
+
+/* Return the placewewant associated with statusbar_x, i.e, the
+ * zero-based column position of the cursor.  The value will be no
+ * smaller than statusbar_x. */
+size_t statusbar_xplustabs(void)
+{
+    return strnlenpt(answer, statusbar_x);
+}
+
+/* nano scrolls horizontally within a line in chunks.  This function
+ * returns the column number of the first character displayed in the
+ * statusbar prompt when the cursor is at the given column with the
+ * prompt ending at start_col.  Note that (0 <= column -
+ * get_statusbar_page_start(column) < COLS). */
+size_t get_statusbar_page_start(size_t start_col, size_t column)
+{
+    if (column == start_col || column < COLS - 1)
+       return 0;
+    else
+       return column - start_col - (column - start_col) % (COLS -
+               start_col - 1);
+}
+
+/* Repaint the statusbar when getting a character in nanogetstr().  Note
+ * that we must turn on A_REVERSE here, since do_help() turns it off! */
+void nanoget_repaint(const char *buf, size_t x)
+{
+    size_t start_col, xpt, page_start;
+    char *expanded;
+
+    assert(x <= strlen(buf));
+
+    start_col = strlenpt(prompt) + 1;
+    xpt = strnlenpt(buf, x);
+    page_start = get_statusbar_page_start(start_col, start_col + xpt);
+
+    wattron(bottomwin, A_REVERSE);
+
+    blank_statusbar();
+
+    mvwaddnstr(bottomwin, 0, 0, prompt, actual_x(prompt, COLS - 2));
+    waddch(bottomwin, ':');
+    waddch(bottomwin, (page_start == 0) ? ' ' : '$');
+
+    expanded = display_string(buf, page_start, COLS - start_col - 1,
+       FALSE);
+    waddstr(bottomwin, expanded);
+    free(expanded);
+
+    wmove(bottomwin, 0, start_col + xpt + 1 - page_start);
+
+    wattroff(bottomwin, A_REVERSE);
+}
+
+/* Get the input from the keyboard; this should only be called from
+ * statusq(). */
+int nanogetstr(bool allow_tabs, const char *curranswer,
+#ifndef NANO_SMALL
+       filestruct **history_list,
+#endif
+       const shortcut *s
+#ifndef DISABLE_TABCOMP
+       , bool *list
+#endif
+       )
+{
+    int kbinput;
+    bool meta_key, func_key, s_or_t, ran_func, finished;
+    size_t curranswer_len;
+#ifndef DISABLE_TABCOMP
+    bool tabbed = FALSE;
+       /* Whether we've pressed Tab. */
+#endif
+#ifndef NANO_SMALL
+    char *history = NULL;
+       /* The current history string. */
+    char *magichistory = NULL;
+       /* The temporary string typed at the bottom of the history, if
+        * any. */
+#ifndef DISABLE_TABCOMP
+    int last_kbinput = ERR;
+       /* The key we pressed before the current key. */
+    size_t complete_len = 0;
+       /* The length of the original string that we're trying to
+        * tab complete, if any. */
+#endif
+#endif /* !NANO_SMALL */
+
+    answer = mallocstrcpy(answer, curranswer);
+    curranswer_len = strlen(answer);
+
+    /* Only put statusbar_x at the end of the string if it's
+     * uninitialized, if it would be past the end of curranswer, 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 > curranswer_len ||
+               resetstatuspos)
+       statusbar_x = curranswer_len;
+
+    currshortcut = s;
+
+    nanoget_repaint(answer, statusbar_x);
+
+    /* Refresh the edit window and the statusbar before getting
+     * input. */
+    wnoutrefresh(edit);
+    wnoutrefresh(bottomwin);
+
+    /* If we're using restricted mode, we aren't allowed to change the
+     * name of a file once it has one because that would allow writing
+     * 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 = do_statusbar_input(&meta_key, &func_key,
+       &s_or_t, &ran_func, &finished, TRUE)) != NANO_CANCEL_KEY &&
+       kbinput != NANO_ENTER_KEY) {
+
+       assert(statusbar_x <= strlen(answer));
+
+#ifndef DISABLE_TABCOMP
+       if (kbinput != NANO_TAB_KEY)
+           tabbed = FALSE;
+#endif
+
+       switch (kbinput) {
+           case NANO_TAB_KEY:
+#ifndef DISABLE_TABCOMP
+#ifndef NANO_SMALL
+               if (history_list != NULL) {
+                   if (last_kbinput != NANO_TAB_KEY)
+                       complete_len = strlen(answer);
+
+                   if (complete_len > 0) {
+                       answer = mallocstrcpy(answer,
+                               get_history_completion(history_list,
+                               answer, complete_len));
+                       statusbar_x = strlen(answer);
+                   }
+               } else
+#endif /* !NANO_SMALL */
+               if (allow_tabs)
+                   answer = input_tab(answer, &statusbar_x, &tabbed,
+                       list);
+#endif /* !DISABLE_TABCOMP */
+               break;
+           case NANO_PREVLINE_KEY:
+#ifndef NANO_SMALL
+               if (history_list != NULL) {
+                   /* If we're scrolling up at the bottom of the
+                    * history list and answer isn't blank, save answer
+                    * in magichistory. */
+                   if ((*history_list)->next == NULL &&
+                       answer[0] != '\0')
+                       magichistory = mallocstrcpy(magichistory,
+                               answer);
+
+                   /* Get the older search from the history list and
+                    * save it in answer.  If there is no older search,
+                    * don't do anything. */
+                   if ((history =
+                       get_history_older(history_list)) != NULL) {
+                       answer = mallocstrcpy(answer, history);
+                       statusbar_x = strlen(answer);
+                   }
+
+                   /* This key has a shortcut list entry when it's used
+                    * to move to an older search, which means that
+                    * finished has been set to TRUE.  Set it back to
+                    * FALSE here, so that we aren't kicked out of the
+                    * statusbar prompt. */
+                   finished = FALSE;
+               }
+#endif /* !NANO_SMALL */
+               break;
+           case NANO_NEXTLINE_KEY:
+#ifndef NANO_SMALL
+               if (history_list != NULL) {
+                   /* Get the newer search from the history list and
+                    * save it in answer.  If there is no newer search,
+                    * don't do anything. */
+                   if ((history =
+                       get_history_newer(history_list)) != NULL) {
+                       answer = mallocstrcpy(answer, history);
+                       statusbar_x = strlen(answer);
+                   }
+
+                   /* If, after scrolling down, we're at the bottom of
+                    * the history list, answer is blank, and
+                    * magichistory is set, save magichistory in
+                    * answer. */
+                   if ((*history_list)->next == NULL &&
+                       answer[0] == '\0' && magichistory != NULL) {
+                       answer = mallocstrcpy(answer, magichistory);
+                       statusbar_x = strlen(answer);
+                   }
+               }
+#endif /* !NANO_SMALL */
+               break;
+       }
+
+       /* If we have a shortcut with an associated function, break out
+        * if we're finished after running or trying to run the
+        * function. */
+       if (finished)
+           break;
+
+#if !defined(NANO_SMALL) && !defined(DISABLE_TABCOMP)
+       last_kbinput = kbinput;
+#endif
+
+       nanoget_repaint(answer, statusbar_x);
+       wnoutrefresh(bottomwin);
+    }
+
+#ifndef NANO_SMALL
+    /* Set the current position in the history list to the bottom and
+     * free magichistory, if we need to. */
+    if (history_list != NULL) {
+       history_reset(*history_list);
+
+       if (magichistory != NULL)
+           free(magichistory);
+    }
+#endif
+
+    /* We finished putting in an answer or ran a normal shortcut's
+     * associated function, so reset statusbar_x. */
+    if (kbinput == NANO_CANCEL_KEY || kbinput == NANO_ENTER_KEY ||
+       ran_func)
+       statusbar_x = (size_t)-1;
+
+    return kbinput;
+}
+
+/* Ask a question on the statusbar.  Answer will be stored in answer
+ * global.  Returns -1 on aborted enter, -2 on a blank string, and 0
+ * otherwise, the valid shortcut key caught.  curranswer is any editable
+ * text that we want to put up by default.
+ *
+ * The allow_tabs parameter indicates whether we should allow tabs to be
+ * interpreted. */
+int statusq(bool allow_tabs, const shortcut *s, const char *curranswer,
+#ifndef NANO_SMALL
+       filestruct **history_list,
+#endif
+       const char *msg, ...)
+{
+    va_list ap;
+    int retval;
+#ifndef DISABLE_TABCOMP
+    bool list = FALSE;
+#endif
+
+    prompt = charealloc(prompt, ((COLS - 4) * mb_cur_max()) + 1);
+
+    bottombars(s);
+
+    va_start(ap, msg);
+    vsnprintf(prompt, (COLS - 4) * mb_cur_max(), msg, ap);
+    va_end(ap);
+    null_at(&prompt, actual_x(prompt, COLS - 4));
+
+    retval = nanogetstr(allow_tabs, curranswer,
+#ifndef NANO_SMALL
+               history_list,
+#endif
+               s
+#ifndef DISABLE_TABCOMP
+               , &list
+#endif
+               );
+
+    resetstatuspos = FALSE;
+
+    switch (retval) {
+       case NANO_CANCEL_KEY:
+           retval = -1;
+           resetstatuspos = TRUE;
+           break;
+       case NANO_ENTER_KEY:
+           retval = (answer[0] == '\0') ? -2 : 0;
+           resetstatuspos = TRUE;
+           break;
+    }
+
+    blank_statusbar();
+    wnoutrefresh(bottomwin);
+
+#ifdef DEBUG
+    fprintf(stderr, "answer = \"%s\"\n", answer);
+#endif
+
+#ifndef DISABLE_TABCOMP
+    /* If we've done tab completion, there might be a list of filename
+     * matches on the edit window at this point.  Make sure that they're
+     * cleared off. */
+    if (list)
+       edit_refresh();
+#endif
+
+    return retval;
+}
+
+void statusq_abort(void)
+{
+    resetstatuspos = TRUE;
+}
index 955f8f2522be01e83e8cc1d94136310443bd8ac4..3ca6f77abc3d3499933cedbfd4f6014d3bb48c57 100644 (file)
@@ -416,6 +416,45 @@ bool do_mouse(void);
 #endif
 void do_output(char *output, size_t output_len, bool allow_cntrls);
 
+/* Public functions in prompt.c. */
+int do_statusbar_input(bool *meta_key, bool *func_key, bool *s_or_t,
+       bool *ran_func, bool *finished, bool allow_funcs);
+#ifndef DISABLE_MOUSE
+bool do_statusbar_mouse(void);
+#endif
+void do_statusbar_output(char *output, size_t output_len, bool
+       *got_enter, bool allow_cntrls);
+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);
+#ifndef NANO_SMALL
+bool do_statusbar_next_word(bool allow_punct);
+bool do_statusbar_prev_word(bool allow_punct);
+#endif
+void do_statusbar_verbatim_input(bool *got_enter);
+size_t statusbar_xplustabs(void);
+size_t get_statusbar_page_start(size_t start_col, size_t column);
+void nanoget_repaint(const char *buf, size_t x);
+int nanogetstr(bool allow_tabs, const char *curranswer,
+#ifndef NANO_SMALL
+       filestruct **history_list,
+#endif
+       const shortcut *s
+#ifndef DISABLE_TABCOMP
+       , bool *list
+#endif
+       );
+int statusq(bool allow_tabs, const shortcut *s, const char *curranswer,
+#ifndef NANO_SMALL
+       filestruct **history_list,
+#endif
+       const char *msg, ...);
+void statusq_abort(void);
+
 /* Public functions in rcfile.c. */
 #ifdef ENABLE_NANORC
 void rcfile_error(const char *msg, ...);
@@ -617,27 +656,6 @@ 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 *ran_func, bool *finished, bool allow_funcs);
-#ifndef DISABLE_MOUSE
-bool do_statusbar_mouse(void);
-#endif
-void do_statusbar_output(char *output, size_t output_len, bool
-       *got_enter, bool allow_cntrls);
-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);
-#ifndef NANO_SMALL
-bool do_statusbar_next_word(bool allow_punct);
-bool do_statusbar_prev_word(bool allow_punct);
-#endif
-void do_statusbar_verbatim_input(bool *got_enter);
-size_t statusbar_xplustabs(void);
-size_t get_statusbar_page_start(size_t start_col, size_t column);
 void blank_line(WINDOW *win, int y, int x, int n);
 void blank_titlebar(void);
 void blank_topbar(void);
@@ -647,22 +665,6 @@ void blank_bottombars(void);
 void check_statusblank(void);
 char *display_string(const char *buf, size_t start_col, size_t len, bool
        dollars);
-void nanoget_repaint(const char *buf, size_t x);
-int nanogetstr(bool allow_tabs, const char *curranswer,
-#ifndef NANO_SMALL
-       filestruct **history_list,
-#endif
-       const shortcut *s
-#ifndef DISABLE_TABCOMP
-       , bool *list
-#endif
-       );
-int statusq(bool allow_tabs, const shortcut *s, const char *curranswer,
-#ifndef NANO_SMALL
-       filestruct **history_list,
-#endif
-       const char *msg, ...);
-void statusq_abort(void);
 void titlebar(const char *path);
 void set_modified(void);
 void statusbar(const char *msg, ...);
index bef79c4258d5cad2a78137e5482e6bb5c8fa6bd7..91abf7b62901ed29f7e19a23d152a8e9f7f96d07 100644 (file)
@@ -38,11 +38,6 @@ static int *key_buffer = NULL;
 static size_t key_buffer_len = 0;
                                /* The length of the default keystroke
                                 * buffer. */
-static char *prompt = NULL;
-                               /* The prompt string for statusbar
-                                * questions. */
-static size_t statusbar_x = (size_t)-1;
-                               /* The cursor position in answer. */
 static int statusblank = 0;
                                /* The number of keystrokes left after
                                 * we call statusbar(), before we
@@ -50,9 +45,6 @@ static int statusblank = 0;
 static bool disable_cursorpos = FALSE;
                                /* Should we temporarily disable
                                 * constant cursor position display? */
-static bool resetstatuspos = FALSE;
-                               /* Should we reset the cursor position
-                                * at the statusbar prompt? */
 
 /* Control character compatibility:
  *
@@ -1667,559 +1659,6 @@ 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 *ran_func, 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;
-    *ran_func = 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 == TRUE && input == KEY_MOUSE) {
-       if (do_statusbar_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 ||
-#ifndef NANO_SMALL
-               input == NANO_NEXTWORD_KEY ||
-#endif
-               (*meta_key == TRUE && (
-#ifndef NANO_SMALL
-               input == NANO_PREVWORD_KEY ||
-#endif
-               input == NANO_VERBATIM_KEY)));
-
-    /* Set s_or_t to TRUE if we got a shortcut. */
-    *s_or_t = have_shortcut;
-
-    if (allow_funcs) {
-       /* If we got a character, and it isn't a shortcut or toggle,
-        * it's a normal text character.  Display the warning if we're
-        * in view mode, or add the character to the input buffer if
-        * we're not. */
-       if (input != ERR && *s_or_t == FALSE) {
-           /* 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) || openfile->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_key_buffer_len() == 0) {
-           if (kbinput != NULL) {
-
-               /* Display all the characters in the input buffer at
-                * once, filtering out control characters. */
-               char *output = charalloc(kbinput_len + 1);
-               size_t i;
-               bool got_enter;
-                       /* Whether we got the Enter key. */
-
-               for (i = 0; i < kbinput_len; i++)
-                   output[i] = (char)kbinput[i];
-               output[i] = '\0';
-
-               do_statusbar_output(output, kbinput_len, &got_enter,
-                       FALSE);
-
-               free(output);
-
-               /* 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) || openfile->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) || openfile->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) || openfile->filename[0] ==
-                       '\0' || currshortcut != writefile_list)
-                       do_statusbar_cut_text();
-                   break;
-#ifndef NANO_SMALL
-               case NANO_NEXTWORD_KEY:
-                   do_statusbar_next_word(FALSE);
-                   break;
-               case NANO_PREVWORD_KEY:
-                   if (*meta_key == TRUE)
-                       do_statusbar_prev_word(FALSE);
-                   break;
-#endif
-               case NANO_VERBATIM_KEY:
-                   if (*meta_key == TRUE) {
-                       /* If we're using restricted mode, the filename
-                        * isn't blank, and we're at the "Write File"
-                        * prompt, disable verbatim input. */
-                       if (!ISSET(RESTRICTED) ||
-                               openfile->filename[0] == '\0' ||
-                               currshortcut != writefile_list) {
-                           bool got_enter;
-                               /* Whether we got the Enter key. */
-
-                           do_statusbar_verbatim_input(&got_enter);
-
-                           /* If we got the Enter key, set input to the
-                            * key value for Enter, and set finished to
-                            * TRUE to indicate that we're done. */
-                           if (got_enter) {
-                               input = NANO_ENTER_KEY;
-                               *finished = TRUE;
-                           }
-                       }
-                       break;
-                   }
-               /* Handle the normal statusbar prompt shortcuts, setting
-                * ran_func to TRUE if we try to run their associated
-                * functions and setting finished to TRUE to indicate
-                * that we're done after trying to run their associated
-                * functions. */
-               default:
-                   if (s->func != NULL) {
-                       *ran_func = TRUE;
-                       if (!ISSET(VIEW_MODE) || s->viewok)
-                           s->func();
-                   }
-                   *finished = TRUE;
-           }
-       }
-    }
-
-    return input;
-}
-
-#ifndef DISABLE_MOUSE
-bool do_statusbar_mouse(void)
-{
-    int mouse_x, mouse_y;
-    bool retval = get_mouseinput(&mouse_x, &mouse_y, TRUE);
-
-    if (!retval) {
-       /* We can click in the statusbar window text to move the
-        * cursor. */
-       if (wenclose(bottomwin, mouse_y, mouse_x)) {
-           size_t start_col = strlenpt(prompt) + 1;
-
-           /* Subtract out the sizes of topwin and edit. */
-           mouse_y -= (2 - no_more_space()) + editwinrows;
-
-           /* Move to where the click occurred. */
-           if (mouse_x > start_col && mouse_y == 0) {
-               statusbar_x = actual_x(answer,
-                       get_statusbar_page_start(start_col, start_col +
-                       statusbar_xplustabs()) + mouse_x - start_col -
-                       1);
-               nanoget_repaint(answer, statusbar_x);
-           }
-       }
-    }
-
-    return retval;
-}
-#endif
-
-/* The user typed output_len multibyte characters.  Add them to the
- * statusbar prompt, setting got_enter to TRUE if we get a newline, and
- * filtering out all control characters if allow_cntrls is TRUE. */
-void do_statusbar_output(char *output, size_t output_len, bool
-       *got_enter, bool allow_cntrls)
-{
-    size_t answer_len, i = 0;
-    char *char_buf = charalloc(mb_cur_max());
-    int char_buf_len;
-
-    assert(answer != NULL);
-
-    answer_len = strlen(answer);
-    *got_enter = FALSE;
-
-    while (i < output_len) {
-       /* If allow_cntrls is FALSE, filter out nulls and newlines,
-        * since they're control characters. */
-       if (allow_cntrls) {
-           /* Null to newline, if needed. */
-           if (output[i] == '\0')
-               output[i] = '\n';
-           /* Newline to Enter, if needed. */
-           else if (output[i] == '\n') {
-               /* Set got_enter to TRUE to indicate that we got the
-                * Enter key, put back the rest of the characters in
-                * output so that they can be parsed and output again,
-                * and get out. */
-               *got_enter = TRUE;
-               unparse_kbinput(output + i, output_len - i);
-               return;
-           }
-       }
-
-       /* Interpret the next multibyte character. */
-       char_buf_len = parse_mbchar(output + i, char_buf, NULL);
-
-       i += char_buf_len;
-
-       /* If allow_cntrls is FALSE, filter out a control character. */
-       if (!allow_cntrls && is_cntrl_mbchar(output + i - char_buf_len))
-           continue;
-
-       /* More dangerousness fun =) */
-       answer = charealloc(answer, answer_len + (char_buf_len * 2));
-
-       assert(statusbar_x <= answer_len);
-
-       charmove(&answer[statusbar_x + char_buf_len],
-               &answer[statusbar_x], answer_len - statusbar_x +
-               char_buf_len);
-       strncpy(&answer[statusbar_x], char_buf, char_buf_len);
-       answer_len += char_buf_len;
-
-       statusbar_x += char_buf_len;
-    }
-
-    free(char_buf);
-}
-
-void do_statusbar_home(void)
-{
-#ifndef NANO_SMALL
-    if (ISSET(SMART_HOME)) {
-       size_t statusbar_x_save = statusbar_x;
-
-       statusbar_x = indent_length(answer);
-
-       if (statusbar_x == statusbar_x_save ||
-               statusbar_x == strlen(answer))
-           statusbar_x = 0;
-    } else
-#endif
-       statusbar_x = 0;
-}
-
-void do_statusbar_end(void)
-{
-    statusbar_x = strlen(answer);
-}
-
-void do_statusbar_right(void)
-{
-    if (statusbar_x < strlen(answer))
-       statusbar_x = move_mbright(answer, statusbar_x);
-}
-
-void do_statusbar_left(void)
-{
-    if (statusbar_x > 0)
-       statusbar_x = move_mbleft(answer, statusbar_x);
-}
-
-void do_statusbar_backspace(void)
-{
-    if (statusbar_x > 0) {
-       do_statusbar_left();
-       do_statusbar_delete();
-    }
-}
-
-void do_statusbar_delete(void)
-{
-    if (answer[statusbar_x] != '\0') {
-       int char_buf_len = parse_mbchar(answer + statusbar_x, NULL,
-               NULL);
-       size_t line_len = strlen(answer + statusbar_x);
-
-       assert(statusbar_x < strlen(answer));
-
-       charmove(answer + statusbar_x, answer + statusbar_x +
-               char_buf_len, strlen(answer) - statusbar_x -
-               char_buf_len + 1);
-
-       null_at(&answer, statusbar_x + line_len - char_buf_len);
-    }
-}
-
-/* Move text from the statusbar prompt into oblivion. */
-void do_statusbar_cut_text(void)
-{
-    assert(answer != NULL);
-
-#ifndef NANO_SMALL
-    if (ISSET(CUT_TO_END))
-       null_at(&answer, statusbar_x);
-    else {
-#endif
-       null_at(&answer, 0);
-       statusbar_x = 0;
-#ifndef NANO_SMALL
-    }
-#endif
-}
-
-#ifndef NANO_SMALL
-/* Move to the next word at the statusbar prompt.  If allow_punct is
- * TRUE, treat punctuation as part of a word.  Return TRUE if we started
- * on a word, and FALSE otherwise. */
-bool do_statusbar_next_word(bool allow_punct)
-{
-    char *char_mb;
-    int char_mb_len;
-    bool end_line = FALSE, started_on_word = FALSE;
-
-    assert(answer != NULL);
-
-    char_mb = charalloc(mb_cur_max());
-
-    /* Move forward until we find the character after the last letter of
-     * the current word. */
-    while (!end_line) {
-       char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL);
-
-       /* If we've found it, stop moving forward through the current
-        * line. */
-       if (!is_word_mbchar(char_mb, allow_punct))
-           break;
-
-       /* If we haven't found it, then we've started on a word, so set
-        * started_on_word to TRUE. */
-       started_on_word = TRUE;
-
-       if (answer[statusbar_x] == '\0')
-           end_line = TRUE;
-       else
-           statusbar_x += char_mb_len;
-    }
-
-    /* Move forward until we find the first letter of the next word. */
-    if (answer[statusbar_x] == '\0')
-       end_line = TRUE;
-    else
-       statusbar_x += char_mb_len;
-
-    while (!end_line) {
-       char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL);
-
-       /* If we've found it, stop moving forward through the current
-        * line. */
-       if (is_word_mbchar(char_mb, allow_punct))
-           break;
-
-       if (answer[statusbar_x] == '\0')
-           end_line = TRUE;
-       else
-           statusbar_x += char_mb_len;
-    }
-
-    free(char_mb);
-
-    /* Return whether we started on a word. */
-    return started_on_word;
-}
-
-/* Move to the previous word at the statusbar prompt.  If allow_punct is
- * TRUE, treat punctuation as part of a word.  Return TRUE if we started
- * on a word, and FALSE otherwise. */
-bool do_statusbar_prev_word(bool allow_punct)
-{
-    char *char_mb;
-    int char_mb_len;
-    bool begin_line = FALSE, started_on_word = FALSE;
-
-    assert(answer != NULL);
-
-    char_mb = charalloc(mb_cur_max());
-
-    /* Move backward until we find the character before the first letter
-     * of the current word. */
-    while (!begin_line) {
-       char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL);
-
-       /* If we've found it, stop moving backward through the current
-        * line. */
-       if (!is_word_mbchar(char_mb, allow_punct))
-           break;
-
-       /* If we haven't found it, then we've started on a word, so set
-        * started_on_word to TRUE. */
-       started_on_word = TRUE;
-
-       if (statusbar_x == 0)
-           begin_line = TRUE;
-       else
-           statusbar_x = move_mbleft(answer, statusbar_x);
-    }
-
-    /* Move backward until we find the last letter of the previous
-     * word. */
-    if (statusbar_x == 0)
-       begin_line = TRUE;
-    else
-       statusbar_x = move_mbleft(answer, statusbar_x);
-
-    while (!begin_line) {
-       char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL);
-
-       /* If we've found it, stop moving backward through the current
-        * line. */
-       if (is_word_mbchar(char_mb, allow_punct))
-           break;
-
-       if (statusbar_x == 0)
-           begin_line = TRUE;
-       else
-           statusbar_x = move_mbleft(answer, statusbar_x);
-    }
-
-    /* If we've found it, move backward until we find the character
-     * before the first letter of the previous word. */
-    if (!begin_line) {
-       if (statusbar_x == 0)
-           begin_line = TRUE;
-       else
-           statusbar_x = move_mbleft(answer, statusbar_x);
-
-       while (!begin_line) {
-           char_mb_len = parse_mbchar(answer + statusbar_x, char_mb,
-               NULL);
-
-           /* If we've found it, stop moving backward through the
-            * current line. */
-           if (!is_word_mbchar(char_mb, allow_punct))
-               break;
-
-           if (statusbar_x == 0)
-               begin_line = TRUE;
-           else
-               statusbar_x = move_mbleft(answer, statusbar_x);
-       }
-
-       /* If we've found it, move forward to the first letter of the
-        * previous word. */
-       if (!begin_line)
-           statusbar_x += char_mb_len;
-    }
-
-    free(char_mb);
-
-    /* Return whether we started on a word. */
-    return started_on_word;
-}
-#endif /* !NANO_SMALL */
-
-void do_statusbar_verbatim_input(bool *got_enter)
-{
-    int *kbinput;
-    size_t kbinput_len, i;
-    char *output;
-
-    *got_enter = FALSE;
-
-    /* Read in all the verbatim characters. */
-    kbinput = get_verbatim_kbinput(bottomwin, &kbinput_len);
-
-    /* Display all the verbatim characters at once, not filtering out
-     * control characters. */
-    output = charalloc(kbinput_len + 1);
-
-    for (i = 0; i < kbinput_len; i++)
-       output[i] = (char)kbinput[i];
-    output[i] = '\0';
-
-    do_statusbar_output(output, kbinput_len, got_enter, TRUE);
-
-    free(output);
-}
-
-/* Return the placewewant associated with statusbar_x, i.e, the
- * zero-based column position of the cursor.  The value will be no
- * smaller than statusbar_x. */
-size_t statusbar_xplustabs(void)
-{
-    return strnlenpt(answer, statusbar_x);
-}
-
-/* nano scrolls horizontally within a line in chunks.  This function
- * returns the column number of the first character displayed in the
- * statusbar prompt when the cursor is at the given column with the
- * prompt ending at start_col.  Note that (0 <= column -
- * get_statusbar_page_start(column) < COLS). */
-size_t get_statusbar_page_start(size_t start_col, size_t column)
-{
-    if (column == start_col || column < COLS - 1)
-       return 0;
-    else
-       return column - start_col - (column - start_col) % (COLS -
-               start_col - 1);
-}
-
 /* Move to (x, y) in win, and display a line of n spaces with the
  * current attributes. */
 void blank_line(WINDOW *win, int y, int x, int n)
@@ -2434,292 +1873,6 @@ char *display_string(const char *buf, size_t start_col, size_t len, bool
     return converted;
 }
 
-/* Repaint the statusbar when getting a character in nanogetstr().  Note
- * that we must turn on A_REVERSE here, since do_help() turns it off! */
-void nanoget_repaint(const char *buf, size_t x)
-{
-    size_t start_col, xpt, page_start;
-    char *expanded;
-
-    assert(x <= strlen(buf));
-
-    start_col = strlenpt(prompt) + 1;
-    xpt = strnlenpt(buf, x);
-    page_start = get_statusbar_page_start(start_col, start_col + xpt);
-
-    wattron(bottomwin, A_REVERSE);
-
-    blank_statusbar();
-
-    mvwaddnstr(bottomwin, 0, 0, prompt, actual_x(prompt, COLS - 2));
-    waddch(bottomwin, ':');
-    waddch(bottomwin, (page_start == 0) ? ' ' : '$');
-
-    expanded = display_string(buf, page_start, COLS - start_col - 1,
-       FALSE);
-    waddstr(bottomwin, expanded);
-    free(expanded);
-
-    wmove(bottomwin, 0, start_col + xpt + 1 - page_start);
-
-    wattroff(bottomwin, A_REVERSE);
-}
-
-/* Get the input from the keyboard; this should only be called from
- * statusq(). */
-int nanogetstr(bool allow_tabs, const char *curranswer,
-#ifndef NANO_SMALL
-       filestruct **history_list,
-#endif
-       const shortcut *s
-#ifndef DISABLE_TABCOMP
-       , bool *list
-#endif
-       )
-{
-    int kbinput;
-    bool meta_key, func_key, s_or_t, ran_func, finished;
-    size_t curranswer_len;
-#ifndef DISABLE_TABCOMP
-    bool tabbed = FALSE;
-       /* Whether we've pressed Tab. */
-#endif
-#ifndef NANO_SMALL
-    char *history = NULL;
-       /* The current history string. */
-    char *magichistory = NULL;
-       /* The temporary string typed at the bottom of the history, if
-        * any. */
-#ifndef DISABLE_TABCOMP
-    int last_kbinput = ERR;
-       /* The key we pressed before the current key. */
-    size_t complete_len = 0;
-       /* The length of the original string that we're trying to
-        * tab complete, if any. */
-#endif
-#endif /* !NANO_SMALL */
-
-    answer = mallocstrcpy(answer, curranswer);
-    curranswer_len = strlen(answer);
-
-    /* Only put statusbar_x at the end of the string if it's
-     * uninitialized, if it would be past the end of curranswer, 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 > curranswer_len ||
-               resetstatuspos)
-       statusbar_x = curranswer_len;
-
-    currshortcut = s;
-
-    nanoget_repaint(answer, statusbar_x);
-
-    /* Refresh the edit window and the statusbar before getting
-     * input. */
-    wnoutrefresh(edit);
-    wnoutrefresh(bottomwin);
-
-    /* If we're using restricted mode, we aren't allowed to change the
-     * name of a file once it has one because that would allow writing
-     * 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 = do_statusbar_input(&meta_key, &func_key,
-       &s_or_t, &ran_func, &finished, TRUE)) != NANO_CANCEL_KEY &&
-       kbinput != NANO_ENTER_KEY) {
-
-       assert(statusbar_x <= strlen(answer));
-
-#ifndef DISABLE_TABCOMP
-       if (kbinput != NANO_TAB_KEY)
-           tabbed = FALSE;
-#endif
-
-       switch (kbinput) {
-           case NANO_TAB_KEY:
-#ifndef DISABLE_TABCOMP
-#ifndef NANO_SMALL
-               if (history_list != NULL) {
-                   if (last_kbinput != NANO_TAB_KEY)
-                       complete_len = strlen(answer);
-
-                   if (complete_len > 0) {
-                       answer = mallocstrcpy(answer,
-                               get_history_completion(history_list,
-                               answer, complete_len));
-                       statusbar_x = strlen(answer);
-                   }
-               } else
-#endif /* !NANO_SMALL */
-               if (allow_tabs)
-                   answer = input_tab(answer, &statusbar_x, &tabbed,
-                       list);
-#endif /* !DISABLE_TABCOMP */
-               break;
-           case NANO_PREVLINE_KEY:
-#ifndef NANO_SMALL
-               if (history_list != NULL) {
-                   /* If we're scrolling up at the bottom of the
-                    * history list and answer isn't blank, save answer
-                    * in magichistory. */
-                   if ((*history_list)->next == NULL &&
-                       answer[0] != '\0')
-                       magichistory = mallocstrcpy(magichistory,
-                               answer);
-
-                   /* Get the older search from the history list and
-                    * save it in answer.  If there is no older search,
-                    * don't do anything. */
-                   if ((history =
-                       get_history_older(history_list)) != NULL) {
-                       answer = mallocstrcpy(answer, history);
-                       statusbar_x = strlen(answer);
-                   }
-
-                   /* This key has a shortcut list entry when it's used
-                    * to move to an older search, which means that
-                    * finished has been set to TRUE.  Set it back to
-                    * FALSE here, so that we aren't kicked out of the
-                    * statusbar prompt. */
-                   finished = FALSE;
-               }
-#endif /* !NANO_SMALL */
-               break;
-           case NANO_NEXTLINE_KEY:
-#ifndef NANO_SMALL
-               if (history_list != NULL) {
-                   /* Get the newer search from the history list and
-                    * save it in answer.  If there is no newer search,
-                    * don't do anything. */
-                   if ((history =
-                       get_history_newer(history_list)) != NULL) {
-                       answer = mallocstrcpy(answer, history);
-                       statusbar_x = strlen(answer);
-                   }
-
-                   /* If, after scrolling down, we're at the bottom of
-                    * the history list, answer is blank, and
-                    * magichistory is set, save magichistory in
-                    * answer. */
-                   if ((*history_list)->next == NULL &&
-                       answer[0] == '\0' && magichistory != NULL) {
-                       answer = mallocstrcpy(answer, magichistory);
-                       statusbar_x = strlen(answer);
-                   }
-               }
-#endif /* !NANO_SMALL */
-               break;
-       }
-
-       /* If we have a shortcut with an associated function, break out
-        * if we're finished after running or trying to run the
-        * function. */
-       if (finished)
-           break;
-
-#if !defined(NANO_SMALL) && !defined(DISABLE_TABCOMP)
-       last_kbinput = kbinput;
-#endif
-
-       nanoget_repaint(answer, statusbar_x);
-       wnoutrefresh(bottomwin);
-    }
-
-#ifndef NANO_SMALL
-    /* Set the current position in the history list to the bottom and
-     * free magichistory, if we need to. */
-    if (history_list != NULL) {
-       history_reset(*history_list);
-
-       if (magichistory != NULL)
-           free(magichistory);
-    }
-#endif
-
-    /* We finished putting in an answer or ran a normal shortcut's
-     * associated function, so reset statusbar_x. */
-    if (kbinput == NANO_CANCEL_KEY || kbinput == NANO_ENTER_KEY ||
-       ran_func)
-       statusbar_x = (size_t)-1;
-
-    return kbinput;
-}
-
-/* Ask a question on the statusbar.  Answer will be stored in answer
- * global.  Returns -1 on aborted enter, -2 on a blank string, and 0
- * otherwise, the valid shortcut key caught.  curranswer is any editable
- * text that we want to put up by default.
- *
- * The allow_tabs parameter indicates whether we should allow tabs to be
- * interpreted. */
-int statusq(bool allow_tabs, const shortcut *s, const char *curranswer,
-#ifndef NANO_SMALL
-       filestruct **history_list,
-#endif
-       const char *msg, ...)
-{
-    va_list ap;
-    int retval;
-#ifndef DISABLE_TABCOMP
-    bool list = FALSE;
-#endif
-
-    prompt = charealloc(prompt, ((COLS - 4) * mb_cur_max()) + 1);
-
-    bottombars(s);
-
-    va_start(ap, msg);
-    vsnprintf(prompt, (COLS - 4) * mb_cur_max(), msg, ap);
-    va_end(ap);
-    null_at(&prompt, actual_x(prompt, COLS - 4));
-
-    retval = nanogetstr(allow_tabs, curranswer,
-#ifndef NANO_SMALL
-               history_list,
-#endif
-               s
-#ifndef DISABLE_TABCOMP
-               , &list
-#endif
-               );
-
-    resetstatuspos = FALSE;
-
-    switch (retval) {
-       case NANO_CANCEL_KEY:
-           retval = -1;
-           resetstatuspos = TRUE;
-           break;
-       case NANO_ENTER_KEY:
-           retval = (answer[0] == '\0') ? -2 : 0;
-           resetstatuspos = TRUE;
-           break;
-    }
-
-    blank_statusbar();
-    wnoutrefresh(bottomwin);
-
-#ifdef DEBUG
-    fprintf(stderr, "answer = \"%s\"\n", answer);
-#endif
-
-#ifndef DISABLE_TABCOMP
-    /* If we've done tab completion, there might be a list of filename
-     * matches on the edit window at this point.  Make sure that they're
-     * cleared off. */
-    if (list)
-       edit_refresh();
-#endif
-
-    return retval;
-}
-
-void statusq_abort(void)
-{
-    resetstatuspos = TRUE;
-}
-
 void titlebar(const char *path)
 {
     int space = COLS;