do_gotolinecolumn_void()), nano.1, and nano.texi. (DLR,
suggested by PFTank)
- Overhaul the history code to work more consistently, and clean
- up various parts of it. Note that history tab completion has
- been removed. New function history_has_changed(); changes to
- load_history(), writehist(), thanks_for_all_the_fish(),
- history_init(), find_node() (renamed find_history()),
- update_history(), get_history_older(), get_history_newer(),
- do_search(), do_replace(), nanogetstr(), and statusq();
- removal of remove_node(), insert_node(), and
- get_history_completion(). (DLR)
+ up various parts of it. New function history_has_changed();
+ changes to load_history(), writehist(),
+ thanks_for_all_the_fish(), history_init(), find_node()
+ (renamed find_history()), update_history(),
+ get_history_older(), get_history_newer(),
+ get_history_completion(), do_search(), do_replace(),
+ nanogetstr(), and statusq(); removal of remove_node() and
+ insert_node(). (DLR)
- Replace all instances of strncpy() with charcpy(), since the
only difference between them is that the former pads strings
with nulls when they're longer than the number of characters
* replace history) from oldest to newest. Assume the last
* history entry is a blank line. */
filestruct **history = &search_history;
- filestruct **historyage = &searchage;
- filestruct **historybot = &searchbot;
char *line = NULL;
size_t buflen = 0;
ssize_t read;
}
if (read > 0) {
unsunder(line, read);
- update_history(history, historyage, historybot,
- line);
- } else {
+ update_history(history, line);
+ } else
history = &replace_history;
- historyage = &replaceage;
- historybot = &replacebot;
- }
}
fclose(hist);
void load_history(void);
bool writehist(FILE *hist, filestruct *histhead);
void save_history(void);
+#ifndef DISABLE_TABCOMP
+char *get_history_completion(filestruct **h, char *s, size_t len);
+#endif
#endif
/* Public functions in global.c. */
#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
bool history_has_changed(void);
void history_init(void);
-filestruct *find_history(filestruct *h, const char *s);
-void update_history(filestruct **h, filestruct **hage, filestruct
- **hbot, const char *s);
+filestruct *find_history(filestruct *h_start, filestruct *h_end, const
+ char *s, size_t len);
+void update_history(filestruct **h, const char *s);
char *get_history_older(filestruct **h);
char *get_history_newer(filestruct **h);
#endif
void nanoget_repaint(const char *buf, const char *inputbuf, size_t x);
int nanogetstr(bool allow_tabs, const char *buf, const char *curranswer,
#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
- filestruct *history_list,
+ filestruct **history_list,
#endif
const shortcut *s
#ifndef DISABLE_TABCOMP
);
int statusq(bool allow_tabs, const shortcut *s, const char *curranswer,
#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
- filestruct *history_list,
+ filestruct **history_list,
#endif
const char *msg, ...);
void statusq_abort(void);
i = statusq(FALSE, replacing ? replace_list : whereis_list,
backupstring,
#ifndef NANO_SMALL
- search_history,
+ &search_history,
#endif
"%s%s%s%s%s%s", _("Search"),
/* If answer is not "", add this search string to the search history
* list. */
if (answer[0] != '\0')
- update_history(&search_history, &searchage, &searchbot, answer);
+ update_history(&search_history, answer);
#endif
findnextstr_wrap_reset();
* copy answer into last_search. */
if (answer[0] != '\0') {
#ifndef NANO_SMALL
- update_history(&search_history, &searchage, &searchbot, answer);
+ update_history(&search_history, answer);
#endif
last_search = mallocstrcpy(last_search, answer);
}
i = statusq(FALSE, replace_list_2, last_replace,
#ifndef NANO_SMALL
- replace_history,
+ &replace_history,
#endif
_("Replace with"));
/* Add this replace string to the replace history list. i == 0
* means that the string is not "". */
if (i == 0)
- update_history(&replace_history, &replaceage, &replacebot,
- answer);
+ update_history(&replace_history, answer);
#endif
if (i != 0 && i != -2) {
replacebot = replace_history;
}
-/* Return the first node containing the string s in the history list,
- * starting at h, or NULL if there isn't one. */
-filestruct *find_history(filestruct *h, const char *s)
+/* Return the first node containing the first len characters of the
+ * string s in the history list, starting at h_start and ending at
+ * h_end, or NULL if there isn't one. */
+filestruct *find_history(filestruct *h_start, filestruct *h_end, const
+ char *s, size_t len)
{
- assert(h != NULL);
+ filestruct *p;
- for (; h->next != NULL; h = h->next) {
- if (strcmp(s, h->data) == 0)
- return h;
+ for (p = h_start; p != h_end->next && p != NULL; p = p->next) {
+ if (strncmp(s, p->data, len) == 0)
+ return p;
}
return NULL;
}
-/* Update a history list. h should be the current position in the list,
- * hage should be the top of the list, and hbot should be the bottom of
- * the list. */
-void update_history(filestruct **h, filestruct **hage, filestruct
- **hbot, const char *s)
+/* Update a history list. h should be the current position in the
+ * list. */
+void update_history(filestruct **h, const char *s)
{
- filestruct *p;
+ filestruct **hage = NULL, **hbot = NULL, *p;
+
+ assert(h != NULL && s != NULL);
+
+ if (*h == search_history) {
+ hage = &searchage;
+ hbot = &searchbot;
+ } else if (*h == replace_history) {
+ hage = &replaceage;
+ hbot = &replacebot;
+ }
- assert(h != NULL && hage != NULL && hbot != NULL && s != NULL);
+ assert(hage != NULL && hbot != NULL);
/* If this string is already in the history, delete it. */
- p = find_history(*hage, s);
+ p = find_history(*hage, *hbot, s, (size_t)-1);
if (p != NULL) {
filestruct *foo, *bar;
return (*h)->data;
}
+
+#ifndef DISABLE_TABCOMP
+/* Move h to the next string that's a tab completion of the string s,
+ * looking at only the first len characters of s, and return that
+ * string. If there isn't one, or if len is 0, don't move h, truncate s
+ * to len characters, and return s. */
+char *get_history_completion(filestruct **h, char *s, size_t len)
+{
+ assert(s != NULL);
+
+ if (len > 0) {
+ filestruct *hage = NULL, *hbot = NULL, *p;
+
+ assert(h != NULL);
+
+ if (*h == search_history) {
+ hage = searchage;
+ hbot = searchbot;
+ } else if (*h == replace_history) {
+ hage = replaceage;
+ hbot = replacebot;
+ }
+
+ assert(hage != NULL && hbot != NULL);
+
+ /* Search the history list from the entry after the current
+ * position to the bottom for a match of len characters. */
+ p = find_history((*h)->next, hbot, s, len);
+
+ if (p != NULL) {
+ *h = p;
+ return (*h)->data;
+ }
+
+ /* Search the history list from the top to the current position
+ * for a match of len characters. */
+ p = find_history(hage, *h, s, len);
+
+ if (p != NULL) {
+ *h = p;
+ return (*h)->data;
+ }
+ }
+
+ /* If we're here, we didn't find a match, or len is 0. Truncate s
+ * to len characters, and return it. */
+ null_at(&s, len);
+
+ return s;
+}
+#endif
#endif /* !NANO_SMALL && ENABLE_NANORC */
* statusq(). */
int nanogetstr(bool allow_tabs, const char *buf, const char *curranswer,
#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
- filestruct *history_list,
+ filestruct **history_list,
#endif
const shortcut *s
#ifndef DISABLE_TABCOMP
/* Whether we've pressed Tab. */
#endif
#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
+#ifndef DISABLE_TABCOMP
+ size_t complete_len = 0;
+ /* The length of the original string that we're trying to
+ * tab complete, if any. */
+#endif
+ int last_kbinput = ERR;
+ /* The key we pressed before the current key. */
char *history = NULL;
/* The current history string. */
char *magichistory = NULL;
switch (kbinput) {
case NANO_TAB_KEY:
#ifndef DISABLE_TABCOMP
+#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
+ 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
if (allow_tabs)
answer = input_tab(answer, &statusbar_x, &tabbed,
list);
* history list, answer isn't blank, and
* magichistory isn't set, save answer in
* magichistory. */
- if (history_list->next == NULL &&
+ if ((*history_list)->next == NULL &&
answer[0] != '\0' && magichistory == NULL)
magichistory = mallocstrcpy(NULL, answer);
* save it in answer. If there is no older search,
* don't do anything. */
if ((history =
- get_history_older(&history_list)) != NULL) {
+ get_history_older(history_list)) != NULL) {
answer = mallocstrcpy(answer, history);
statusbar_x = strlen(answer);
}
* save it in answer. If there is no newer search,
* don't do anything. */
if ((history =
- get_history_newer(&history_list)) != NULL) {
+ get_history_newer(history_list)) != NULL) {
answer = mallocstrcpy(answer, history);
statusbar_x = strlen(answer);
}
* the history list, answer is blank, and
* magichistory is set, save magichistory in
* answer. */
- if (history_list->next == NULL &&
+ if ((*history_list)->next == NULL &&
answer[0] == '\0' && magichistory != NULL) {
answer = mallocstrcpy(answer, magichistory);
statusbar_x = strlen(answer);
if (finished)
break;
+#if !defined(NANO_SMALL) && defined(ENABLE_NANORC) && !defined(DISABLE_TABCOMP)
+ last_kbinput = kbinput;
+#endif
+
nanoget_repaint(buf, answer, statusbar_x);
wrefresh(bottomwin);
}
* interpreted. */
int statusq(bool allow_tabs, const shortcut *s, const char *curranswer,
#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
- filestruct *history_list,
+ filestruct **history_list,
#endif
const char *msg, ...)
{