diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt index da9aeb7fea..46279110a7 100644 --- a/runtime/doc/editing.txt +++ b/runtime/doc/editing.txt @@ -1,4 +1,4 @@ -*editing.txt* For Vim version 9.0. Last change: 2023 Apr 23 +*editing.txt* For Vim version 9.0. Last change: 2023 Sep 22 VIM REFERENCE MANUAL by Bram Moolenaar @@ -385,7 +385,9 @@ as a wildcard when "[" is in the 'isfname' option. A simple way to avoid this is to use "path\[[]abc]", this matches the file "path\[abc]". *starstar-wildcard* -Expanding "**" is possible on Unix, Win32, macOS and a few other systems. +Expanding "**" is possible on Unix, Win32, macOS and a few other systems (but +it may depend on your 'shell' setting. It's known to work correctly for zsh; for +bash this requires at least bash version >= 4.X). This allows searching a directory tree. This goes up to 100 directories deep. Note there are some commands where this works slightly differently, see |file-searching|. diff --git a/src/os_unix.c b/src/os_unix.c index 45c6b440a5..c5a54e419e 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -6701,14 +6701,17 @@ mch_expand_wildcards( #define STYLE_GLOB 1 // use "glob", for csh #define STYLE_VIMGLOB 2 // use "vimglob", for Posix sh #define STYLE_PRINT 3 // use "print -N", for zsh -#define STYLE_BT 4 // `cmd` expansion, execute the pattern - // directly +#define STYLE_BT 4 // `cmd` expansion, execute the pattern directly +#define STYLE_GLOBSTAR 5 // use extended shell glob for bash (this uses extended + // globbing functionality using globstar, needs bash > 4) int shell_style = STYLE_ECHO; int check_spaces; static int did_find_nul = FALSE; int ampersand = FALSE; // vimglob() function to define for Posix shell static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >"; + // vimglob() function with globstar setting enabled, only for bash >= 4.X + static char *sh_globstar_opt = "[[ ${BASH_VERSINFO[0]} -ge 4 ]] && shopt -s globstar; "; *num_file = 0; // default: no files found *file = NULL; @@ -6755,6 +6758,8 @@ mch_expand_wildcards( * If we use *zsh, "print -N" will work better than "glob". * STYLE_VIMGLOB: NL separated * If we use *sh*, we define "vimglob()". + * STYLE_GLOBSTAR: NL separated + * If we use *bash*, we define "vimglob() and enable globstar option". * STYLE_ECHO: space separated. * A shell we don't know, stay safe and use "echo". */ @@ -6769,9 +6774,13 @@ mch_expand_wildcards( else if (STRCMP(p_sh + len - 3, "zsh") == 0) shell_style = STYLE_PRINT; } - if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh), - "sh") != NULL) - shell_style = STYLE_VIMGLOB; + if (shell_style == STYLE_ECHO) + { + if (strstr((char *)gettail(p_sh), "bash") != NULL) + shell_style = STYLE_GLOBSTAR; + else if (strstr((char *)gettail(p_sh), "sh") != NULL) + shell_style = STYLE_VIMGLOB; + } // Compute the length of the command. We need 2 extra bytes: for the // optional '&' and for the NUL. @@ -6779,6 +6788,9 @@ mch_expand_wildcards( len = STRLEN(tempname) + 29; if (shell_style == STYLE_VIMGLOB) len += STRLEN(sh_vimglob_func); + else if (shell_style == STYLE_GLOBSTAR) + len += STRLEN(sh_vimglob_func) + + STRLEN(sh_globstar_opt); for (i = 0; i < num_pat; ++i) { @@ -6847,6 +6859,11 @@ mch_expand_wildcards( STRCAT(command, "print -N >"); else if (shell_style == STYLE_VIMGLOB) STRCAT(command, sh_vimglob_func); + else if (shell_style == STYLE_GLOBSTAR) + { + STRCAT(command, sh_globstar_opt); + STRCAT(command, sh_vimglob_func); + } else STRCAT(command, "echo >"); } @@ -7031,7 +7048,9 @@ mch_expand_wildcards( } } // file names are separated with NL - else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB) + else if (shell_style == STYLE_BT || + shell_style == STYLE_VIMGLOB || + shell_style == STYLE_GLOBSTAR) { buffer[len] = NUL; // make sure the buffer ends in NUL p = buffer; @@ -7112,7 +7131,7 @@ mch_expand_wildcards( (*file)[i] = p; // Space or NL separates if (shell_style == STYLE_ECHO || shell_style == STYLE_BT - || shell_style == STYLE_VIMGLOB) + || shell_style == STYLE_VIMGLOB || shell_style == STYLE_GLOBSTAR) { while (!(shell_style == STYLE_ECHO && *p == ' ') && *p != '\n' && *p != NUL) diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index 2cc57163dd..4ec4666855 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -3625,4 +3625,23 @@ func Test_fullcommand() call assert_equal('', fullcommand(10)) endfunc +" Test for glob() with shell special patterns +func Test_glob_extended_bash() + CheckExecutable bash + let _shell = &shell + set shell=bash + + call mkdir('Xtestglob/foo/bar/src', 'p') + call writefile([], 'Xtestglob/foo/bar/src/foo.sh') + call writefile([], 'Xtestglob/foo/bar/src/foo.h') + call writefile([], 'Xtestglob/foo/bar/src/foo.cpp') + + " Sort output of glob() otherwise we end up with different + " ordering depending on whether file system is case-sensitive. + let expected = ['Xtestglob/foo/bar/src/foo.cpp', 'Xtestglob/foo/bar/src/foo.h'] + call assert_equal(expected, sort(glob('Xtestglob/**/foo.{h,cpp}', 0, 1))) + call delete('Xtestglob', 'rf') + let &shell=_shell +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index aef4b1a641..d54df70ba5 100644 --- a/src/version.c +++ b/src/version.c @@ -699,6 +699,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1946, /**/ 1945, /**/