From c96bafbb4cb535b81f7bb50ae75302e6a703e531 Mon Sep 17 00:00:00 2001
From: Rishabh Dave
Date: Mon, 5 Dec 2016 12:20:01 +0100
Subject: [PATCH 01/10] new feature: add a search facility to help
Allow the user to search in a help text with ^W.
This fulfills https://savannah.gnu.org/bugs/?28994.
---
src/files.c | 20 ++++--
src/global.c | 32 +++++----
src/help.c | 215 ++++++++++++++++++++++++++++++++++++++++-------------------
src/nano.c | 4 +-
src/nano.h | 3 +-
src/prompt.c | 5 +-
src/proto.h | 5 ++
src/search.c | 3 +-
src/winio.c | 21 +++---
9 files changed, 204 insertions(+), 104 deletions(-)
diff --git a/src/files.c b/src/files.c
index 8c4b5b83..cd2fc6a5 100644
--- a/src/files.c
+++ b/src/files.c
@@ -470,7 +470,7 @@ bool open_buffer(const char *filename, bool undoable)
if (new_buffer) {
make_new_buffer();
- if (has_valid_path(realname)) {
+ if (!inhelp && has_valid_path(realname)) {
#ifndef NANO_TINY
if (ISSET(LOCKING) && filename[0] != '\0') {
/* When not overriding an existing lock, discard the buffer. */
@@ -489,7 +489,7 @@ bool open_buffer(const char *filename, bool undoable)
/* If the filename isn't blank, and we are not in NOREAD_MODE,
* open the file. Otherwise, treat it as a new file. */
rc = (filename[0] != '\0' && !ISSET(NOREAD_MODE)) ?
- open_file(realname, new_buffer, FALSE, &f) : -2;
+ open_file(realname, new_buffer, inhelp, &f) : -2;
/* If we have a file, and we're loading into a new buffer, update
* the filename. */
@@ -590,7 +590,8 @@ void replace_marked_buffer(const char *filename, filestruct *top, size_t top_x,
void display_buffer(void)
{
/* Update the titlebar, since the filename may have changed. */
- titlebar(NULL);
+ if (!inhelp)
+ titlebar(NULL);
#ifndef DISABLE_COLOR
/* Make sure we're using the buffer's associated colors. */
@@ -639,9 +640,10 @@ void switch_to_prevnext_buffer(bool to_next)
display_buffer();
/* Indicate the switch on the statusbar. */
- statusline(HUSH, _("Switched to %s"),
- ((openfile->filename[0] == '\0') ?
- _("New Buffer") : openfile->filename));
+ if (!inhelp)
+ statusline(HUSH, _("Switched to %s"),
+ ((openfile->filename[0] == '\0') ?
+ _("New Buffer") : openfile->filename));
#ifdef DEBUG
dump_filestruct(openfile->current);
@@ -908,6 +910,10 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable,
/* Set the desired x position at the end of what was inserted. */
openfile->placewewant = xplustabs();
+ /* If we've read a help file, don't give any feedback. */
+ if (inhelp)
+ return;
+
if (!writable)
statusline(ALERT, _("File '%s' is unwritable"), filename);
#ifndef NANO_TINY
@@ -1001,7 +1007,7 @@ int open_file(const char *filename, bool newfie, bool quiet, FILE **f)
if (*f == NULL) {
statusline(ALERT, _("Error reading %s: %s"), filename, strerror(errno));
close(fd);
- } else
+ } else if (!inhelp)
statusbar(_("Reading File"));
}
diff --git a/src/global.c b/src/global.c
index d2e5eb20..8bed7701 100644
--- a/src/global.c
+++ b/src/global.c
@@ -27,6 +27,11 @@
#include "assert.h"
/* Global variables. */
+bool inhelp = FALSE;
+ /* Indicates we are displaying the help text. */
+char *title = NULL;
+ /* Title of the help text. */
+
#ifndef NANO_TINY
volatile sig_atomic_t the_window_resized = FALSE;
/* Set to TRUE by the handler whenever a SIGWINCH occurs. */
@@ -711,6 +716,9 @@ void shortcut_init(void)
add_to_funcs(total_refresh, MHELP, refresh_tag, "x", 0, VIEW);
+ add_to_funcs(do_search, MHELP, whereis_tag, "x", 0, VIEW);
+ add_to_funcs(do_research, MHELP, whereis_next_tag, "x", 0, VIEW);
+
add_to_funcs(do_up_void, MHELP, prev_line_tag, "x", 0, VIEW);
add_to_funcs(do_down_void, MHELP, next_line_tag, "x" , 0, VIEW);
#endif
@@ -1035,8 +1043,8 @@ void shortcut_init(void)
/* Start associating key combos with functions in specific menus. */
- add_to_sclist(MMOST, "^G", 0, do_help_void, 0);
- add_to_sclist(MMOST, "F1", 0, do_help_void, 0);
+ add_to_sclist(MMOST & ~MFINDINHELP, "^G", 0, do_help_void, 0);
+ add_to_sclist(MMOST & ~MFINDINHELP, "F1", 0, do_help_void, 0);
add_to_sclist(MMAIN|MHELP|MBROWSER, "^X", 0, do_exit, 0);
add_to_sclist(MMAIN|MHELP|MBROWSER, "F2", 0, do_exit, 0);
add_to_sclist(MMAIN, "^O", 0, do_writeout_void, 0);
@@ -1044,8 +1052,8 @@ void shortcut_init(void)
add_to_sclist(MMAIN, "^R", 0, do_insertfile_void, 0);
add_to_sclist(MMAIN, "F5", 0, do_insertfile_void, 0);
add_to_sclist(MMAIN, "Ins", 0, do_insertfile_void, 0);
- add_to_sclist(MMAIN|MBROWSER, "^W", 0, do_search, 0);
- add_to_sclist(MMAIN|MBROWSER, "F6", 0, do_search, 0);
+ add_to_sclist(MMAIN|MBROWSER|MHELP, "^W", 0, do_search, 0);
+ add_to_sclist(MMAIN|MBROWSER|MHELP, "F6", 0, do_search, 0);
add_to_sclist(MMAIN, "^\\", 0, do_replace, 0);
add_to_sclist(MMAIN, "M-R", 0, do_replace, 0);
add_to_sclist(MMAIN, "F14", 0, do_replace, 0);
@@ -1083,8 +1091,8 @@ void shortcut_init(void)
add_to_sclist(MMAIN|MHELP, "M-/", 0, do_last_line, 0);
add_to_sclist(MMAIN|MHELP, "^End", CONTROL_END, do_last_line, 0);
add_to_sclist(MMAIN|MHELP, "M-?", 0, do_last_line, 0);
- add_to_sclist(MMAIN|MBROWSER, "M-W", 0, do_research, 0);
- add_to_sclist(MMAIN|MBROWSER, "F16", 0, do_research, 0);
+ add_to_sclist(MMAIN|MBROWSER|MHELP, "M-W", 0, do_research, 0);
+ add_to_sclist(MMAIN|MBROWSER|MHELP, "F16", 0, do_research, 0);
#ifndef NANO_TINY
add_to_sclist(MMAIN, "M-]", 0, do_find_bracket, 0);
add_to_sclist(MMAIN, "M-A", 0, do_mark, 0);
@@ -1227,17 +1235,17 @@ void shortcut_init(void)
add_to_sclist(MWHEREIS, "^T", 0, do_gotolinecolumn_void, 0);
add_to_sclist(MGOTOLINE, "^T", 0, gototext_void, 0);
#ifndef DISABLE_HISTORIES
- add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE, "^P", 0, get_history_older_void, 0);
- add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE, "^N", 0, get_history_newer_void, 0);
+ add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE|MFINDINHELP, "^P", 0, get_history_older_void, 0);
+ add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE|MFINDINHELP, "^N", 0, get_history_newer_void, 0);
#ifdef ENABLE_UTF8
if (using_utf8()) {
- add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE, "\xE2\x86\x91", KEY_UP, get_history_older_void, 0);
- add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE, "\xE2\x86\x93", KEY_DOWN, get_history_newer_void, 0);
+ add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE|MFINDINHELP, "\xE2\x86\x91", KEY_UP, get_history_older_void, 0);
+ add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE|MFINDINHELP, "\xE2\x86\x93", KEY_DOWN, get_history_newer_void, 0);
} else
#endif
{
- add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE, "Up", KEY_UP, get_history_older_void, 0);
- add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE, "Down", KEY_DOWN, get_history_newer_void, 0);
+ add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE|MFINDINHELP, "Up", KEY_UP, get_history_older_void, 0);
+ add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE|MFINDINHELP, "Down", KEY_DOWN, get_history_newer_void, 0);
}
#endif
#ifndef DISABLE_BROWSER
diff --git a/src/help.c b/src/help.c
index a672d90a..e96340a7 100644
--- a/src/help.c
+++ b/src/help.c
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#ifndef DISABLE_HELP
@@ -34,31 +35,90 @@ static char *end_of_intro = NULL;
/* The point in the help text where the introductory paragraphs end
* and the shortcut descriptions begin. */
+const char *beg_of_intro = NULL;
+ /* The point in the help text where the introductory paragraphs
+ * begin. */
+
+char *tempfilename = NULL;
+ /* Name of the safe temporary file that we will use for wrapping
+ * and writing the help text. */
+
+/* Writes the hard wrapped help text in the temp file and displays it. */
+void display_the_help_text(bool redisplaying)
+{
+ int line_size;
+ const char *ptr = beg_of_intro;
+ /* The current line of the help text. */
+ FILE *fp = fopen(tempfilename, "w+b");
+
+ if (fp == NULL) {
+ statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
+ return;
+ }
+
+ /* Wrap and copy the rest of the help_text into the temporary file. */
+ while (strlen(ptr) > 0) {
+ line_size = help_line_len(ptr);
+ fwrite(ptr, sizeof(char), line_size, fp);
+ ptr += line_size;
+
+ /* Hard wrap the lines in the help text. */
+ if (*ptr != '\n')
+ fwrite("\n", sizeof(char), 1, fp);
+ else
+ while (*ptr == '\n')
+ fwrite(ptr++, sizeof(char), 1, fp);
+ }
+ fclose(fp);
+
+ if (redisplaying)
+ close_buffer();
+
+ if (!ISSET(MULTIBUFFER)) {
+ SET(MULTIBUFFER);
+ open_buffer(tempfilename, FALSE);
+ UNSET(MULTIBUFFER);
+ } else
+ open_buffer(tempfilename, FALSE);
+
+ display_buffer();
+}
+
/* Our main help-viewer function. */
void do_help(void)
{
int kbinput = ERR;
bool old_no_help = ISSET(NO_HELP);
- size_t line = 0;
- /* The line number in help_text of the first displayed help
- * line. This variable is zero-based. */
- size_t last_line = 0;
- /* The line number in help_text of the last help line. This
- * variable is zero-based. */
+ bool was_whitespace = ISSET(WHITESPACE_DISPLAY);
int oldmenu = currmenu;
/* The menu we were called from. */
const char *ptr;
/* The current line of the help text. */
- size_t old_line = (size_t)-1;
- /* The line we were on before the current line. */
functionptrtype func;
/* The function of the key the user typed in. */
+ FILE *fp;
+ int line_size;
+ int saved_margin = 0;
+ /* For avoiding the line numbers on the help screen. */
+ char *saved_answer = (answer != NULL) ? strdup(answer) : NULL;
+ /* Store current answer when user invokes help at the prompt. */
+
+ inhelp = TRUE;
- /* Don't show a cursor in the help screen. */
- curs_set(0);
- blank_edit();
blank_statusbar();
+ /* Get a safe temporary file for displaying the help text. If we can't
+ * obtain one, return. */
+ tempfilename = safe_tempfile(&fp);
+ fclose(fp);
+ if (tempfilename == NULL) {
+ statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
+
+ inhelp = FALSE;
+ free(saved_answer);
+ return;
+ }
+
/* Set help_text as the string to display. */
help_init();
@@ -71,61 +131,48 @@ void do_help(void)
window_init();
}
+ UNSET(WHITESPACE_DISPLAY);
+
bottombars(MHELP);
wnoutrefresh(bottomwin);
- while (TRUE) {
- size_t i;
-
- ptr = help_text;
-
- /* Find the line number of the last line of the help text. */
- for (last_line = 0; *ptr != '\0'; last_line++) {
- ptr += help_line_len(ptr);
- if (*ptr == '\n')
- ptr++;
- }
-
- if (last_line > 0)
- last_line--;
-
- /* Redisplay if the text was scrolled or an invalid key was pressed. */
- if (line != old_line || kbinput == ERR) {
- blank_edit();
-
- ptr = help_text;
-
- /* Advance in the text to the first line to be displayed. */
- for (i = 0; i < line; i++) {
- ptr += help_line_len(ptr);
- if (*ptr == '\n')
- ptr++;
- }
-
- /* Now display as many lines as the window will hold. */
- for (i = 0; i < editwinrows && *ptr != '\0'; i++) {
- size_t j = help_line_len(ptr);
-
- mvwaddnstr(edit, i, 0, ptr, j);
- ptr += j;
- if (*ptr == '\n')
- ptr++;
- }
- }
+#ifdef ENABLE_LINENUMBERS
+ if (ISSET(LINE_NUMBERS)) {
+ saved_margin = margin;
+ margin = 0;
+ UNSET(LINE_NUMBERS);
+ }
+#endif
- wnoutrefresh(edit);
+ /* Extract title from help_text and display it. */
+ title = charalloc(MAX_BUF_SIZE * sizeof(char));
+ ptr = help_text;
+ line_size = break_line(ptr, 74, TRUE);
+ strncpy(title, ptr, line_size);
+ title[line_size] = '\0';
+ titlebar(title);
+
+ /* Skip the title and point to the beginning of the introductory
+ * paragraphs. */
+ ptr += line_size;
+ while (*ptr == '\n')
+ ++ptr;
+ beg_of_intro = ptr;
+
+ display_the_help_text(FALSE);
+ curs_set(0);
- old_line = line;
+ while (TRUE) {
+ edit_refresh();
lastmessage = HUSH;
+ focusing = TRUE;
kbinput = get_kbinput(edit);
#ifndef NANO_TINY
- if (kbinput == KEY_WINCH) {
- kbinput = ERR;
- continue; /* Redraw the screen. */
- }
+ if (kbinput == KEY_WINCH)
+ continue;
#endif
#ifndef DISABLE_MOUSE
@@ -141,31 +188,47 @@ void do_help(void)
if (func == total_refresh) {
total_redraw();
} else if (func == do_up_void) {
- if (line > 0)
- line--;
+ do_up(TRUE);
} else if (func == do_down_void) {
- if (line + (editwinrows - 1) < last_line)
- line++;
+ if (openfile->edittop->lineno + editwinrows < openfile->
+ filebot->lineno)
+ do_down(TRUE);
} else if (func == do_page_up) {
- if (line > editwinrows - 2)
- line -= editwinrows - 2;
- else
- line = 0;
+ do_page_up();
} else if (func == do_page_down) {
- if (line + (editwinrows - 1) < last_line)
- line += editwinrows - 2;
+ do_page_down();
} else if (func == do_first_line) {
- line = 0;
+ do_first_line();
} else if (func == do_last_line) {
- if (line + (editwinrows - 1) < last_line)
- line = last_line - (editwinrows - 1);
+ do_last_line();
+ } else if (func == do_search) {
+ do_search();
+ bottombars(MHELP);
+ wnoutrefresh(bottomwin);
+ curs_set(1);
+ } else if (func == do_research) {
+ do_research();
+ currmenu = MHELP;
+ curs_set(1);
} else if (func == do_exit) {
/* Exit from the help viewer. */
+ close_buffer();
break;
} else
unbound_key(kbinput);
}
+
+ /* We're exiting from the help screen. So, restore the flags and the
+ * original menu, refresh the entire screen and deallocate the memory. */
+
+#ifdef ENABLE_LINENUMBERS
+ if (saved_margin != 0) {
+ margin = saved_margin;
+ SET(LINE_NUMBERS);
+ }
+#endif
+
if (old_no_help) {
blank_bottombars();
wnoutrefresh(bottomwin);
@@ -175,14 +238,26 @@ void do_help(void)
} else
bottombars(oldmenu);
+ if (was_whitespace)
+ SET(WHITESPACE_DISPLAY);
+
+ free(title);
+ title = NULL;
+ inhelp = FALSE;
+
#ifndef DISABLE_BROWSER
if (oldmenu == MBROWSER || oldmenu == MWHEREISFILE || oldmenu == MGOTODIR)
browser_refresh();
else
#endif
- edit_refresh();
+ total_refresh();
+
+ free(answer);
+ answer = saved_answer;
+
+ remove(tempfilename);
+ free(tempfilename);
- /* We're exiting from the help screen. */
free(help_text);
}
diff --git a/src/nano.c b/src/nano.c
index ae044be2..cae8a8ab 100644
--- a/src/nano.c
+++ b/src/nano.c
@@ -1419,7 +1419,7 @@ void do_toggle(int flag)
enabled = !enabled;
statusline(HUSH, "%s %s", _(flagtostr(flag)),
- enabled ? _("enabled") : _("disabled"));
+ enabled ? _("enabled") : _("disabled"));
}
/* Bleh. */
@@ -1564,7 +1564,7 @@ void unbound_key(int code)
statusline(ALERT, _("Unbound key: M-%c"), toupper(code));
} else if (code < 0x20)
statusline(ALERT, _("Unbound key: ^%c"), code + 0x40);
- else
+ else if (currmenu != MHELP)
statusline(ALERT, _("Unbound key: %c"), code);
}
diff --git a/src/nano.h b/src/nano.h
index 37226adb..10f9e4bc 100644
--- a/src/nano.h
+++ b/src/nano.h
@@ -538,9 +538,10 @@ enum
#define MGOTODIR (1<<12)
#define MYESNO (1<<13)
#define MLINTER (1<<14)
+#define MFINDINHELP (1<<15)
/* This is an abbreviation for all menus except Help and YesNo. */
#define MMOST (MMAIN|MWHEREIS|MREPLACE|MREPLACEWITH|MGOTOLINE|MWRITEFILE|MINSERTFILE|\
- MEXTCMD|MBROWSER|MWHEREISFILE|MGOTODIR|MSPELL|MLINTER)
+ MEXTCMD|MBROWSER|MWHEREISFILE|MGOTODIR|MFINDINHELP|MSPELL|MLINTER)
/* Basic control codes. */
#define TAB_CODE 0x09
diff --git a/src/prompt.c b/src/prompt.c
index add814d8..161c77af 100644
--- a/src/prompt.c
+++ b/src/prompt.c
@@ -611,8 +611,9 @@ int do_prompt(bool allow_tabs, bool allow_files,
int retval;
functionptrtype func = NULL;
bool listed = FALSE;
- /* Save a possible current statusbar x position. */
+ /* Save a possible current statusbar x position and prompt. */
size_t was_statusbar_x = statusbar_x;
+ char *saved_prompt = prompt;
bottombars(menu);
@@ -635,7 +636,7 @@ int do_prompt(bool allow_tabs, bool allow_files,
refresh_func);
free(prompt);
- prompt = NULL;
+ prompt = saved_prompt;
#ifndef NANO_TINY
if (retval == KEY_WINCH)
diff --git a/src/proto.h b/src/proto.h
index fa9df316..8a923eb4 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -24,6 +24,10 @@
#include "nano.h"
/* All external variables. See global.c for their descriptions. */
+
+extern bool inhelp;
+extern char *title;
+
#ifndef NANO_TINY
extern volatile sig_atomic_t the_window_resized;
#endif
@@ -337,6 +341,7 @@ void thanks_for_all_the_fish(void);
/* All functions in help.c. */
#ifndef DISABLE_HELP
+void display_the_help_text(bool redisplaying);
void do_help(void);
void help_init(void);
functionptrtype parse_help_input(int *kbinput);
diff --git a/src/search.c b/src/search.c
index e6867617..f62ae138 100644
--- a/src/search.c
+++ b/src/search.c
@@ -143,7 +143,8 @@ int search_init(bool replacing, bool use_answer)
/* This is now one simple call. It just does a lot. */
i = do_prompt(FALSE, FALSE,
- replacing ? MREPLACE : MWHEREIS, backupstring,
+ inhelp ? MFINDINHELP : (replacing ? MREPLACE : MWHEREIS),
+ backupstring,
#ifndef DISABLE_HISTORIES
&search_history,
#endif
diff --git a/src/winio.c b/src/winio.c
index a7f6c931..162f8e5e 100644
--- a/src/winio.c
+++ b/src/winio.c
@@ -1960,10 +1960,9 @@ char *display_string(const char *buf, size_t start_col, size_t span,
/* If path is NULL, we're in normal editing mode, so display the current
* version of nano, the current filename, and whether the current file
- * has been modified on the titlebar. If path isn't NULL, we're in the
- * file browser, and path contains the directory to start the file
- * browser in, so display the current version of nano and the contents
- * of path on the titlebar. */
+ * has been modified on the titlebar. If path isn't NULL, we're either
+ * in the file browser or the help viewer, so show either the current
+ * directory or the title of help text, that is: whatever is in path. */
void titlebar(const char *path)
{
size_t verlen, prefixlen, pathlen, statelen;
@@ -1995,12 +1994,13 @@ void titlebar(const char *path)
* then sacrifice the prefix, and only then start dottifying. */
/* Figure out the path, prefix and state strings. */
+ if (inhelp)
+ state = _("Help");
#ifndef DISABLE_BROWSER
- if (path != NULL)
+ else if (path != NULL)
prefix = _("DIR:");
- else
#endif
- {
+ else {
if (openfile->filename[0] == '\0')
path = _("New Buffer");
else {
@@ -3155,8 +3155,11 @@ void total_redraw(void)
void total_refresh(void)
{
total_redraw();
- titlebar(NULL);
- edit_refresh();
+ titlebar(title);
+ if (inhelp)
+ display_the_help_text(TRUE);
+ else
+ edit_refresh();
bottombars(currmenu);
}
--
2.12.1