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.

Raspunde prin e-mail lui