changeset 24130:c3d1f65365c4 v8.2.2606

patch 8.2.2606: strchars() defaults to counting composing characters Commit: https://github.com/vim/vim/commit/70ce8a1561c5396e4c4381f76a005cbb97646f80 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Mar 14 19:02:09 2021 +0100 patch 8.2.2606: strchars() defaults to counting composing characters Problem: strchars() defaults to counting composing characters. Solution: Add strcharlen() which ignores composing characters.
author Bram Moolenaar <Bram@vim.org>
date Sun, 14 Mar 2021 19:15:03 +0100
parents 147967e557f7
children 81f596485c08
files runtime/doc/eval.txt runtime/doc/usr_41.txt src/evalfunc.c src/testdir/test_utf8.vim src/version.c
diffstat 5 files changed, 59 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2923,10 +2923,11 @@ str2list({expr} [, {utf8}])	List	convert
 					ASCII/UTF8 value
 str2nr({expr} [, {base} [, {quoted}]])
 				Number	convert String to Number
+strcharlen({expr})		Number	character length of the String {expr}
 strcharpart({str}, {start} [, {len}])
 				String	{len} characters of {str} at
 					character {start}
-strchars({expr} [, {skipcc}])	Number	character length of the String {expr}
+strchars({expr} [, {skipcc}])	Number	character count of the String {expr}
 strdisplaywidth({expr} [, {col}]) Number display length of the String {expr}
 strftime({format} [, {time}])	String	format time with a specified format
 strgetchar({str}, {index})	Number	get char {index} from {str}
@@ -10276,6 +10277,19 @@ str2nr({expr} [, {base} [, {quoted}]])		
 		Can also be used as a |method|: >
 			GetText()->str2nr()
 
+
+strcharlen({expr})					*strcharlen()*
+		The result is a Number, which is the number of characters
+		in String {expr}.  Composing characters are ignored.
+		|strchars()| can count the number of characters, counting
+		composing characters separately.
+
+		Also see |strlen()|, |strdisplaywidth()| and |strwidth()|.
+
+		Can also be used as a |method|: >
+			GetText()->strcharlen()
+
+
 strcharpart({src}, {start} [, {len}])			*strcharpart()*
 		Like |strpart()| but using character index and length instead
 		of byte index and length.  Composing characters are counted
@@ -10288,12 +10302,15 @@ strcharpart({src}, {start} [, {len}])			
 		Can also be used as a |method|: >
 			GetText()->strcharpart(5)
 
+
 strchars({expr} [, {skipcc}])					*strchars()*
 		The result is a Number, which is the number of characters
 		in String {expr}.
 		When {skipcc} is omitted or zero, composing characters are
 		counted separately.
 		When {skipcc} set to 1, Composing characters are ignored.
+		|strcharlen()| does the same.
+
 		Also see |strlen()|, |strdisplaywidth()| and |strwidth()|.
 
 		{skipcc} is only available after 7.4.755.  For backward
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -611,7 +611,8 @@ String manipulation:					*string-functio
 	stridx()		first index of a short string in a long string
 	strridx()		last index of a short string in a long string
 	strlen()		length of a string in bytes
-	strchars()		length of a string in characters
+	strcharlen()		length of a string in characters
+	strchars()		number of characters in a string
 	strwidth()		size of string when displayed
 	strdisplaywidth()	size of string when displayed, deals with tabs
 	setcellwidths()		set character cell width overrides
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -223,6 +223,7 @@ static void f_str2float(typval_T *argvar
 #endif
 static void f_str2list(typval_T *argvars, typval_T *rettv);
 static void f_str2nr(typval_T *argvars, typval_T *rettv);
+static void f_strcharlen(typval_T *argvars, typval_T *rettv);
 static void f_strchars(typval_T *argvars, typval_T *rettv);
 static void f_strgetchar(typval_T *argvars, typval_T *rettv);
 static void f_stridx(typval_T *argvars, typval_T *rettv);
@@ -1572,6 +1573,8 @@ static funcentry_T global_functions[] =
 			ret_list_number,    f_str2list},
     {"str2nr",		1, 3, FEARG_1,	    arg3_string_nr_bool,
 			ret_number,	    f_str2nr},
+    {"strcharlen",	1, 1, FEARG_1,	    NULL,
+			ret_number,	    f_strcharlen},
     {"strcharpart",	2, 3, FEARG_1,	    NULL,
 			ret_string,	    f_strcharpart},
     {"strchars",	1, 2, FEARG_1,	    NULL,
@@ -9236,31 +9239,45 @@ f_strlen(typval_T *argvars, typval_T *re
 					      tv_get_string(&argvars[0])));
 }
 
+    static void
+strchar_common(typval_T *argvars, typval_T *rettv, int skipcc)
+{
+    char_u		*s = tv_get_string(&argvars[0]);
+    varnumber_T		len = 0;
+    int			(*func_mb_ptr2char_adv)(char_u **pp);
+
+    func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
+    while (*s != NUL)
+    {
+	func_mb_ptr2char_adv(&s);
+	++len;
+    }
+    rettv->vval.v_number = len;
+}
+
+/*
+ * "strcharlen()" function
+ */
+    static void
+f_strcharlen(typval_T *argvars, typval_T *rettv)
+{
+    strchar_common(argvars, rettv, TRUE);
+}
+
 /*
  * "strchars()" function
  */
     static void
 f_strchars(typval_T *argvars, typval_T *rettv)
 {
-    char_u		*s = tv_get_string(&argvars[0]);
     varnumber_T		skipcc = FALSE;
-    varnumber_T		len = 0;
-    int			(*func_mb_ptr2char_adv)(char_u **pp);
 
     if (argvars[1].v_type != VAR_UNKNOWN)
 	skipcc = tv_get_bool(&argvars[1]);
     if (skipcc < 0 || skipcc > 1)
 	semsg(_(e_using_number_as_bool_nr), skipcc);
     else
-    {
-	func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
-	while (*s != NUL)
-	{
-	    func_mb_ptr2char_adv(&s);
-	    ++len;
-	}
-	rettv->vval.v_number = len;
-    }
+	strchar_common(argvars, rettv, skipcc);
 }
 
 /*
--- a/src/testdir/test_utf8.vim
+++ b/src/testdir/test_utf8.vim
@@ -11,7 +11,7 @@ func Test_visual_block_insert()
   bwipeout!
 endfunc
 
-" Test for built-in function strchars()
+" Test for built-in functions strchars() and strcharlen()
 func Test_strchars()
   let inp = ["a", "あいa", "A\u20dd", "A\u20dd\u20dd", "\u20dd"]
   let exp = [[1, 1, 1], [3, 3, 3], [2, 2, 1], [3, 3, 1], [1, 1, 1]]
@@ -20,6 +20,13 @@ func Test_strchars()
     call assert_equal(exp[i][1], inp[i]->strchars(0))
     call assert_equal(exp[i][2], strchars(inp[i], 1))
   endfor
+
+  let exp = [1, 3, 1, 1, 1]
+  for i in range(len(inp))
+    call assert_equal(exp[i], inp[i]->strcharlen())
+    call assert_equal(exp[i], strcharlen(inp[i]))
+  endfor
+
   call assert_fails("let v=strchars('abc', [])", 'E745:')
   call assert_fails("let v=strchars('abc', 2)", 'E1023:')
 endfunc
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2606,
+/**/
     2605,
 /**/
     2604,