]> git.wh0rd.org Git - nano.git/commitdiff
Ken's search history patch, minus the .nano_history stuff
authorChris Allegretta <chrisa@asty.org>
Sun, 5 Jan 2003 20:41:21 +0000 (20:41 +0000)
committerChris Allegretta <chrisa@asty.org>
Sun, 5 Jan 2003 20:41:21 +0000 (20:41 +0000)
git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@1334 35c25a1d-7b9e-4130-9fde-d3aeb78583b8

ChangeLog
files.c
global.c
nano.c
nano.h
proto.h
rcfile.c
search.c
winio.c

index 0491575537f0c1a78b4a7eb4c118f7d1e584934e..fcd1a85576900759208fe089b3b64b781c432f1a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 CVS code -
+Changes
 - General:
+       - Search history and replace history up/down cursor arrows, w/history 
+         tab completion, not available w/NANO_SMALL.  Changes to 
+         statusq, others (Ken Tyler).  Added shortcut to search/replace 
+         shortcuts so people will know it's there, forced KEY_UP and KEY_DOWN
+         defs in nano.h (Chris, in case blame needs to be placed later).
        - Translation updates (see po/ChangeLog for details).
        - Forward-ported Chris' --disable-wrapping-as-root option from
          1.0.9.  Per Jordi's suggestions, have it override
@@ -62,6 +68,8 @@ CVS code -
        - If there's a page or less of text, do an edit_update() if the
          mark is on; otherwise, the highlight won't be displayed. (DLR)
 - nano.c:
+       - Added free_history list calls clean up, added init of list headers
+          modified statusq calls (Ken Tyler).
   do_prev_word()
        - Make the assert match that in do_next_word(). (DLR)
   do_enter()
diff --git a/files.c b/files.c
index 719bd960e15d18921da8f2674379279d3397a3be..e37935db5903184264bd8dcf332900796a4dc711 100644 (file)
--- a/files.c
+++ b/files.c
@@ -426,21 +426,21 @@ int do_insertfile(int loading_file)
     if (operating_dir != NULL && strcmp(operating_dir, ".") != 0)
 #ifdef ENABLE_MULTIBUFFER 
        if (ISSET(MULTIBUFFER))
