changeset 13513:4064f342bea4 v8.0.1630

patch 8.0.1630: trimming white space is not that easy commit https://github.com/vim/vim/commit/295ac5ab5e840af6051bed5ec9d9acc3c73445de Author: Bram Moolenaar <Bram@vim.org> Date: Thu Mar 22 23:04:02 2018 +0100 patch 8.0.1630: trimming white space is not that easy Problem: Trimming white space is not that easy. Solution: Add the trim() function. (Bukn, closes https://github.com/vim/vim/issues/1280)
author Christian Brabandt <cb@256bit.org>
date Thu, 22 Mar 2018 23:15:06 +0100
parents 511cb52e0aa8
children a193655e5330
files runtime/doc/eval.txt src/evalfunc.c src/testdir/test_functions.vim src/version.c
diffstat 4 files changed, 111 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2463,6 +2463,7 @@ tolower({expr})			String	the String {exp
 toupper({expr})			String	the String {expr} switched to uppercase
 tr({src}, {fromstr}, {tostr})	String	translate chars of {src} in {fromstr}
 					to chars in {tostr}
+trim({text}[, {mask}]) 		String	trim characters in {mask} from {text}
 trunc({expr})			Float	truncate Float {expr}
 type({name})			Number	type of variable {name}
 undofile({name})		String	undo file name for {name}
@@ -8659,6 +8660,22 @@ tr({src}, {fromstr}, {tostr})				*tr()*
 			echo tr("<blob>", "<>", "{}")
 <		returns "{blob}"
 
+trim({text}[, {mask}])						*trim()*
+		Return {text} as a String where any character in {mask} is
+		removed from the beginning and  end of {text}.
+		If {mask} is not given, {mask} is all characters up to 0x20,
+		which includes Tab, space, NL and CR, plus the non-breaking
+		space character 0xa0.
+		This code deals with multibyte characters properly.
+
+		Examples: >
+			echo trim("  \r\t\t\r RESERVE \t \t\n\x0B\x0B")."_TAIL"
+<		returns "RESERVE_TAIL" >
+			echo trim("needrmvRESERVEnnneeedddrrmmmmvv", "ednmrv")
+<		returns "RESERVE" >
+			echo trim("rm<blob1><blob2><any_chars>rrmm<blob1><blob2><blob2>", "rm<blob1><blob2>")
+<		returns "any_chas"
+
 trunc({expr})							*trunc()*
 		Return the largest integral value with magnitude less than or
 		equal to {expr} as a |Float| (truncate towards zero).
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -430,6 +430,7 @@ static void f_timer_stopall(typval_T *ar
 static void f_tolower(typval_T *argvars, typval_T *rettv);
 static void f_toupper(typval_T *argvars, typval_T *rettv);
 static void f_tr(typval_T *argvars, typval_T *rettv);
+static void f_trim(typval_T *argvars, typval_T *rettv);
 #ifdef FEAT_FLOAT
 static void f_trunc(typval_T *argvars, typval_T *rettv);
 #endif
@@ -899,6 +900,7 @@ static struct fst
     {"tolower",		1, 1, f_tolower},
     {"toupper",		1, 1, f_toupper},
     {"tr",		3, 3, f_tr},
+    {"trim",		1, 2, f_trim},
 #ifdef FEAT_FLOAT
     {"trunc",		1, 1, f_trunc},
 #endif
@@ -5539,7 +5541,7 @@ f_getwinpos(typval_T *argvars UNUSED, ty
 	return;
 #ifdef FEAT_GUI
     if (gui.in_use)
-	gui_mch_get_winpos(&x, &y);
+	(void)gui_mch_get_winpos(&x, &y);
 # if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
     else
 # endif
@@ -13203,6 +13205,72 @@ error:
     rettv->vval.v_string = ga.ga_data;
 }
 
+/*
+ * "trim({expr})" function
+ */
+    static void
+f_trim(typval_T *argvars, typval_T *rettv)
+{
+    char_u	buf1[NUMBUFLEN];
+    char_u	buf2[NUMBUFLEN];
+    char_u	*head = get_tv_string_buf_chk(&argvars[0], buf1);
+    char_u	*mask = NULL;
+    char_u	*tail;
+    char_u	*prev;
+    char_u	*p;
+    int		c1;
+
+    rettv->v_type = VAR_STRING;
+    if (head == NULL)
+    {
+	rettv->vval.v_string = NULL;
+	return;
+    }
+
+    if (argvars[1].v_type == VAR_STRING)
+	mask = get_tv_string_buf_chk(&argvars[1], buf2);
+
+    while (*head != NUL)
+    {
+	c1 = PTR2CHAR(head);
+	if (mask == NULL)
+	{
+	    if (c1 > ' ' && c1 != 0xa0)
+		break;
+	}
+	else
+	{
+	    for (p = mask; *p != NUL; MB_PTR_ADV(p))
+		if (c1 == PTR2CHAR(p))
+		    break;
+	    if (*p == NUL)
+		break;
+	}
+	MB_PTR_ADV(head);
+    }
+
+    for (tail = head + STRLEN(head); tail > head; tail = prev)
+    {
+	prev = tail;
+	MB_PTR_BACK(head, prev);
+	c1 = PTR2CHAR(prev);
+	if (mask == NULL)
+	{
+	    if (c1 > ' ' && c1 != 0xa0)
+		break;
+	}
+	else
+	{
+	    for (p = mask; *p != NUL; MB_PTR_ADV(p))
+		if (c1 == PTR2CHAR(p))
+		    break;
+	    if (*p == NUL)
+		break;
+	}
+    }
+    rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
+}
+
 #ifdef FEAT_FLOAT
 /*
  * "trunc({float})" function
--- a/src/testdir/test_functions.vim
+++ b/src/testdir/test_functions.vim
@@ -876,3 +876,26 @@ func Test_shellescape()
 
   let &shell = save_shell
 endfunc
+
+func Test_trim()
+  call assert_equal("Testing", trim("  \t\r\r\x0BTesting  \t\n\r\n\t\x0B\x0B"))
+  call assert_equal("Testing", trim("  \t  \r\r\n\n\x0BTesting  \t\n\r\n\t\x0B\x0B"))
+  call assert_equal("RESERVE", trim("xyz \twwRESERVEzyww \t\t", " wxyz\t"))
+  call assert_equal("wRE    \tSERVEzyww", trim("wRE    \tSERVEzyww"))
+  call assert_equal("abcd\t     xxxx   tail", trim(" \tabcd\t     xxxx   tail"))
+  call assert_equal("\tabcd\t     xxxx   tail", trim(" \tabcd\t     xxxx   tail", " "))
+  call assert_equal(" \tabcd\t     xxxx   tail", trim(" \tabcd\t     xxxx   tail", "abx"))
+  call assert_equal("RESERVE", trim("你RESERVE好", "你好"))
+  call assert_equal("您R E SER V E早", trim("你好您R E SER V E早好你你", "你好"))
+  call assert_equal("你好您R E SER V E早好你你", trim(" \n\r\r   你好您R E SER V E早好你你    \t  \x0B", ))
+  call assert_equal("您R E SER V E早好你你    \t  \x0B", trim("    你好您R E SER V E早好你你    \t  \x0B", " 你好"))
+  call assert_equal("您R E SER V E早好你你    \t  \x0B", trim("    tteesstttt你好您R E SER V E早好你你    \t  \x0B ttestt", " 你好tes"))
+  call assert_equal("您R E SER V E早好你你    \t  \x0B", trim("    tteesstttt你好您R E SER V E早好你你    \t  \x0B ttestt", "   你你你好好好tttsses"))
+  call assert_equal("留下", trim("这些些不要这些留下这些", "这些不要"))
+  call assert_equal("", trim("", ""))
+  call assert_equal("a", trim("a", ""))
+  call assert_equal("", trim("", "a"))
+
+  let chars = join(map(range(1, 0x20) + [0xa0], {n -> nr2char(n)}), '')
+  call assert_equal("x", trim(chars . "x" . chars))
+endfunc
--- a/src/version.c
+++ b/src/version.c
@@ -767,6 +767,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1630,
+/**/
     1629,
 /**/
     1628,