]> granicus.if.org Git - vim/commitdiff
patch 8.2.5019: cannot get the first screen column of a character v8.2.5019
authorLemonBoy <thatlemon@gmail.com>
Thu, 26 May 2022 11:10:37 +0000 (12:10 +0100)
committerBram Moolenaar <Bram@vim.org>
Thu, 26 May 2022 11:10:37 +0000 (12:10 +0100)
Problem:    Cannot get the first screen column of a character.
Solution:   Let virtcol() optionally return a list. (closes #10482,
            closes #7964)

runtime/doc/builtin.txt
src/evalfunc.c
src/testdir/test_functions.vim
src/testdir/test_vim9_builtin.vim
src/version.c

index 5b20ea3322224f3de715d5d14241cbbbbe8b6c9f..0aa2effcd0f122bcb9dcea609da153b82e9a2ff4 100644 (file)
@@ -689,7 +689,8 @@ undotree()                  List    undo file tree
 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
+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,6 +781,7 @@ add({object}, {expr})                                       *add()*
 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,13 +938,14 @@ autocmd_add({acmds})                                      *autocmd_add()*
                                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 a autocmd
+                   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,7 +955,7 @@ autocmd_add({acmds})                                        *autocmd_add()*
                                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.
+                               multiple times for an autocmd event in a group.
 
                Returns v:true on success and v:false on failure.
                Examples: >
@@ -9727,7 +9730,7 @@ values({dict})                                            *values()*
                Can also be used as a |method|: >
                        mydict->values()
 
-virtcol({expr})                                                *virtcol()*
+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,13 +9739,17 @@ virtcol({expr})                                         *virtcol()*
                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'|
+
+               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,11 +9761,22 @@ virtcol({expr})                                         *virtcol()*
                            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: >
-  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
+                       " 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: >
index 6abd53a73e5c179fdd8506d38502f93b5c4ef9bc..a5300a1700bacaeb6219111702f0ad42831ef7ee 100644 (file)
@@ -994,6 +994,7 @@ static argcheck_T arg2_string_dict[] = {arg_string, arg_dict_any};
 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};
@@ -1457,6 +1458,20 @@ ret_getreg(int argcount,
     return &t_string;
 }
 
+    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,
@@ -2665,8 +2680,8 @@ static funcentry_T global_functions[] =
                        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},
+    {"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,23 +10395,26 @@ f_type(typval_T *argvars, typval_T *rettv)
 }
 
 /*
- * "virtcol(string)" function
+ * "virtcol(string, bool)" function
  */
     static void
 f_virtcol(typval_T *argvars, typval_T *rettv)
 {
-    colnr_T    vcol = 0;
+    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)
+           && (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)
+           && fnum == curbuf->b_fnum)
     {
        // Limit the column to a valid value, getvvcol() doesn't check.
        if (fp->col < 0)
@@ -10407,11 +10425,23 @@ f_virtcol(typval_T *argvars, typval_T *rettv)
            if (fp->col > len)
                fp->col = len;
        }
-       getvvcol(curwin, fp, NULL, NULL, &vcol);
-       ++vcol;
+       getvvcol(curwin, fp, &vcol_start, NULL, &vcol_end);
+       ++vcol_start;
+       ++vcol_end;
     }
 
-    rettv->vval.v_number = vcol;
+    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;
 }
 
 /*
index 1a05a590fc20a81ce414ea6f8a90794595de8989..af07a64243d915c9b8b327704b626aab1ab2819c 100644 (file)
@@ -2947,4 +2947,15 @@ func Test_exepath()
   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
index 4f39ebb51e759a68e5524263e477772a78b75f2f..e83e320c730a015c34e1eba4a0d7e9314ffc5522 100644 (file)
@@ -4494,14 +4494,23 @@ def Test_values()
 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')
+  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, ['abcdefgh'])
+  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(9, virtcol([1, '$']))
+  assert_equal(13, virtcol([1, '$']))
   assert_equal(0, virtcol([10, '$']))
   bw!
 enddef
index 690a703b40c5e90bdc3f7339c783abf493256374..9589d792c87f858c487274c0f9acb26d14759089 100644 (file)
@@ -734,6 +734,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    5019,
 /**/
     5018,
 /**/