diff src/evalfunc.c @ 23563:87671ccc6c6b v8.2.2324

patch 8.2.2324: not easy to get mark en cursor posotion by character count Commit: https://github.com/vim/vim/commit/6f02b00bb0958f70bc15534e115b4c6dadff0e06 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jan 10 20:22:54 2021 +0100 patch 8.2.2324: not easy to get mark en cursor posotion by character count Problem: Not easy to get mark en cursor posotion by character count. Solution: Add functions that use character index. (Yegappan Lakshmanan, closes #7648)
author Bram Moolenaar <Bram@vim.org>
date Sun, 10 Jan 2021 20:30:04 +0100
parents 98185d3dd369
children 34aa2907082a
line wrap: on
line diff
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -47,6 +47,7 @@ static void f_ceil(typval_T *argvars, ty
 #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,12 +88,14 @@ static void f_function(typval_T *argvars
 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,7 +193,9 @@ static void f_searchdecl(typval_T *argva
 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,6 +795,8 @@ static funcentry_T global_functions[] =
 			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,6 +935,8 @@ static funcentry_T global_functions[] =
 			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,6 +951,8 @@ static funcentry_T global_functions[] =
 			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,10 +1405,14 @@ static funcentry_T global_functions[] =
 			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,6 +2439,61 @@ f_char2nr(typval_T *argvars, typval_T *r
 }
 
 /*
+ * 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,42 +2567,7 @@ get_optional_window(typval_T *argvars, i
     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;
+    get_col(argvars, rettv, FALSE);
 }
 
 /*
@@ -2633,26 +2668,24 @@ f_cosh(typval_T *argvars, typval_T *rett
 #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)
+ * 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[1].v_type == VAR_UNKNOWN)
+    if (argvars[0].v_type == VAR_LIST)
     {
 	pos_T	    pos;
 	colnr_T	    curswant = -1;
 
-	if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
+	if (list2fpos(argvars, &pos, NULL, &curswant, charcol) == FAIL)
 	{
 	    emsg(_(e_invarg));
 	    return;
@@ -2666,15 +2699,24 @@ f_cursor(typval_T *argvars, typval_T *re
 	    set_curswant = FALSE;
 	}
     }
-    else
+    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,6 +2735,19 @@ f_cursor(typval_T *argvars, typval_T *re
     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,6 +3942,88 @@ f_getchangelist(typval_T *argvars, typva
 #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,77 +4156,19 @@ f_getpid(typval_T *argvars UNUSED, typva
     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);
+    getpos_both(argvars, rettv, TRUE, FALSE);
+}
+
+    static void
+f_getcursorcharpos(typval_T *argvars, typval_T *rettv)
+{
+    getpos_both(argvars, rettv, TRUE, TRUE);
 }
 
 /*
@@ -4098,7 +4177,7 @@ f_getcurpos(typval_T *argvars, typval_T 
     static void
 f_getpos(typval_T *argvars, typval_T *rettv)
 {
-    getpos_both(argvars, rettv, FALSE);
+    getpos_both(argvars, rettv, FALSE, FALSE);
 }
 
 /*
@@ -6183,14 +6262,14 @@ f_line(typval_T *argvars, typval_T *rett
 									 == OK)
 	    {
 		check_cursor();
-		fp = var2fpos(&argvars[0], TRUE, &fnum);
+		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);
+	fp = var2fpos(&argvars[0], TRUE, &fnum, FALSE);
 
     if (fp != NULL)
 	lnum = fp->lnum;
@@ -8065,6 +8144,60 @@ f_searchpos(typval_T *argvars, typval_T 
 	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,6 +8240,15 @@ f_setcharsearch(typval_T *argvars, typva
 }
 
 /*
+ * "setcursorcharpos" function
+ */
+    static void
+f_setcursorcharpos(typval_T *argvars, typval_T *rettv UNUSED)
+{
+    set_cursorpos(argvars, rettv, TRUE);
+}
+
+/*
  * "setenv()" function
  */
     static void
@@ -8165,41 +8307,7 @@ f_setfperm(typval_T *argvars, typval_T *
     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));
-	}
-    }
+    set_position(argvars, rettv, FALSE);
 }
 
 /*
@@ -9947,7 +10055,7 @@ f_virtcol(typval_T *argvars, typval_T *r
     int		fnum = curbuf->b_fnum;
     int		len;
 
-    fp = var2fpos(&argvars[0], FALSE, &fnum);
+    fp = var2fpos(&argvars[0], FALSE, &fnum, FALSE);
     if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
 						    && fnum == curbuf->b_fnum)
     {