]> granicus.if.org Git - vim/commitdiff
patch 8.0.1630: trimming white space is not that easy v8.0.1630
authorBram Moolenaar <Bram@vim.org>
Thu, 22 Mar 2018 22:04:02 +0000 (23:04 +0100)
committerBram Moolenaar <Bram@vim.org>
Thu, 22 Mar 2018 22:04:02 +0000 (23:04 +0100)
Problem:    Trimming white space is not that easy.
Solution:   Add the trim() function. (Bukn, closes #1280)

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

index 663f491df2b6fa13212dd1c6d0fd88ad99435549..387186f83df0f81b89ad0be8f44e0a4f9f959ac4 100644 (file)
@@ -2463,6 +2463,7 @@ tolower({expr})                   String  the String {expr} switched to lowercase
 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).
index c025a3486b65050b9a1b6fdea15e21e3c09ab565..780458af9559e824edd857bccd3acb0f2c4f84cd 100644 (file)
@@ -430,6 +430,7 @@ static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
 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, typval_T *rettv)
        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
index ffc3bc3785751bb2b24d835dcbf31e51c9aca0fc..49e5d1f1a6c0ff922f6aacd8a0161b57c170b97c 100644 (file)
@@ -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
index ce1ed2053c1de0eb34265b74644470f0220e6274..84f2a3e42dfe2693b767dfbe4cd1df655839b411 100644 (file)
@@ -766,6 +766,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1630,
 /**/
     1629,
 /**/