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)
diff --git a/src/eval.c b/src/eval.c
index 9c91e52..a0877f6 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -5054,6 +5054,61 @@
#endif
/*
+ * Convert the specified byte index of line 'lnum' in buffer 'buf' to a
+ * character index. Works only for loaded buffers. Returns -1 on failure.
+ * The index of the first character is one.
+ */
+ int
+buf_byteidx_to_charidx(buf_T *buf, int lnum, int byteidx)
+{
+ char_u *str;
+
+ if (buf == NULL || buf->b_ml.ml_mfp == NULL)
+ return -1;
+
+ if (lnum > buf->b_ml.ml_line_count)
+ lnum = buf->b_ml.ml_line_count;
+
+ str = ml_get_buf(buf, lnum, FALSE);
+ if (str == NULL)
+ return -1;
+
+ if (*str == NUL)
+ return 1;
+
+ return mb_charlen_len(str, byteidx + 1);
+}
+
+/*
+ * Convert the specified character index of line 'lnum' in buffer 'buf' to a
+ * byte index. Works only for loaded buffers. Returns -1 on failure. The index
+ * of the first byte and the first character is one.
+ */
+ int
+buf_charidx_to_byteidx(buf_T *buf, int lnum, int charidx)
+{
+ char_u *str;
+ char_u *t;
+
+ if (buf == NULL || buf->b_ml.ml_mfp == NULL)
+ return -1;
+
+ if (lnum > buf->b_ml.ml_line_count)
+ lnum = buf->b_ml.ml_line_count;
+
+ str = ml_get_buf(buf, lnum, FALSE);
+ if (str == NULL)
+ return -1;
+
+ // Convert the character offset to a byte offset
+ t = str;
+ while (*t != NUL && --charidx > 0)
+ t += mb_ptr2len(t);
+
+ return t - str + 1;
+}
+
+/*
* Translate a String variable into a position.
* Returns NULL when there is an error.
*/
@@ -5061,7 +5116,8 @@
var2fpos(
typval_T *varp,
int dollar_lnum, // TRUE when $ is last line
- int *fnum) // set to fnum for '0, 'A, etc.
+ int *fnum, // set to fnum for '0, 'A, etc.
+ int charcol) // return character column
{
char_u *name;
static pos_T pos;
@@ -5083,7 +5139,10 @@
pos.lnum = list_find_nr(l, 0L, &error);
if (error || pos.lnum <= 0 || pos.lnum > curbuf->b_ml.ml_line_count)
return NULL; // invalid line number
- len = (long)STRLEN(ml_get(pos.lnum));
+ if (charcol)
+ len = (long)mb_charlen(ml_get(pos.lnum));
+ else
+ len = (long)STRLEN(ml_get(pos.lnum));
// Get the column number
// We accept "$" for the column number: last column.
@@ -5118,18 +5177,29 @@
if (name == NULL)
return NULL;
if (name[0] == '.') // cursor
- return &curwin->w_cursor;
+ {
+ pos = curwin->w_cursor;
+ if (charcol)
+ pos.col = buf_byteidx_to_charidx(curbuf, pos.lnum, pos.col) - 1;
+ return &pos;
+ }
if (name[0] == 'v' && name[1] == NUL) // Visual start
{
if (VIsual_active)
- return &VIsual;
- return &curwin->w_cursor;
+ pos = VIsual;
+ else
+ pos = curwin->w_cursor;
+ if (charcol)
+ pos.col = buf_byteidx_to_charidx(curbuf, pos.lnum, pos.col) - 1;
+ return &pos;
}
if (name[0] == '\'') // mark
{
pp = getmark_buf_fnum(curbuf, name[1], FALSE, fnum);
if (pp == NULL || pp == (pos_T *)-1 || pp->lnum <= 0)
return NULL;
+ if (charcol)
+ pp->col = buf_byteidx_to_charidx(curbuf, pp->lnum, pp->col) - 1;
return pp;
}
@@ -5164,7 +5234,10 @@
else
{
pos.lnum = curwin->w_cursor.lnum;
- pos.col = (colnr_T)STRLEN(ml_get_curline());
+ if (charcol)
+ pos.col = (colnr_T)mb_charlen(ml_get_curline());
+ else
+ pos.col = (colnr_T)STRLEN(ml_get_curline());
}
return &pos;
}
@@ -5184,7 +5257,8 @@
typval_T *arg,
pos_T *posp,
int *fnump,
- colnr_T *curswantp)
+ colnr_T *curswantp,
+ int charcol)
{
list_T *l = arg->vval.v_list;
long i = 0;
@@ -5216,6 +5290,18 @@
n = list_find_nr(l, i++, NULL); // col
if (n < 0)
return FAIL;
+ // If character position is specified, then convert to byte position
+ if (charcol)
+ {
+ buf_T *buf;
+
+ // Get the text for the specified line in a loaded buffer
+ buf = buflist_findnr(fnump == NULL ? curbuf->b_fnum : *fnump);
+ if (buf == NULL || buf->b_ml.ml_mfp == NULL)
+ return FAIL;
+
+ n = buf_charidx_to_byteidx(buf, posp->lnum, n);
+ }
posp->col = n;
n = list_find_nr(l, i, NULL); // off