diff --git a/ChangeLog b/ChangeLog
index bfbb9020adf098d3f168eaaa4c60919fdf257e68..aff1fcb28f845f4792acf91a25ab7af84a0a526f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -120,6 +120,11 @@ CVS code -
   do_browser()
 	- Call check_statblank() instead of blanking the statusbar
 	  unconditionally, for consistency. (David Benbennick)
+- global.c:
+  shortcut_init()
+	- Don't assign any handler functions to the help browser keys,
+	  as the help browser handles them all internally. (David
+	  Benbennick)
 - move.c:
   do_first_line(), do_last_line()
 	- Move these functions here from winio.c. (DLR)
@@ -354,6 +359,10 @@ CVS code -
 	  that slang and other non-ncurses versions of curses will
 	  properly place the cursor back in the edit window instead of
 	  leaving it at the end of the statusbar. (DLR)
+  do_help()
+	- Overhaul for efficiency, and allow scrolling through the help
+	  via the arrow keys as well as the paging keys. (David
+	  Benbennick)
   do_credits()
 	- Use napms() instead of nanosleep(), as it does the same thing
 	  (aside from taking an argument in milliseconds instead of
diff --git a/src/global.c b/src/global.c
index be8ce563314f2b2ec066280b847c6df596322c84..7ae2b514c5e0a6787c8b3b18b67341f69158de04 100644
--- a/src/global.c
+++ b/src/global.c
@@ -865,15 +865,23 @@ void shortcut_init(int unjustify)
 
     sc_init_one(&help_list, NANO_PREVPAGE_KEY, _("Prev Page"),
 		IFHELP(nano_prevpage_msg, NANO_NO_KEY), NANO_PREVPAGE_FKEY,
-		NANO_NO_KEY, VIEW, do_page_up);
+		NANO_NO_KEY, VIEW, 0);
 
     sc_init_one(&help_list, NANO_NEXTPAGE_KEY, _("Next Page"),
 		IFHELP(nano_nextpage_msg, NANO_NO_KEY), NANO_NEXTPAGE_FKEY,
-		NANO_NO_KEY, VIEW, do_page_down);
+		NANO_NO_KEY, VIEW, 0);
+
+    sc_init_one(&help_list, NANO_PREVLINE_KEY, _("Prev Line"),
+		IFHELP(nano_prevline_msg, NANO_NO_KEY), NANO_NO_KEY,
+		NANO_NO_KEY, VIEW, 0);
+
+    sc_init_one(&help_list, NANO_NEXTLINE_KEY, _("Next Line"),
+		IFHELP(nano_nextline_msg, NANO_NO_KEY), NANO_NO_KEY,
+		NANO_NO_KEY, VIEW, 0);
 
     sc_init_one(&help_list, NANO_EXIT_KEY, _("Exit"),
 		IFHELP(nano_exit_msg, NANO_NO_KEY), NANO_EXIT_FKEY,
-		NANO_NO_KEY, VIEW, do_exit);
+		NANO_NO_KEY, VIEW, 0);
 #endif
 
     free_shortcutage(&writefile_list);
