]> git.wh0rd.org Git - nano.git/commitdiff
add DB's changes to titlebar() (with a few tweaks of mine) to make it
authorDavid Lawrence Ramsey <pooka109@gmail.com>
Sun, 23 May 2004 21:11:14 +0000 (21:11 +0000)
committerDavid Lawrence Ramsey <pooka109@gmail.com>
Sun, 23 May 2004 21:11:14 +0000 (21:11 +0000)
handle shorter screen widths better and display the filename using
display_string(), my strnlen() equivalent so the new titlebar() will
work on systems without strnlen(), and a few of DB's other minor changes
to make other display-related functions handle shorter screen widths
better, among other things

git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@1754 35c25a1d-7b9e-4130-9fde-d3aeb78583b8

ChangeLog
configure.ac
src/files.c
src/nano.c
src/nano.h
src/proto.h
src/search.c
src/utils.c
src/winio.c

index b2b92083260e2bbbe0676f58c867f65bf03a0d85..ea28c312bfff7292fadc72dd31d680889fc08de9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -63,6 +63,8 @@ CVS code -
          true beginning of the line.  This option is disabled in tiny
          mode.  Changes to do_home(), nanogetstr(), etc. (DLR;
          suggested by Stephan T. Lavavej)
+       - Minor tweaks to the punctuation in some statusbar messages.
+         (DLR)
 - files.c:
   add_open_file()
        - Rearrange the NANO_SMALL #ifdef so that the code to set the
@@ -71,6 +73,9 @@ CVS code -
   do_writeout()
        - Refactor so that no recursion is needed if we try to exit with
          a modified file that has no name when TEMP_OPT is set. (DLR)
+  do_browser()
+       - Call check_statblank() instead of blanking the statusbar
+         unconditionally, for consistency. (David Benbennick)
 - nano.c:
   do_toggle(), finish()
        - Call blank_statusbar() and blank_bottombars() to blank out
@@ -83,12 +88,21 @@ CVS code -
          during wait() and can then call cancel_fork() properly. (DLR)
   do_delete()
        - Tweak for efficiency. (David Benbennick)
+  do_spell()
+       - Tweak for efficiency. (David Benbennick)
+       - Change the statusbar entries used in cases of failure so that
+         they all display the actual error that occurred. (David
+         Benbennick and DLR)
+  do_int_speller(), do_alt_speller()
+       - Make these functions return const char*'s instead of char*'s.
+         (David Benbennick)
   justify_format()
        - Remove redundant assignment. (DLR)
   do_para_search()
        - Remove unneeded edit_update() calls. (David Benbennick)
   do_justify()
-       - Remove unneeded edit_update() calls. (David Benbennick)
+       - Remove unneeded edit_update() calls, and add a few minor
+         efficiency tweaks. (David Benbennick)
        - Simplify an if statement. (DLR)
   do_exit()
        - Refactor so that no recursion is needed if we try to exit with
@@ -170,8 +184,8 @@ CVS code -
          since 1.3.0. (David Benbennick)
 - utils.c:
   is_blank_char()
-       - Add new function is_blank_char() as an isblank() equivalent,
-         since isblank() is a GNU extension. (DLR)
+       - New function used as an isblank() equivalent, since isblank()
+         is a GNU extension. (DLR)
   nstricmp(), nstrnicmp()
        - Add extra blank lines for greater readability, and remove
          unneeded test for n's being less than zero (since it's already
@@ -183,6 +197,9 @@ CVS code -
          nstrnicmp(). (DLR)  David Benbennick: Tweak for efficiency.
        - Include and use only when strcasestr() is unavailable, since
          strcasestr() is a GNU extension. (DLR)
+  nstrnlen()
+       - New function used as a strnlen() equivalent, since strnlen()
+         is a GNU extension. (DLR)
 - winio.c:
   get_verbatim_kbinput()
        - Refactor the output in the DEBUG #ifdef.  It didn't work
@@ -197,11 +214,25 @@ CVS code -
   get_escape_seq_kbinput()
        - Add proper support for the keypad values and escape sequences
          generated by the NumLock glitch. (DLR)
