# HG changeset patch # User Bram Moolenaar # Date 1668269703 -3600 # Node ID 1a32f1a4f8234ac857cc652aee2d5d61cccc0104 # Parent cb66d96c185f993d47c408ce21dabfb167ed73bc patch 9.0.0863: col() and charcol() only work for the current window Commit: https://github.com/vim/vim/commit/4c8d2f02b3ce037bbe1d5ee12887e343c6bde88f Author: Yegappan Lakshmanan Date: Sat Nov 12 16:07:47 2022 +0000 patch 9.0.0863: col() and charcol() only work for the current window Problem: col() and charcol() only work for the current window. Solution: Add an optional winid argument. (Yegappan Lakshmanan, closes #11466, closes #11461) diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -116,13 +116,13 @@ ch_status({handle} [, {options}]) changenr() Number current change number char2nr({expr} [, {utf8}]) Number ASCII/UTF-8 value of first char in {expr} charclass({string}) Number character class of {string} -charcol({expr}) Number column number of cursor or mark +charcol({expr} [, {winid}]) 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 +col({expr} [, {winid}]) 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 @@ -1474,7 +1474,7 @@ charclass({string}) *charclass()* Returns 0 if {string} is not a |String|. -charcol({expr}) *charcol()* +charcol({expr} [, {winid}]) *charcol()* Same as |col()| but returns the character index of the column position given with {expr} instead of the byte position. @@ -1557,8 +1557,8 @@ clearmatches([{win}]) *clearmatches( Can also be used as a |method|: > GetWin()->clearmatches() < - *col()* -col({expr}) The result is a Number, which is the byte index of the column +col({expr} [, {winid}) *col()* + The result is a Number, which is the byte index of the column position given with {expr}. The accepted positions are: . the cursor position $ the end of the cursor line (the result is the @@ -1573,6 +1573,8 @@ col({expr}) The result is a Number, whic and column number. Most useful when the column is "$", to get the last column of a specific line. When "lnum" or "col" is out of range then col() returns zero. + With the optional {winid} argument the values are obtained for + that window instead of the current window. To get the line number use |line()|. To get both use |getpos()|. For the screen column position use |virtcol()|. For the @@ -1583,7 +1585,8 @@ col({expr}) The result is a Number, whic col("$") length of cursor line plus one col("'t") column of mark t col("'" .. markname) column of mark markname -< The first column is 1. Returns 0 if {expr} is invalid. +< The first column is 1. Returns 0 if {expr} is invalid or when + the window with ID {winid} is not found. For an uppercase mark the column may actually be in another buffer. For the cursor position, when 'virtualedit' is active, the diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -1058,6 +1058,7 @@ static argcheck_T arg2_string_list_numbe 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_or_list_number[] = {arg_string_or_list_any, arg_number}; 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}; @@ -1774,7 +1775,7 @@ static funcentry_T global_functions[] = ret_number, f_char2nr}, {"charclass", 1, 1, FEARG_1, arg1_string, ret_number, f_charclass}, - {"charcol", 1, 1, FEARG_1, arg1_string_or_list_any, + {"charcol", 1, 2, FEARG_1, arg2_string_or_list_number, ret_number, f_charcol}, {"charidx", 2, 3, FEARG_1, arg3_string_number_bool, ret_number, f_charidx}, @@ -1784,7 +1785,7 @@ static funcentry_T global_functions[] = ret_number, f_cindent}, {"clearmatches", 0, 1, FEARG_1, arg1_number, ret_void, f_clearmatches}, - {"col", 1, 1, FEARG_1, arg1_string_or_list_any, + {"col", 1, 2, FEARG_1, arg2_string_or_list_number, ret_number, f_col}, {"complete", 2, 2, FEARG_2, arg2_number_list, ret_void, f_complete}, @@ -3389,12 +3390,31 @@ get_col(typval_T *argvars, typval_T *ret { colnr_T col = 0; pos_T *fp; - int fnum = curbuf->b_fnum; - - if (in_vim9script() - && check_for_string_or_list_arg(argvars, 0) == FAIL) - return; - + switchwin_T switchwin; + int winchanged = FALSE; + + if (check_for_string_or_list_arg(argvars, 0) == FAIL + || check_for_opt_number_arg(argvars, 1) == FAIL) + return; + + if (argvars[1].v_type != VAR_UNKNOWN) + { + tabpage_T *tp; + win_T *wp; + + // use the window specified in the second argument + wp = win_id2wp_tp((int)tv_get_number(&argvars[1]), &tp); + if (wp == NULL || tp == NULL) + return; + + if (switch_win_noblock(&switchwin, wp, tp, TRUE) != OK) + return; + + check_cursor(); + winchanged = TRUE; + } + + int fnum = curbuf->b_fnum; fp = var2fpos(&argvars[0], FALSE, &fnum, charcol); if (fp != NULL && fnum == curbuf->b_fnum) { @@ -3427,6 +3447,9 @@ get_col(typval_T *argvars, typval_T *ret } } rettv->vval.v_number = col; + + if (winchanged) + restore_win_noblock(&switchwin, TRUE); } /* diff --git a/src/testdir/test_cursor_func.vim b/src/testdir/test_cursor_func.vim --- a/src/testdir/test_cursor_func.vim +++ b/src/testdir/test_cursor_func.vim @@ -287,8 +287,9 @@ endfunc " Test for the charcol() function func Test_charcol() - call assert_fails('call charcol({})', 'E731:') - call assert_equal(0, charcol(0)) + call assert_fails('call charcol({})', 'E1222:') + call assert_fails('call charcol(".", [])', 'E1210:') + call assert_fails('call charcol(0)', 'E1222:') new call setline(1, ['', "01\tà4è678", 'Ⅵ', '012345678']) @@ -344,6 +345,25 @@ func Test_charcol() call assert_equal([1, 10, 2, 10, 7], g:InsertCurrentCol) iunmap + " Test for getting the column number in another window. + let winid = win_getid() + new + call win_execute(winid, 'normal 1G') + call assert_equal(1, charcol('.', winid)) + call assert_equal(1, charcol('$', winid)) + call win_execute(winid, 'normal 2G6l') + call assert_equal(7, charcol('.', winid)) + call assert_equal(10, charcol('$', winid)) + + " calling from another tab page also works + tabnew + call assert_equal(7, charcol('.', winid)) + call assert_equal(10, charcol('$', winid)) + tabclose + + " unknown window ID + call assert_equal(0, charcol('.', 10001)) + %bw! endfunc diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -1484,7 +1484,8 @@ func Test_col() call assert_equal(0, col([1, 100])) call assert_equal(0, col([1])) call assert_equal(0, col(test_null_list())) - call assert_fails('let c = col({})', 'E731:') + call assert_fails('let c = col({})', 'E1222:') + call assert_fails('let c = col(".", [])', 'E1210:') " test for getting the visual start column func T() @@ -1514,6 +1515,15 @@ func Test_col() call assert_equal(4, col('.')) set virtualedit& + " Test for getting the column number in another window + let winid = win_getid() + new + call win_execute(winid, 'normal 1G$') + call assert_equal(3, col('.', winid)) + call win_execute(winid, 'normal 2G') + call assert_equal(8, col('$', winid)) + call assert_equal(0, col('.', 5001)) + bw! endfunc diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -687,6 +687,7 @@ enddef def Test_charcol() v9.CheckDefAndScriptFailure(['charcol(10)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1222: String or List required for argument 1']) v9.CheckDefAndScriptFailure(['charcol({a: 10})'], ['E1013: Argument 1: type mismatch, expected string but got dict', 'E1222: String or List required for argument 1']) + v9.CheckDefAndScriptFailure(['charcol(".", [])'], ['E1013: Argument 2: type mismatch, expected number but got list', 'E1210: Number required for argument 2']) v9.CheckDefExecAndScriptFailure(['charcol("")'], 'E1209: Invalid value for a line number') new setline(1, ['abcdefgh']) @@ -734,6 +735,7 @@ def Test_col() v9.CheckDefAndScriptFailure(['col(10)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1222: String or List required for argument 1']) v9.CheckDefAndScriptFailure(['col({a: 10})'], ['E1013: Argument 1: type mismatch, expected string but got dict', 'E1222: String or List required for argument 1']) v9.CheckDefAndScriptFailure(['col(true)'], ['E1013: Argument 1: type mismatch, expected string but got bool', 'E1222: String or List required for argument 1']) + v9.CheckDefAndScriptFailure(['col(".", [])'], ['E1013: Argument 2: type mismatch, expected number but got list', 'E1210: Number required for argument 2']) v9.CheckDefExecAndScriptFailure(['col("")'], 'E1209: Invalid value for a line number') bw! enddef diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -53,7 +53,7 @@ def Test_expr1_ternary() assert_equal(function('len'), Res) var RetOne: func(string): number = function('len') - var RetTwo: func(string): number = function('charcol') + var RetTwo: func(string): number = function('strlen') var RetThat: func = g:atrue ? RetOne : RetTwo assert_equal(function('len'), RetThat) diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 863, +/**/ 862, /**/ 861,