Patch 8.2.5019
Problem: Cannot get the first screen column of a character.
Solution: Let virtcol() optionally return a list. (closes #10482,
closes #7964)
Files: runtime/doc/builtin.txt, src/evalfunc.c,
src/testdir/test_functions.vim, src/testdir/test_vim9_builtin.vim
*** ../vim-8.2.5018/runtime/doc/builtin.txt 2022-05-24 11:40:07.514685757
+0100
--- runtime/doc/builtin.txt 2022-05-26 12:00:32.582468991 +0100
***************
*** 689,695 ****
uniq({list} [, {func} [, {dict}]])
List remove adjacent duplicates from a list
values({dict}) List values in {dict}
! virtcol({expr}) Number screen column of cursor or mark
visualmode([expr]) String last visual mode used
wildmenumode() Number whether 'wildmenu' mode is
active
win_execute({id}, {command} [, {silent}])
--- 689,696 ----
uniq({list} [, {func} [, {dict}]])
List remove adjacent duplicates from a list
values({dict}) List values in {dict}
! virtcol({expr} [, {list}]) Number or List
! screen column of cursor or mark
visualmode([expr]) String last visual mode used
wildmenumode() Number whether 'wildmenu' mode is
active
win_execute({id}, {command} [, {silent}])
***************
*** 780,785 ****
--- 781,787 ----
and({expr}, {expr}) *and()*
Bitwise AND on the two arguments. The arguments are converted
to a number. A List, Dict or Float argument causes an error.
+ Also see `or()` and `xor()`.
Example: >
:let flag = and(bits, 0x80)
< Can also be used as a |method|: >
***************
*** 936,948 ****
item is ignored.
cmd Ex command to execute for this autocmd event
event autocmd event name. Refer to |autocmd-events|.
group autocmd group name. Refer to |autocmd-groups|.
If this group doesn't exist then it is
created. If not specified or empty, then the
default group is used.
nested boolean flag, set to v:true to add a nested
autocmd. Refer to |autocmd-nested|.
! once boolean flag, set to v:true to add a autocmd
which executes only once. Refer to
|autocmd-once|.
pattern autocmd pattern string. Refer to
--- 938,951 ----
item is ignored.
cmd Ex command to execute for this autocmd event
event autocmd event name. Refer to |autocmd-events|.
+ TODO: currently only accepts one event.
group autocmd group name. Refer to |autocmd-groups|.
If this group doesn't exist then it is
created. If not specified or empty, then the
default group is used.
nested boolean flag, set to v:true to add a nested
autocmd. Refer to |autocmd-nested|.
! once boolean flag, set to v:true to add an autocmd
which executes only once. Refer to
|autocmd-once|.
pattern autocmd pattern string. Refer to
***************
*** 952,958 ****
commands associated with the specified autocmd
event and group and add the {cmd}. This is
useful to avoid adding the same command
! multiple times for a autocmd event in a group.
Returns v:true on success and v:false on failure.
Examples: >
--- 955,961 ----
commands associated with the specified autocmd
event and group and add the {cmd}. This is
useful to avoid adding the same command
! multiple times for an autocmd event in a group.
Returns v:true on success and v:false on failure.
Examples: >
***************
*** 9727,9733 ****
Can also be used as a |method|: >
mydict->values()
! virtcol({expr}) *virtcol()*
The result is a Number, which is the screen column of the file
position given with {expr}. That is, the last screen position
occupied by the character at that position, when the screen
--- 9736,9742 ----
Can also be used as a |method|: >
mydict->values()
! virtcol({expr} [, {list}]) *virtcol()*
The result is a Number, which is the screen column of the file
position given with {expr}. That is, the last screen position
occupied by the character at that position, when the screen
***************
*** 9736,9748 ****
the <Tab>. For example, for a <Tab> in column 1, with 'ts'
set to 8, it returns 8. |conceal| is ignored.
For the byte position use |col()|.
For the use of {expr} see |col()|.
! When 'virtualedit' is used {expr} can be [lnum, col, off], where
! "off" is the offset in screen columns from the start of the
! character. E.g., a position within a <Tab> or after the last
! character. When "off" is omitted zero is used.
! When Virtual editing is active in the current mode, a position
! beyond the end of the line can be returned. |'virtualedit'|
The accepted positions are:
. the cursor position
$ the end of the cursor line (the result is the
--- 9745,9761 ----
the <Tab>. For example, for a <Tab> in column 1, with 'ts'
set to 8, it returns 8. |conceal| is ignored.
For the byte position use |col()|.
+
For the use of {expr} see |col()|.
!
! When 'virtualedit' is used {expr} can be [lnum, col, off],
! where "off" is the offset in screen columns from the start of
! the character. E.g., a position within a <Tab> or after the
! last character. When "off" is omitted zero is used. When
! Virtual editing is active in the current mode, a position
! beyond the end of the line can be returned. Also see
! |'virtualedit'|
!
The accepted positions are:
. the cursor position
$ the end of the cursor line (the result is the
***************
*** 9754,9764 ****
cursor is the end). When not in Visual mode
returns the cursor position. Differs from |'<| in
that it's updated right away.
Note that only marks in the current file can be used.
Examples: >
! virtcol(".") with text "foo^Lbar", with cursor on the "^L",
returns 5
! virtcol("$") with text "foo^Lbar", returns 9
! virtcol("'t") with text " there", with 't at 'h', returns 6
< The first column is 1. 0 is returned for an error.
A more advanced example that echoes the maximum length of
all lines: >
--- 9767,9788 ----
cursor is the end). When not in Visual mode
returns the cursor position. Differs from |'<| in
that it's updated right away.
+
+ If {list} is present and non-zero then virtcol() returns a List
+ with the first and last screen position occupied by the
+ character.
+
Note that only marks in the current file can be used.
Examples: >
! " With text "foo^Lbar" and cursor on the "^L":
!
! virtcol(".") " returns 5
! virtcol(".", 1) " returns [4, 5]
! virtcol("$") " returns 9
!
! " With text " there", with 't at 'h':
!
! virtcol("'t") " returns 6
< The first column is 1. 0 is returned for an error.
A more advanced example that echoes the maximum length of
all lines: >
*** ../vim-8.2.5018/src/evalfunc.c 2022-05-21 20:16:51.003567195 +0100
--- src/evalfunc.c 2022-05-26 11:52:49.938931235 +0100
***************
*** 994,999 ****
--- 994,1000 ----
static argcheck_T arg2_string_list_number[] = {arg_string, arg_list_number};
static argcheck_T arg2_string_number[] = {arg_string, arg_number};
static argcheck_T arg2_string_or_list_dict[] = {arg_string_or_list_any,
arg_dict_any};
+ static argcheck_T arg2_string_or_list_bool[] = {arg_string_or_list_any,
arg_bool};
static argcheck_T arg2_string_string_or_number[] = {arg_string,
arg_string_or_nr};
static argcheck_T arg3_any_list_dict[] = {NULL, arg_list_any, arg_dict_any};
static argcheck_T arg3_buffer_lnum_lnum[] = {arg_buffer, arg_lnum, arg_lnum};
***************
*** 1458,1463 ****
--- 1459,1478 ----
}
static type_T *
+ ret_virtcol(int argcount,
+ type2_T *argtypes UNUSED,
+ type_T **decl_type)
+ {
+ // Assume that if the second argument is passed it's non-zero
+ if (argcount == 2)
+ {
+ *decl_type = &t_list_any;
+ return &t_list_number;
+ }
+ return &t_number;
+ }
+
+ static type_T *
ret_maparg(int argcount,
type2_T *argtypes UNUSED,
type_T **decl_type UNUSED)
***************
*** 2665,2672 ****
ret_first_arg, f_uniq},
{"values", 1, 1, FEARG_1, arg1_dict_any,
ret_list_any, f_values},
! {"virtcol", 1, 1, FEARG_1, arg1_string_or_list_any,
! ret_number, f_virtcol},
{"visualmode", 0, 1, 0, arg1_bool,
ret_string, f_visualmode},
{"wildmenumode", 0, 0, 0, NULL,
--- 2680,2687 ----
ret_first_arg, f_uniq},
{"values", 1, 1, FEARG_1, arg1_dict_any,
ret_list_any, f_values},
! {"virtcol", 1, 2, FEARG_1, arg2_string_or_list_bool,
! ret_virtcol, f_virtcol},
{"visualmode", 0, 1, 0, arg1_bool,
ret_string, f_visualmode},
{"wildmenumode", 0, 0, 0, NULL,
***************
*** 10380,10402 ****
}
/*
! * "virtcol(string)" function
*/
static void
f_virtcol(typval_T *argvars, typval_T *rettv)
{
! colnr_T vcol = 0;
pos_T *fp;
int fnum = curbuf->b_fnum;
int len;
if (in_vim9script()
! && check_for_string_or_list_arg(argvars, 0) == FAIL)
return;
fp = var2fpos(&argvars[0], FALSE, &fnum, FALSE);
if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
! && fnum == curbuf->b_fnum)
{
// Limit the column to a valid value, getvvcol() doesn't check.
if (fp->col < 0)
--- 10395,10420 ----
}
/*
! * "virtcol(string, bool)" function
*/
static void
f_virtcol(typval_T *argvars, typval_T *rettv)
{
! colnr_T vcol_start = 0;
! colnr_T vcol_end = 0;
pos_T *fp;
int fnum = curbuf->b_fnum;
int len;
if (in_vim9script()
! && (check_for_string_or_list_arg(argvars, 0) == FAIL
! || (argvars[1].v_type != VAR_UNKNOWN
! && check_for_bool_arg(argvars, 1) == FAIL)))
return;
fp = var2fpos(&argvars[0], FALSE, &fnum, FALSE);
if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
! && fnum == curbuf->b_fnum)
{
// Limit the column to a valid value, getvvcol() doesn't check.
if (fp->col < 0)
***************
*** 10407,10417 ****
if (fp->col > len)
fp->col = len;
}
! getvvcol(curwin, fp, NULL, NULL, &vcol);
! ++vcol;
}
! rettv->vval.v_number = vcol;
}
/*
--- 10425,10447 ----
if (fp->col > len)
fp->col = len;
}
! getvvcol(curwin, fp, &vcol_start, NULL, &vcol_end);
! ++vcol_start;
! ++vcol_end;
}
! if (argvars[1].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[1]))
! {
! if (rettv_list_alloc(rettv) == OK)
! {
! list_append_number(rettv->vval.v_list, vcol_start);
! list_append_number(rettv->vval.v_list, vcol_end);
! }
! else
! rettv->vval.v_number = 0;
! }
! else
! rettv->vval.v_number = vcol_end;
}
/*
*** ../vim-8.2.5018/src/testdir/test_functions.vim 2022-05-20
10:39:14.832585770 +0100
--- src/testdir/test_functions.vim 2022-05-26 11:52:49.938931235 +0100
***************
*** 2947,2950 ****
--- 2947,2961 ----
endif
endfunc
+ " Test for virtcol()
+ func Test_virtcol()
+ enew!
+ call setline(1, "the\tquick\tbrown\tfox")
+ norm! 4|
+ call assert_equal(8, virtcol('.'))
+ call assert_equal(8, virtcol('.', v:false))
+ call assert_equal([4, 8], virtcol('.', v:true))
+ bwipe!
+ endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
*** ../vim-8.2.5018/src/testdir/test_vim9_builtin.vim 2022-05-19
10:31:06.969630503 +0100
--- src/testdir/test_vim9_builtin.vim 2022-05-26 12:07:07.810073881 +0100
***************
*** 4494,4507 ****
enddef
def Test_virtcol()
! v9.CheckDefAndScriptFailure(['virtcol(1.1)'], ['E1013: Argument 1: type
mismatch, expected string but got float', 'E1222: String or List required for
argument 1'])
! v9.CheckDefExecAndScriptFailure(['virtcol("")'], 'E1209: Invalid value for
a line number')
new
! setline(1, ['abcdefgh'])
cursor(1, 4)
assert_equal(4, virtcol('.'))
assert_equal(4, virtcol([1, 4]))
! assert_equal(9, virtcol([1, '$']))
assert_equal(0, virtcol([10, '$']))
bw!
enddef
--- 4494,4516 ----
enddef
def Test_virtcol()
! v9.CheckDefAndScriptFailure(['virtcol(1.1)'], [
! 'E1013: Argument 1: type mismatch, expected string but got float',
! 'E1222: String or List required for argument 1'])
! v9.CheckDefAndScriptFailure(['virtcol(".", "a")'], [
! 'E1013: Argument 2: type mismatch, expected bool but got string',
! 'E1212: Bool required for argument 2'])
! v9.CheckDefExecAndScriptFailure(['virtcol("")'],
! 'E1209: Invalid value for a line number')
new
! setline(1, ['abcde和平fgh'])
cursor(1, 4)
assert_equal(4, virtcol('.'))
+ assert_equal([4, 4], virtcol('.', 1))
+ cursor(1, 6)
+ assert_equal([6, 7], virtcol('.', 1))
assert_equal(4, virtcol([1, 4]))
! assert_equal(13, virtcol([1, '$']))
assert_equal(0, virtcol([10, '$']))
bw!
enddef
*** ../vim-8.2.5018/src/version.c 2022-05-25 19:15:06.382288150 +0100
--- src/version.c 2022-05-26 11:56:00.990804039 +0100
***************
*** 736,737 ****
--- 736,739 ----
{ /* Add new patch number below this line */
+ /**/
+ 5019,
/**/
--
I'd like to meet the man who invented sex and see what he's working on now.
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ 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/20220526111114.29F821C0B4C%40moolenaar.net.