+  get_mouseinput()
+       - Don't ungetch() anything if there's no control key and no meta
+         key defined in the shortcut we clicked. (DLR)
   bottombars()
        - Don't display any more than MAIN_VISIBLE shortcuts.  Adding
          justification of the entire file above made the search
          shortcut list longer than this and hence made the shortcuts in
          it so short as to be almost incomprehensible. (DLR)
+       - Tweak for efficiency and to better handle shorter screen
+         widths. (David Benbennick)
+       - Restructure the if block used for the sentinel key values,
+         dynamically allocate keystr based on the number of columns
+         available, and make sure we can display shortcuts even when
+         the number of available columns is too short for any complete
+         one. (DLR)
+  onekey()
+       - Don't bother padding the displayed shortcuts with spaces.
+         (David Benbennick)
+       - Convert len to a size_t. (DLR)
   edit_add()
        - Minor cosmetic reformatting.  Also remove unused int
          searched_later_lines. (DLR)
@@ -210,9 +241,24 @@ CVS code -
          (David Benbennick)
   blank_titlebar()
        - New function used to blank the titlebar in topwin. (DLR)
+  blank_statusbar_refresh()
+       - Removed, as it's now unnecessary. (David Benbennick)
+  titlebar()
+       - Overhaul to use display_string() to display the filename, and
+         to better handle shorter screen widths.  Also remove
+         now-unneeded wrefresh(topwin) calls. (David Benbennick)
+         DLR: Tweak to reserve enough space for "Modified" in all
+         cases, to make sure that the version message takes up no more
+         more than 1/3 of the available width, and to include a
+         reset_cursor() call so that the cursor is always in the right
+         place.
   bottombars()
        - Call blank_bottombars() instead of blank_bottomwin(). (David
          Benbennick)
+  check_statblank()
+       - Overhaul for efficiency, (David Benbennick)  DLR: Add
+         reset_cursor() call to ensure that the cursor is always in the
+         right place.
   edit_refresh()
        - Remove apparently unneeded leaveok() calls. (David Benbennick)
   statusbar()
@@ -228,9 +274,9 @@ CVS code -
          translations are done after initialization in order to avoid
          an error when compiling with -pedantic. (David Benbennick)
 - configure.ac:
-       - Add tests for isblank() and strcasestr(), and define
-         _GNU_SOURCE so that the tests work properly.  Increase the
-         minimum required autoconf version to 2.54. (DLR)
+       - Add tests for isblank(), strcasestr(), and strnlen(), and
+         define _GNU_SOURCE so that the tests work properly.  Increase
+         the minimum required autoconf version to 2.54. (DLR)
        - Reformat the test programs so that they aren't packed into
          fewer lines than usual, so as to make them easier to read, and
          remove unnecessary inclusion of stdio.h in the slang test
index 18e3fb626f5755b7854512b6b98edfd8dd878319..0c774f88405f0e8af0c08460d204b0d03d725816 100644 (file)
@@ -289,7 +289,7 @@ AC_MSG_WARN([*** Can not use slang when cross-compiling])),
     esac], [AC_MSG_RESULT(no)])
 
 dnl Checks for functions