diff --git a/src/winio.c b/src/winio.c
index 601b63011a87e40ccfb2bc0665aa58fef18ee11e..e09e74367d91ed98bf8f2def6be34be8d4b983be 100644
--- a/src/winio.c
+++ b/src/winio.c
@@ -3019,12 +3019,23 @@ int line_len(const char *ptr)
  * nothing, and dynamic! */
 int do_help(void)
 {
-    int i, page = 0, kbinput = ERR, meta_key, no_more = 0;
-    int no_help_flag = FALSE;
-    const shortcut *oldshortcut;
+    int line = 0;
+	/* The line number in help_text of the first displayed help line.
+	 * This variable is zero-based. */
+    int no_more = 0;
+	/* no_more means the end of the help text is shown, so don't go down
+	 * any more. */
+    int kbinput = ERR, meta_key;
+
+    int no_help_flag = ISSET(NO_HELP);
+    int old_cursor = curs_set(0);
+#ifndef DISABLE_MOUSE
+    const shortcut *oldshortcut = currshortcut;
+	/* We will set currshortcut to allow clicking on the help
+	   screen shortcut list. */
+#endif
 
     blank_edit();
-    curs_set(0);
     wattroff(bottomwin, A_REVERSE);
     blank_statusbar();
 
@@ -3032,51 +3043,65 @@ int do_help(void)
     help_init();
     assert(help_text != NULL);
 
-    oldshortcut = currshortcut;
-
+#ifndef DISABLE_MOUSE
+    /* Set currshortcut to allow clicking on the help screen shortcut
+     * list, AFTER help_init(). */
     currshortcut = help_list;
+#endif
 
     if (ISSET(NO_HELP)) {
-
 	/* Well, if we're going to do this, we should at least do it the
 	 * right way. */
-	no_help_flag = TRUE;
 	UNSET(NO_HELP);
 	window_init();
-	bottombars(help_list);
-
-    } else
-	bottombars(help_list);
+    }
+    bottombars(help_list);
 
     do {
+	int i;
+	int old_line = line;
+	    /* We redisplay the help only if it moved. */
 	const char *ptr = help_text;
 
 	switch (kbinput) {
 #ifndef DISABLE_MOUSE
-	case KEY_MOUSE:
-	    do_mouse();
-	    break;
+	    case KEY_MOUSE:
+		do_mouse();
+		break;
 #endif
-	case NANO_NEXTPAGE_KEY:
-	case NANO_NEXTPAGE_FKEY:
-	    if (!no_more) {
-		blank_edit();
-		page++;
-	    }
-	    break;
-	case NANO_PREVPAGE_KEY:
-	case NANO_PREVPAGE_FKEY:
-	    if (page > 0) {
-		no_more = 0;
-		blank_edit();
-		page--;
-	    }
-	    break;
+	    case NANO_NEXTPAGE_KEY:
+	    case NANO_NEXTPAGE_FKEY:
+		if (!no_more)
+		    line += editwinrows - 2;
+		break;
+	    case NANO_PREVPAGE_KEY:
+	    case NANO_PREVPAGE_FKEY:
+		if (line > 0) {
+		    line -= editwinrows - 2;
+		    if (line < 0)
+			line = 0;
+		}
+		break;
+	    case NANO_PREVLINE_KEY:
+		if (line > 0)
+		    line--;
+		break;
+	    case NANO_NEXTLINE_KEY:
+		if (!no_more)
+		    line++;
+		break;
 	}
 
+	if (line == old_line && kbinput != ERR)
+	    goto skip_redisplay;
+
+	blank_edit();
+
+	assert(COLS > 5);
+
 	/* Calculate where in the text we should be, based on the
 	 * page. */
-	for (i = 1; i < page * (editwinrows - 1); i++) {
+	for (i = 0; i < line; i++) {
 	    ptr += line_len(ptr);
 	    if (*ptr == '\n')
 		ptr++;
@@ -3090,14 +3115,15 @@ int do_help(void)
 	    if (*ptr == '\n')
 		ptr++;
 	}
+	no_more = (*ptr == '\0');
 
-	if (*ptr == '\0') {
-	    no_more = 1;
-	    continue;
-	}
-    } while ((kbinput = get_kbinput(edit, &meta_key)) != NANO_EXIT_KEY && kbinput != NANO_EXIT_FKEY);
+  skip_redisplay:
+	kbinput = get_kbinput(edit, &meta_key);
+    } while (kbinput != NANO_EXIT_KEY && kbinput != NANO_EXIT_FKEY);
 
+#ifndef DISABLE_MOUSE
     currshortcut = oldshortcut;
+#endif
 
     if (no_help_flag) {
 	blank_bottombars();
@@ -3107,7 +3133,7 @@ int do_help(void)
     } else
 	bottombars(currshortcut);
 
-    curs_set(1);
+    curs_set(old_cursor);
     edit_refresh();
 
     /* The help_init() at the beginning allocated help_text, which has