diff --git a/README.md b/README.md index 02c594a..39b33e6 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,7 @@ It ultilizes vim's native matchfuzzypos function and popup window feature. - vim > 9.0 - The maintained version is written in vim9, but it also has a vim8 branch for older vim. -- any of grep, ag or rg -- find or fd +- any of grep, ag or rg for FuzzyGrep command - [vim-devicons](https://github.com/ryanoasis/vim-devicons) (optional) ## Install @@ -106,6 +105,13 @@ let g:enable_fuzzyy_keymaps = 0 " Default to 0 let g:files_respect_gitignore = 1 +" FuzzyFiles will exclude the files/directory in these two lists +" only work when g:files_respect_gitignore = 0 +" The following is the default +let g:fuzzyy_files_ignore_file = ['*.beam', '*.so', '*.exe', '*.dll', '*.dump', + '*.core', '*.swn', '*.swp'] +var g:fuzzyy_files_ignore_dir = ['.git', '.hg', '.svn', '.rebar', '.eunit'] + " Change navigation keymaps " The following is the default let g:fuzzyy_keymaps = { @@ -132,9 +138,9 @@ let g:fuzzyy_menu_matched_hl = 'cursearch' " Default to 1 if vim-devicons is installed, 0 otherwise let g:fuzzyy_devicons = 1 -" Enable dropdown theme +" Whether enable dropdown theme " Default to 0 -let g:fuzzyy_dropdown = 1 +let g:fuzzyy_dropdown = 0 " Enable FuzzyMRUFiles command. " If enabled, the MRU list will be recorded into ~/.vim_mru_files in Unix diff --git a/autoload/fuzzy/files.vim b/autoload/fuzzy/files.vim index 7bc9e04..9c1d76d 100644 --- a/autoload/fuzzy/files.vim +++ b/autoload/fuzzy/files.vim @@ -2,6 +2,7 @@ vim9script import autoload 'utils/selector.vim' import autoload 'utils/devicons.vim' +import autoload 'utils/cmdbuilder.vim' var last_result_len: number var cur_pattern: string @@ -14,56 +15,9 @@ var jid: job var menu_wid: number var files_update_tid: number var cache: dict -var cmdstr: string var matched_hl_offset = 0 var devicon_char_width = devicons.GetDeviconCharWidth() -var commands: dict -var has_git = executable('git') ? v:true : v:false - -def InsideGitRepo(): bool - if has_git - return stridx(system('git rev-parse --is-inside-work-tree'), 'true') == 0 - else - echom 'fuzzyy: git is not installed' - return v:false - endif -enddef - -if executable('fd') - commands = { - 'default': 'fd --type f -H -I -E .git', - 'gitignore': 'fd --type f -H -E .git', - } -else - if has('win32') - commands = { - 'default': 'powershell -command "gci . -r -n -File"', - } - else - commands = { - 'default': 'find . -type f -not -path "*/.git/*"', - } - endif - # TODO bugs - if has_git && InsideGitRepo() - commands.gitignore = 'git ls-files --cached --other --exclude-standard --full-name .' - else - commands.gitignore = v:null - endif -endif - -if has_git - commands.only_git_files = 'git ls-files' -endif - -def GetOrDefault(name: string, default: any): any - if exists(name) - return eval(name) - endif - return default -enddef - var enable_devicons = exists('g:fuzzyy_devicons') && exists('g:WebDevIconsGetFileTypeSymbol') ? g:fuzzyy_devicons : exists('g:WebDevIconsGetFileTypeSymbol') if enable_devicons @@ -71,26 +25,7 @@ if enable_devicons matched_hl_offset = devicons.GetDeviconWidth() + 1 endif -# options -var respect_gitignore = GetOrDefault('g:files_respect_gitignore', 0) -var only_git_files = GetOrDefault('g:files_only_git_files', 0) - -def InitConfig() - cmdstr = '' - if only_git_files - && commands.only_git_files != v:null - && InsideGitRepo() - cmdstr = commands.only_git_files - elseif respect_gitignore - && commands.gitignore != v:null - && InsideGitRepo() - cmdstr = commands.gitignore - else - cmdstr = commands.default - endif -enddef - -InitConfig() +var cmdstr = cmdbuilder.Build() def ProcessResult(list_raw: list, ...args: list): list var limit = -1 @@ -204,7 +139,6 @@ def FilesJobStart(path: string, cmd: string) enddef def ErrCb(channel: channel, msg: string) - # echom ['err'] enddef def ExitCb(j: job, status: number) @@ -286,3 +220,4 @@ export def Start(windows: dict, ...args: list) files_update_tid = timer_start(400, function('FilesUpdateMenu'), {'repeat': -1}) # Profiling() enddef + diff --git a/autoload/utils/cmdbuilder.vim b/autoload/utils/cmdbuilder.vim new file mode 100644 index 0000000..d0274ce --- /dev/null +++ b/autoload/utils/cmdbuilder.vim @@ -0,0 +1,145 @@ +vim9script + +var file_ignore_default = ['*.beam', '*.so', '*.exe', '*.dll', '*.dump', + '*.core', '*.swn', '*.swp'] +var dir_ignore_default = ['.git', '.hg', '.svn', '.rebar', '.eunit'] + +# OPTIONS +var respect_gitignore = exists('g:files_respect_gitignore') ? + g:files_respect_gitignore : 0 +var only_git_files = exists('g:files_only_git_files') ? + g:files_only_git_files : 0 +var file_ignore = exists('g:fuzzyy_files_ignore_file') + && type(g:fuzzyy_files_ignore_file) == v:t_list ? + g:fuzzyy_files_ignore_file : file_ignore_default +var dir_ignore = exists('g:fuzzyy_files_ignore_dir') + && type(g:fuzzyy_files_ignore_dir) == v:t_list ? + g:fuzzyy_files_ignore_dir : dir_ignore_default + +var has_git = executable('git') ? v:true : v:false + +def InsideGitRepo(): bool + if has_git + return stridx(system('git rev-parse --is-inside-work-tree'), 'true') == 0 + else + echom 'fuzzyy: git is not installed' + return v:false + endif +enddef + +export def Build_fd(): string + if respect_gitignore + return 'fd --type f -H -E .git' + endif + var dir_list_parsed = reduce(dir_ignore, + (acc, dir) => acc .. "-E " .. dir .. " ", "") + + var file_list_parsed = reduce(file_ignore, + (acc, file) => acc .. "-E " .. file .. " ", "") + + var result = "fd --type f -H -I " .. dir_list_parsed .. file_list_parsed + + return result +enddef + +export def Build_find(): string + var file_list_parsed = reduce(file_ignore, + (acc, file) => acc .. "-not -name " .. file .. " ", "") + + var ParseDir = (dir): string => "*/" .. dir .. "/*" + var dir_list_parsed = "" + if len(dir_ignore) > 0 + dir_list_parsed = reduce(dir_ignore, (acc, dir) => acc .. "-not -path " .. ParseDir(dir) .. " ", " ") + endif + var result = "find . " .. dir_list_parsed + if len(file_ignore) > 0 + result ..= reduce(file_ignore, (acc, file) => acc .. "-not -name " .. file .. " ", " ") + endif + result ..= "-type f -print " + + return result +enddef + +# GCI doc isn't clear. Get-ChildItem -Recurse -Exclude only matches exclusion +# on the leaf, not the parent path. +# +# Link: +# https://stackoverflow.com/questions/15294836/how-can-i-exclude-multiple-folders-using-get-childitem-exclude#:~:text=The%20documentation%20isn%27t%20clear%20on%20this%2C%20but%20Get%2DChildItem%20%2DRecurse%20%2DExclude%20only%20matches%20exclusion%20on%20the%20leaf%20(Split%2DPath%20%24_.FullName%20%2DLeaf)%2C%20not%20the%20parent%20path%20(Split%2DPath%20%24_.FullName%20%2DParent). +# +# That's why module builds GCI cmd and piping it into Where-filter +export def Build_gci(): string + var build_dir_filter = reduce(dir_ignore, (acc, dir) => acc .. "$_ -notlike '*\\" + .. dir .. "\\*' -and $_ -notlike '" .. dir .. "\\*'" + .. " -and ", "") + -> trim(" -and ", 2) + + var build_file_filter = reduce(file_ignore, (acc, file) => acc + .. "$_ -notlike '" .. file .. "' -and ", "") + -> trim(" -and ", 2) + + var build_filter = "| Where-Object { " + if len(dir_ignore) > 0 + build_filter ..= build_dir_filter + endif + if len(dir_ignore) > 0 && len(file_ignore) > 0 + build_filter ..= " -and " + endif + if len(file_ignore) > 0 + build_filter ..= build_file_filter + endif + build_filter ..= "} " + + var cmd = "Get-ChildItem . -Name -Force -File -Recurse " + if len(dir_ignore) > 0 || len(file_ignore) > 0 + cmd ..= build_filter + endif + + return "powershell -command " .. '"' .. cmd .. '"' +enddef + +export def Build_git_ls_files(): string +enddef + +def RespectGitignore(): string + var cmdstr = '' + if executable('fd') + cmdstr = Build_fd() + elseif has_git && InsideGitRepo() + cmdstr = 'git ls-files --cached --other --exclude-standard --full-name .' + endif + return cmdstr +enddef + +def OnlyGitFile(): string + var cmdstr = '' + if has_git && InsideGitRepo() + cmdstr = 'git ls-files' + endif + return cmdstr +enddef + +export def Build(): string + var cmdstr = '' + if only_git_files + cmdstr = OnlyGitFile() + if cmdstr != '' + return cmdstr + endif + endif + if respect_gitignore + cmdstr = RespectGitignore() + if cmdstr != '' + return cmdstr + endif + endif + if executable('fd') #fd is cross-platform + cmdstr = Build_fd() + else + if has('win32') + cmdstr = Build_gci() + else + cmdstr = Build_find() + endif + endif + return cmdstr +enddef