Patch 8.2.2324
Problem: Not easy to get mark en cursor posotion by character count.
Solution: Add functions that use character index. (Yegappan Lakshmanan,
closes #7648)
Files: runtime/doc/eval.txt, runtime/doc/usr_41.txt, src/eval.c,
src/evalfunc.c, src/proto/eval.pro, src/tag.c,
src/testdir/test_cursor_func.vim, src/typval.c
*** ../vim-8.2.2323/runtime/doc/eval.txt 2021-01-02 18:31:10.887220293
+0100
--- runtime/doc/eval.txt 2021-01-10 20:11:39.916682240 +0100
***************
*** 2441,2452 ****
changenr() Number current change number
char2nr({expr} [, {utf8}]) Number ASCII/UTF8 value of first char in {expr}
charclass({string}) Number character class of {string}
charidx({string}, {idx} [, {countcc}])
Number char index of byte {idx} in {string}
chdir({dir}) String change current working directory
cindent({lnum}) Number C indent for line {lnum}
clearmatches([{win}]) none clear all matches
! col({expr}) Number column nr of cursor or mark
complete({startcol}, {matches}) none set Insert mode completion
complete_add({expr}) Number add completion match
complete_check() Number check for key typed during completion
--- 2477,2489 ----
changenr() Number current change number
char2nr({expr} [, {utf8}]) Number ASCII/UTF8 value of first char in {expr}
charclass({string}) Number character class of {string}
+ charcol({expr}) Number column number of cursor or mark
charidx({string}, {idx} [, {countcc}])
Number char index of byte {idx} in {string}
chdir({dir}) String change current working directory
cindent({lnum}) Number C indent for line {lnum}
clearmatches([{win}]) none clear all matches
! col({expr}) Number column byte index of cursor or mark
complete({startcol}, {matches}) none set Insert mode completion
complete_add({expr}) Number add completion match
complete_check() Number check for key typed during completion
***************
*** 2524,2529 ****
--- 2561,2567 ----
getchangelist([{expr}]) List list of change list items
getchar([expr]) Number get one character from the user
getcharmod() Number modifiers for the last typed character
+ getcharpos({expr}) List position of cursor, mark, etc.
getcharsearch() Dict last character search
getcmdline() String return the current command-line
getcmdpos() Number return cursor position in command-line
***************
*** 2532,2537 ****
--- 2570,2576 ----
getcompletion({pat}, {type} [, {filtered}])
List list of cmdline completion matches
getcurpos([{winnr}]) List position of the cursor
+ getcursorcharpos([{winnr}]) List character position of the cursor
getcwd([{winnr} [, {tabnr}]]) String get the current working directory
getenv({name}) String return environment variable
getfontname([{name}]) String name of font being used
***************
*** 2722,2728 ****
none change an existing property type
prop_type_delete({name} [, {props}])
none delete a property type
! prop_type_get([{name} [, {props}]])
Dict get property type values
prop_type_list([{props}]) List get list of property types
pum_getpos() Dict position and size of pum if visible
--- 2761,2767 ----
none change an existing property type
prop_type_delete({name} [, {props}])
none delete a property type
! prop_type_get({name} [, {props}])
Dict get property type values
prop_type_list([{props}]) List get list of property types
pum_getpos() Dict position and size of pum if visible
***************
*** 2794,2801 ****
--- 2833,2842 ----
setbufvar({expr}, {varname}, {val})
none set {varname} in buffer {expr} to {val}
setcellwidths({list}) none set character cell width overrides
+ setcharpos({expr}, {list}) Number set the {expr} position to {list}
setcharsearch({dict}) Dict set character search from {dict}
setcmdpos({pos}) Number set cursor position in command-line
+ setcursorcharpos({list}) Number move cursor to position in {list}
setenv({name}, {val}) none set environment variable
setfperm({fname}, {mode}) Number set {fname} file permissions to {mode}
setline({lnum}, {line}) Number set line {lnum} to {line}
***************
*** 2862,2868 ****
str2nr({expr} [, {base} [, {quoted}]])
Number convert String to Number
strcharpart({str}, {start} [, {len}])
! String {len} characters of {str} at {start}
strchars({expr} [, {skipcc}]) Number character length of the String {expr}
strdisplaywidth({expr} [, {col}]) Number display length of the String {expr}
strftime({format} [, {time}]) String format time with a specified format
--- 2903,2910 ----
str2nr({expr} [, {base} [, {quoted}]])
Number convert String to Number
strcharpart({str}, {start} [, {len}])
! String {len} characters of {str} at
! character {start}
strchars({expr} [, {skipcc}]) Number character length of the String {expr}
strdisplaywidth({expr} [, {col}]) Number display length of the String {expr}
strftime({format} [, {time}]) String format time with a specified format
***************
*** 3443,3451 ****
byteidx({expr}, {nr}) *byteidx()*
Return byte index of the {nr}'th character in the string
! {expr}. Use zero for the first character, it returns zero.
! This function is only useful when there are multibyte
! characters, otherwise the returned value is equal to {nr}.
Composing characters are not counted separately, their byte
length is added to the preceding base character. See
|byteidxcomp()| below for counting composing characters
--- 3487,3496 ----
byteidx({expr}, {nr}) *byteidx()*
Return byte index of the {nr}'th character in the string
! {expr}. Use zero for the first character, it then returns
! zero.
! If there are no multibyte characters the returned value is
! equal to {nr}.
Composing characters are not counted separately, their byte
length is added to the preceding base character. See
|byteidxcomp()| below for counting composing characters
***************
*** 3475,3482 ****
< The first and third echo result in 3 ('e' plus composing
character is 3 bytes), the second echo results in 1 ('e' is
one byte).
! Only works different from byteidx() when 'encoding' is set to
! a Unicode encoding.
Can also be used as a |method|: >
GetName()->byteidxcomp(idx)
--- 3520,3527 ----
< The first and third echo result in 3 ('e' plus composing
character is 3 bytes), the second echo results in 1 ('e' is
one byte).
! Only works differently from byteidx() when 'encoding' is set
! to a Unicode encoding.
Can also be used as a |method|: >
GetName()->byteidxcomp(idx)
***************
*** 3552,3557 ****
--- 3597,3614 ----
other specific Unicode class
The class is used in patterns and word motions.
+ *charcol()*
+ charcol({expr}) Same as |col()| but returns the character index of the
column
+ position given with {expr} instead of the byte position.
+
+ Example:
+ With the cursor on '세' in line 5 with text "여보세요": >
+ charcol('.') returns 3
+ col('.') returns 7
+
+ < Can also be used as a |method|: >
+ GetPos()->col()
+ <
*charidx()*
charidx({string}, {idx} [, {countcc}])
Return the character index of the byte at {idx} in {string}.
***************
*** 3642,3648 ****
out of range then col() returns zero.
To get the line number use |line()|. To get both use
|getpos()|.
! For the screen column position use |virtcol()|.
Note that only marks in the current file can be used.
Examples: >
col(".") column of cursor
--- 3699,3706 ----
out of range then col() returns zero.
To get the line number use |line()|. To get both use
|getpos()|.
! For the screen column position use |virtcol()|. For the
! character position use |charcol()|.
Note that only marks in the current file can be used.
Examples: >
col(".") column of cursor
***************
*** 3943,3948 ****
--- 4001,4009 ----
This is like the return value of |getpos()| or |getcurpos()|,
but without the first item.
+ To position the cursor using the character count, use
+ |setcursorcharpos()|.
+
Does not change the jumplist.
If {lnum} is greater than the number of lines in the buffer,
the cursor will be positioned at the last line in the buffer.
***************
*** 5164,5169 ****
--- 5243,5262 ----
character itself are obtained. Thus Shift-a results in "A"
without a modifier.
+ *getcharpos()*
+ getcharpos({expr})
+ Get the position for {expr}. Same as |getpos()| but the column
+ number in the returned List is a character index instead of
+ a byte index.
+
+ Example:
+ With the cursor on '세' in line 5 with text "여보세요": >
+ getcharpos('.') returns [0, 5, 3, 0]
+ getpos('.') returns [0, 5, 7, 0]
+ <
+ Can also be used as a |method|: >
+ GetMark()->getcharpos()
+
getcharsearch()
*getcharsearch()*
Return the current character search information as a {dict}
with the following entries:
***************
*** 5289,5296 ****
includes an extra "curswant" item in the list:
[0, lnum, col, off, curswant] ~
The "curswant" number is the preferred column when moving the
! cursor vertically. Also see |getpos()|.
! The first "bufnum" item is always zero.
The optional {winid} argument can specify the window. It can
be the window number or the |window-ID|. The last known
--- 5382,5392 ----
includes an extra "curswant" item in the list:
[0, lnum, col, off, curswant] ~
The "curswant" number is the preferred column when moving the
! cursor vertically. Also see |getcursorcharpos()| and
! |getpos()|.
! The first "bufnum" item is always zero. The byte position of
! the cursor is returned in 'col'. To get the character
! position, use |getcursorcharpos()|.
The optional {winid} argument can specify the window. It can
be the window number or the |window-ID|. The last known
***************
*** 5304,5310 ****
call setpos('.', save_cursor)
< Note that this only works within the window. See
|winrestview()| for restoring more state.
! *getcwd()*
getcwd([{winnr} [, {tabnr}]])
The result is a String, which is the name of the current
working directory.
--- 5400,5423 ----
call setpos('.', save_cursor)
< Note that this only works within the window. See
|winrestview()| for restoring more state.
!
! Can also be used as a |method|: >
! GetWinid()->getcurpos()
!
! < *getcursorcharpos()*
! getcursorcharpos([{winid}])
! Same as |getcurpos()| but the column number in the returned
! List is a character index instead of a byte index.
!
! Example:
! With the cursor on '보' in line 3 with text "여보세요": >
! getcursorcharpos() returns [0, 3, 2, 0, 3]
! getcurpos() returns [0, 3, 4, 0, 3]
!
! < Can also be used as a |method|: >
! GetWinid()->getcursorcharpos()
!
! < *getcwd()*
getcwd([{winnr} [, {tabnr}]])
The result is a String, which is the name of the current
working directory.
***************
*** 5602,5619 ****
Note that for '< and '> Visual mode matters: when it is "V"
(visual line mode) the column of '< is zero and the column of
'> is a large number.
This can be used to save and restore the position of a mark: >
let save_a_mark = getpos("'a")
...
call setpos("'a", save_a_mark)
! < Also see |getcurpos()| and |setpos()|.
Can also be used as a |method|: >
GetMark()->getpos()
-
getqflist([{what}]) *getqflist()*
! Returns a list with all the current quickfix errors. Each
list item is a dictionary with these entries:
bufnr number of buffer that has the file name, use
bufname() to get the name
--- 5724,5743 ----
Note that for '< and '> Visual mode matters: when it is "V"
(visual line mode) the column of '< is zero and the column of
'> is a large number.
+ The column number in the returned List is the byte position
+ within the line. To get the character position in the line,
+ use |getcharpos()|
This can be used to save and restore the position of a mark: >
let save_a_mark = getpos("'a")
...
call setpos("'a", save_a_mark)
! < Also see |getcharpos()|, |getcurpos()| and |setpos()|.
Can also be used as a |method|: >
GetMark()->getpos()
getqflist([{what}]) *getqflist()*
! Returns a |List| with all the current quickfix errors. Each
list item is a dictionary with these entries:
bufnr number of buffer that has the file name, use
bufname() to get the name
***************
*** 9116,9122 ****
--- 9260,9281 ----
To clear the overrides pass an empty list: >
setcellwidths([]);
+ < You can use the script $VIMRUNTIME/tools/emoji_list.vim to see
+ the effect for known emoji characters.
+
+ setcharpos({expr}, {list}) *setcharpos()*
+ Same as |setpos()| but uses the specified column number as the
+ character index instead of the byte index in the line.
+
+ Example:
+ With the text "여보세요" in line 8: >
+ call setcharpos('.', [0, 8, 4, 0])
+ < positions the cursor on the fourth character '요'. >
+ call setpos('.', [0, 8, 4, 0])
+ < positions the cursor on the second character '보'.
+ Can also be used as a |method|: >
+ GetPosition()->setcharpos('.')
setcharsearch({dict}) *setcharsearch()*
Set the current character search information to {dict},
***************
*** 9159,9164 ****
--- 9318,9338 ----
Can also be used as a |method|: >
GetPos()->setcmdpos()
+ setcursorcharpos({lnum}, {col} [, {off}]) *setcursorcharpos()*
+ setcursorcharpos({list})
+ Same as |cursor()| but uses the specified column number as the
+ character index instead of the byte index in the line.
+
+ Example:
+ With the text "여보세요" in line 4: >
+ call setcursorcharpos(4, 3)
+ < positions the cursor on the third character '세'. >
+ call cursor(4, 3)
+ < positions the cursor on the first character '여'.
+
+ Can also be used as a |method|: >
+ GetCursorPos()->setcursorcharpos()
+
setenv({name}, {val}) *setenv()*
Set environment variable {name} to {val}.
When {val} is |v:null| the environment variable is deleted.
***************
*** 9268,9274 ****
"lnum" and "col" are the position in the buffer. The first
column is 1. Use a zero "lnum" to delete a mark. If "col" is
! smaller than 1 then 1 is used.
The "off" number is only used when 'virtualedit' is set. Then
it is the offset in screen columns from the start of the
--- 9444,9451 ----
"lnum" and "col" are the position in the buffer. The first
column is 1. Use a zero "lnum" to delete a mark. If "col" is
! smaller than 1 then 1 is used. To use the character count
! instead of the byte count, use |setcharpos()|.
The "off" number is only used when 'virtualedit' is set. Then
it is the offset in screen columns from the start of the
***************
*** 9288,9294 ****
Returns 0 when the position could be set, -1 otherwise.
An error message is given if {expr} is invalid.
! Also see |getpos()| and |getcurpos()|.
This does not restore the preferred column for moving
vertically; if you set the cursor position with this, |j| and
--- 9465,9471 ----
Returns 0 when the position could be set, -1 otherwise.
An error message is given if {expr} is invalid.
! Also see |setcharpos()|, |getpos()| and |getcurpos()|.
This does not restore the preferred column for moving
vertically; if you set the cursor position with this, |j| and
*** ../vim-8.2.2323/runtime/doc/usr_41.txt 2020-12-28 12:56:54.179617297
+0100
--- runtime/doc/usr_41.txt 2021-01-10 19:55:52.679431025 +0100
***************
*** 745,750 ****
--- 753,763 ----
screenchar() get character code at a screen line/row
screenchars() get character codes at a screen line/row
screenstring() get string of characters at a screen line/row
+ charcol() character number of the cursor or a mark
+ getcharpos() get character position of cursor, mark, etc.
+ setcharpos() set character position of cursor, mark, etc.
+ getcursorcharpos() get character position of the cursor
+ setcursorcharpos() set character position of the cursor
Working with text in the current buffer: *text-functions*
getline() get a line or list of lines from the buffer
*** ../vim-8.2.2323/src/eval.c 2021-01-09 15:45:20.353451132 +0100
--- src/eval.c 2021-01-10 20:13:44.516542119 +0100
***************
*** 5054,5059 ****
--- 5054,5114 ----
#endif
/*
+ * Convert the specified byte index of line 'lnum' in buffer 'buf' to a
+ * character index. Works only for loaded buffers. Returns -1 on failure.
+ * The index of the first character is one.
+ */
+ int
+ buf_byteidx_to_charidx(buf_T *buf, int lnum, int byteidx)
+ {
+ char_u *str;
+
+ if (buf == NULL || buf->b_ml.ml_mfp == NULL)
+ return -1;
+
+ if (lnum > buf->b_ml.ml_line_count)
+ lnum = buf->b_ml.ml_line_count;
+
+ str = ml_get_buf(buf, lnum, FALSE);
+ if (str == NULL)
+ return -1;
+
+ if (*str == NUL)
+ return 1;
+
+ return mb_charlen_len(str, byteidx + 1);
+ }
+
+ /*
+ * Convert the specified character index of line 'lnum' in buffer 'buf' to a
+ * byte index. Works only for loaded buffers. Returns -1 on failure. The
index
+ * of the first byte and the first character is one.
+ */
+ int
+ buf_charidx_to_byteidx(buf_T *buf, int lnum, int charidx)
+ {
+ char_u *str;
+ char_u *t;
+
+ if (buf == NULL || buf->b_ml.ml_mfp == NULL)
+ return -1;
+
+ if (lnum > buf->b_ml.ml_line_count)
+ lnum = buf->b_ml.ml_line_count;
+
+ str = ml_get_buf(buf, lnum, FALSE);
+ if (str == NULL)
+ return -1;
+
+ // Convert the character offset to a byte offset
+ t = str;
+ while (*t != NUL && --charidx > 0)
+ t += mb_ptr2len(t);
+
+ return t - str + 1;
+ }
+
+ /*
* Translate a String variable into a position.
* Returns NULL when there is an error.
*/
***************
*** 5061,5067 ****
var2fpos(
typval_T *varp,
int dollar_lnum, // TRUE when $ is last line
! int *fnum) // set to fnum for '0, 'A, etc.
{
char_u *name;
static pos_T pos;
--- 5116,5123 ----
var2fpos(
typval_T *varp,
int dollar_lnum, // TRUE when $ is last line
! int *fnum, // set to fnum for '0, 'A, etc.
! int charcol) // return character column
{
char_u *name;
static pos_T pos;
***************
*** 5083,5089 ****
pos.lnum = list_find_nr(l, 0L, &error);
if (error || pos.lnum <= 0 || pos.lnum > curbuf->b_ml.ml_line_count)
return NULL; // invalid line number
! len = (long)STRLEN(ml_get(pos.lnum));
// Get the column number
// We accept "$" for the column number: last column.
--- 5139,5148 ----
pos.lnum = list_find_nr(l, 0L, &error);
if (error || pos.lnum <= 0 || pos.lnum > curbuf->b_ml.ml_line_count)
return NULL; // invalid line number
! if (charcol)
! len = (long)mb_charlen(ml_get(pos.lnum));
! else
! len = (long)STRLEN(ml_get(pos.lnum));
// Get the column number
// We accept "$" for the column number: last column.
***************
*** 5118,5135 ****
if (name == NULL)
return NULL;
if (name[0] == '.') // cursor
! return &curwin->w_cursor;
if (name[0] == 'v' && name[1] == NUL) // Visual start
{
if (VIsual_active)
! return &VIsual;
! return &curwin->w_cursor;
}
if (name[0] == '\'') // mark
{
pp = getmark_buf_fnum(curbuf, name[1], FALSE, fnum);
if (pp == NULL || pp == (pos_T *)-1 || pp->lnum <= 0)
return NULL;
return pp;
}
--- 5177,5205 ----
if (name == NULL)
return NULL;
if (name[0] == '.') // cursor
! {
! pos = curwin->w_cursor;
! if (charcol)
! pos.col = buf_byteidx_to_charidx(curbuf, pos.lnum, pos.col) - 1;
! return &pos;
! }
if (name[0] == 'v' && name[1] == NUL) // Visual start
{
if (VIsual_active)
! pos = VIsual;
! else
! pos = curwin->w_cursor;
! if (charcol)
! pos.col = buf_byteidx_to_charidx(curbuf, pos.lnum, pos.col) - 1;
! return &pos;
}
if (name[0] == '\'') // mark
{
pp = getmark_buf_fnum(curbuf, name[1], FALSE, fnum);
if (pp == NULL || pp == (pos_T *)-1 || pp->lnum <= 0)
return NULL;
+ if (charcol)
+ pp->col = buf_byteidx_to_charidx(curbuf, pp->lnum, pp->col) - 1;
return pp;
}
***************
*** 5164,5170 ****
else
{
pos.lnum = curwin->w_cursor.lnum;
! pos.col = (colnr_T)STRLEN(ml_get_curline());
}
return &pos;
}
--- 5234,5243 ----
else
{
pos.lnum = curwin->w_cursor.lnum;
! if (charcol)
! pos.col = (colnr_T)mb_charlen(ml_get_curline());
! else
! pos.col = (colnr_T)STRLEN(ml_get_curline());
}
return &pos;
}
***************
*** 5184,5190 ****
typval_T *arg,
pos_T *posp,
int *fnump,
! colnr_T *curswantp)
{
list_T *l = arg->vval.v_list;
long i = 0;
--- 5257,5264 ----
typval_T *arg,
pos_T *posp,
int *fnump,
! colnr_T *curswantp,
! int charcol)
{
list_T *l = arg->vval.v_list;
long i = 0;
***************
*** 5216,5221 ****
--- 5290,5307 ----
n = list_find_nr(l, i++, NULL); // col
if (n < 0)
return FAIL;
+ // If character position is specified, then convert to byte position
+ if (charcol)
+ {
+ buf_T *buf;
+
+ // Get the text for the specified line in a loaded buffer
+ buf = buflist_findnr(fnump == NULL ? curbuf->b_fnum : *fnump);
+ if (buf == NULL || buf->b_ml.ml_mfp == NULL)
+ return FAIL;
+
+ n = buf_charidx_to_byteidx(buf, posp->lnum, n);
+ }
posp->col = n;
n = list_find_nr(l, i, NULL); // off
*** ../vim-8.2.2323/src/evalfunc.c 2021-01-07 20:23:29.842515296 +0100
--- src/evalfunc.c 2021-01-10 19:55:52.679431025 +0100
***************
*** 47,52 ****
--- 47,53 ----
#endif
static void f_changenr(typval_T *argvars, typval_T *rettv);
static void f_char2nr(typval_T *argvars, typval_T *rettv);
+ static void f_charcol(typval_T *argvars, typval_T *rettv);
static void f_charidx(typval_T *argvars, typval_T *rettv);
static void f_col(typval_T *argvars, typval_T *rettv);
static void f_confirm(typval_T *argvars, typval_T *rettv);
***************
*** 87,98 ****
--- 88,101 ----
static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
static void f_get(typval_T *argvars, typval_T *rettv);
static void f_getchangelist(typval_T *argvars, typval_T *rettv);
+ static void f_getcharpos(typval_T *argvars, typval_T *rettv);
static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
static void f_getenv(typval_T *argvars, typval_T *rettv);
static void f_getfontname(typval_T *argvars, typval_T *rettv);
static void f_getjumplist(typval_T *argvars, typval_T *rettv);
static void f_getpid(typval_T *argvars, typval_T *rettv);
static void f_getcurpos(typval_T *argvars, typval_T *rettv);
+ static void f_getcursorcharpos(typval_T *argvars, typval_T *rettv);
static void f_getpos(typval_T *argvars, typval_T *rettv);
static void f_getreg(typval_T *argvars, typval_T *rettv);
static void f_getreginfo(typval_T *argvars, typval_T *rettv);
***************
*** 190,196 ****
--- 193,201 ----
static void f_searchpair(typval_T *argvars, typval_T *rettv);
static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
static void f_searchpos(typval_T *argvars, typval_T *rettv);
+ static void f_setcharpos(typval_T *argvars, typval_T *rettv);
static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
+ static void f_setcursorcharpos(typval_T *argvars, typval_T *rettv);
static void f_setenv(typval_T *argvars, typval_T *rettv);
static void f_setfperm(typval_T *argvars, typval_T *rettv);
static void f_setpos(typval_T *argvars, typval_T *rettv);
***************
*** 790,795 ****
--- 795,802 ----
ret_number, f_char2nr},
{"charclass", 1, 1, FEARG_1, NULL,
ret_number, f_charclass},
+ {"charcol", 1, 1, FEARG_1, NULL,
+ ret_number, f_charcol},
{"charidx", 2, 3, FEARG_1, NULL,
ret_number, f_charidx},
{"chdir", 1, 1, FEARG_1, NULL,
***************
*** 928,933 ****
--- 935,942 ----
ret_number, f_getchar},
{"getcharmod", 0, 0, 0, NULL,
ret_number, f_getcharmod},
+ {"getcharpos", 1, 1, FEARG_1, NULL,
+ ret_list_number, f_getcharpos},
{"getcharsearch", 0, 0, 0, NULL,
ret_dict_any, f_getcharsearch},
{"getcmdline", 0, 0, 0, NULL,
***************
*** 942,947 ****
--- 951,958 ----
ret_list_string, f_getcompletion},
{"getcurpos", 0, 1, FEARG_1, NULL,
ret_list_number, f_getcurpos},
+ {"getcursorcharpos", 0, 1, FEARG_1, NULL,
+ ret_list_number, f_getcursorcharpos},
{"getcwd", 0, 2, FEARG_1, NULL,
ret_string, f_getcwd},
{"getenv", 1, 1, FEARG_1, NULL,
***************
*** 1394,1403 ****
--- 1405,1418 ----
ret_void, f_setbufvar},
{"setcellwidths", 1, 1, FEARG_1, NULL,
ret_void, f_setcellwidths},
+ {"setcharpos", 2, 2, FEARG_2, NULL,
+ ret_number, f_setcharpos},
{"setcharsearch", 1, 1, FEARG_1, NULL,
ret_void, f_setcharsearch},
{"setcmdpos", 1, 1, FEARG_1, NULL,
ret_number, f_setcmdpos},
+ {"setcursorcharpos", 1, 3, FEARG_1, NULL,
+ ret_number, f_setcursorcharpos},
{"setenv", 2, 2, FEARG_2, NULL,
ret_void, f_setenv},
{"setfperm", 2, 2, FEARG_1, NULL,
***************
*** 2424,2429 ****
--- 2439,2499 ----
}
/*
+ * Get the current cursor column and store it in 'rettv'. If 'charcol' is
TRUE,
+ * returns the character index of the column. Otherwise, returns the byte
index
+ * of the column.
+ */
+ static void
+ get_col(typval_T *argvars, typval_T *rettv, int charcol)
+ {
+ colnr_T col = 0;
+ pos_T *fp;
+ int fnum = curbuf->b_fnum;
+
+ fp = var2fpos(&argvars[0], FALSE, &fnum, charcol);
+ if (fp != NULL && fnum == curbuf->b_fnum)
+ {
+ if (fp->col == MAXCOL)
+ {
+ // '> can be MAXCOL, get the length of the line then
+ if (fp->lnum <= curbuf->b_ml.ml_line_count)
+ col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
+ else
+ col = MAXCOL;
+ }
+ else
+ {
+ col = fp->col + 1;
+ // col(".") when the cursor is on the NUL at the end of the line
+ // because of "coladd" can be seen as an extra column.
+ if (virtual_active() && fp == &curwin->w_cursor)
+ {
+ char_u *p = ml_get_cursor();
+
+ if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
+ curwin->w_virtcol - curwin->w_cursor.coladd))
+ {
+ int l;
+
+ if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
+ col += l;
+ }
+ }
+ }
+ }
+ rettv->vval.v_number = col;
+ }
+
+ /*
+ * "charcol()" function
+ */
+ static void
+ f_charcol(typval_T *argvars, typval_T *rettv)
+ {
+ get_col(argvars, rettv, TRUE);
+ }
+
+ /*
* "charidx()" function
*/
static void
***************
*** 2497,2538 ****
static void
f_col(typval_T *argvars, typval_T *rettv)
{
! colnr_T col = 0;
! pos_T *fp;
! int fnum = curbuf->b_fnum;
!
! fp = var2fpos(&argvars[0], FALSE, &fnum);
! if (fp != NULL && fnum == curbuf->b_fnum)
! {
! if (fp->col == MAXCOL)
! {
! // '> can be MAXCOL, get the length of the line then
! if (fp->lnum <= curbuf->b_ml.ml_line_count)
! col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
! else
! col = MAXCOL;
! }
! else
! {
! col = fp->col + 1;
! // col(".") when the cursor is on the NUL at the end of the line
! // because of "coladd" can be seen as an extra column.
! if (virtual_active() && fp == &curwin->w_cursor)
! {
! char_u *p = ml_get_cursor();
!
! if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
! curwin->w_virtcol - curwin->w_cursor.coladd))
! {
! int l;
!
! if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
! col += l;
! }
! }
! }
! }
! rettv->vval.v_number = col;
}
/*
--- 2567,2573 ----
static void
f_col(typval_T *argvars, typval_T *rettv)
{
! get_col(argvars, rettv, FALSE);
}
/*
***************
*** 2633,2658 ****
#endif
/*
! * "cursor(lnum, col)" function, or
! * "cursor(list)"
! *
! * Moves the cursor to the specified line and column.
! * Returns 0 when the position could be set, -1 otherwise.
*/
static void
! f_cursor(typval_T *argvars, typval_T *rettv)
{
long line, col;
long coladd = 0;
int set_curswant = TRUE;
rettv->vval.v_number = -1;
! if (argvars[1].v_type == VAR_UNKNOWN)
{
pos_T pos;
colnr_T curswant = -1;
! if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
{
emsg(_(e_invarg));
return;
--- 2668,2691 ----
#endif
/*
! * Set the cursor position.
! * If 'charcol' is TRUE, then use the column number as a character offet.
! * Otherwise use the column number as a byte offset.
*/
static void
! set_cursorpos(typval_T *argvars, typval_T *rettv, int charcol)
{
long line, col;
long coladd = 0;
int set_curswant = TRUE;
rettv->vval.v_number = -1;
! if (argvars[0].v_type == VAR_LIST)
{
pos_T pos;
colnr_T curswant = -1;
! if (list2fpos(argvars, &pos, NULL, &curswant, charcol) == FAIL)
{
emsg(_(e_invarg));
return;
***************
*** 2666,2680 ****
set_curswant = FALSE;
}
}
! else
{
line = tv_get_lnum(argvars);
if (line < 0)
semsg(_(e_invarg2), tv_get_string(&argvars[0]));
col = (long)tv_get_number_chk(&argvars[1], NULL);
if (argvars[2].v_type != VAR_UNKNOWN)
coladd = (long)tv_get_number_chk(&argvars[2], NULL);
}
if (line < 0 || col < 0 || coladd < 0)
return; // type error; errmsg already given
if (line > 0)
--- 2699,2722 ----
set_curswant = FALSE;
}
}
! else if ((argvars[0].v_type == VAR_NUMBER ||
! argvars[0].v_type == VAR_STRING)
! && argvars[1].v_type == VAR_NUMBER)
{
line = tv_get_lnum(argvars);
if (line < 0)
semsg(_(e_invarg2), tv_get_string(&argvars[0]));
col = (long)tv_get_number_chk(&argvars[1], NULL);
+ if (charcol)
+ col = buf_charidx_to_byteidx(curbuf, line, col);
if (argvars[2].v_type != VAR_UNKNOWN)
coladd = (long)tv_get_number_chk(&argvars[2], NULL);
}
+ else
+ {
+ emsg(_(e_invarg));
+ return;
+ }
if (line < 0 || col < 0 || coladd < 0)
return; // type error; errmsg already given
if (line > 0)
***************
*** 2693,2698 ****
--- 2735,2753 ----
rettv->vval.v_number = 0;
}
+ /*
+ * "cursor(lnum, col)" function, or
+ * "cursor(list)"
+ *
+ * Moves the cursor to the specified line and column.
+ * Returns 0 when the position could be set, -1 otherwise.
+ */
+ static void
+ f_cursor(typval_T *argvars, typval_T *rettv)
+ {
+ set_cursorpos(argvars, rettv, FALSE);
+ }
+
#ifdef MSWIN
/*
* "debugbreak()" function
***************
*** 3887,3892 ****
--- 3942,4029 ----
#endif
}
+ static void
+ getpos_both(
+ typval_T *argvars,
+ typval_T *rettv,
+ int getcurpos,
+ int charcol)
+ {
+ pos_T *fp = NULL;
+ pos_T pos;
+ win_T *wp = curwin;
+ list_T *l;
+ int fnum = -1;
+
+ if (rettv_list_alloc(rettv) == OK)
+ {
+ l = rettv->vval.v_list;
+ if (getcurpos)
+ {
+ if (argvars[0].v_type != VAR_UNKNOWN)
+ {
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp != NULL)
+ fp = &wp->w_cursor;
+ }
+ else
+ fp = &curwin->w_cursor;
+ if (fp != NULL && charcol)
+ {
+ pos = *fp;
+ pos.col = buf_byteidx_to_charidx(wp->w_buffer, pos.lnum,
+ pos.col) - 1;
+ fp = &pos;
+ }
+ }
+ else
+ fp = var2fpos(&argvars[0], TRUE, &fnum, charcol);
+ if (fnum != -1)
+ list_append_number(l, (varnumber_T)fnum);
+ else
+ list_append_number(l, (varnumber_T)0);
+ list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
+ : (varnumber_T)0);
+ list_append_number(l, (fp != NULL)
+ ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
+ : (varnumber_T)0);
+ list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
+ (varnumber_T)0);
+ if (getcurpos)
+ {
+ int save_set_curswant = curwin->w_set_curswant;
+ colnr_T save_curswant = curwin->w_curswant;
+ colnr_T save_virtcol = curwin->w_virtcol;
+
+ if (wp == curwin)
+ update_curswant();
+ list_append_number(l, wp == NULL ? 0 : wp->w_curswant == MAXCOL
+ ? (varnumber_T)MAXCOL : (varnumber_T)wp->w_curswant + 1);
+
+ // Do not change "curswant", as it is unexpected that a get
+ // function has a side effect.
+ if (wp == curwin && save_set_curswant)
+ {
+ curwin->w_set_curswant = save_set_curswant;
+ curwin->w_curswant = save_curswant;
+ curwin->w_virtcol = save_virtcol;
+ curwin->w_valid &= ~VALID_VIRTCOL;
+ }
+ }
+ }
+ else
+ rettv->vval.v_number = FALSE;
+ }
+
+ /*
+ * "getcharpos()" function
+ */
+ static void
+ f_getcharpos(typval_T *argvars UNUSED, typval_T *rettv)
+ {
+ getpos_both(argvars, rettv, FALSE, TRUE);
+ }
+
/*
* "getcharsearch()" function
*/
***************
*** 4019,4095 ****
rettv->vval.v_number = mch_get_pid();
}
- static void
- getpos_both(
- typval_T *argvars,
- typval_T *rettv,
- int getcurpos)
- {
- pos_T *fp = NULL;
- win_T *wp = curwin;
- list_T *l;
- int fnum = -1;
-
- if (rettv_list_alloc(rettv) == OK)
- {
- l = rettv->vval.v_list;
- if (getcurpos)
- {
- if (argvars[0].v_type != VAR_UNKNOWN)
- {
- wp = find_win_by_nr_or_id(&argvars[0]);
- if (wp != NULL)
- fp = &wp->w_cursor;
- }
- else
- fp = &curwin->w_cursor;
- }
- else
- fp = var2fpos(&argvars[0], TRUE, &fnum);
- if (fnum != -1)
- list_append_number(l, (varnumber_T)fnum);
- else
- list_append_number(l, (varnumber_T)0);
- list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
- : (varnumber_T)0);
- list_append_number(l, (fp != NULL)
- ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
- : (varnumber_T)0);
- list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
- (varnumber_T)0);
- if (getcurpos)
- {
- int save_set_curswant = curwin->w_set_curswant;
- colnr_T save_curswant = curwin->w_curswant;
- colnr_T save_virtcol = curwin->w_virtcol;
-
- if (wp == curwin)
- update_curswant();
- list_append_number(l, wp == NULL ? 0 : wp->w_curswant == MAXCOL
- ? (varnumber_T)MAXCOL : (varnumber_T)wp->w_curswant + 1);
-
- // Do not change "curswant", as it is unexpected that a get
- // function has a side effect.
- if (wp == curwin && save_set_curswant)
- {
- curwin->w_set_curswant = save_set_curswant;
- curwin->w_curswant = save_curswant;
- curwin->w_virtcol = save_virtcol;
- curwin->w_valid &= ~VALID_VIRTCOL;
- }
- }
- }
- else
- rettv->vval.v_number = FALSE;
- }
-
/*
* "getcurpos()" function
*/
static void
f_getcurpos(typval_T *argvars, typval_T *rettv)
{
! getpos_both(argvars, rettv, TRUE);
}
/*
--- 4156,4174 ----
rettv->vval.v_number = mch_get_pid();
}
/*
* "getcurpos()" function
*/
static void
f_getcurpos(typval_T *argvars, typval_T *rettv)
{
! getpos_both(argvars, rettv, TRUE, FALSE);
! }
!
! static void
! f_getcursorcharpos(typval_T *argvars, typval_T *rettv)
! {
! getpos_both(argvars, rettv, TRUE, TRUE);
}
/*
***************
*** 4098,4104 ****
static void
f_getpos(typval_T *argvars, typval_T *rettv)
{
! getpos_both(argvars, rettv, FALSE);
}
/*
--- 4177,4183 ----
static void
f_getpos(typval_T *argvars, typval_T *rettv)
{
! getpos_both(argvars, rettv, FALSE, FALSE);
}
/*
***************
*** 6183,6196 ****
== OK)
{
check_cursor();
! fp = var2fpos(&argvars[0], TRUE, &fnum);
}
restore_win_noblock(save_curwin, save_curtab, TRUE);
}
}
else
// use current window
! fp = var2fpos(&argvars[0], TRUE, &fnum);
if (fp != NULL)
lnum = fp->lnum;
--- 6262,6275 ----
== OK)
{
check_cursor();
! fp = var2fpos(&argvars[0], TRUE, &fnum, FALSE);
}
restore_win_noblock(save_curwin, save_curtab, TRUE);
}
}
else
// use current window
! fp = var2fpos(&argvars[0], TRUE, &fnum, FALSE);
if (fp != NULL)
lnum = fp->lnum;
***************
*** 8065,8070 ****
--- 8144,8203 ----
list_append_number(rettv->vval.v_list, (varnumber_T)n);
}
+ /*
+ * Set the cursor or mark position.
+ * If 'charpos' is TRUE, then use the column number as a character offet.
+ * Otherwise use the column number as a byte offset.
+ */
+ static void
+ set_position(typval_T *argvars, typval_T *rettv, int charpos)
+ {
+ pos_T pos;
+ int fnum;
+ char_u *name;
+ colnr_T curswant = -1;
+
+ rettv->vval.v_number = -1;
+
+ name = tv_get_string_chk(argvars);
+ if (name != NULL)
+ {
+ if (list2fpos(&argvars[1], &pos, &fnum, &curswant, charpos) == OK)
+ {
+ if (pos.col != MAXCOL && --pos.col < 0)
+ pos.col = 0;
+ if ((name[0] == '.' && name[1] == NUL))
+ {
+ // set cursor; "fnum" is ignored
+ curwin->w_cursor = pos;
+ if (curswant >= 0)
+ {
+ curwin->w_curswant = curswant - 1;
+ curwin->w_set_curswant = FALSE;
+ }
+ check_cursor();
+ rettv->vval.v_number = 0;
+ }
+ else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
+ {
+ // set mark
+ if (setmark_pos(name[1], &pos, fnum) == OK)
+ rettv->vval.v_number = 0;
+ }
+ else
+ emsg(_(e_invarg));
+ }
+ }
+ }
+ /*
+ * "setcharpos()" function
+ */
+ static void
+ f_setcharpos(typval_T *argvars, typval_T *rettv)
+ {
+ set_position(argvars, rettv, TRUE);
+ }
+
static void
f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
{
***************
*** 8107,8112 ****
--- 8240,8254 ----
}
/*
+ * "setcursorcharpos" function
+ */
+ static void
+ f_setcursorcharpos(typval_T *argvars, typval_T *rettv UNUSED)
+ {
+ set_cursorpos(argvars, rettv, TRUE);
+ }
+
+ /*
* "setenv()" function
*/
static void
***************
*** 8165,8205 ****
static void
f_setpos(typval_T *argvars, typval_T *rettv)
{
! pos_T pos;
! int fnum;
! char_u *name;
! colnr_T curswant = -1;
!
! rettv->vval.v_number = -1;
! name = tv_get_string_chk(argvars);
! if (name != NULL)
! {
! if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
! {
! if (pos.col != MAXCOL && --pos.col < 0)
! pos.col = 0;
! if (name[0] == '.' && name[1] == NUL)
! {
! // set cursor; "fnum" is ignored
! curwin->w_cursor = pos;
! if (curswant >= 0)
! {
! curwin->w_curswant = curswant - 1;
! curwin->w_set_curswant = FALSE;
! }
! check_cursor();
! rettv->vval.v_number = 0;
! }
! else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
! {
! // set mark
! if (setmark_pos(name[1], &pos, fnum) == OK)
! rettv->vval.v_number = 0;
! }
! else
! emsg(_(e_invarg));
! }
! }
}
/*
--- 8307,8313 ----
static void
f_setpos(typval_T *argvars, typval_T *rettv)
{
! set_position(argvars, rettv, FALSE);
}
/*
***************
*** 9947,9953 ****
int fnum = curbuf->b_fnum;
int len;
! fp = var2fpos(&argvars[0], FALSE, &fnum);
if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
&& fnum == curbuf->b_fnum)
{
--- 10055,10061 ----
int fnum = curbuf->b_fnum;
int len;
! fp = var2fpos(&argvars[0], FALSE, &fnum, FALSE);
if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
&& fnum == curbuf->b_fnum)
{
*** ../vim-8.2.2323/src/proto/eval.pro 2021-01-09 13:20:32.200472552 +0100
--- src/proto/eval.pro 2021-01-10 19:55:52.679431025 +0100
***************
*** 55,62 ****
char_u *echo_string(typval_T *tv, char_u **tofree, char_u *numbuf, int
copyID);
char_u *string_quote(char_u *str, int function);
int string2float(char_u *text, float_T *value);
! pos_T *var2fpos(typval_T *varp, int dollar_lnum, int *fnum);
! int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp);
int get_env_len(char_u **arg);
int get_id_len(char_u **arg);
int get_name_len(char_u **arg, char_u **alias, int evaluate, int verbose);
--- 55,64 ----
char_u *echo_string(typval_T *tv, char_u **tofree, char_u *numbuf, int
copyID);
char_u *string_quote(char_u *str, int function);
int string2float(char_u *text, float_T *value);
! int buf_byteidx_to_charidx(buf_T *buf, int lnum, int byteidx);
! int buf_charidx_to_byteidx(buf_T *buf, int lnum, int charidx);
! pos_T *var2fpos(typval_T *varp, int dollar_lnum, int *fnum, int charcol);
! int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp, int
char_col);
int get_env_len(char_u **arg);
int get_id_len(char_u **arg);
int get_name_len(char_u **arg, char_u **alias, int evaluate, int verbose);
*** ../vim-8.2.2323/src/tag.c 2021-01-04 12:41:49.507891351 +0100
--- src/tag.c 2021-01-10 19:55:52.679431025 +0100
***************
*** 4201,4207 ****
// parse 'from' for the cursor position before the tag jump
if ((di = dict_find(itemdict, (char_u *)"from", -1)) == NULL)
continue;
! if (list2fpos(&di->di_tv, &mark, &fnum, NULL) != OK)
continue;
if ((tagname =
dict_get_string(itemdict, (char_u *)"tagname", TRUE)) == NULL)
--- 4201,4207 ----
// parse 'from' for the cursor position before the tag jump
if ((di = dict_find(itemdict, (char_u *)"from", -1)) == NULL)
continue;
! if (list2fpos(&di->di_tv, &mark, &fnum, NULL, FALSE) != OK)
continue;
if ((tagname =
dict_get_string(itemdict, (char_u *)"tagname", TRUE)) == NULL)
*** ../vim-8.2.2323/src/testdir/test_cursor_func.vim 2020-12-21
21:58:42.607687803 +0100
--- src/testdir/test_cursor_func.vim 2021-01-10 19:55:52.683431015 +0100
***************
*** 1,4 ****
! " Tests for cursor().
func Test_wrong_arguments()
call assert_fails('call cursor(1. 3)', 'E474:')
--- 1,4 ----
! " Tests for cursor() and other functions that get/set the cursor position
func Test_wrong_arguments()
call assert_fails('call cursor(1. 3)', 'E474:')
***************
*** 123,126 ****
--- 123,309 ----
bwipe!
endfunc
+ func SaveVisualStartCharPos()
+ call add(g:VisualStartPos, getcharpos('v'))
+ return ''
+ endfunc
+
+ " Test for the getcharpos() function
+ func Test_getcharpos()
+ call assert_fails('call getcharpos({})', 'E731:')
+ call assert_equal([0, 0, 0, 0], getcharpos(0))
+ new
+ call setline(1, ['', "01\tà4è678", 'Ⅵ', '012345678'])
+
+ " Test for '.' and '$'
+ normal 1G
+ call assert_equal([0, 1, 1, 0], getcharpos('.'))
+ call assert_equal([0, 4, 1, 0], getcharpos('$'))
+ normal 2G6l
+ call assert_equal([0, 2, 7, 0], getcharpos('.'))
+ normal 3G$
+ call assert_equal([0, 3, 1, 0], getcharpos('.'))
+ normal 4G$
+ call assert_equal([0, 4, 9, 0], getcharpos('.'))
+
+ " Test for a mark
+ normal 2G7lmmgg
+ call assert_equal([0, 2, 8, 0], getcharpos("'m"))
+ delmarks m
+ call assert_equal([0, 0, 0, 0], getcharpos("'m"))
+
+ " Test for the visual start column
+ vnoremap <expr> <F3> SaveVisualStartCharPos()
+ let g:VisualStartPos = []
+ exe "normal 2G6lv$\<F3>ohh\<F3>o\<F3>"
+ call assert_equal([[0, 2, 7, 0], [0, 2, 9, 0], [0, 2, 5, 0]],
g:VisualStartPos)
+ call assert_equal([0, 2, 9, 0], getcharpos('v'))
+ let g:VisualStartPos = []
+ exe "normal 3Gv$\<F3>o\<F3>"
+ call assert_equal([[0, 3, 1, 0], [0, 3, 1, 0]], g:VisualStartPos)
+ let g:VisualStartPos = []
+ exe "normal 1Gv$\<F3>o\<F3>"
+ call assert_equal([[0, 1, 1, 0], [0, 1, 1, 0]], g:VisualStartPos)
+ vunmap <F3>
+
+ %bw!
+ endfunc
+
+ " Test for the setcharpos() function
+ func Test_setcharpos()
+ call assert_equal(-1, setcharpos('.', test_null_list()))
+ new
+ call setline(1, ['', "01\tà4è678", 'Ⅵ', '012345678'])
+ call setcharpos('.', [0, 1, 1, 0])
+ call assert_equal([1, 1], [line('.'), col('.')])
+ call setcharpos('.', [0, 2, 7, 0])
+ call assert_equal([2, 9], [line('.'), col('.')])
+ call setcharpos('.', [0, 3, 4, 0])
+ call assert_equal([3, 1], [line('.'), col('.')])
+ call setcharpos('.', [0, 3, 1, 0])
+ call assert_equal([3, 1], [line('.'), col('.')])
+ call setcharpos('.', [0, 4, 0, 0])
+ call assert_equal([4, 1], [line('.'), col('.')])
+ call setcharpos('.', [0, 4, 20, 0])
+ call assert_equal([4, 9], [line('.'), col('.')])
+
+ " Test for mark
+ delmarks m
+ call setcharpos("'m", [0, 2, 9, 0])
+ normal `m
+ call assert_equal([2, 11], [line('.'), col('.')])
+
+ %bw!
+ call assert_equal(-1, setcharpos('.', [10, 3, 1, 0]))
+ endfunc
+
+ func SaveVisualStartCharCol()
+ call add(g:VisualStartCol, charcol('v'))
+ return ''
+ endfunc
+
+ " Test for the charcol() function
+ func Test_charcol()
+ call assert_fails('call charcol({})', 'E731:')
+ call assert_equal(0, charcol(0))
+ new
+ call setline(1, ['', "01\tà4è678", 'Ⅵ', '012345678'])
+
+ " Test for '.' and '$'
+ normal 1G
+ call assert_equal(1, charcol('.'))
+ call assert_equal(1, charcol('$'))
+ normal 2G6l
+ call assert_equal(7, charcol('.'))
+ call assert_equal(10, charcol('$'))
+ normal 3G$
+ call assert_equal(1, charcol('.'))
+ call assert_equal(2, charcol('$'))
+ normal 4G$
+ call assert_equal(9, charcol('.'))
+ call assert_equal(10, charcol('$'))
+
+ " Test for [lnum, '$']
+ call assert_equal(1, charcol([1, '$']))
+ call assert_equal(10, charcol([2, '$']))
+ call assert_equal(2, charcol([3, '$']))
+ call assert_equal(0, charcol([5, '$']))
+
+ " Test for a mark
+ normal 2G7lmmgg
+ call assert_equal(8, charcol("'m"))
+ delmarks m
+ call assert_equal(0, charcol("'m"))
+
+ " Test for the visual start column
+ vnoremap <expr> <F3> SaveVisualStartCharCol()
+ let g:VisualStartCol = []
+ exe "normal 2G6lv$\<F3>ohh\<F3>o\<F3>"
+ call assert_equal([7, 9, 5], g:VisualStartCol)
+ call assert_equal(9, charcol('v'))
+ let g:VisualStartCol = []
+ exe "normal 3Gv$\<F3>o\<F3>"
+ call assert_equal([1, 1], g:VisualStartCol)
+ let g:VisualStartCol = []
+ exe "normal 1Gv$\<F3>o\<F3>"
+ call assert_equal([1, 1], g:VisualStartCol)
+ vunmap <F3>
+
+ %bw!
+ endfunc
+
+ " Test for getcursorcharpos()
+ func Test_getcursorcharpos()
+ call assert_equal(getcursorcharpos(), getcursorcharpos(0))
+ call assert_equal([0, 0, 0, 0, 0], getcursorcharpos(-1))
+ call assert_equal([0, 0, 0, 0, 0], getcursorcharpos(1999))
+
+ new
+ call setline(1, ['', "01\tà4è678", 'Ⅵ', '012345678'])
+ normal 1G9l
+ call assert_equal([0, 1, 1, 0, 1], getcursorcharpos())
+ normal 2G9l
+ call assert_equal([0, 2, 9, 0, 14], getcursorcharpos())
+ normal 3G9l
+ call assert_equal([0, 3, 1, 0, 1], getcursorcharpos())
+ normal 4G9l
+ call assert_equal([0, 4, 9, 0, 9], getcursorcharpos())
+
+ let winid = win_getid()
+ normal 2G5l
+ wincmd w
+ call assert_equal([0, 2, 6, 0, 11], getcursorcharpos(winid))
+ %bw!
+ endfunc
+
+ " Test for setcursorcharpos()
+ func Test_setcursorcharpos()
+ call assert_fails('call setcursorcharpos(test_null_list())', 'E474:')
+ call assert_fails('call setcursorcharpos([1])', 'E474:')
+ call assert_fails('call setcursorcharpos([1, 1, 1, 1, 1])', 'E474:')
+ new
+ call setline(1, ['', "01\tà4è678", 'Ⅵ', '012345678'])
+ normal G
+ call setcursorcharpos([1, 1])
+ call assert_equal([1, 1], [line('.'), col('.')])
+ call setcursorcharpos([2, 7, 0])
+ call assert_equal([2, 9], [line('.'), col('.')])
+ call setcursorcharpos(3, 4)
+ call assert_equal([3, 1], [line('.'), col('.')])
+ call setcursorcharpos([3, 1])
+ call assert_equal([3, 1], [line('.'), col('.')])
+ call setcursorcharpos([4, 0, 0, 0])
+ call assert_equal([4, 1], [line('.'), col('.')])
+ call setcursorcharpos([4, 20])
+ call assert_equal([4, 9], [line('.'), col('.')])
+ normal 1G
+ call setcursorcharpos([100, 100, 100, 100])
+ call assert_equal([4, 9], [line('.'), col('.')])
+ normal 1G
+ call setcursorcharpos('$', 1)
+ call assert_equal([4, 1], [line('.'), col('.')])
+
+ %bw!
+ endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
*** ../vim-8.2.2323/src/typval.c 2021-01-09 16:21:33.996353408 +0100
--- src/typval.c 2021-01-10 19:55:52.683431015 +0100
***************
*** 1579,1585 ****
if (lnum <= 0) // no valid number, try using arg like line()
{
int fnum;
! pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
if (fp != NULL)
lnum = fp->lnum;
--- 1579,1585 ----
if (lnum <= 0) // no valid number, try using arg like line()
{
int fnum;
! pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum, FALSE);
if (fp != NULL)
lnum = fp->lnum;
*** ../vim-8.2.2323/src/version.c 2021-01-10 19:23:23.352958354 +0100
--- src/version.c 2021-01-10 19:57:13.771202312 +0100
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 2324,
/**/
--
~
~
~
".signature" 4 lines, 50 characters written
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
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 on the web visit
https://groups.google.com/d/msgid/vim_dev/202101101923.10AJNM5O419873%40masaka.moolenaar.net.