]> granicus.if.org Git - vim/commitdiff
patch 8.2.1741: pathshorten() only supports using one character v8.2.1741
authorBram Moolenaar <Bram@vim.org>
Fri, 25 Sep 2020 20:42:48 +0000 (22:42 +0200)
committerBram Moolenaar <Bram@vim.org>
Fri, 25 Sep 2020 20:42:48 +0000 (22:42 +0200)
Problem:    pathshorten() only supports using one character.
Solution:   Add an argument to control the length. (closes #7006)

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

index 08530077676d4411f51a6349e746d33abd699914..50e5995c6d95421d27b2f2542493a42a08f8ef05 100644 (file)
@@ -2661,7 +2661,7 @@ mzeval({expr})                    any     evaluate |MzScheme| expression
 nextnonblank({lnum})           Number  line nr of non-blank line >= {lnum}
 nr2char({expr} [, {utf8}])     String  single char with ASCII/UTF8 value {expr}
 or({expr}, {expr})             Number  bitwise OR
-pathshorten({expr})            String  shorten directory names in a path
+pathshorten({expr} [, {len}])  String  shorten directory names in a path
 perleval({expr})               any     evaluate |Perl| expression
 popup_atcursor({what}, {options}) Number create popup window near the cursor
 popup_beval({what}, {options}) Number  create popup window for 'ballooneval'
@@ -7656,13 +7656,17 @@ or({expr}, {expr})                                      *or()*
                        :let bits = bits->or(0x80)
 
 
-pathshorten({expr})                                    *pathshorten()*
+pathshorten({expr} [, {len}])                          *pathshorten()*
                Shorten directory names in the path {expr} and return the
                result.  The tail, the file name, is kept as-is.  The other
-               components in the path are reduced to single letters.  Leading
-               '~' and '.' characters are kept.  Example: >
+               components in the path are reduced to {len} letters in length.
+               If {len} is omitted or smaller than 1 then 1 is used (single
+               letters).  Leading '~' and '.' characters are kept.  Examples: >
                        :echo pathshorten('~/.vim/autoload/myfile.vim')
 <                      ~/.v/a/myfile.vim ~
+>
+                       :echo pathshorten('~/.vim/autoload/myfile.vim', 2)
+<                      ~/.vi/au/myfile.vim ~
                It doesn't matter if the path exists or not.
 
                Can also be used as a |method|: >
index 9bdeb52d9e721534725b2003c2de67a9f8a56d1d..57c4ffbce8ff1e393fc3cd0f388dac11487c509a 100644 (file)
@@ -779,7 +779,7 @@ static funcentry_T global_functions[] =
     {"nextnonblank",   1, 1, FEARG_1,    ret_number,   f_nextnonblank},
     {"nr2char",                1, 2, FEARG_1,    ret_string,   f_nr2char},
     {"or",             2, 2, FEARG_1,    ret_number,   f_or},
-    {"pathshorten",    1, 1, FEARG_1,    ret_string,   f_pathshorten},
+    {"pathshorten",    1, 2, FEARG_1,    ret_string,   f_pathshorten},
     {"perleval",       1, 1, FEARG_1,    ret_any,
 #ifdef FEAT_PERL
            f_perleval
index bdd9098b8027d12385014f37cf76821d003ba562..197825db36a47ea91c4924bf652519fd7d078b87 100644 (file)
@@ -1351,6 +1351,69 @@ f_mkdir(typval_T *argvars, typval_T *rettv)
     rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
 }
 
+/*
+ * Shorten the path of a file from "~/foo/../.bar/fname" to "~/f/../.b/fname"
+ * "trim_len" specifies how many characters to keep for each directory.
+ * Must be 1 or more.
+ * It's done in-place.
+ */
+    static void
+shorten_dir_len(char_u *str, int trim_len)
+{
+    char_u     *tail, *s, *d;
+    int                skip = FALSE;
+    int                dirchunk_len = 0;
+
+    tail = gettail(str);
+    d = str;
+    for (s = str; ; ++s)
+    {
+       if (s >= tail)              // copy the whole tail
+       {
+           *d++ = *s;
+           if (*s == NUL)
+               break;
+       }
+       else if (vim_ispathsep(*s))         // copy '/' and next char
+       {
+           *d++ = *s;
+           skip = FALSE;
+           dirchunk_len = 0;
+       }
+       else if (!skip)
+       {
+           *d++ = *s;                  // copy next char
+           if (*s != '~' && *s != '.') // and leading "~" and "."
+           {
+               ++dirchunk_len; // only count word chars for the size
+
+               // keep copying chars until we have our preferred length (or
+               // until the above if/else branches move us along)
+               if (dirchunk_len >= trim_len)
+                   skip = TRUE;
+           }
+
+           if (has_mbyte)
+           {
+               int l = mb_ptr2len(s);
+
+               while (--l > 0)
+                   *d++ = *++s;
+           }
+       }
+    }
+}
+
+/*
+ * Shorten the path of a file from "~/foo/../.bar/fname" to "~/f/../.b/fname"
+ * It's done in-place.
+ */
+    void
+shorten_dir(char_u *str)
+{
+    shorten_dir_len(str, 1);
+}
+
 /*
  * "pathshorten()" function
  */
@@ -1358,9 +1421,18 @@ f_mkdir(typval_T *argvars, typval_T *rettv)
 f_pathshorten(typval_T *argvars, typval_T *rettv)
 {
     char_u     *p;
+    int                trim_len = 1;
+
+    if (argvars[1].v_type != VAR_UNKNOWN)
+    {
+       trim_len = (int)tv_get_number(&argvars[1]);
+       if (trim_len < 1)
+           trim_len = 1;
+    }
 
     rettv->v_type = VAR_STRING;
     p = tv_get_string_chk(&argvars[0]);
+
     if (p == NULL)
        rettv->vval.v_string = NULL;
     else
@@ -1368,7 +1440,7 @@ f_pathshorten(typval_T *argvars, typval_T *rettv)
        p = vim_strsave(p);
        rettv->vval.v_string = p;
        if (p != NULL)
-           shorten_dir(p);
+           shorten_dir_len(p, trim_len);
     }
 }
 
