CVS code -
+- General:
+ - Implement filename searches in the file browser. New
+ functions filesearch_init(), findnextfile(),
+ findnextfile_wrap_reset(), filesearch_abort(),
+ do_filesearch(), do_fileresearch(), do_first_file(),
+ do_last_file(), do_help_void(), and do_browser_help(); changes
+ to do_browser(), parse_browser_input(), shortcut_init(),
+ do_help(), and help_init(). (DLR)
GNU nano 1.3.11 - 2006.03.30
- General:
- UTF-8 support. [DONE]
- Support for paragraph searches. [DONE]
- Support for justifying the entire file at once. [DONE]
-- Support for filename searches in the file browser.
+- Support for filename searches in the file browser. [DONE]
- Undo/Redo keys?
- Rebindable keys?
- Keystroke to implement "Add next sequence as raw" like vi's ^V. [DONE]
/* The number of columns in the longest filename in the list. */
static size_t selected = 0;
/* The currently selected filename in the list. */
+static bool search_last_file = FALSE;
+ /* Have we gone past the last file while searching? */
/* Our browser function. path is the path to start browsing from.
* Assume path has already been tilde-expanded. */
case NANO_HELP_KEY:
#ifndef DISABLE_HELP
- do_help();
+ do_browser_help();
curs_set(0);
#else
nano_disabled_msg();
total_redraw();
break;
+ /* Search for a filename. */
+ case NANO_WHEREIS_KEY:
+ curs_set(1);
+ do_filesearch();
+ curs_set(0);
+ break;
+
+ /* Search for another filename. */
+ case NANO_WHEREIS_NEXT_KEY:
+ do_fileresearch();
+ break;
+
/* Go to a specific directory. */
case NANO_GOTOLINE_KEY:
curs_set(1);
case 's':
*kbinput = NANO_ENTER_KEY;
break;
+ case 'W':
+ case 'w':
+ *kbinput = NANO_WHEREIS_KEY;
+ break;
}
}
}
wnoutrefresh(edit);
}
+/* Set up the system variables for a filename search. Return -1 if the
+ * search should be canceled (due to Cancel, a blank search string, or a
+ * failed regcomp()), return 0 on success, and return 1 on rerun calling
+ * program. */
+int filesearch_init(void)
+{
+ int i = 0;
+ char *buf;
+ static char *backupstring = NULL;
+ /* The search string we'll be using. */
+
+ /* If backupstring doesn't exist, initialize it to "". */
+ if (backupstring == NULL)
+ backupstring = mallocstrcpy(NULL, "");
+
+ /* We display the search prompt below. If the user types a partial
+ * search string and then Replace or a toggle, we will return to
+ * do_search() or do_replace() and be called again. In that case,
+ * we should put the same search string back up. */
+
+ search_init_globals();
+
+ if (last_search[0] != '\0') {
+ char *disp = display_string(last_search, 0, COLS / 3, FALSE);
+
+ buf = charalloc(strlen(disp) + 7);
+ /* We use (COLS / 3) here because we need to see more on the
+ * line. */
+ sprintf(buf, " [%s%s]", disp,
+ (strlenpt(last_search) > COLS / 3) ? "..." : "");
+ free(disp);
+ } else
+ buf = mallocstrcpy(NULL, "");
+
+ /* This is now one simple call. It just does a lot. */
+ i = do_prompt(FALSE,
+#ifndef DISABLE_TABCOMP
+ TRUE,
+#endif
+ whereis_file_list, backupstring,
+#ifndef NANO_TINY
+ &search_history,
+#endif
+ browser_refresh, "%s%s%s%s%s%s", _("Search"),
+#ifndef NANO_TINY
+ /* This string is just a modifier for the search prompt; no
+ * grammar is implied. */
+ ISSET(CASE_SENSITIVE) ? _(" [Case Sensitive]") :
+#endif
+ "",
+#ifdef HAVE_REGEX_H
+ /* This string is just a modifier for the search prompt; no
+ * grammar is implied. */
+ ISSET(USE_REGEXP) ? _(" [Regexp]") :
+#endif
+ "",
+#ifndef NANO_TINY
+ /* This string is just a modifier for the search prompt; no
+ * grammar is implied. */
+ ISSET(BACKWARDS_SEARCH) ? _(" [Backwards]") :
+#endif
+ "", "", buf);
+
+ /* Release buf now that we don't need it anymore. */
+ free(buf);
+
+ free(backupstring);
+ backupstring = NULL;
+
+ /* Cancel any search, or just return with no previous search. */
+ if (i == -1 || (i < 0 && last_search[0] == '\0') ||
+ (i == 0 && answer[0] == '\0')) {
+ statusbar(_("Cancelled"));
+ return -1;
+ } else {
+ switch (i) {
+ case -2: /* It's an empty string. */
+ case 0: /* It's a new string. */
+#ifdef HAVE_REGEX_H
+ /* Use last_search if answer is an empty string, or
+ * answer if it isn't. */
+ if (ISSET(USE_REGEXP) &&
+ regexp_init((i == -2) ? last_search :
+ answer) == 0)
+ return -1;
+#endif
+ break;
+#ifndef NANO_TINY
+ case TOGGLE_CASE_KEY:
+ TOGGLE(CASE_SENSITIVE);
+ backupstring = mallocstrcpy(backupstring, answer);
+ return 1;
+ case TOGGLE_BACKWARDS_KEY:
+ TOGGLE(BACKWARDS_SEARCH);
+ backupstring = mallocstrcpy(backupstring, answer);
+ return 1;
+#endif
+#ifdef HAVE_REGEX_H
+ case NANO_REGEXP_KEY:
+ TOGGLE(USE_REGEXP);
+ backupstring = mallocstrcpy(backupstring, answer);
+ return 1;
+#endif
+ default:
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* Look for needle. If no_sameline is TRUE, skip over selected when
+ * looking for needle. begin is the location of the filename where we
+ * first started searching. The return value specifies whether we found
+ * anything. */
+bool findnextfile(bool no_sameline, size_t begin, const char *needle)
+{
+ size_t currselected = selected;
+ /* The location in the current file list of the match we
+ * find. */
+ const char *rev_start = tail(filelist[currselected]), *found = NULL;
+
+#ifndef NANO_TINY
+ if (ISSET(BACKWARDS_SEARCH))
+ rev_start += strlen(tail(filelist[currselected]));
+#endif
+
+ /* Look for needle in the current filename we're searching. */
+ while (TRUE) {
+ found = strstrwrapper(tail(filelist[currselected]), needle,
+ rev_start);
+
+ /* We've found a potential match. If we're not allowed to find
+ * a match on the same filename we started on and this potential
+ * match is on that line, continue searching. */
+ if (found != NULL && (!no_sameline || currselected != begin))
+ break;
+
+ /* We've finished processing the filenames, so get out. */
+ if (search_last_file) {
+ not_found_msg(needle);
+ return FALSE;
+ }
+
+ /* Move to the previous or next filename in the list. If we've
+ * reached the start or end of the list, wrap around. */
+#ifndef NANO_TINY
+ if (ISSET(BACKWARDS_SEARCH)) {
+ if (currselected > 0)
+ currselected--;
+ else {
+ currselected = filelist_len - 1;
+ statusbar(_("Search Wrapped"));
+ }
+ } else {
+#endif
+ if (currselected < filelist_len - 1)
+ currselected++;
+ else {
+ currselected = 0;
+ statusbar(_("Search Wrapped"));
+ }
+#ifndef NANO_TINY
+ }
+#endif
+
+ /* We've reached the original starting file. */
+ if (currselected == begin)
+ search_last_file = TRUE;
+
+ rev_start = tail(filelist[currselected]);
+#ifndef NANO_TINY
+ if (ISSET(BACKWARDS_SEARCH))
+ rev_start += strlen(tail(filelist[currselected]));
+#endif
+ }
+
+ /* We've definitely found something. */
+ selected = currselected;
+
+ return TRUE;
+}
+
+/* Clear the flag indicating that a search reached the last file in the
+ * list. We need to do this just before a new search. */
+void findnextfile_wrap_reset(void)
+{
+ search_last_file = FALSE;
+}
+
+/* Abort the current filename search. Clean up by setting the current
+ * shortcut list to the browser shortcut list, displaying it, and
+ * decompiling the compiled regular expression we used in the last
+ * search, if any. */
+void filesearch_abort(void)
+{
+ currshortcut = browser_list;
+ bottombars(browser_list);
+#ifdef HAVE_REGEX_H
+ regexp_cleanup();
+#endif
+}
+
+/* Search for a filename. */
+void do_filesearch(void)
+{
+ size_t begin = selected;
+ int i;
+ bool didfind;
+
+ i = filesearch_init();
+ if (i == -1) /* Cancel, blank search string, or regcomp()
+ * failed. */
+ filesearch_abort();
+#if !defined(NANO_TINY) || defined(HAVE_REGEX_H)
+ else if (i == 1) /* Case Sensitive, Backwards, or Regexp search
+ * toggle. */
+ do_filesearch();
+#endif
+
+ if (i != 0)
+ return;
+
+ /* If answer is now "", copy last_search into answer. */
+ if (answer[0] == '\0')
+ answer = mallocstrcpy(answer, last_search);
+ else
+ last_search = mallocstrcpy(last_search, answer);
+
+#ifndef NANO_TINY
+ /* If answer is not "", add this search string to the search history
+ * list. */
+ if (answer[0] != '\0')
+ update_history(&search_history, answer);
+#endif
+
+ findnextfile_wrap_reset();
+ didfind = findnextfile(FALSE, begin, answer);
+
+ /* Check to see if there's only one occurrence of the string and
+ * we're on it now. */
+ if (selected == begin && didfind) {
+ /* Do the search again, skipping over the current line. We
+ * should only end up back at the same position if the string
+ * isn't found again, in which case it's the only occurrence. */
+ didfind = findnextfile(TRUE, begin, answer);
+ if (selected == begin && !didfind)
+ statusbar(_("This is the only occurrence"));
+ }
+
+ filesearch_abort();
+}
+
+/* Search for the last filename without prompting. */
+void do_fileresearch(void)
+{
+ size_t begin = selected;
+ bool didfind;
+
+ search_init_globals();
+
+ if (last_search[0] != '\0') {
+#ifdef HAVE_REGEX_H
+ /* Since answer is "", use last_search! */
+ if (ISSET(USE_REGEXP) && regexp_init(last_search) == 0)
+ return;
+#endif
+
+ findnextfile_wrap_reset();
+ didfind = findnextfile(FALSE, begin, answer);
+
+ /* Check to see if there's only one occurrence of the string and
+ * we're on it now. */
+ if (selected == begin && didfind) {
+ /* Do the search again, skipping over the current line. We
+ * should only end up back at the same position if the
+ * string isn't found again, in which case it's the only
+ * occurrence. */
+ didfind = findnextfile(TRUE, begin, answer);
+ if (selected == begin && !didfind)
+ statusbar(_("This is the only occurrence"));
+ }
+ } else
+ statusbar(_("No current search pattern"));
+
+ filesearch_abort();
+}
+
+void do_first_file(void)
+{
+ selected = 0;
+}
+
+void do_last_file(void)
+{
+ selected = filelist_len - 1;
+}
+
/* Strip one directory from the end of path. */
void striponedir(char *path)
{
#ifndef DISABLE_BROWSER
shortcut *browser_list = NULL;
/* The file browser shortcut list. */
+shortcut *whereis_file_list = NULL;
+ /* The file browser "Search" shortcut list. */
shortcut *gotodir_list = NULL;
/* The "Go To Directory" shortcut list. */
#endif
const char *cancel_msg = N_("Cancel");
const char *get_help_msg = N_("Get Help");
const char *exit_msg = N_("Exit");
+ const char *whereis_msg = N_("Where Is");
const char *prev_page_msg = N_("Prev Page");
const char *next_page_msg = N_("Next Page");
const char *go_to_line_msg = N_("Go To Line");
const char *replace_msg = N_("Replace");
+#ifndef NANO_TINY
+ const char *whereis_next_msg = N_("Where Is Next");
+#endif
const char *refresh_msg = N_("Refresh");
const char *first_line_msg = N_("First Line");
const char *last_line_msg = N_("Last Line");
#endif
#ifndef DISABLE_BROWSER
const char *to_files_msg = N_("To Files");
+ const char *first_file_msg = N_("First File");
+ const char *last_file_msg = N_("Last File");
#endif
#ifndef DISABLE_HELP
const char *nano_cancel_msg = N_("Cancel the current function");
#endif
#ifndef DISABLE_BROWSER
const char *nano_exitbrowser_msg = N_("Exit from the file browser");
+ const char *nano_firstfile_msg =
+ N_("Go to the first file in the list");
+ const char *nano_lastfile_msg =
+ N_("Go to the last file in the list");
const char *nano_gotodir_msg = N_("Go to directory");
#endif
#endif /* !DISABLE_HELP */
IFHELP(nano_help_msg, NANO_NO_KEY), NANO_HELP_FKEY, NANO_NO_KEY,
VIEW,
#ifndef DISABLE_HELP
- do_help
+ do_help_void
#else
nano_disabled_msg
#endif
, !ISSET(RESTRICTED) ? do_insertfile_void : nano_disabled_msg);
/* Translators: try to keep this string under 10 characters long. */
- sc_init_one(&main_list, NANO_WHEREIS_KEY, N_("Where Is"),
+ sc_init_one(&main_list, NANO_WHEREIS_KEY, whereis_msg,
IFHELP(nano_whereis_msg, NANO_NO_KEY), NANO_WHEREIS_FKEY,
NANO_NO_KEY, VIEW, do_search);
IFHELP(nano_mark_msg, NANO_MARK_ALTKEY), NANO_MARK_FKEY,
NANO_NO_KEY, VIEW, do_mark);
- sc_init_one(&main_list, NANO_NO_KEY, N_("Where Is Next"),
+ /* Translators: try to keep this string under 16 characters long. */
+ sc_init_one(&main_list, NANO_NO_KEY, whereis_next_msg,
IFHELP(nano_whereis_next_msg, NANO_WHEREIS_NEXT_KEY),
NANO_WHEREIS_NEXT_FKEY, NANO_NO_KEY, VIEW, do_research);
#endif
IFHELP(nano_help_msg, NANO_NO_KEY), NANO_HELP_FKEY, NANO_NO_KEY,
VIEW,
#ifndef DISABLE_HELP
- do_help
+ do_help_void
#else
nano_disabled_msg
#endif
IFHELP(nano_help_msg, NANO_NO_KEY), NANO_HELP_FKEY, NANO_NO_KEY,
VIEW,
#ifndef DISABLE_HELP
- do_help
+ do_help_void
#else
nano_disabled_msg
#endif
IFHELP(nano_help_msg, NANO_NO_KEY), NANO_HELP_FKEY, NANO_NO_KEY,
VIEW,
#ifndef DISABLE_HELP
- do_help
+ do_help_void
#else
nano_disabled_msg
#endif
IFHELP(nano_help_msg, NANO_NO_KEY), NANO_HELP_FKEY, NANO_NO_KEY,
VIEW,
#ifndef DISABLE_HELP
- do_help
+ do_help_void
#else
nano_disabled_msg
#endif
IFHELP(nano_help_msg, NANO_NO_KEY), NANO_HELP_FKEY, NANO_NO_KEY,
VIEW,
#ifndef DISABLE_HELP
- do_help
+ do_help_void
#else
nano_disabled_msg
#endif
IFHELP(nano_help_msg, NANO_NO_KEY), NANO_HELP_FKEY, NANO_NO_KEY,
VIEW,
#ifndef DISABLE_HELP
- do_help
+ do_help_void
#else
nano_disabled_msg
#endif
IFHELP(nano_help_msg, NANO_NO_KEY), NANO_HELP_FKEY, NANO_NO_KEY,
VIEW,
#ifndef DISABLE_HELP
- do_help
+ do_help_void
#else
nano_disabled_msg
#endif
IFHELP(nano_help_msg, NANO_NO_KEY), NANO_HELP_FKEY, NANO_NO_KEY,
VIEW,
#ifndef DISABLE_HELP
- do_help
+ do_help_void
#else
nano_disabled_msg
#endif
IFHELP(nano_nextpage_msg, NANO_NO_KEY), NANO_NEXTPAGE_FKEY,
NANO_NO_KEY, VIEW, NULL);
+ sc_init_one(&browser_list, NANO_WHEREIS_KEY, whereis_msg,
+ IFHELP(nano_whereis_msg, NANO_NO_KEY), NANO_NO_KEY, NANO_NO_KEY,
+ VIEW, NULL);
+
+ sc_init_one(&browser_list, NANO_NO_KEY, whereis_next_msg,
+ IFHELP(nano_whereis_next_msg, NANO_WHEREIS_NEXT_KEY),
+ NANO_WHEREIS_NEXT_FKEY, NANO_NO_KEY, VIEW, NULL);
+
/* Translators: try to keep this string under 22 characters long. */
sc_init_one(&browser_list, NANO_GOTOLINE_KEY, N_("Go To Dir"),
IFHELP(nano_gotodir_msg, NANO_GOTOLINE_ALTKEY),
NANO_GOTOLINE_FKEY, NANO_NO_KEY, VIEW, NULL);
+ free_shortcutage(&whereis_file_list);
+
+ sc_init_one(&whereis_file_list, NANO_HELP_KEY, get_help_msg,
+ IFHELP(nano_help_msg, NANO_NO_KEY), NANO_HELP_FKEY, NANO_NO_KEY,
+ VIEW,
+#ifndef DISABLE_HELP
+ do_browser_help
+#else
+ nano_disabled_msg
+#endif
+ );
+
+ sc_init_one(&whereis_file_list, NANO_CANCEL_KEY, cancel_msg,
+ IFHELP(nano_cancel_msg, NANO_NO_KEY), NANO_NO_KEY, NANO_NO_KEY,
+ VIEW, NULL);
+
+ sc_init_one(&whereis_file_list, NANO_FIRSTFILE_KEY, first_file_msg,
+ IFHELP(nano_firstfile_msg, NANO_NO_KEY), NANO_FIRSTFILE_FKEY,
+ NANO_NO_KEY, VIEW, do_first_file);
+
+ sc_init_one(&whereis_file_list, NANO_LASTFILE_KEY, last_file_msg,
+ IFHELP(nano_lastfile_msg, NANO_NO_KEY), NANO_LASTFILE_FKEY,
+ NANO_NO_KEY, VIEW, do_last_file);
+
+#ifndef NANO_SMALL
+ sc_init_one(&whereis_file_list, NANO_NO_KEY, case_sens_msg,
+ IFHELP(nano_case_msg, TOGGLE_CASE_KEY), NANO_NO_KEY,
+ NANO_NO_KEY, VIEW, NULL);
+
+ sc_init_one(&whereis_file_list, NANO_NO_KEY, backwards_msg,
+ IFHELP(nano_reverse_msg, TOGGLE_BACKWARDS_KEY), NANO_NO_KEY,
+ NANO_NO_KEY, VIEW, NULL);
+#endif
+
+#ifdef HAVE_REGEX_H
+ sc_init_one(&whereis_file_list, NANO_NO_KEY, regexp_msg,
+ IFHELP(nano_regexp_msg, NANO_REGEXP_KEY), NANO_NO_KEY,
+ NANO_NO_KEY, VIEW, NULL);
+#endif
+
+#ifndef NANO_SMALL
+ sc_init_one(&whereis_file_list, NANO_PREVLINE_KEY, history_msg,
+ IFHELP(nano_history_msg, NANO_NO_KEY), NANO_NO_KEY, NANO_NO_KEY,
+ VIEW, NULL);
+#endif
+
free_shortcutage(&gotodir_list);
sc_init_one(&gotodir_list, NANO_HELP_KEY, get_help_msg,
IFHELP(nano_help_msg, NANO_NO_KEY), NANO_HELP_FKEY, NANO_NO_KEY,
VIEW,
#ifndef DISABLE_HELP
- do_help
+ do_help_void
#else
nano_disabled_msg
#endif
static char *help_text = NULL;
/* The text displayed in the help window. */
-/* Our dynamic, shortcut-list-compliant help function. */
-void do_help(void)
+/* Our dynamic, shortcut-list-compliant help function. refresh_func is
+ * the function we will call to refresh the edit window.*/
+void do_help(void (*refresh_func)(void))
{
int line = 0;
/* The line number in help_text of the first displayed help
bottombars(currshortcut);
curs_set(1);
- edit_refresh();
+ refresh_func();
/* The help_init() at the beginning allocated help_text. Since
* help_text has now been written to the screen, we don't need it
help_text = NULL;
}
+/* Start the help browser for the edit window. */
+void do_help_void(void)
+{
+ do_help(&edit_refresh);
+}
+
+#ifndef DISABLE_BROWSER
+/* Start the help browser for the file browser. */
+void do_browser_help(void)
+{
+ do_help(&browser_refresh);
+}
+#endif
+
/* This function allocates help_text, and stores the help string in it.
* help_text should be NULL initially. */
void help_init(void)
"in the file browser:\n\n");
htx[1] = NULL;
htx[2] = NULL;
+ } else if (currshortcut == whereis_file_list) {
+ htx[0] = N_("Browser Search Command Help Text\n\n "
+ "Enter the words or characters you would like to "
+ "search for, and then press Enter. If there is a "
+ "match for the text you entered, the screen will be "
+ "updated to the location of the nearest match for the "
+ "search string.\n\n The previous search string will be "
+ "shown in brackets after the search prompt. Hitting "
+ "Enter without entering any text will perform the "
+ "previous search.\n\n ");
+ htx[1] = N_("The following function keys are available in "
+ "Browser Search mode:\n\n");
+ htx[2] = NULL;
} else if (currshortcut == gotodir_list) {
htx[0] = N_("Browser Go To Directory Help Text\n\n "
"Enter the name of the directory you would like to "
#define NANO_SPELL_FKEY KEY_F(12)
#define NANO_FIRSTLINE_KEY NANO_PREVPAGE_KEY
#define NANO_FIRSTLINE_FKEY NANO_PREVPAGE_FKEY
+#define NANO_FIRSTFILE_KEY NANO_FIRSTLINE_KEY
+#define NANO_FIRSTFILE_FKEY NANO_FIRSTLINE_FKEY
#define NANO_LASTLINE_KEY NANO_NEXTPAGE_KEY
#define NANO_LASTLINE_FKEY NANO_NEXTPAGE_FKEY
+#define NANO_LASTFILE_KEY NANO_LASTLINE_KEY
+#define NANO_LASTFILE_FKEY NANO_LASTLINE_FKEY
#define NANO_REFRESH_KEY NANO_CONTROL_L
#define NANO_JUSTIFY_KEY NANO_CONTROL_J
#define NANO_JUSTIFY_FKEY KEY_F(4)
#endif
#ifndef DISABLE_BROWSER
extern shortcut *browser_list;
+extern shortcut *whereis_file_list;
extern shortcut *gotodir_list;
#endif
void browser_init(const char *path, DIR *dir);
void parse_browser_input(int *kbinput, bool *meta_key, bool *func_key);
void browser_refresh(void);
+int filesearch_init(void);
+bool findnextfile(bool no_sameline, size_t begin, const char *needle);
+void findnextfile_wrap_reset(void);
+void filesearch_abort(void);
+void do_filesearch(void);
+void do_fileresearch(void);
+void do_first_file(void);
+void do_last_file(void);
void striponedir(char *path);
#endif
/* Public functions in help.c. */
#ifndef DISABLE_HELP
-void do_help(void);
+void do_help(void (*refresh_func)(void));
+void do_help_void(void);
+#ifndef DISABLE_BROWSER
+void do_browser_help(void);
+#endif
void help_init(void);
size_t help_line_len(const char *ptr);
#endif