aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/builtin.txt3
-rw-r--r--runtime/lua/vim/_meta/vimfn.lua3
-rw-r--r--src/nvim/eval.lua3
-rw-r--r--src/nvim/move.c17
-rw-r--r--test/old/testdir/test_cursor_func.vim9
5 files changed, 34 insertions, 1 deletions
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 7356f644a1..bc5f0948e2 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -8434,6 +8434,9 @@ virtcol2col({winid}, {lnum}, {col}) *virtcol2col()*
{lnum}, then the byte index of the character at the last
virtual column is returned.
+ For a multi-byte character, the column number of the first
+ byte in the character is returned.
+
The {winid} argument can be the window number or the
|window-ID|. If this is zero, then the current window is used.
diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua
index acf1b3a0f5..d1173e8a42 100644
--- a/runtime/lua/vim/_meta/vimfn.lua
+++ b/runtime/lua/vim/_meta/vimfn.lua
@@ -10016,6 +10016,9 @@ function vim.fn.virtcol(expr, list) end
--- {lnum}, then the byte index of the character at the last
--- virtual column is returned.
---
+--- For a multi-byte character, the column number of the first
+--- byte in the character is returned.
+---
--- The {winid} argument can be the window number or the
--- |window-ID|. If this is zero, then the current window is used.
---
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index 8a0d7575b3..8a36509f9a 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -11931,6 +11931,9 @@ M.funcs = {
{lnum}, then the byte index of the character at the last
virtual column is returned.
+ For a multi-byte character, the column number of the first
+ byte in the character is returned.
+
The {winid} argument can be the window number or the
|window-ID|. If this is zero, then the current window is used.
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 0ed30070a5..a68f6a2d50 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -1163,6 +1163,21 @@ void f_screenpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
tv_dict_add_nr(dict, S_LEN("endcol"), ecol);
}
+/// Convert a virtual (screen) column to a character column. The first column
+/// is one. For a multibyte character, the column number of the first byte is
+/// returned.
+static int virtcol2col(win_T *wp, linenr_T lnum, int vcol)
+{
+ int offset = vcol2col(wp, lnum, vcol);
+ char *line = ml_get_buf(wp->w_buffer, lnum, false);
+ char *p = line + offset;
+
+ // For a multibyte character, need to return the column number of the first byte.
+ MB_PTR_BACK(line, p);
+
+ return (int)(p - line + 1);
+}
+
/// "virtcol2col({winid}, {lnum}, {col})" function
void f_virtcol2col(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -1190,7 +1205,7 @@ void f_virtcol2col(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
- rettv->vval.v_number = vcol2col(wp, lnum, screencol);
+ rettv->vval.v_number = virtcol2col(wp, lnum, screencol);
}
/// Scroll the current window down by "line_count" logical lines. "CTRL-Y"
diff --git a/test/old/testdir/test_cursor_func.vim b/test/old/testdir/test_cursor_func.vim
index f73bd4f2b9..3d6ad8405c 100644
--- a/test/old/testdir/test_cursor_func.vim
+++ b/test/old/testdir/test_cursor_func.vim
@@ -531,6 +531,15 @@ func Test_virtcol2col()
call assert_equal(-1, virtcol2col(0, -1, 1))
call assert_equal(-1, virtcol2col(0, 1, -1))
call assert_equal(5, virtcol2col(0, 1, 20))
+
+ " Multibyte character
+ call setline(1, ['a✅✅✅'])
+ call assert_equal(1, virtcol2col(0, 1, 1))
+ call assert_equal(2, virtcol2col(0, 1, 3))
+ call assert_equal(5, virtcol2col(0, 1, 5))
+ call assert_equal(8, virtcol2col(0, 1, 7))
+ call assert_equal(8, virtcol2col(0, 1, 8))
+
call assert_fails('echo virtcol2col("0", 1, 20)', 'E1210:')
call assert_fails('echo virtcol2col(0, "1", 20)', 'E1210:')
call assert_fails('echo virtcol2col(0, 1, "1")', 'E1210:')