Commit: patch 9.2.0939: mbyte: wrong cell count for an overlong UTF-8 sequence

Christian Brabandt <[email protected]> Tue, 11 Aug 2026 21:30:05 +0200
Newsgroups gmane.editors.vim.devel
Message-ID <[email protected]>
patch 9.2.0939: mbyte: wrong cell count for an overlong UTF-8 sequence

Commit: https://github.com/vim/vim/commit/0cdcd95cc2f6a000aafe084f31299cc69affc139
Author: Hirohito Higashi <[email protected]>
Date:   Tue Aug 11 19:16:00 2026 +0000

    patch 9.2.0939: mbyte: wrong cell count for an overlong UTF-8 sequence
    
    Problem:  An overlong UTF-8 encoding of an unprintable ASCII character is
              displayed as <xx> but counted as two screen cells, so that the
              cursor ends up in the wrong position when editing the line.
    Solution: Count four cells for an unprintable overlong sequence.
    
    fixes:  #20988
    closes: #21005
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
    Signed-off-by: Hirohito Higashi <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

diff --git a/src/mbyte.c b/src/mbyte.c
index 54ee229a1..e196f30ca 100644
--- a/src/mbyte.c
+++ b/src/mbyte.c
@@ -1645,7 +1645,7 @@ utf_ptr2cells(
 	    return 4;
 	// If the char is ASCII it must be an overlong sequence.
 	if (c < 0x80)
-	    return char2cells(c);
+	    return vim_isprintc(c) ? char2cells(c) : 4;
 	return utf_char2cells(c);
     }
     return 1;
@@ -1689,7 +1689,7 @@ utf_ptr2cells_len(char_u *p, int size)
 	    return 4;
 	// If the char is ASCII it must be an overlong sequence.
 	if (c < 0x80)
-	    return char2cells(c);
+	    return vim_isprintc(c) ? char2cells(c) : 4;
 	return utf_char2cells(c);
     }
     return 1;
diff --git a/src/testdir/test_utf8.vim b/src/testdir/test_utf8.vim
index a0cd5bd79..3070d4cc4 100644
--- a/src/testdir/test_utf8.vim
+++ b/src/testdir/test_utf8.vim
@@ -372,4 +372,20 @@ func Test_print_overlong()
   bwipe!
 endfunc
 
+" The cell count of an overlong encoded character must match what is drawn.
+func Test_overlong_utf8_cells()
+  call assert_equal(4, strdisplaywidth("\xc0\x81"))     " <01>
+  call assert_equal(4, strdisplaywidth("\xe0\x80\x81")) " <01>, three bytes
+  call assert_equal(4, strdisplaywidth("\xc1\xbf"))     " <7f>
+  call assert_equal(4, strdisplaywidth("\xc0\x89"))     " <09>, not a Tab
+
+  new
+  call setline(1, "\xc1\x81\xc0\x81\xc0\x80")
+  call assert_equal('A<01><00>', ScreenLines(1, 9)[0])
+  normal! $
+  call assert_equal(5, col('.'))
+  call assert_equal([6, 9], virtcol('.', v:true))
+  bwipe!
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 48a1faf0f..6405f229e 100644
--- a/src/version.c
+++ b/src/version.c
@@ -763,6 +763,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    939,
 /**/
     938,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups "vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1wtsAn-007aIe-Ui%40256bit.org.