summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/editing.txt6
-rw-r--r--src/os_unix.c33
-rw-r--r--src/testdir/test_functions.vim19
-rw-r--r--src/version.c2
4 files changed, 51 insertions, 9 deletions
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
@@ -700,6 +700,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1946,
+/**/
1945,
/**/
1944,