Commit 90bd25c1 authored by Rishabh Dave's avatar Rishabh Dave Committed by Benno Schulenberg
Browse files

new feature: add a search facility to the help viewer

Allow the user to search in a help text with ^W and M-W.

Achieve this by not writing the help text directly to the screen
but first writing it to a temporary file and then opening this file
in a new buffer, and treating it specially: the normal file-reading
feedback is suppressed, the titlebar shows the headline of the text,
the cursor is hidden, and the menu is limited to just the up and down
movements and searching.

This fulfills https://savannah.gnu.org/bugs/?28994

.
Signed-off-by: default avatarRishabh Dave <rishabhddave@gmail.com>
No related merge requests found
Showing with 206 additions and 104 deletions
+206 -104
......@@ -465,7 +465,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. */
......@@ -484,7 +484,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. */
......@@ -585,7 +585,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. */
......@@ -634,9 +635,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);
......@@ -903,6 +905,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
......@@ -996,7 +1002,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"));
}
......
......@@ -58,6 +58,11 @@ message_type lastmessage = HUSH;
filestruct *pletion_line = NULL;
/* The line where the last completion was found, if any. */
bool inhelp = FALSE;
/* Whether we are in the help viewer. */
char *title = NULL;
/* When not NULL: the title of the current help text. */
int controlleft, controlright, controlup, controldown, controlhome, controlend;
#ifndef NANO_TINY
int shiftcontrolleft, shiftcontrolright, shiftcontrolup, shiftcontroldown;
......@@ -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|MHELP|MBROWSER, "^W", 0, do_search, 0);
add_to_sclist(MMAIN|MHELP|MBROWSER, "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|MHELP|MBROWSER, "M-W", 0, do_research, 0);
add_to_sclist(MMAIN|MHELP|MBROWSER, "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
......
......@@ -24,6 +24,7 @@
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#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);
}
......
......@@ -1416,7 +1416,7 @@ void do_toggle(int flag)
enabled = !enabled;
statusline(HUSH, "%s %s", _(flagtostr(flag)),
enabled ? _("enabled") : _("disabled"));
enabled ? _("enabled") : _("disabled"));
}
/* Bleh. */
......@@ -1561,7 +1561,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);
}
......
......@@ -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
......
......@@ -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)
......
......@@ -24,6 +24,7 @@
#include "nano.h"
/* All external variables. See global.c for their descriptions. */
#ifndef NANO_TINY
extern volatile sig_atomic_t the_window_resized;
#endif
......@@ -46,6 +47,9 @@ extern message_type lastmessage;
extern filestruct *pletion_line;
extern bool inhelp;
extern char *title;
extern int controlleft;
extern int controlright;
extern int controlup;
......@@ -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);
......
......@@ -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
......
......@@ -1961,10 +1961,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;
......@@ -1996,12 +1995,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 {
......@@ -3142,8 +3142,13 @@ void total_redraw(void)
void total_refresh(void)
{
total_redraw();
titlebar(NULL);
edit_refresh();
titlebar(title);
#ifndef DISABLE_HELP
if (inhelp)
display_the_help_text(TRUE);
else
#endif
edit_refresh();
bottombars(currmenu);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment