changeset 22385:770fe121ca64 v8.2.1741

patch 8.2.1741: pathshorten() only supports using one character Commit: https://github.com/vim/vim/commit/6a33ef0deb5c75c003a9f3bd1c57f3ca5e77327e Author: Bram Moolenaar <Bram@vim.org> Date: Fri Sep 25 22:42:48 2020 +0200 patch 8.2.1741: pathshorten() only supports using one character Problem: pathshorten() only supports using one character. Solution: Add an argument to control the length. (closes https://github.com/vim/vim/issues/7006)
author Bram Moolenaar <Bram@vim.org>
date Fri, 25 Sep 2020 22:45:06 +0200
parents 66f9cafbb9b8
children 21d63dec6f6a
files runtime/doc/eval.txt src/evalfunc.c src/filepath.c src/proto/filepath.pro src/testdir/test_functions.vim src/version.c
diffstat 6 files changed, 103 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2661,7 +2661,7 @@ mzeval({expr})			any	evaluate |MzScheme|
 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|: >
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -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
--- a/src/filepath.c
+++ b/src/filepath.c
@@ -1352,15 +1352,87 @@ f_mkdir(typval_T *argvars, typval_T *ret
 }
 
 /*
+ * 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
  */
     void
 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_
 	p = vim_strsave(p);
 	rettv->vval.v_string = p;
 	if (p != NULL)
-	    shorten_dir(p);
+	    shorten_dir_len(p, trim_len);
     }
 }
 
@@ -2707,47 +2779,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.
  * "fname" must be writable!.
--- a/src/proto/filepath.pro
+++ b/src/proto/filepath.pro
@@ -21,6 +21,7 @@ void f_glob2regpat(typval_T *argvars, ty
 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);
--- a/src/testdir/test_functions.vim
+++ b/src/testdir/test_functions.vim
@@ -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()
--- 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 */
 /**/
+    1741,
+/**/
     1740,
 /**/
     1739,