Skip to content

feat: add custom ignore dir/files. #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Aug 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 = {
Expand All @@ -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
Expand Down
71 changes: 3 additions & 68 deletions autoload/fuzzy/files.vim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -14,83 +15,17 @@ var jid: job
var menu_wid: number
var files_update_tid: number
var cache: dict<any>
var cmdstr: string
var matched_hl_offset = 0
var devicon_char_width = devicons.GetDeviconCharWidth()

var commands: dict<any>
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
# devicons take 3/4(macvim) chars position plus 1 space
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<string>, ...args: list<any>): list<string>
var limit = -1
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -286,3 +220,4 @@ export def Start(windows: dict<any>, ...args: list<any>)
files_update_tid = timer_start(400, function('FilesUpdateMenu'), {'repeat': -1})
# Profiling()
enddef

145 changes: 145 additions & 0 deletions autoload/utils/cmdbuilder.vim
Original file line number Diff line number Diff line change
@@ -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