@@ -2706,47 +2778,6 @@ vim_ispathsep_nocolon(int c)
        ;
 }
 
-/*
- * Shorten the path of a file from "~/foo/../.bar/fname" to "~/f/../.b/fname"
- * It's done in-place.
- */
-    void
-shorten_dir(char_u *str)
-{
-    char_u     *tail, *s, *d;
-    int                skip = FALSE;
-
-    tail = gettail(str);
-    d = str;
-    for (s = str; ; ++s)
-    {
-       if (s >= tail)              // copy the whole tail
-       {
-           *d++ = *s;
-           if (*s == NUL)
-               break;
-       }
-       else if (vim_ispathsep(*s))         // copy '/' and next char
-       {
-           *d++ = *s;
-           skip = FALSE;
-       }
-       else if (!skip)
-       {
-           *d++ = *s;              // copy next char
-           if (*s != '~' && *s != '.') // and leading "~" and "."
-               skip = TRUE;
-           if (has_mbyte)
-           {
-               int l = mb_ptr2len(s);
-
-               while (--l > 0)
-                   *d++ = *++s;
-           }
-       }
-    }
-}
-
 /*
  * Return TRUE if the directory of "fname" exists, FALSE otherwise.
  * Also returns TRUE if there is no directory name.
index b0a6de9c9f51b598b2d6e2a339bb95d6f11a99c0..b502b8e49453f23207c98bdcb8c042a8cbe0b1c7 100644 (file)
@@ -21,6 +21,7 @@ void f_glob2regpat(typval_T *argvars, typval_T *rettv);
 void f_globpath(typval_T *argvars, typval_T *rettv);
 void f_isdirectory(typval_T *argvars, typval_T *rettv);
 void f_mkdir(typval_T *argvars, typval_T *rettv);
+void shorten_dir(char_u *str);
 void f_pathshorten(typval_T *argvars, typval_T *rettv);
 void f_readdir(typval_T *argvars, typval_T *rettv);
 void f_readdirex(typval_T *argvars, typval_T *rettv);
@@ -40,7 +41,6 @@ char_u *getnextcomp(char_u *fname);
 char_u *get_past_head(char_u *path);
 int vim_ispathsep(int c);
 int vim_ispathsep_nocolon(int c);
-void shorten_dir(char_u *str);
 int dir_of_file_exists(char_u *fname);
 int vim_fnamecmp(char_u *x, char_u *y);
 int vim_fnamencmp(char_u *x, char_u *y, size_t len);
index 5e4eacd044ffe63ece84f38ca416695e101eb977..45b997f501845726bb01f7acdc58037c8755a60a 100644 (file)
@@ -500,6 +500,24 @@ func Test_pathshorten()
   call assert_equal('.~f/bar', pathshorten('.~foo/bar'))
   call assert_equal('~/f/bar', pathshorten('~/foo/bar'))
   call assert_fails('call pathshorten([])', 'E730:')
+
+  " test pathshorten with optional variable to set preferred size of shortening
+  call assert_equal('', pathshorten('', 2))
+  call assert_equal('foo', pathshorten('foo', 2))
+  call assert_equal('/foo', pathshorten('/foo', 2))
+  call assert_equal('fo/', pathshorten('foo/', 2))
+  call assert_equal('fo/bar', pathshorten('foo/bar', 2))
+  call assert_equal('fo/ba/foobar', pathshorten('foo/bar/foobar', 2))
+  call assert_equal('/fo/ba/foobar', pathshorten('/foo/bar/foobar', 2))
+  call assert_equal('.fo/bar', pathshorten('.foo/bar', 2))
+  call assert_equal('~fo/bar', pathshorten('~foo/bar', 2))
+  call assert_equal('~.fo/bar', pathshorten('~.foo/bar', 2))
+  call assert_equal('.~fo/bar', pathshorten('.~foo/bar', 2))
+  call assert_equal('~/fo/bar', pathshorten('~/foo/bar', 2))
+  call assert_fails('call pathshorten([],2)', 'E730:')
+  call assert_notequal('~/fo/bar', pathshorten('~/foo/bar', 3))
+  call assert_equal('~/foo/bar', pathshorten('~/foo/bar', 3))
+  call assert_equal('~/f/bar', pathshorten('~/foo/bar', 0))
 endfunc
 
 func Test_strpart()
index 4295f2f68cf0c5ca689f59adc6a972accb45a4a3..2258be9771b329cf72991df7faf4c5b74c1dbc09 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1741,
 /**/
     1740,
 /**/