-AC_CHECK_FUNCS(snprintf vsnprintf isblank strcasecmp strncasecmp strcasestr)
+AC_CHECK_FUNCS(snprintf vsnprintf isblank strcasecmp strncasecmp strcasestr strnlen)
 if test "x$ac_cv_func_snprintf" = "xno" -o "xac_cv_func_vsnprintf" = "xno"
 then
        AM_PATH_GLIB_2_0(2.0.0,,
index d0a803839d11f24fb331f3b9d712e39d0a578f53..ec737597fb17bf1482a603430c4b9c284f3c5ed7 100644 (file)
@@ -1453,7 +1453,7 @@ int write_file(const char *name, int tmp, int append, int nonamechange)
     /* If NOFOLLOW_SYMLINKS is set, it doesn't make sense to prepend or
      * append to a symlink.  Here we warn about the contradiction. */
     if (ISSET(NOFOLLOW_SYMLINKS) && anyexists && S_ISLNK(lst.st_mode)) {
-       statusbar(_("Cannot prepend or append to a symlink with --nofollow set."));
+       statusbar(_("Cannot prepend or append to a symlink with --nofollow set"));
        goto cleanup_and_exit;
     }
 
@@ -2592,7 +2592,7 @@ char *do_browser(const char *inpath)
        char *new_path;
            /* Used by the Go To Directory prompt. */
 
-       blank_statusbar_refresh();
+       check_statblank();
 
 #if !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
        currshortcut = browser_list;
@@ -2951,7 +2951,7 @@ void load_history(void)
             if (errno != ENOENT) {
                /* Don't save history when we quit. */
                UNSET(HISTORYLOG);
-               rcfile_error(_("Unable to open ~/.nano_history file, %s"), strerror(errno));
+               rcfile_error(_("Unable to open ~/.nano_history file: %s"), strerror(errno));
            }
            free(nanohist);
        } else {
@@ -3001,28 +3001,28 @@ void save_history(void)
     if (homenv != NULL || userage != NULL) {
        hist = fopen(nanohist, "wb");
        if (hist == NULL) {
-           rcfile_msg(_("Unable to write ~/.nano_history file, %s"), strerror(errno));
+           rcfile_msg(_("Unable to write ~/.nano_history file: %s"), strerror(errno));
        } else {
            /* set rw only by owner for security ?? */
            chmod(nanohist, S_IRUSR | S_IWUSR);
            /* write oldest first */
-           for (h = search_history.tail ; h->prev ; h = h->prev) {
+           for (h = search_history.tail; h->prev; h = h->prev) {
                h->data = charealloc(h->data, strlen(h->data) + 2);
                strcat(h->data, "\n");
                if (fputs(h->data, hist) == EOF) {
-                   rcfile_msg(_("Unable to write ~/.nano_history file, %s"), strerror(errno));
+                   rcfile_msg(_("Unable to write ~/.nano_history file: %s"), strerror(errno));
                    goto come_from;
                }
            }
            if (fputs("\n", hist) == EOF) {
-                   rcfile_msg(_("Unable to write ~/.nano_history file, %s"), strerror(errno));
+                   rcfile_msg(_("Unable to write ~/.nano_history file: %s"), strerror(errno));
                    goto come_from;
            }
-           for (h = replace_history.tail ; h->prev ; h = h->prev) {
+           for (h = replace_history.tail; h->prev; h = h->prev) {
                h->data = charealloc(h->data, strlen(h->data) + 2);
                strcat(h->data, "\n");
                if (fputs(h->data, hist) == EOF) {
-                   rcfile_msg(_("Unable to write ~/.nano_history file, %s"), strerror(errno));
+                   rcfile_msg(_("Unable to write ~/.nano_history file: %s"), strerror(errno));
                    goto come_from;
                }
            }
index 8246592c958f509d123b2c4c4b503d366e63ada5..d0b5501d4d70045b5d9bfbf74cad6d9c8b7df58b 100644 (file)
@@ -1531,7 +1531,7 @@ int do_int_spell_fix(const char *word)
 
 /* Integrated spell checking using 'spell' program.  Return value: NULL
  * for normal termination, otherwise the error string. */
-char *do_int_speller(char *tempfile_name)
+const char *do_int_speller(char *tempfile_name)
 {
     char *read_buff, *read_buff_ptr, *read_buff_word;
     size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
@@ -1717,7 +1717,7 @@ char *do_int_speller(char *tempfile_name)
 
 /* External spell checking.  Return value: NULL for normal termination,
  * otherwise the error string. */
-char *do_alt_speller(char *tempfile_name)
+const char *do_alt_speller(char *tempfile_name)
 {
     int alt_spell_status, lineno_cur = current->lineno;
     int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
@@ -1814,11 +1814,11 @@ char *do_alt_speller(char *tempfile_name)
 int do_spell(void)
 {
     int i;
-    char *temp, *spell_msg;
+    char *temp = safe_tempnam(0, "nano.");
+    const char *spell_msg;
 
-    if ((temp = safe_tempnam(0, "nano.")) == NULL) {
-       statusbar(_("Could not create a temporary filename: %s"),
-                 strerror(errno));
+    if (temp == NULL) {
+       statusbar(_("Could not create temp file: %s"), strerror(errno));
        return 0;
     }
 
@@ -1830,7 +1830,7 @@ int do_spell(void)
        i = write_file(temp, 1, 0, 0);
 
     if (i == -1) {
-       statusbar(_("Spell checking failed: unable to write temp file!"));
+       statusbar(_("Unable to write temp file: %s"), strerror(errno));
        free(temp);
        return 0;
     }
@@ -1841,19 +1841,18 @@ int do_spell(void)
     add_open_file(1);
 #endif
 
-    if (alt_speller != NULL)
-       spell_msg = do_alt_speller(temp);
-    else
-       spell_msg = do_int_speller(temp);
+    spell_msg = alt_speller != NULL ? do_alt_speller(temp) :
+       do_int_speller(temp);
     unlink(temp);
     free(temp);
 
     if (spell_msg != NULL) {
-       statusbar(_("Spell checking failed: %s"), spell_msg);
+       statusbar(_("Spell checking failed: %s: %s"), spell_msg,
+               strerror(errno));
        return 0;
-    }
+    } else
+       statusbar(_("Finished checking spelling"));
 
-    statusbar(_("Finished checking spelling"));
     return 1;
 }
 #endif /* !DISABLE_SPELLER */
@@ -2436,8 +2435,8 @@ int do_justify(int full_justify)
            int break_pos;
                /* Where we will break the line. */
 
-           indent_len = indent_length(current->data + quote_len) +
-               quote_len
+           indent_len = quote_len + indent_length(current->data +
+               quote_len);
 
            /* justify_format() removes excess spaces from the line, and
             * changes tabs to spaces.  After calling it, we call
@@ -2540,7 +2539,7 @@ int do_justify(int full_justify)
 #ifndef NANO_SMALL
                if (mark_beginbuf == current->next) {
                    if (mark_beginx < indent_len + break_pos) {
-                       mark_beginbuf = current;
+                       mark_beginbuf = current;
                        if (mark_beginx <= indent_len)
                            mark_beginx = line_len + 1;
                        else
@@ -2616,7 +2615,6 @@ int do_justify(int full_justify)
 
     /* Now get a keystroke and see if it's unjustify; if not, unget the
      * keystroke and return. */
-
     {
        int meta_key;
        i = get_kbinput(edit, &meta_key);
@@ -2624,11 +2622,10 @@ int do_justify(int full_justify)
        /* If it was a mouse click, parse it with do_mouse() and it
         * might become the unjustify key.  Else give it back to the
         * input stream. */
-       if (i == KEY_MOUSE)
+       if (i == KEY_MOUSE) {
            do_mouse();
-       else
-           ungetch(i);
-       i = get_kbinput(edit, &meta_key);
+           i = get_kbinput(edit, &meta_key);
+       }
 #endif
     }
 
@@ -2655,7 +2652,6 @@ int do_justify(int full_justify)
            cutbuffer->prev->next = cutbuffer;
        } else
            fileage = cutbuffer;
-       cutbuffer = NULL;
 
        last_par_line->next = NULL;
        free_filestruct(first_par_line);
@@ -2668,14 +2664,13 @@ int do_justify(int full_justify)
        mark_beginx = mark_beginx_save;
 #endif
        flags = flags_save;
-       if (!ISSET(MODIFIED)) {
+       if (!ISSET(MODIFIED))
            titlebar(NULL);
-           wrefresh(topwin);
-       }
        edit_refresh();
     }
     cutbuffer = cutbuffer_save;
-    blank_statusbar_refresh();
+    /* Note that now cutbottom is invalid, but that's okay. */
+    blank_statusbar();
     /* Display the shortcut list with UnCut. */
     shortcut_init(0);
     display_main_list();
index c979a27d194e3f0acf5b9c085c5bc8904cf32fdd..3a9386e6494248165c1fd2c541445f509e418f9c 100644 (file)
@@ -92,8 +92,8 @@
 # endif
 #endif
 
-/* If no isblank(), strcasecmp(), strncasecmp(), or strcasestr(), use
- * the versions we have. */
+/* If no isblank(), strcasecmp(), strncasecmp(), strcasestr(), or
+ * strnlen(), use the versions we have. */
 #ifndef HAVE_ISBLANK
 #define isblank is_blank_char
 #endif
 #define strcasestr nstristr
 #endif
 
+#ifndef HAVE_STRNLEN
+#define strnlen nstrnlen
+#endif
+
 /* Assume ERR is defined as -1.  To avoid duplicate case values when
  * some key definitions are missing, we have to set all of these, and
  * all of the special sentinel values below, to different negative
index a3cf85c271c83348fcecd77e3686198c53362029..becfc7e28cbf99cb9605bc303e7be0155a89b15a 100644 (file)
@@ -295,8 +295,8 @@ int do_wrap(filestruct *inptr);
 #endif
 #ifndef DISABLE_SPELLER
 int do_int_spell_fix(const char *word);
-char *do_int_speller(char *tempfile_name);
-char *do_alt_speller(char *tempfile_name);
+const char *do_int_speller(char *tempfile_name);
+const char *do_alt_speller(char *tempfile_name);
 int do_spell(void);
 #endif
 #if !defined(DISABLE_WRAPPING) && !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
@@ -447,6 +447,9 @@ const char *revstrstr(const char *haystack, const char *needle, const
 const char *revstristr(const char *haystack, const char *needle, const
        char *rev_start);
 #endif
+#ifndef HAVE_STRNLEN
+size_t nstrnlen(const char *s, size_t maxlen);
+#endif
 const char *strstrwrapper(const char *haystack, const char *needle,
        const char *start);
 void nperror(const char *s);
@@ -484,7 +487,6 @@ size_t strlenpt(const char *buf);
 void blank_titlebar(void);
 void blank_edit(void);
 void blank_statusbar(void);
-void blank_statusbar_refresh(void);
 void check_statblank(void);
 void blank_bottombars(void);
 char *display_string(const char *buf, size_t start_col, size_t len);
@@ -502,7 +504,7 @@ void titlebar(const char *path);
 void set_modified(void);
 void statusbar(const char *msg, ...);
 void bottombars(const shortcut *s);
-void onekey(const char *keystroke, const char *desc, int len);
+void onekey(const char *keystroke, const char *desc, size_t len);
 #ifndef NDEBUG
 int check_linenumbers(const filestruct *fileptr);
 #endif
index 588111f8fa179a1cb91d55f28e38bcffc9a1474a..0102cfe3fe0d3e2e58b112130e44fa07246dc5f2 100644 (file)
@@ -539,7 +539,7 @@ char *replace_line(const char *needle)
     /* Calculate the size of the new line. */
 #ifdef HAVE_REGEX_H
     if (ISSET(USE_REGEXP)) {
-       search_match_count = regmatches[0].rm_eo - regmatches[0].rm_so;
+       search_match_count = regmatches[0].rm_eo - regmatches[0].rm_so;
        new_line_size = replace_regexp(NULL, 0);
     } else {
 #endif
index 4e5cbe0bb6d2183c3d7f569d063850280aef39b2..f18d11dd68c56cda355d0e617ab4909183699c44 100644 (file)
@@ -209,6 +209,21 @@ const char *revstristr(const char *haystack, const char *needle, const
 }
 #endif /* !NANO_SMALL */
 
+#ifndef HAVE_STRNLEN
+/* This function is equivalent to strnlen(). */
+size_t nstrnlen(const char *s, size_t maxlen)
+{
+    size_t n = 0;
+
+    assert(s != NULL);
+
+    for (; maxlen > 0 && *s != '\0'; maxlen--, n++, s++)
+       ;
+
+    return n;
+}
+#endif
+
 /* If we are searching backwards, we will find the last match that
  * starts no later than start.  Otherwise we find the first match
  * starting no earlier than start.  If we are doing a regexp search, we
index 2ca439c5a0d5e49aa775a6c95fbdfb1391546ac8..d5a4879c79c3fc513fcc7725dac3a9f9ae7aaf1c 100644 (file)
@@ -1002,7 +1002,7 @@ int get_mouseinput(int *mouse_x, int *mouse_y, int allow_shortcuts)
         * both. */
        if (s->ctrlval != NANO_NO_KEY)
            ungetch(s->ctrlval);
-       else {
+       else if (s->ctrlval != NANO_NO_KEY) {
            ungetch(s->metaval);
            ungetch(NANO_CONTROL_3);
        }
@@ -1109,19 +1109,16 @@ void blank_statusbar(void)
     mvwaddstr(bottomwin, 0, 0, hblank);
 }
 
-void blank_statusbar_refresh(void)
-{
-    blank_statusbar();
-    wrefresh(bottomwin);
-}
-
 void check_statblank(void)
 {
     if (statblank > 1)
        statblank--;
     else if (statblank == 1 && !ISSET(CONSTUPDATE)) {
-       statblank--;
-       blank_statusbar_refresh();
+       statblank = 0;
+       blank_statusbar();
+       wnoutrefresh(bottomwin);
+       reset_cursor();
+       wrefresh(edit);
     }
 }
 
@@ -1544,50 +1541,143 @@ int nanogetstr(int allowtabs, const char *buf, const char *def,
 
 void titlebar(const char *path)
 {
-    int namelen, space;
-    const char *what = path;
-
-    if (path == NULL)
-       what = filename;
+    size_t space;
+       /* The space we have available for display. */
+    size_t verlen = strlen(VERMSG) + 1;
+       /* The length of the version message. */
+    const char *prefix;
+       /* "File:", "Dir:", or "New Buffer".  Goes before filename. */
+    size_t prefixlen;
+       /* strlen(prefix) + 1. */
+    const char *state;
+       /* "Modified", "View", or spaces the length of "Modified".
+        * Tells the state of this buffer. */
+    size_t statelen = 0;
+       /* strlen(state) + 1. */
+    char *exppath = NULL;
+       /* The file name, expanded for display. */
+    size_t explen = 0;
+       /* strlen(exppath) + 1. */
+    int newbuffer = FALSE;
+       /* Do we say "New Buffer"? */
+    int dots = FALSE;
+       /* Do we put an ellipsis before the path? */
+
+    assert(path != NULL || filename != NULL);
+    assert(COLS >= 0);
 
     wattron(topwin, A_REVERSE);
 
     blank_titlebar();
-    mvwaddnstr(topwin, 0, 2, VERMSG, COLS - 3);
 
-    space = COLS - sizeof(VERMSG) - 23;
+    if (COLS <= 5 || COLS - 5 < verlen)
+       space = 0;
+    else {
+       space = COLS - 5 - verlen;
+       /* Reserve 2/3 of the screen for after the version message. */
+       if (space < COLS - (COLS / 3))
+           space = COLS - (COLS / 3);
+    }
 
-    namelen = strlen(what);
+    if (COLS > 4) {
+       /* The version message should only take up 1/3 of the screen. */
+       mvwaddnstr(topwin, 0, 2, VERMSG, COLS / 3);
+       waddstr(topwin, "  ");
+    }
 
-    if (space > 0) {
-        if (what[0] == '\0')
-           mvwaddnstr(topwin, 0, COLS / 2 - 6, _("New Buffer"),
-                       COLS / 2 + COLS % 2 - 6);
-        else if (namelen > space) {
-           if (path == NULL)
-               waddstr(topwin, _("  File: ..."));
-           else
-               waddstr(topwin, _("   DIR: ..."));
-           waddstr(topwin, &what[namelen - space]);
-       } else {
-           if (path == NULL)
-               mvwaddstr(topwin, 0, COLS / 2 - (namelen / 2 + 1),
-                               _("File: "));
-           else
-               mvwaddstr(topwin, 0, COLS / 2 - (namelen / 2 + 1),
-                               _(" DIR: "));
-           waddstr(topwin, what);
-       }
-    } /* If we don't have space, we shouldn't bother */
     if (ISSET(MODIFIED))
-       mvwaddnstr(topwin, 0, COLS - 11, _(" Modified "), 11);
-    else if (ISSET(VIEW_MODE))
-       mvwaddnstr(topwin, 0, COLS - 11, _(" View "), 11);
+       state = _("Modified");
+    else if (path == NULL && ISSET(VIEW_MODE))
+       state = _("View");
+    else {
+       if (space > 0)
+           statelen = strnlen(_("Modified"), space - 1) + 1;
+       state = &hblank[COLS - statelen];
+    }
+    statelen = strnlen(state, COLS);
+    /* We need a space before state. */
+    if ((ISSET(MODIFIED) || ISSET(VIEW_MODE)) && statelen < COLS)
+       statelen++;
+
+    assert(space >= 0);
+    if (space == 0 || statelen >= space)
+       goto the_end;
+
+#ifndef DISABLE_BROWSER
+    if (path != NULL)
+       prefix = _("DIR:");
+    else
+#endif
+    if (filename[0] == '\0') {
+       prefix = _("New Buffer");
+       newbuffer = TRUE;
+    } else
+       prefix = _("File:");
+    assert(statelen < space);
+    prefixlen = strnlen(prefix, space - statelen);
+    /* If newbuffer is FALSE, we need a space after prefix. */
+    if (!newbuffer && prefixlen + statelen < space)
+       prefixlen++;
+
+    if (path == NULL)
+       path = filename;
+    if (space > prefixlen + statelen)
+       space -= prefixlen + statelen;
+    else
+       space = 0;
+       /* space is now the room we have for the file name. */
+    if (!newbuffer) {
+       size_t lenpt = strlenpt(path), start_col;
+
+       if (lenpt > space)
+           start_col = actual_x(path, lenpt - space);
+       else
+           start_col = 0;
+       exppath = display_string(path, start_col, space);
+       dots = (lenpt > space);
+       explen = strlen(exppath);
+    }
+
+    if (!dots) {
+       /* There is room for the whole filename, so we center it. */
+       waddnstr(topwin, hblank, (space - explen) / 3);
+       waddnstr(topwin, prefix, prefixlen);
+       if (!newbuffer) {
+           assert(strlen(prefix) + 1 == prefixlen);
+           waddch(topwin, ' ');
+           waddstr(topwin, exppath);
+       }
+    } else {
+       /* We will say something like "File: ...ename". */
+       waddnstr(topwin, prefix, prefixlen);
+       if (space == 0 || newbuffer)
+           goto the_end;
+       waddch(topwin, ' ');
+       waddnstr(topwin, "...", space);
+       if (space <= 3)
+           goto the_end;
+       space -= 3;
+       assert(explen = space + 3);
+       waddnstr(topwin, exppath + 3, space);
+    }
+
+  the_end:
+
+    free(exppath);
+
+    if (COLS <= 1 || statelen >= COLS - 1)
+       mvwaddnstr(topwin, 0, 0, state, COLS);
+    else {
+       assert(COLS - statelen - 2 >= 0);
+       mvwaddch(topwin, 0, COLS - statelen - 2, ' ');
+       mvwaddnstr(topwin, 0, COLS - statelen - 1, state, statelen);
+    }
 
     wattroff(topwin, A_REVERSE);
 
-    wrefresh(topwin);
+    wnoutrefresh(topwin);
     reset_cursor();
+    wrefresh(edit);
 }
 
 /* If modified is not already set, set it and update titlebar. */
@@ -1596,7 +1686,6 @@ void set_modified(void)
     if (!ISSET(MODIFIED)) {
        SET(MODIFIED);
        titlebar(NULL);
-       wrefresh(topwin);
     }
 }
 
@@ -1650,79 +1739,75 @@ void statusbar(const char *msg, ...)
 
 void bottombars(const shortcut *s)
 {
-    int i, j, numcols;
-    char keystr[9];
-    int slen;
+    size_t i, colwidth, slen;
+    char *keystr;
 
     if (ISSET(NO_HELP))
        return;
 
     if (s == main_list) {
        slen = MAIN_VISIBLE;
-       assert(MAIN_VISIBLE <= length_of_list(s));
+       assert(slen <= length_of_list(s));
     } else {
        slen = length_of_list(s);
 
-       /* Don't show any more shortcuts than the main list does */
+       /* Don't show any more shortcuts than the main list does. */
        if (slen > MAIN_VISIBLE)
            slen = MAIN_VISIBLE;
     }
 
-    /* There will be this many columns of shortcuts */
-    numcols = (slen + (slen % 2)) / 2;
+    /* There will be this many characters per column.  We need at least
+     * 3 to display anything properly.*/
+    colwidth = COLS / ((slen / 2) + (slen % 2));
+    keystr = charalloc(colwidth);
 
     blank_bottombars();
 
-    for (i = 0; i < numcols; i++) {
-       for (j = 0; j <= 1; j++) {
-
-           wmove(bottomwin, 1 + j, i * (COLS / numcols));
+    for (i = 0; i < slen; i++, s = s->next) {
+       wmove(bottomwin, 1 + i % 2, (i / 2) * colwidth);
 
-           /* Yucky sentinel values we can't handle a better way */
-           if (s->ctrlval != NANO_NO_KEY) {
+       /* Yucky sentinel values we can't handle a better way. */
 #ifndef NANO_SMALL
-               if (s->ctrlval == NANO_HISTORY_KEY)
-                   strncpy(keystr, _("Up"), 8);
-               else
+       if (s->ctrlval == NANO_HISTORY_KEY)
+           strncpy(keystr, _("Up"), colwidth);
+       else
 #endif
-               if (s->ctrlval == NANO_CONTROL_SPACE)
-                   strcpy(keystr, "^ ");
-               else if (s->ctrlval == NANO_CONTROL_8)
-                   strcpy(keystr, "^?");
-               else
-                   sprintf(keystr, "^%c", s->ctrlval + 64);
-           } else if (s->metaval != NANO_NO_KEY)
-               sprintf(keystr, "M-%c", toupper(s->metaval));
-
-           onekey(keystr, s->desc, COLS / numcols);
-
-           s = s->next;
-           if (s == NULL)
-               goto break_completely_out;
-       }
+       if (s->ctrlval == NANO_CONTROL_SPACE)
+           strncpy(keystr, "^ ", colwidth);
+       else if (s->ctrlval == NANO_CONTROL_8)
+           strncpy(keystr, "^?", colwidth);
+       /* Normal values.  Assume that the shortcut has an equivalent
+        * control key, meta key sequence, or both. */
+       else if (s->ctrlval != NANO_NO_KEY)
+           snprintf(keystr, colwidth, "^%c", s->ctrlval + 64);
+       else if (s->metaval != NANO_NO_KEY)
+           snprintf(keystr, colwidth, "M-%c", toupper(s->metaval));
+
+       onekey(keystr, s->desc, colwidth);
     }
 
-  break_completely_out:
-    wrefresh(bottomwin);
+    free(keystr);
+
+    wnoutrefresh(bottomwin);
+    reset_cursor();
+    wrefresh(edit);
 }
 
-/* Write a shortcut key to the help area at the bottom of the window. 
- * keystroke is e.g. "^G" and desc is e.g. "Get Help".
- * We are careful to write exactly len characters, even if len is
- * very small and keystroke and desc are long. */
-void onekey(const char *keystroke, const char *desc, int len)
+/* Write a shortcut key to the help area at the bottom of the window.
+ * keystroke is e.g. "^G" and desc is e.g. "Get Help".  We are careful
+ * to write at most len characters, even if len is very small and
+ * keystroke and desc are long.  Note that waddnstr(,,(size_t)-1) adds
+ * the whole string!  We do not bother padding the entry with blanks. */
+void onekey(const char *keystroke, const char *desc, size_t len)
 {
+    assert(keystroke != NULL && desc != NULL && len >= 0);
     wattron(bottomwin, A_REVERSE);
     waddnstr(bottomwin, keystroke, len);
     wattroff(bottomwin, A_REVERSE);
-    len -= strlen(keystroke);
+    len -= strlen(keystroke) + 1;
     if (len > 0) {
        waddch(bottomwin, ' ');
-       len--;
        waddnstr(bottomwin, desc, len);
-       len -= strlen(desc);
-       for (; len > 0; len--)
-           waddch(bottomwin, ' ');
     }
 }
 
@@ -2330,7 +2415,7 @@ int do_yesno(int all, const char *msg)
     nostr = _("Nn");
     allstr = _("Aa");
 
-    /* Remove gettext call for keybindings until we clear the thing
+    /* Remove gettext() call for keybindings until we clear the thing
      * up. */
     if (!ISSET(NO_HELP)) {
        char shortstr[3];               /* Temp string for Y, N, A. */