-           i = statusq(1, insertfile_list, inspath, _("File to insert into new buffer [from %s] "),
+           i = statusq(1, insertfile_list, inspath, 0, _("File to insert into new buffer [from %s] "),
                operating_dir);
        else
 #endif
-           i = statusq(1, insertfile_list, inspath, _("File to insert [from %s] "),
+           i = statusq(1, insertfile_list, inspath, 0, _("File to insert [from %s] "),
                operating_dir);
 
     else
 #endif
 #ifdef ENABLE_MULTIBUFFER 
        if (ISSET(MULTIBUFFER))
-           i = statusq(1, insertfile_list, inspath, _("File to insert into new buffer [from ./] "));
+           i = statusq(1, insertfile_list, inspath, 0, _("File to insert into new buffer [from ./] "));
        else
 #endif
-           i = statusq(1, insertfile_list, inspath, _("File to insert [from ./] "));
+           i = statusq(1, insertfile_list, inspath, 0, _("File to insert [from ./] "));
 
     if (i != -1) {
        inspath = mallocstrcpy(inspath, answer);
@@ -492,7 +492,7 @@ int do_insertfile(int loading_file)
 #endif /* ENABLE_MULTIBUFFER */
        if (i == NANO_EXTCMD_KEY) {
            int ts;
-           ts = statusq(1, extcmd_list, "", _("Command to execute "));
+           ts = statusq(1, extcmd_list, "", 0, _("Command to execute "));
            if (ts == -1  || answer == NULL || answer[0] == '\0') {
                statusbar(_("Cancelled"));
                UNSET(KEEP_CUTBUFFER);
@@ -1711,34 +1711,34 @@ int do_writeout(const char *path, int exiting, int append)
        /* Be nice to the translation folks */
        if (ISSET(MARK_ISSET) && !exiting) {
            if (append == 2)
-               i = statusq(1, writefile_list, "",
+               i = statusq(1, writefile_list, "", 0,
                    "%s%s%s", _("Prepend Selection to File"), formatstr, backupstr);
-           else if (append == 1)
-               i = statusq(1, writefile_list, "",
+           else if (append)
+               i = statusq(1, writefile_list, "", 0,
                    "%s%s%s", _("Append Selection to File"), formatstr, backupstr);
            else
-               i = statusq(1, writefile_list, "",
+               i = statusq(1, writefile_list, "", 0,
                    "%s%s%s", _("Write Selection to File"), formatstr, backupstr);
        } else {
            if (append == 2)
-               i = statusq(1, writefile_list, answer,
+               i = statusq(1, writefile_list, answer, 0,
                    "%s%s%s", _("File Name to Prepend to"), formatstr, backupstr);
-           else if (append == 1)
-               i = statusq(1, writefile_list, answer,
+           else if (append)
+               i = statusq(1, writefile_list, answer, 0,
                    "%s%s%s", _("File Name to Append to"), formatstr, backupstr);
            else
-               i = statusq(1, writefile_list, answer,
+               i = statusq(1, writefile_list, answer, 0,
                    "%s%s%s", _("File Name to Write"), formatstr, backupstr);
        }
 #else
        if (append == 2)
-           i = statusq(1, writefile_list, answer,
+           i = statusq(1, writefile_list, answer, 0,
                "%s", _("File Name to Prepend to"));
-       else if (append == 1)
-           i = statusq(1, writefile_list, answer,
+       else if (append)
+           i = statusq(1, writefile_list, answer, 0,
                "%s", _("File Name to Append to"));
        else
-           i = statusq(1, writefile_list, answer,
+           i = statusq(1, writefile_list, answer, 0,
                "%s", _("File Name to Write"));
 #endif /* !NANO_SMALL */
 
@@ -2650,7 +2650,7 @@ char *do_browser(const char *inpath)
        case NANO_GOTO_KEY:
 
            curs_set(1);
-           j = statusq(0, gotodir_list, "", _("Goto Directory"));
+           j = statusq(0, gotodir_list, "", 0, _("Goto Directory"));
            bottombars(browser_list);
            curs_set(0);
 
index 5ffaa9f60533f82365264e5c909c5c9d436d43a8..b9a09bd3fc7988363f5e13242b4e46fa6ecc26f4 100644 (file)
--- a/global.c
+++ b/global.c
@@ -36,6 +36,7 @@ int wrap_at = -CHARS_FROM_EOL;/* Right justified fill value, allows resize */
 char *last_search = NULL;      /* Last string we searched for */
 char *last_replace = NULL;     /* Last replacement string */
 int search_last_line;          /* Is this the last search line? */
+int past_editbuff;             /* search lines not displayed */
 
 int flags = 0;                 /* Our new flag containing many options */
 WINDOW *edit;                  /* The file portion of the editor */
@@ -134,6 +135,11 @@ const shortcut *currshortcut;      /* Current shortcut list we're using */
 toggle *toggles = NULL;
 #endif
 
+#ifndef NANO_SMALL
+historyheadtype search_history;
+historyheadtype replace_history;
+#endif
+
 /* Regular expressions */
 
 #ifdef HAVE_REGEX_H
@@ -327,7 +333,7 @@ void shortcut_init(int unjustify)
        "", *nano_gotodir_msg = "", *nano_case_msg =
        "", *nano_reverse_msg = "", *nano_execute_msg =
        "", *nano_dos_msg = "", *nano_mac_msg =
-       "", *nano_backup_msg = "";
+       "", *nano_backup_msg = "", *nano_editstr_msg = "";
 
 #ifdef ENABLE_MULTIBUFFER
     const char *nano_openprev_msg = "", *nano_opennext_msg =
@@ -383,6 +389,7 @@ void shortcut_init(int unjustify)
     nano_dos_msg = _("Write file out in DOS format");
     nano_mac_msg = _("Write file out in Mac format");
     nano_backup_msg = _("Back up original file when saving");
+    nano_editstr_msg = _("Edit the previous search/replace strings");
 #ifdef HAVE_REGEX_H
     nano_regexp_msg = _("Use regular expressions");
     nano_bracket_msg = _("Find other bracket");
@@ -606,6 +613,14 @@ void shortcut_init(int unjustify)
     sc_init_one(&whereis_list, TOGGLE_REGEXP_KEY, _("Regexp"),
                IFHELP(nano_regexp_msg, 0), 0, 0, VIEW, 0);
 #endif
+
+#ifndef NANO_SMALL
+    sc_init_one(&whereis_list, KEY_UP, _("History"),
+               IFHELP(nano_editstr_msg, 0), 0, 0, VIEW, 0);
+#endif
+
+
+
 #endif /* !NANO_SMALL */
 
     free_shortcutage(&replace_list);
@@ -639,6 +654,12 @@ void shortcut_init(int unjustify)
     sc_init_one(&replace_list, TOGGLE_REGEXP_KEY, _("Regexp"),
                IFHELP(nano_regexp_msg, 0), 0, 0, VIEW, 0);
 #endif
+
+#ifndef NANO_SMALL
+    sc_init_one(&replace_list, KEY_UP, _("History"),
+               IFHELP(nano_editstr_msg, 0), 0, 0, VIEW, 0);
+#endif
+
 #endif /* !NANO_SMALL */
 
     free_shortcutage(&replace_list_2);
@@ -655,6 +676,11 @@ void shortcut_init(int unjustify)
     sc_init_one(&replace_list_2, NANO_LASTLINE_KEY, _("Last Line"),
                IFHELP(nano_lastline_msg, 0), 0, 0, VIEW, do_last_line);
 
+#ifndef NANO_SMALL
+    sc_init_one(&replace_list_2, KEY_UP, _("History"),
+               IFHELP(nano_editstr_msg, 0), 0, 0, VIEW, 0);
+#endif
+
     free_shortcutage(&goto_list);
 
     sc_init_one(&goto_list, NANO_HELP_KEY, _("Get Help"),
@@ -885,5 +911,10 @@ void thanks_for_all_the_fish(void)
        free(bill);
     }
 #endif /* ENABLE_COLOR */
+#ifndef NANO_SMALL
+    /* free history lists */
+    free_history(&search_history);
+    free_history(&replace_history);
+#endif
 }
 #endif /* DEBUG */
diff --git a/nano.c b/nano.c
index cbe94ecb7ae71bf38cd779d8062038d66c717623..e8de005c77ba9b72002acbd46fb4f72c7ffc3f6c 100644 (file)
--- a/nano.c
+++ b/nano.c
@@ -66,6 +66,12 @@ static sigjmp_buf jmpbuf;    /* Used to return to mainloop after SIGWINCH */
 /* What we do when we're all set to exit */
 RETSIGTYPE finish(int sigage)
 {
+
+#ifndef NANO_SMALL
+    free_history(&search_history);
+    free_history(&replace_history);
+#endif
+
     keypad(edit, TRUE);
     keypad(bottomwin, TRUE);
 
@@ -1633,7 +1639,7 @@ int do_int_spell_fix(const char *word)
            do_replace_highlight(TRUE, word);
 
            /* allow replace word to be corrected */
-           i = statusq(0, spell_list, last_replace, _("Edit a replacement"));
+           i = statusq(0, spell_list, last_replace, 0, _("Edit a replacement"));
 
            do_replace_highlight(FALSE, word);
 
@@ -3093,6 +3099,7 @@ int main(int argc, char *argv[])
 #endif
        }
     }
+
        if (!ISSET(NO_RCFILE))
            do_rcfile();
 #else
@@ -3334,6 +3341,10 @@ int main(int argc, char *argv[])
        keypad(bottomwin, TRUE);
     }
 
+#ifndef NANO_SMALL
+    history_init();
+#endif
+
 #ifdef ENABLE_COLOR
     do_colorinit();
 #endif /* ENABLE_COLOR */
diff --git a/nano.h b/nano.h
index 70581c56845fc530ddad49a9fd8ede1b9d2800b5..ca8a5d73370cbc61f6e68cfcacb73614bb2565dd 100644 (file)
--- a/nano.h
+++ b/nano.h
 #define KEY_END -1
 #endif /* KEY_END */
 
+/* Snatch these out of the ncurse sdefs, so we can use them in search
+   history regardless of whethere we're using ncurses or not */
+#ifndef KEY_UP
+#define KEY_UP   0403
+#define KEY_DOWN 0402
+#endif /* KEY_UP */
+
+
 #define VERMSG "GNU nano " VERSION
 
 #if defined(DISABLE_WRAPPING) && defined(DISABLE_JUSTIFY)
@@ -190,6 +198,21 @@ typedef struct syntaxtype {
 
 #endif /* ENABLE_COLOR */
 
+#ifndef NANO_SMALL
+typedef struct historytype {
+    struct historytype *next;
+    struct historytype *prev;
+    char *data;
+} historytype;
+typedef struct historyheadtype {
+    struct historytype *next;  /* keep *next and *prev members together */
+    struct historytype *prev;  /* and in same order as in historytype */
+    struct historytype *tail;
+    struct historytype *current;
+    int count;
+    int len;
+} historyheadtype;
+#endif /* !NANO_SMALL */
 
 /* Bitwise flags so we can save space (or more correctly, not waste it) */
 
@@ -397,4 +420,6 @@ typedef enum {
 /* Minimum fill length (space available for text before wrapping occurs) */
 #define MIN_FILL_LENGTH 10
 
+/* Maximum number of search history strings saved, same value used for replace history */
+#define MAX_SEARCH_HISTORY 100
 #endif /* !NANO_H */
diff --git a/proto.h b/proto.h
index 51388a179a12f321bd0021ed71df3a940e40395d..01278bf1d404955511443ffc89bb93fa582b5b1c 100644 (file)
--- a/proto.h
+++ b/proto.h
@@ -40,6 +40,7 @@ extern long totsize;
 extern int temp_opt;
 extern int wrap_at, flags, tabsize;
 extern int search_last_line;
+extern int past_editbuff;
 extern int currslen;
 
 #ifndef DISABLE_JUSTIFY
@@ -109,6 +110,11 @@ extern regmatch_t synfilematches[1];
 extern toggle *toggles;
 #endif
 
+#ifndef NANO_SMALL
+extern historyheadtype search_history;
+extern historyheadtype replace_history;
+#endif
+
 /* Functions we want available */
 
 /* Public functions in color.c */
@@ -355,6 +361,17 @@ int do_gotoline_void(void);
 void do_gotopos(int line, int pos_x, int pos_y, int pos_placewewant);
 #endif
 int do_find_bracket(void);
+#ifndef NANO_SMALL
+void history_init(void);
+historytype *find_node(historytype *h, char *s);
+void remove_node(historytype *r);
+void insert_node(historytype *h, const char *s);
+void update_history(historyheadtype *h, char *s);
+char *get_history_older(historyheadtype *h);
+char *get_history_newer(historyheadtype *h);
+char *get_history_completion(historyheadtype *h, char *s);
+void free_history(historyheadtype *h);
+#endif
 
 /* Public functions in utils.c */
 int is_cntrl_char(int c);
@@ -398,6 +415,9 @@ void blank_statusbar_refresh(void);
 void check_statblank(void);
 void nanoget_repaint(const char *buf, const char *inputbuf, int x);
 int nanogetstr(int allowtabs, const char *buf, const char *def,
+#ifndef NANO_SMALL
+               historyheadtype *history_list,
+#endif
                const shortcut *s
 #ifndef DISABLE_TABCOMP
                , int *list
@@ -426,6 +446,9 @@ void edit_refresh(void);
 void edit_refresh_clearok(void);
 void edit_update(filestruct *fileptr, topmidbotnone location);
 int statusq(int tabs, const shortcut *s, const char *def,
+#ifndef NANO_SMALL
+               historyheadtype *history_list,
+#endif
                const char *msg, ...);
 int do_yesno(int all, int leavecursor, const char *msg, ...);
 int total_refresh(void);
index 24994087490c25721970d862183b05440713daa3..234bb1c273de3c9feac3e4d4e2f9aca2bd95e759 100644 (file)
--- a/rcfile.c
+++ b/rcfile.c
@@ -607,9 +607,10 @@ void do_rcfile(void)
 
     lineno = 0;
 
-    if (userage == NULL)
+    if (userage == NULL) {
        rcfile_error(_("I can't find my home directory!  Wah!"));
-    else {
+       SET(NO_RCFILE); /* if no .nanorc, don't try to read .nano_history */
+    } else {
        nanorc = nrealloc(nanorc, strlen(userage->pw_dir) + 9);
        sprintf(nanorc, "%s/.nanorc", userage->pw_dir);
 
@@ -621,9 +622,11 @@ void do_rcfile(void)
 #endif
        if ((rcstream = fopen(nanorc, "r")) == NULL) {
            /* Don't complain about the file not existing */
-           if (errno != ENOENT)
+           if (errno != ENOENT) {
                rcfile_error(_("Unable to open ~/.nanorc file, %s"),
                        strerror(errno));
+               SET(NO_RCFILE);
+           }
        } else {
            parse_rcfile(rcstream);
            fclose(rcstream);
index 115b9a64ecfa0800088d776f71a38e7b86d92d71..80b0a4a7d9de402e99c3eb72316b531eec549c76 100644 (file)
--- a/search.c
+++ b/search.c
 #include <unistd.h>
 #include <stdio.h>
 #include <ctype.h>
+#include <errno.h>
 #include <assert.h>
 #include "proto.h"
 #include "nano.h"
 
+#ifndef NANO_SMALL
+#ifdef ENABLE_NANORC
+#include <pwd.h>
+#endif
+#endif
+
 static int past_editbuff;
        /* findnextstr() is now searching lines not displayed */
 
@@ -89,7 +96,7 @@ void search_init_globals(void)
 }
 
 /* Set up the system variables for a search or replace.  Returns -1 on
-   abort, 0 on success, and 1 on rerun calling program 
+   abort, 0 on success, and 1 on rerun calling program
    Return -2 to run opposite program (search -> replace, replace ->
    search).
 
@@ -110,24 +117,37 @@ int search_init(int replacing)
        backupstring = NULL;
        UNSET(CLEAR_BACKUPSTRING);
     }
-       
-     /* Okay, fun time.  backupstring is our holder for what is being 
+
+     /* Okay, fun time.  backupstring is our holder for what is being
        returned from the statusq call.  Using answer for this would be tricky.
        Here, if we're using PICO_MODE, we only want nano to put the
        old string back up as editable if it's not the same as last_search.
 
        Otherwise, if we don't already have a backupstring, set it to
        last_search. */
-
+#if 0
+/* might need again ;)*/
     if (ISSET(PICO_MODE)) {
        if (backupstring == NULL || !strcmp(backupstring, last_search)) {
+           /* backupstring = mallocstrcpy(backupstring, ""); */
            backupstring = charalloc(1);
            backupstring[0] = '\0';
        }
-    }
-    else if (backupstring == NULL)
+    } else
+#endif
+    if (backupstring == NULL)
+#ifndef NANO_SMALL
+       backupstring = mallocstrcpy(backupstring, search_history.current->data);
+#else
        backupstring = mallocstrcpy(backupstring, last_search);
+#endif
 
+/* NEW TEST */
+    if (ISSET(PICO_MODE)) {
+       backupstring = mallocstrcpy(backupstring, "");
+       search_history.current = (historytype *)&search_history.next;
+    }
+/* */
     /* If using Pico messages, we do things the old fashioned way... */
     if (ISSET(PICO_MODE) && last_search[0] != '\0') {
        buf = charalloc(COLS / 3 + 7);
@@ -141,7 +161,10 @@ int search_init(int replacing)
 
     /* This is now one simple call.  It just does a lot */
     i = statusq(0, replacing ? replace_list : whereis_list, backupstring,
-       "%s%s%s%s%s%s", 
+#ifndef NANO_SMALL
+       &search_history,
+#endif
+       "%s%s%s%s%s%s",
        _("Search"),
 
        /* This string is just a modifier for the search prompt,
@@ -168,6 +191,9 @@ int search_init(int replacing)
        reset_cursor();
        free(backupstring);
        backupstring = NULL;
+#ifndef NANO_SMALL
+       search_history.current = search_history.next;
+#endif
        return -1;
     } else {
        switch (i) {
@@ -210,7 +236,14 @@ int search_init(int replacing)
        case NANO_FROMSEARCHTOGOTO_KEY:
            free(backupstring);
            backupstring = NULL;
-           do_gotoline_void();
+#ifndef NANO_SMALL
+           search_history.current = search_history.next;
+#endif
+           i = (int)strtol(answer, &buf, 10);          /* just testing answer here */
+           if (!(errno == ERANGE || *answer == '\0' || *buf != '\0'))
+               do_gotoline(-1, 0);
+           else
+               do_gotoline_void();
            return -3;
        default:
            do_early_abort();
@@ -301,7 +334,7 @@ filestruct *findnextstr(int quiet, int bracket_mode,
                not_found_msg(needle);
            return NULL;
        }
-    } 
+    }
 #ifndef NANO_SMALL
     else {     /* reverse search */
        current_x_find = current_x - 1;
@@ -403,6 +436,9 @@ int do_search(void)
     /* The sneaky user deleted the previous search string */
     if (!ISSET(PICO_MODE) && answer[0] == '\0') {
        statusbar(_("Search Cancelled"));
+#ifndef NANO_SMALL
+       search_history.current = search_history.next;
+#endif
        search_abort();
        return 0;
     }
@@ -415,6 +451,11 @@ int do_search(void)
     else
        last_search = mallocstrcpy(last_search, answer);
 
+#ifndef NANO_SMALL
+    /* add this search string to the search history list */
+    update_history(&search_history, answer);
+#endif /* !NANO_SMALL */
+
     search_last_line = 0;
     didfind = findnextstr(FALSE, FALSE, current, current_x, answer);
 
@@ -697,6 +738,10 @@ int do_replace(void)
        return 0;
     }
 
+#ifndef NANO_SMALL
+    update_history(&search_history, answer);
+#endif /* !NANO_SMALL */
+
     /* Again, there was a previous string, but they deleted it and hit enter */
     if (!ISSET(PICO_MODE) && answer[0] == '\0') {
        statusbar(_("Replace Cancelled"));
@@ -710,6 +755,7 @@ int do_replace(void)
        answer = mallocstrcpy(answer, last_search);
     else
        last_search = mallocstrcpy(last_search, answer);
+
     prevanswer = mallocstrcpy(prevanswer, last_search);
 
     if (ISSET(PICO_MODE) && last_replace[0] != '\0') {
@@ -718,16 +764,34 @@ int do_replace(void)
 
            strncpy(buf, last_replace, COLS / 3 - 1);
            strcpy(buf + COLS / 3 - 1, "...");
-           i = statusq(0, replace_list_2, "", _("Replace with [%s]"),
-                       buf);
+           i = statusq(0, replace_list_2, "",
+#ifndef NANO_SMALL
+               &replace_history,
+#endif
+               _("Replace with [%s]"), buf);
            free(buf);
        } else
-           i = statusq(0, replace_list_2, "", _("Replace with [%s]"),
-                       last_replace);
-    } else
-       i = statusq(0, replace_list_2, last_replace, _("Replace with"));
+           i = statusq(0, replace_list_2, "",
+#ifndef NANO_SMALL
+                &replace_history,
+#endif
+               _("Replace with [%s]") ,last_replace);
+    } else {
+#ifndef NANO_SMALL
+       replace_history.current = (historytype *)&replace_history.next;
+       last_replace = mallocstrcpy(last_replace, "");
+#endif
+       i = statusq(0, replace_list_2, last_replace,
+#ifndef NANO_SMALL
+               &replace_history,
+#endif
+               _("Replace with"));
+   }
+#ifndef NANO_SMALL
+    if (i == 0)
+       update_history(&replace_history, answer);
+#endif /* !NANO_SMALL */
 
-    /* save where we are */
     begin = current;
     beginx = current_x;
     search_last_line = 0;
@@ -753,7 +817,7 @@ void goto_abort(void)
 int do_gotoline(int line, int save_pos)
 {
     if (line <= 0) {           /* Ask for it */
-       if (statusq(0, goto_list, "", _("Enter line number"))) {
+       if (statusq(0, goto_list, (line ? answer : ""), 0, _("Enter line number"))) {
            statusbar(_("Aborted"));
            goto_abort();
            return 0;
@@ -780,9 +844,9 @@ int do_gotoline(int line, int save_pos)
        edit_update(current, NONE);
     else
        edit_update(current, CENTER);
-
     placewewant = 0;
     goto_abort();
+    blank_statusbar_refresh();
     return 1;
 }
 
@@ -820,7 +884,9 @@ int do_find_bracket(void)
     filestruct *current_save;
 
     ch_under_cursor = current->data[current_x];
+
+/*    if ((!(pos = strchr(brackets, ch_under_cursor))) || (!((offset = pos - brackets) < 8))) { */
+
     if (((pos = strchr(brackets, ch_under_cursor)) == NULL) || (((offset = pos - brackets) < 8) == 0)) {
        statusbar(_("Not a bracket"));
        return 1;
@@ -880,3 +946,126 @@ int do_find_bracket(void)
     return 0;
 }
 #endif
+
+#ifndef NANO_SMALL
+/*
+ * search and replace history list support functions
+ */
+
+/* initialize search and replace history lists */
+void history_init(void)
+{
+    search_history.next = (historytype *)&search_history.prev;
+    search_history.prev = NULL;
+    search_history.tail = (historytype *)&search_history.next;
+    search_history.current = search_history.next;
+    search_history.count = 0;
+    search_history.len = 0;
+
+    replace_history.next = (historytype *)&replace_history.prev;
+    replace_history.prev = NULL;
+    replace_history.tail = (historytype *)&replace_history.next;
+    replace_history.current = replace_history.next;
+    replace_history.count = 0;
+    replace_history.len = 0;
+}
+
+/* find first node containing string *s in history list *h */
+historytype *find_node(historytype *h, char *s)
+{
+    for ( ; h->next ; h = h->next)
+       if (strcmp(s, h->data) == 0)
+           return h;
+    return NULL;
+}
+
+/* remove node *r */
+void remove_node(historytype *r)
+{
+    r->prev->next = r->next;
+    r->next->prev = r->prev;
+    free(r->data);
+    free(r);
+}
+
+/* add a node after node *h */
+void insert_node(historytype *h, const char *s)
+{
+    historytype *a;
+
+    a = nmalloc(sizeof(historytype));
+    a->next = h->next;
+    a->prev = h->next->prev;
+    h->next->prev = a;
+    h->next = a;
+    a->data = mallocstrcpy(NULL, s);
+}
+
+/* update history list */
+void update_history(historyheadtype *h, char *s)
+{
+    historytype *p;
+
+    if ((p = find_node(h->next, s))) {
+       if (p == h->next)               /* catch delete and re-insert of same string in 1st node */
+           goto up_hs;
+       remove_node(p);                         /* delete identical older string */
+       h->count--;
+    }
+    if (h->count == MAX_SEARCH_HISTORY) {      /* list 'full', delete oldest */
+       remove_node(h->tail);
+       h->count--;
+    }
+    insert_node((historytype *)h, s);
+    h->count++;
+up_hs:
+    h->current = h->next;
+}
+
+/* return a pointer to either the next older history or NULL if no more */
+char *get_history_older(historyheadtype *h)
+{
+    if (h->current->next) {            /* any older entries ? */
+       h->current = h->current->next;  /* yes */
+       return h->current->data;        /* return it */
+    }
+    return NULL;                       /* end of list */
+}
+
+char *get_history_newer(historyheadtype *h)
+{
+    if (h->current->prev) {
+       h->current = h->current->prev;
+       if (h->current->prev)
+           return h->current->data;
+    }
+    return NULL;
+}
+
+/* get a completion */
+char *get_history_completion(historyheadtype *h, char *s)
+{
+    historytype *p;
+
+    for (p = h->current->next ; p->next ; p = p->next) {
+       if ((strncmp(s, p->data, h->len) == 0) && (strlen(p->data) != h->len)) {
+           h->current = p;
+           return p->data;
+       }
+    }
+    h->current = (historytype*)h;
+    null_at(&s, h->len);
+    return s;
+}
+
+/* free a history list */
+void free_history(historyheadtype *h)
+{
+    historytype *p, *n;
+
+    for (p = h->next ; (n = p->next) ; p = n)
+       remove_node(p);
+}
+
+/* end of history support functions */
+#endif /* !NANO_SMALL */
diff --git a/winio.c b/winio.c
index e15b4b435c09c4852f456d4e6d67e61982c6ba5d..d6d743047a98f430689d878c1958ea495d062e6a 100644 (file)
--- a/winio.c
+++ b/winio.c
@@ -187,6 +187,9 @@ void nanoget_repaint(const char *buf, const char *inputbuf, int x)
 /* Get the input from the kb; this should only be called from
  * statusq(). */
 int nanogetstr(int allowtabs, const char *buf, const char *def,
+#ifndef NANO_SMALL
+               historyheadtype *history_list,
+#endif
                const shortcut *s
 #ifndef DISABLE_TABCOMP
                , int *list
@@ -202,6 +205,12 @@ int nanogetstr(int allowtabs, const char *buf, const char *def,
        /* used by input_tab() */
     const shortcut *t;
 
+#ifndef NANO_SMALL
+   /* for history */
+    char *history = NULL;
+    char *complete = NULL;
+    int last_kbinput = 0;
+#endif
     xend = strlen(def);
     x = xend;
     answer = (char *)nrealloc(answer, xend + 1);
@@ -300,28 +309,74 @@ int nanogetstr(int allowtabs, const char *buf, const char *def,
                xend--;
            }
            break;
-#ifndef DISABLE_TABCOMP
        case NANO_CONTROL_I:
-           if (allowtabs) {
-               int shift = 0;
+#ifndef NANO_SMALL
+           /* tab history completion */
+           if (history_list) {
+               if ((!complete) || (last_kbinput != NANO_CONTROL_I)) {
+                   history_list->current = (historytype *)history_list;
+                   history_list->len = strlen(answer);
+               }
 
-               answer = input_tab(answer, x, &tabbed, &shift, list);
-               xend = strlen(answer);
-               x += shift;
-               if (x > xend)
+               if (history_list->len) {
+                   complete = get_history_completion(history_list, answer);
+                   xend = strlen(complete);
                    x = xend;
+                   answer = mallocstrcpy(answer, complete);
+               }
            }
-           break;
+#ifndef DISABLE_TABCOMP
+           else {
+#endif
 #endif
+#ifndef DISABLE_TABCOMP
+               if (allowtabs) {
+                   int shift = 0;
+
+                   answer = input_tab(answer, x, &tabbed, &shift, list);
+                   xend = strlen(answer);
+                   x += shift;
+                   if (x > xend)
+                       x = xend;
+               }
+           }
+#endif
+           break;
        case KEY_LEFT:
        case NANO_BACK_KEY:
            if (x > 0)
                x--;
            break;
        case KEY_UP:
+#ifndef NANO_SMALL
+           if (history_list) {
+               /* get older search from the history list */
+               if ((history = get_history_older(history_list))) {
+                   answer = mallocstrcpy(answer, history);
+                   xend = strlen(history);
+               } else {
+                   answer = mallocstrcpy(answer, "");
+                   xend = 0;
+               }
+               x = xend;
+           }
+           break;
+#endif
        case KEY_DOWN:
+#ifndef NANO_SMALL
+           if (history_list) {
+               /* get newer search from the history list */
+               if ((history = get_history_newer(history_list))) {
+                   answer = mallocstrcpy(answer, history);
+                   xend = strlen(history);
+               } else {
+                   answer = mallocstrcpy(answer, "");
+                   xend = 0;
+               }
+               x = xend;
+           }
+#endif
            break;
-
        case KEY_DC:
            goto do_deletekey;
 
@@ -400,7 +455,8 @@ int nanogetstr(int allowtabs, const char *buf, const char *def,
 #ifdef DEBUG
            fprintf(stderr, _("input \'%c\' (%d)\n"), kbinput, kbinput);
 #endif
-       }
+       } /* switch (kbinput) */
+       last_kbinput = kbinput;
        nanoget_repaint(buf, answer, x);
        wrefresh(bottomwin);
     } /* while (kbinput ...) */
@@ -496,11 +552,13 @@ void bottombars(const shortcut *s)
            wmove(bottomwin, 1 + j, i * (COLS / numcols));
 
 #ifndef NANO_SMALL
+           /* Yucky sentinel values we can't handle a better way */
            if (s->val == NANO_CONTROL_SPACE)
                strcpy(keystr, "^ ");
-           else
-#endif /* !NANO_SMALL */
-           if (s->val > 0) {
+           else if (s->val == KEY_UP)
+               strcpy(keystr, _("Up"));
+#endif /* NANO_SMALL */
+           else if (s->val > 0) {
                if (s->val < 64)
                    sprintf(keystr, "^%c", s->val + 64);
                else
@@ -526,6 +584,7 @@ void bottombars(const shortcut *s)
  * very small and keystroke and desc are long. */
 void onekey(const char *keystroke, const char *desc, int len)
 {
+
     wattron(bottomwin, A_REVERSE);
     waddnstr(bottomwin, keystroke, len);
     wattroff(bottomwin, A_REVERSE);
@@ -911,8 +970,8 @@ void update_line(filestruct *fileptr, int index)
 
     original = fileptr->data;
     converted = charalloc(strlenpt(original) + 1);
-    
-    /* Next, convert all the tabs to spaces, so everything else is easy. 
+
+    /* Next, convert all the tabs to spaces, so everything else is easy.
      * Note the internal speller sends us index == -1. */
     index = fileptr == current && index > 0 ? strnlenpt(original, index) : 0;
 #ifndef NANO_SMALL
@@ -1070,6 +1129,9 @@ void edit_update(filestruct *fileptr, topmidbotnone location)
  * New arg tabs tells whether or not to allow tab completion.
  */
 int statusq(int tabs, const shortcut *s, const char *def,
+#ifndef NANO_SMALL
+               historyheadtype *which_history,
+#endif
                const char *msg, ...)
 {
     va_list ap;
@@ -1086,11 +1148,15 @@ int statusq(int tabs, const shortcut *s, const char *def,
     va_end(ap);
     foo[COLS - 4] = '\0';
 
+    ret = nanogetstr(tabs, foo, def,
+#ifndef NANO_SMALL
+               which_history,
+#endif
+               s
 #ifndef DISABLE_TABCOMP
-    ret = nanogetstr(tabs, foo, def, s, &list);
-#else
-    ret = nanogetstr(tabs, foo, def, s);
+               , &list
 #endif
+               );
     free(foo);
 
     switch (ret) {