From 3d9c25b0934108e81b11485e6ec9f7d7d13626e0 Mon Sep 17 00:00:00 2001 From: Nico Madysa Date: Tue, 11 Oct 2022 23:05:30 +0200 Subject: [PATCH] Avoid non-portable glob pattern in `wiki#fzf#pages()`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When `g:wiki_filetypes` contains more than one file type, the function `wiki#fzf#pages()` only shows files that are in a subdirectory of the wiki root (but no deeper). The reason seems to be the glob pattern that the function generates. If `g:wiki_filetypes == ['md']`, the pattern looks like this: **/*.md If `g:wiki_filetypes == ['md', 'wiki]`, the pattern looks like this: **/*.{md,wiki} This makes use of *brace-expansion*. The vim help page for `wildcards` has the following to say: > Which wildcards are supported depends on the system. > These are the common ones: […] It then lists some wildcards, but notably not brace-expansion. While on my system (Ubuntu 22.04), Neovim 0.7.2 seems to support brace-expansion, it does so in an extremely fickle manner: ```vim glob('*.md') " Finds md files at the root glob('**.md') " Finds md files at the root glob('**/*.md') " Finds md files in whole tree, including root glob('*.{md,wiki}') " Finds md and wiki files at the root glob('**.{md,wiki}') " Finds md and wiki files at the root glob('**/*.{md,wiki}') " Finds md and wiki files *one* directory deep ``` It appears that `**` is treated exactly like `*` except in certain circumstances. The presence of brace-expansion seems to disable these circumstances. While it stands to reason that this is a bug, the child has already fallen into the well. This commit proposes to avoid the buggy glob pattern and instead to perform one glob per file type, and combine the results. This may well cause some slowdown for large and nested wikis, but I can't think of a better solution. I've had a sweep through all occurrences of `globpath()` and it seems none outside of `wiki#fzf#pages()` use brace-expansion. --- autoload/wiki/fzf.vim | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/autoload/wiki/fzf.vim b/autoload/wiki/fzf.vim index f554dd5..ba87eeb 100644 --- a/autoload/wiki/fzf.vim +++ b/autoload/wiki/fzf.vim @@ -10,16 +10,7 @@ function! wiki#fzf#pages() abort "{{{1 return endif - let l:root = wiki#get_root() . s:slash - let l:extension = len(g:wiki_filetypes) == 1 - \ ? g:wiki_filetypes[0] - \ : '{' . join(g:wiki_filetypes, ',') . '}' - let l:pages = globpath(l:root, '**/*.' . l:extension, v:false, v:true) - call map(l:pages, {_, x -> x . '#####' - \ .'/' . fnamemodify( - \ substitute(x, '\V' . escape(l:root, '\'), '', ''), - \ ':r') - \}) + let l:pages = s:gather_files() let l:fzf_opts = join([ \ '-d"#####" --with-nth=-1 --print-query --prompt "WikiPages> "', @@ -88,6 +79,28 @@ endfunction "}}}1 +function! s:gather_files() abort "{{{1 + let l:root = wiki#get_root() . s:slash + let l:pages = [] + " Note: It is tempting to do a globpath with a single pattern + " `**/*.{ext1,ext2,...}`, but this is not portable. On at least + " some very common systems, brace-expansion is incompatible with + " recursive `**` globbing and turns the latter into a + " non-recursive `*`. + for l:extension in g:wiki_filetypes + let l:pages += globpath(l:root, '**/*.' . l:extension, v:false, v:true) + endfor + call map(l:pages, {_, x -> x . '#####' + \ .'/' . fnamemodify( + \ substitute(x, '\V' . escape(l:root, '\'), '', ''), + \ ':r') + \}) + return l:pages +endfunction + +let s:slash = exists('+shellslash') && !&shellslash ? '\' : '/' + +" }}}1 function! s:accept_page(lines) abort "{{{1 " a:lines is a list with two or three elements. Two if there were no matches, " and three if there is one or more matching names. The first element is the