Merge pull request #17263 from zeertzjq/vim-8.2.0208

vim-patch:8.2.{0208,0215,0942,3824,3939}: fnamemodify() patches
This commit is contained in:
zeertzjq 2022-02-07 07:13:13 +08:00 committed by GitHub
commit cf86adba61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 57 additions and 21 deletions

View File

@ -908,8 +908,7 @@ These modifiers can be given, in this order:
directory. directory.
:. Reduce file name to be relative to current directory, if :. Reduce file name to be relative to current directory, if
possible. File name is unmodified if it is not below the possible. File name is unmodified if it is not below the
current directory, but on MS-Windows the drive is removed if current directory.
it is the current drive.
For maximum shortness, use ":~:.". For maximum shortness, use ":~:.".
:h Head of the file name (the last component and any separators :h Head of the file name (the last component and any separators
removed). Cannot be used with :e, :r or :t. removed). Cannot be used with :e, :r or :t.

View File

@ -10624,12 +10624,13 @@ int modify_fname(char_u *src, bool tilde_file, size_t *usedlen, char_u **fnamep,
char_u *s, *p, *pbuf; char_u *s, *p, *pbuf;
char_u dirname[MAXPATHL]; char_u dirname[MAXPATHL];
int c; int c;
int has_fullname = 0; bool has_fullname = false;
bool has_homerelative = false;
repeat: repeat:
// ":p" - full path/file_name // ":p" - full path/file_name
if (src[*usedlen] == ':' && src[*usedlen + 1] == 'p') { if (src[*usedlen] == ':' && src[*usedlen + 1] == 'p') {
has_fullname = 1; has_fullname = true;
valid |= VALID_PATH; valid |= VALID_PATH;
*usedlen += 2; *usedlen += 2;
@ -10698,8 +10699,8 @@ repeat:
} }
pbuf = NULL; pbuf = NULL;
// Need full path first (use expand_env() to remove a "~/") // Need full path first (use expand_env() to remove a "~/")
if (!has_fullname) { if (!has_fullname && !has_homerelative) {
if (c == '.' && **fnamep == '~') { if ((c == '.' || c == '~') && **fnamep == '~') {
p = pbuf = expand_env_save(*fnamep); p = pbuf = expand_env_save(*fnamep);
} else { } else {
p = pbuf = (char_u *)FullName_save((char *)*fnamep, FALSE); p = pbuf = (char_u *)FullName_save((char *)*fnamep, FALSE);
@ -10708,18 +10709,33 @@ repeat:
p = *fnamep; p = *fnamep;
} }
has_fullname = 0; has_fullname = false;
if (p != NULL) { if (p != NULL) {
if (c == '.') { if (c == '.') {
os_dirname(dirname, MAXPATHL); os_dirname(dirname, MAXPATHL);
s = path_shorten_fname(p, dirname); if (has_homerelative) {
if (s != NULL) { s = vim_strsave(dirname);
*fnamep = s; home_replace(NULL, s, dirname, MAXPATHL, true);
if (pbuf != NULL) { xfree(s);
xfree(*bufp); // free any allocated file name }
*bufp = pbuf; size_t namelen = STRLEN(dirname);
pbuf = NULL;
// Do not call shorten_fname() here since it removes the prefix
// even though the path does not have a prefix.
if (fnamencmp(p, dirname, namelen) == 0) {
p += namelen;
if (vim_ispathsep(*p)) {
while (*p && vim_ispathsep(*p)) {
p++;
}
*fnamep = p;
if (pbuf != NULL) {
// free any allocated file name
xfree(*bufp);
*bufp = pbuf;
pbuf = NULL;
}
} }
} }
} else { } else {
@ -10730,6 +10746,7 @@ repeat:
*fnamep = s; *fnamep = s;
xfree(*bufp); xfree(*bufp);
*bufp = s; *bufp = s;
has_homerelative = true;
} }
} }
xfree(pbuf); xfree(pbuf);

View File

@ -1111,10 +1111,9 @@ size_t home_replace(const buf_T *const buf, const char_u *src, char_u *const dst
*dst_p++ = '~'; *dst_p++ = '~';
} }
// If it's just the home directory, add "/". // Do not add directory separator into dst, because dst is
if (!vim_ispathsep(src[0]) && --dstlen > 0) { // expected to just return the directory name without the
*dst_p++ = '/'; // directory separator '/'.
}
break; break;
} }
if (p == homedir_env_mod) { if (p == homedir_env_mod) {

View File

@ -1521,7 +1521,7 @@ void simplify_filename(char_u *filename)
p = filename; p = filename;
#ifdef BACKSLASH_IN_FILENAME #ifdef BACKSLASH_IN_FILENAME
if (p[1] == ':') { // skip "x:" if (p[0] != NUL && p[1] == ':') { // skip "x:"
p += 2; p += 2;
} }
#endif #endif
@ -2402,9 +2402,11 @@ static int path_to_absolute(const char_u *fname, char_u *buf, size_t len, int fo
int path_is_absolute(const char_u *fname) int path_is_absolute(const char_u *fname)
{ {
#ifdef WIN32 #ifdef WIN32
if (*fname == NUL) {
return false;
}
// A name like "d:/foo" and "//server/share" is absolute // A name like "d:/foo" and "//server/share" is absolute
return ((isalpha(fname[0]) && fname[1] == ':' return ((isalpha(fname[0]) && fname[1] == ':' && vim_ispathsep_nocolon(fname[2]))
&& vim_ispathsep_nocolon(fname[2]))
|| (vim_ispathsep_nocolon(fname[0]) && fname[0] == fname[1])); || (vim_ispathsep_nocolon(fname[0]) && fname[0] == fname[1]));
#else #else
// UNIX: This just checks if the file name starts with '/' or '~'. // UNIX: This just checks if the file name starts with '/' or '~'.

View File

@ -3,8 +3,10 @@
func Test_fnamemodify() func Test_fnamemodify()
let save_home = $HOME let save_home = $HOME
let save_shell = &shell let save_shell = &shell
let save_shellslash = &shellslash
let $HOME = fnamemodify('.', ':p:h:h') let $HOME = fnamemodify('.', ':p:h:h')
set shell=sh set shell=sh
set shellslash
call assert_equal('/', fnamemodify('.', ':p')[-1:]) call assert_equal('/', fnamemodify('.', ':p')[-1:])
call assert_equal('r', fnamemodify('.', ':p:h')[-1:]) call assert_equal('r', fnamemodify('.', ':p:h')[-1:])
@ -27,6 +29,21 @@ func Test_fnamemodify()
call assert_equal('fb2.tar.gz', fnamemodify('abc.fb2.tar.gz', ':e:e:e')) call assert_equal('fb2.tar.gz', fnamemodify('abc.fb2.tar.gz', ':e:e:e'))
call assert_equal('fb2.tar.gz', fnamemodify('abc.fb2.tar.gz', ':e:e:e:e')) call assert_equal('fb2.tar.gz', fnamemodify('abc.fb2.tar.gz', ':e:e:e:e'))
call assert_equal('tar', fnamemodify('abc.fb2.tar.gz', ':e:e:r')) call assert_equal('tar', fnamemodify('abc.fb2.tar.gz', ':e:e:r'))
call assert_equal(getcwd(), fnamemodify('', ':p:h'))
let cwd = getcwd()
call chdir($HOME)
call assert_equal('foobar', fnamemodify('~/foobar', ':~:.'))
call chdir(cwd)
call mkdir($HOME . '/XXXXXXXX/a', 'p')
call mkdir($HOME . '/XXXXXXXX/b', 'p')
call chdir($HOME . '/XXXXXXXX/a/')
call assert_equal('foo', fnamemodify($HOME . '/XXXXXXXX/a/foo', ':p:~:.'))
call assert_equal('~/XXXXXXXX/b/foo', fnamemodify($HOME . '/XXXXXXXX/b/foo', ':p:~:.'))
call mkdir($HOME . '/XXXXXXXX/a.ext', 'p')
call assert_equal('~/XXXXXXXX/a.ext/foo', fnamemodify($HOME . '/XXXXXXXX/a.ext/foo', ':p:~:.'))
call chdir(cwd)
call delete($HOME . '/XXXXXXXX', 'rf')
call assert_equal('''abc def''', fnamemodify('abc def', ':S')) call assert_equal('''abc def''', fnamemodify('abc def', ':S'))
call assert_equal('''abc" "def''', fnamemodify('abc" "def', ':S')) call assert_equal('''abc" "def''', fnamemodify('abc" "def', ':S'))
@ -44,6 +61,7 @@ func Test_fnamemodify()
let $HOME = save_home let $HOME = save_home
let &shell = save_shell let &shell = save_shell
let &shellslash = save_shellslash
endfunc endfunc
func Test_fnamemodify_er() func Test_fnamemodify_er()
@ -73,6 +91,7 @@ func Test_fnamemodify_er()
call assert_equal('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e:e')) call assert_equal('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e:e'))
call assert_equal('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e:e:e')) call assert_equal('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e:e:e'))
call assert_equal('', fnamemodify('', ':p:t'))
call assert_equal('', fnamemodify(v:_null_string, v:_null_string)) call assert_equal('', fnamemodify(v:_null_string, v:_null_string))
endfunc endfunc