diff --git a/src/chars.c b/src/chars.c
index eb070794f4532927faf3a7c06eef1264d1bbb2f2..e2852cee91cc9bf78f8ae467990d1196855d70b6 100644
--- a/src/chars.c
+++ b/src/chars.c
@@ -230,8 +230,9 @@ char control_mbrep(const char *c)
 
 /* Assess how many bytes the given (multibyte) character occupies.  Return -1
  * if the byte sequence is invalid, and return the number of bytes minus 8
- * when the byte sequence encodes an invalid codepoint. */
-int length_of_char(const char *c)
+ * when it encodes an invalid codepoint.  Also, in the second parameter,
+ * return the number of columns that the character occupies. */
+int length_of_char(const char *c, int *width)
 {
     assert(c != NULL);
 
@@ -249,8 +250,13 @@ int length_of_char(const char *c)
 	/* If the codepoint is invalid... */
 	if (!is_valid_unicode(wc))
 	    return charlen - 8;
-	else
+	else {
+	    *width = wcwidth(wc);
+	    /* If the codepoint is unassigned, assume a width of one. */
+	    if (*width < 0)
+		*width = 1;
 	    return charlen;
+	}
     } else
 #endif
 	return 1;
diff --git a/src/proto.h b/src/proto.h
index 470df16a3ea3a002c74a90eedd116eeb8a93ebe1..3e201e16866fa782749394ec412d13ffa1393cd8 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -188,7 +188,7 @@ bool is_punct_mbchar(const char *c);
 bool is_word_mbchar(const char *c, bool allow_punct);
 char control_rep(const signed char c);
 char control_mbrep(const char *c);
-int length_of_char(const char *c);
+int length_of_char(const char *c, int *width);
 int mbwidth(const char *c);
 int mb_cur_max(void);
 char *make_mbchar(long chr, int *chr_mb_len);
diff --git a/src/winio.c b/src/winio.c
index 0ad2140c753f86f7094d4b3d8f666e841ad6bf42..4552db0f7b851a8f19c410746b3ebb60dd88c8bf 100644
--- a/src/winio.c
+++ b/src/winio.c
@@ -1780,7 +1780,7 @@ char *display_string(const char *buf, size_t start_col, size_t len, bool
     }
 
     while (*buf != '\0') {
-	int charlength;
+	int charlength, charwidth = 1;
 
 	if (*buf == ' ') {
 	    /* Show a space as a visible character, or as a space. */
@@ -1817,7 +1817,7 @@ char *display_string(const char *buf, size_t start_col, size_t len, bool
 	    continue;
 	}
 
-	charlength = length_of_char(buf);
+	charlength = length_of_char(buf, &charwidth);
 
 	/* If buf contains a control character, represent it. */
 	if (is_cntrl_mbchar(buf)) {
@@ -1830,13 +1830,11 @@ char *display_string(const char *buf, size_t start_col, size_t len, bool
 
 	/* If buf contains a valid non-control character, simply copy it. */
 	if (charlength > 0) {
-	    int width = mbwidth(buf);
-
 	    for (; charlength > 0; charlength--)
 		converted[index++] = *(buf++);
 
-	    start_col += width;
-	    if (width > 1)
+	    start_col += charwidth;
+	    if (charwidth > 1)
 		seen_wide = TRUE;
 
 	    continue;