diff --git a/.gitmodules b/.gitmodules index ee5c430..1a8d563 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,9 +28,6 @@ [submodule "vim/bundle/fugitive"] path = vim/bundle/fugitive url = https://github.com/tpope/vim-fugitive.git -[submodule "vim/bundle/zencoding"] - path = vim/bundle/zencoding - url = https://github.com/mattn/zencoding-vim.git [submodule "vim/bundle/syntastic"] path = vim/bundle/syntastic url = https://github.com/scrooloose/syntastic.git @@ -46,12 +43,18 @@ [submodule "vim/snippets/django"] path = vim/snippets/django url = https://github.com/robhudson/snipmate_for_django.git -[submodule "vim/bundle/snipmate"] - path = vim/bundle/snipmate - url = git://github.com/MarcWeber/snipmate.vim.git [submodule "vim/bundle/addon-mw-utils"] path = vim/bundle/addon-mw-utils url = git://github.com/MarcWeber/vim-addon-mw-utils.git [submodule "vim/bundle/coffee-script"] path = vim/bundle/coffee-script url = git://github.com/kchmck/vim-coffee-script.git +[submodule "vim/bundle/tlib_vim"] + path = vim/bundle/tlib_vim + url = https://github.com/tomtom/tlib_vim.git +[submodule "vim/bundle/snipmate"] + path = vim/bundle/snipmate + url = git://github.com/garbas/vim-snipmate.git +[submodule "vim/bundle/emmet"] + path = vim/bundle/emmet + url = https://github.com/mattn/emmet-vim.git diff --git a/.gvimrc.un~ b/.gvimrc.un~ new file mode 100644 index 0000000..2706c04 Binary files /dev/null and b/.gvimrc.un~ differ diff --git a/.vimrc.un~ b/.vimrc.un~ new file mode 100644 index 0000000..653e734 Binary files /dev/null and b/.vimrc.un~ differ diff --git a/config/terminator/config b/config/terminator/config index 685f472..494c8a4 100644 --- a/config/terminator/config +++ b/config/terminator/config @@ -3,6 +3,7 @@ [keybindings] [profiles] [[default]] + scrollback_lines = 3000 [layouts] [[default]] [[[child0]]] diff --git a/install.sh b/install.sh index 3b71784..41a73f5 100755 --- a/install.sh +++ b/install.sh @@ -14,5 +14,8 @@ ln -sf $(pwd)/vim ~/.vim ln -sf $(pwd)/zsh ~/.zsh cd vim/bundle/command-t -rvm use system -rake make +cd ruby/command-t +#rvm use system +rvm use ree --default +ruby extconf.rb +make diff --git a/vim/.netrwhist b/vim/.netrwhist new file mode 100644 index 0000000..3d3e098 --- /dev/null +++ b/vim/.netrwhist @@ -0,0 +1,8 @@ +let g:netrw_dirhistmax =10 +let g:netrw_dirhist_cnt =6 +let g:netrw_dirhist_1='/home/ceichhor/svn_projects/2115_links_im_newsletter_berichtigenOF' +let g:netrw_dirhist_2='/home/ceichhor/svn_projects/waportal' +let g:netrw_dirhist_3='/home/ceichhor/svn_projects/2093_box_aktuelle_kurse' +let g:netrw_dirhist_4='/home/ceichhor/svn_projects/waportal' +let g:netrw_dirhist_5='/home/ceichhor/svn_projects/2093_box_aktuelle_kurse' +let g:netrw_dirhist_6='/home/ceichhor/svn_projects/waportal' diff --git a/vim/autoload/pathogen.vim b/vim/autoload/pathogen.vim index e10fac9..7b89cca 100644 --- a/vim/autoload/pathogen.vim +++ b/vim/autoload/pathogen.vim @@ -1,16 +1,50 @@ " pathogen.vim - path option manipulation -" Maintainer: Tim Pope -" Version: 1.3 +" Maintainer: Tim Pope +" Version: 2.2 " Install in ~/.vim/autoload (or ~\vimfiles\autoload). " -" API is documented below. +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. For maximum ease of reading, +" :set foldmethod=marker if exists("g:loaded_pathogen") || &cp finish endif let g:loaded_pathogen = 1 +function! s:warn(msg) + echohl WarningMsg + echomsg a:msg + echohl NONE +endfunction + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#incubate() (defaults to "bundle/{}"), or an absolute path to invoke +" pathogen#surround(). For backwards compatibility purposes, a full path that +" does not end in {} or * is given to pathogen#runtime_prepend_subdirectories() +" instead. +function! pathogen#infect(...) abort " {{{1 + for path in a:0 ? reverse(copy(a:000)) : ['bundle/{}'] + if path =~# '^[^\\/]\+$' + call s:warn('Change pathogen#infect('.string(path).') to pathogen#infect('.string(path.'/{}').')') + call pathogen#incubate(path . '/{}') + elseif path =~# '^[^\\/]\+[\\/]\%({}\|\*\)$' + call pathogen#incubate(path) + elseif path =~# '[\\/]\%({}\|\*\)$' + call pathogen#surround(path) + else + call s:warn('Change pathogen#infect('.string(path).') to pathogen#infect('.string(path.'/{}').')') + call pathogen#surround(path . '/{}') + endif + endfor + call pathogen#cycle_filetype() + return '' +endfunction " }}}1 + " Split a path into a list. function! pathogen#split(path) abort " {{{1 if type(a:path) == type([]) | return a:path | endif @@ -55,8 +89,11 @@ function! pathogen#uniq(list) abort " {{{1 let i = 0 let seen = {} while i < len(a:list) - if has_key(seen,a:list[i]) + if (a:list[i] ==# '' && exists('empty')) || has_key(seen,a:list[i]) call remove(a:list,i) + elseif a:list[i] ==# '' + let i += 1 + let empty = 1 else let seen[a:list[i]] = 1 let i += 1 @@ -81,36 +118,66 @@ function! pathogen#glob_directories(pattern) abort " {{{1 return filter(pathogen#glob(a:pattern),'isdirectory(v:val)') endfunction "}}}1 -" Checks if a bundle is 'disabled'. A bundle is considered 'disabled' if -" its 'basename()' is included in g:pathogen_disabled[]'. +" Turn filetype detection off and back on again if it was already enabled. +function! pathogen#cycle_filetype() " {{{1 + if exists('g:did_load_filetypes') + filetype off + filetype on + endif +endfunction " }}}1 + +" Check if a bundle is disabled. A bundle is considered disabled if it ends +" in a tilde or its basename or full name is included in the list +" g:pathogen_disabled. function! pathogen#is_disabled(path) " {{{1 - if !exists("g:pathogen_disabled") + if a:path =~# '\~$' + return 1 + elseif !exists("g:pathogen_disabled") return 0 endif let sep = pathogen#separator() - return index(g:pathogen_disabled, strpart(a:path, strridx(a:path, sep)+1)) != -1 + let blacklist = g:pathogen_disabled + return index(blacklist, strpart(a:path, strridx(a:path, sep)+1)) != -1 && index(blacklist, a:path) != 1 endfunction "}}}1 -" Prepend all subdirectories of path to the rtp, and append all 'after' -" directories in those subdirectories. -function! pathogen#runtime_prepend_subdirectories(path) " {{{1 - let sep = pathogen#separator() - let before = filter(pathogen#glob_directories(a:path.sep."*[^~]"), '!pathogen#is_disabled(v:val)') - let after = filter(pathogen#glob_directories(a:path.sep."*[^~]".sep."after"), '!pathogen#is_disabled(v:val[0:-7])') +" Prepend the given directory to the runtime path and append its corresponding +" after directory. If the directory is already included, move it to the +" outermost position. Wildcards are added as is. Ending a path in /{} causes +" all subdirectories to be added (except those in g:pathogen_disabled). +function! pathogen#surround(path) abort " {{{1 + let sep = pathogen#separator() let rtp = pathogen#split(&rtp) - let path = expand(a:path) - call filter(rtp,'v:val[0:strlen(path)-1] !=# path') - let &rtp = pathogen#join(pathogen#uniq(before + rtp + after)) + if a:path =~# '[\\/]{}$' + let path = fnamemodify(a:path[0:-4], ':p:s?[\\/]\=$??') + let before = filter(pathogen#glob_directories(path.sep.'*'), '!pathogen#is_disabled(v:val)') + let after = filter(reverse(pathogen#glob_directories(path.sep."*".sep."after")), '!pathogen#is_disabled(v:val[0:-7])') + call filter(rtp,'v:val[0:strlen(path)-1] !=# path') + else + let path = fnamemodify(a:path, ':p:s?[\\/]\=$??') + let before = [path] + let after = [path . sep . 'after'] + call filter(rtp, 'index(before + after, v:val) == -1') + endif + let &rtp = pathogen#join(before, rtp, after) return &rtp endfunction " }}}1 -" For each directory in rtp, check for a subdirectory named dir. If it -" exists, add all subdirectories of that subdirectory to the rtp, immediately -" after the original directory. If no argument is given, 'bundle' is used. -" Repeated calls with the same arguments are ignored. -function! pathogen#runtime_append_all_bundles(...) " {{{1 +" Prepend all subdirectories of path to the rtp, and append all 'after' +" directories in those subdirectories. Deprecated. +function! pathogen#runtime_prepend_subdirectories(path) " {{{1 + call s:warn('Change pathogen#runtime_prepend_subdirectories('.string(a:path).') to pathogen#surround('.string(a:path.'/{}').')') + return pathogen#surround(a:path . pathogen#separator() . '{}') +endfunction " }}}1 + +" For each directory in the runtime path, add a second entry with the given +" argument appended. If the argument ends in '/{}', add a separate entry for +" each subdirectory. The default argument is 'bundle/{}', which means that +" .vim/bundle/*, $VIM/vimfiles/bundle/*, $VIMRUNTIME/bundle/*, +" $VIM/vim/files/bundle/*/after, and .vim/bundle/*/after will be added (on +" UNIX). +function! pathogen#incubate(...) abort " {{{1 let sep = pathogen#separator() - let name = a:0 ? a:1 : 'bundle' + let name = a:0 ? a:1 : 'bundle/{}' if "\n".s:done_bundles =~# "\\M\n".name."\n" return "" endif @@ -118,25 +185,142 @@ function! pathogen#runtime_append_all_bundles(...) " {{{1 let list = [] for dir in pathogen#split(&rtp) if dir =~# '\"),'!isdirectory(v:val)')) && (!filereadable(dir.sep.'doc'.sep.'tags') || filewritable(dir.sep.'doc'.sep.'tags')) + silent! execute 'helptags' pathogen#fnameescape(dir.'/doc') + endif + endfor + endfor +endfunction " }}}1 + +command! -bar Helptags :call pathogen#helptags() + +" Execute the given command. This is basically a backdoor for --remote-expr. +function! pathogen#execute(...) abort " {{{1 + for command in a:000 + execute command endfor + return '' +endfunction " }}}1 + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort "{{{1 + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif endfunction " }}}1 -" vim:set ft=vim ts=8 sw=2 sts=2: +" Backport of fnameescape(). +function! pathogen#fnameescape(string) abort " {{{1 + if exists('*fnameescape') + return fnameescape(a:string) + elseif a:string ==# '-' + return '\-' + else + return substitute(escape(a:string," \t\n*?[{`$\\%#'\"|!<"),'^[+>]','\\&','') + endif +endfunction " }}}1 + +if exists(':Vedit') + finish +endif + +let s:vopen_warning = 0 + +function! s:find(count,cmd,file,lcd) " {{{1 + let rtp = pathogen#join(1,pathogen#split(&runtimepath)) + let file = pathogen#runtime_findfile(a:file,a:count) + if file ==# '' + return "echoerr 'E345: Can''t find file \"".a:file."\" in runtimepath'" + endif + if !s:vopen_warning + let s:vopen_warning = 1 + let warning = '|echohl WarningMsg|echo "Install scriptease.vim to continue using :V'.a:cmd.'"|echohl NONE' + else + let warning = '' + endif + if a:lcd + let path = file[0:-strlen(a:file)-2] + execute 'lcd `=path`' + return a:cmd.' '.pathogen#fnameescape(a:file) . warning + else + return a:cmd.' '.pathogen#fnameescape(file) . warning + endif +endfunction " }}}1 + +function! s:Findcomplete(A,L,P) " {{{1 + let sep = pathogen#separator() + let cheats = { + \'a': 'autoload', + \'d': 'doc', + \'f': 'ftplugin', + \'i': 'indent', + \'p': 'plugin', + \'s': 'syntax'} + if a:A =~# '^\w[\\/]' && has_key(cheats,a:A[0]) + let request = cheats[a:A[0]].a:A[1:-1] + else + let request = a:A + endif + let pattern = substitute(request,'/\|\'.sep,'*'.sep,'g').'*' + let found = {} + for path in pathogen#split(&runtimepath) + let path = expand(path, ':p') + let matches = split(glob(path.sep.pattern),"\n") + call map(matches,'isdirectory(v:val) ? v:val.sep : v:val') + call map(matches,'expand(v:val, ":p")[strlen(path)+1:-1]') + for match in matches + let found[match] = 1 + endfor + endfor + return sort(keys(found)) +endfunction " }}}1 + +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Ve :execute s:find(,'edit',,0) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vedit :execute s:find(,'edit',,0) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vopen :execute s:find(,'edit',,1) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vsplit :execute s:find(,'split',,1) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vvsplit :execute s:find(,'vsplit',,1) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vtabedit :execute s:find(,'tabedit',,1) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vpedit :execute s:find(,'pedit',,1) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vread :execute s:find(,'read',,1) + +" vim:set et sw=2: diff --git a/vim/bundle/ack b/vim/bundle/ack index a41d5d5..6a57bc0 160000 --- a/vim/bundle/ack +++ b/vim/bundle/ack @@ -1 +1 @@ -Subproject commit a41d5d52c39a31128e969e69acf800b198cb07f9 +Subproject commit 6a57bc0a5877800b5621f6ade5006e58eb582845 diff --git a/vim/bundle/addon-mw-utils b/vim/bundle/addon-mw-utils index b350792..0c5612f 160000 --- a/vim/bundle/addon-mw-utils +++ b/vim/bundle/addon-mw-utils @@ -1 +1 @@ -Subproject commit b3507927727d05551459e086bff78133ca221d5a +Subproject commit 0c5612fa31ee434ba055e21c76f456244b3b5109 diff --git a/vim/bundle/coffee-script b/vim/bundle/coffee-script index c92f18e..827e4a3 160000 --- a/vim/bundle/coffee-script +++ b/vim/bundle/coffee-script @@ -1 +1 @@ -Subproject commit c92f18eb55f7905d426cedc92fd4e50d94e27724 +Subproject commit 827e4a38b07479433b619091469a7495a392df8a diff --git a/vim/bundle/command-t b/vim/bundle/command-t index 54b5bed..13760a7 160000 --- a/vim/bundle/command-t +++ b/vim/bundle/command-t @@ -1 +1 @@ -Subproject commit 54b5bedf6923cfce8ee6c109fbf9e9d296bb76fa +Subproject commit 13760a725779b65fa0f2ebef51806f3c05a52550 diff --git a/vim/bundle/emmet b/vim/bundle/emmet new file mode 160000 index 0000000..1c46c5f --- /dev/null +++ b/vim/bundle/emmet @@ -0,0 +1 @@ +Subproject commit 1c46c5fb775606621906f0bedc8da8bc636c1dac diff --git a/vim/bundle/endwise b/vim/bundle/endwise index d8c887b..bba43b8 160000 --- a/vim/bundle/endwise +++ b/vim/bundle/endwise @@ -1 +1 @@ -Subproject commit d8c887b93b7ceb250c02ee7d9fc36de09f8b120d +Subproject commit bba43b831ae0485cf9b86d16340a6a314b927391 diff --git a/vim/bundle/fugitive b/vim/bundle/fugitive index f112f9b..0095769 160000 --- a/vim/bundle/fugitive +++ b/vim/bundle/fugitive @@ -1 +1 @@ -Subproject commit f112f9b830a8f42375183c9a47965270ae8b3ae4 +Subproject commit 0095769029709b531d2505ee6ad9907dd9bd72a0 diff --git a/vim/bundle/nerdcommenter b/vim/bundle/nerdcommenter index 38630ff..6549cfd 160000 --- a/vim/bundle/nerdcommenter +++ b/vim/bundle/nerdcommenter @@ -1 +1 @@ -Subproject commit 38630ff5eb9378fd8d917b956ba7d4dbf0b896b3 +Subproject commit 6549cfde45339bd4f711504196ff3e8b766ef5e6 diff --git a/vim/bundle/nerdtree b/vim/bundle/nerdtree index 2e072fe..3b98a7f 160000 --- a/vim/bundle/nerdtree +++ b/vim/bundle/nerdtree @@ -1 +1 @@ -Subproject commit 2e072fe0e23a92c75f08cae04cb50ed4212b79f6 +Subproject commit 3b98a7fcae8f9fff356907171f0406ff8cd28921 diff --git a/vim/bundle/rails b/vim/bundle/rails index 878d7f7..981f8d7 160000 --- a/vim/bundle/rails +++ b/vim/bundle/rails @@ -1 +1 @@ -Subproject commit 878d7f780f6ac7eb1c86ac6a7a0b6d980ba202d8 +Subproject commit 981f8d790cbecd5bbbb907aa30a94f63b6aee041 diff --git a/vim/bundle/repeat b/vim/bundle/repeat index c4101c2..b01aafb 160000 --- a/vim/bundle/repeat +++ b/vim/bundle/repeat @@ -1 +1 @@ -Subproject commit c4101c205ef9e06bdfeff571a7dbba2576f08974 +Subproject commit b01aafbd8d44573abf0ad36afb2df66e92f1a680 diff --git a/vim/bundle/snipmate b/vim/bundle/snipmate index 22548b8..2079ea5 160000 --- a/vim/bundle/snipmate +++ b/vim/bundle/snipmate @@ -1 +1 @@ -Subproject commit 22548b8b4869a92a93276ad911f17a9040823047 +Subproject commit 2079ea5aadaada568f78acfc6b565945625ed97d diff --git a/vim/bundle/sparkup b/vim/bundle/sparkup index 04a81b4..b1b4374 160000 --- a/vim/bundle/sparkup +++ b/vim/bundle/sparkup @@ -1 +1 @@ -Subproject commit 04a81b41f116a19184359a6f8685c192f5c36c70 +Subproject commit b1b4374def210ec54ace524fe70503a44d05d6de diff --git a/vim/bundle/surround b/vim/bundle/surround index d9e6bfd..772ab95 160000 --- a/vim/bundle/surround +++ b/vim/bundle/surround @@ -1 +1 @@ -Subproject commit d9e6bfdd902fc661c8fd58ede248ccfc3b3039d7 +Subproject commit 772ab9587b7d1e2c3bae75395c9123803059ba8a diff --git a/vim/bundle/syntastic b/vim/bundle/syntastic index 9f56397..dac07db 160000 --- a/vim/bundle/syntastic +++ b/vim/bundle/syntastic @@ -1 +1 @@ -Subproject commit 9f563979227b1e7aaadd0e154943083db792b2bc +Subproject commit dac07db61758590c71d655ed5403181af4e845a2 diff --git a/vim/bundle/textobj-rubyblock b/vim/bundle/textobj-rubyblock index c6b186d..b5b84e4 160000 --- a/vim/bundle/textobj-rubyblock +++ b/vim/bundle/textobj-rubyblock @@ -1 +1 @@ -Subproject commit c6b186dd5ad74503439c967e0d2ad863fcba93bc +Subproject commit b5b84e49e609439e81aa03fa8e605a6097185665 diff --git a/vim/bundle/textobj-user b/vim/bundle/textobj-user index 8dc7888..9aa5fd0 160000 --- a/vim/bundle/textobj-user +++ b/vim/bundle/textobj-user @@ -1 +1 @@ -Subproject commit 8dc78888b7e3bbd562b2f8c29c96365f61cba194 +Subproject commit 9aa5fd050ecce650fb7ff018397e73a66a41c76b diff --git a/vim/bundle/tlib_vim b/vim/bundle/tlib_vim new file mode 160000 index 0000000..2376d12 --- /dev/null +++ b/vim/bundle/tlib_vim @@ -0,0 +1 @@ +Subproject commit 2376d1233e7d1db8157fdc3157278dda7a2c796f diff --git a/vim/bundle/update_submodules.sh b/vim/bundle/update_submodules.sh index 5220455..0a29fe7 100755 --- a/vim/bundle/update_submodules.sh +++ b/vim/bundle/update_submodules.sh @@ -9,3 +9,6 @@ for dir in $(ls); do cd .. fi done + +git add $(git status | grep "new commits" | awk '{print $3}') +git commit -m " * vim/bundle update" diff --git a/vim/bundle/xmledit b/vim/bundle/xmledit index d04ccce..1335d79 160000 --- a/vim/bundle/xmledit +++ b/vim/bundle/xmledit @@ -1 +1 @@ -Subproject commit d04cccef0ef0a033079c21cae1ebcbd37197c364 +Subproject commit 1335d79a5501b92f43e2540f555045809b409ca5 diff --git a/vim/bundle/zencoding b/vim/bundle/zencoding deleted file mode 160000 index dcc75d8..0000000 --- a/vim/bundle/zencoding +++ /dev/null @@ -1 +0,0 @@ -Subproject commit dcc75d8a19471df51503a22c2f3d83b70fe1586e diff --git a/vim/doc/EasyGrep.txt b/vim/doc/EasyGrep.txt new file mode 100644 index 0000000..c6b9ba9 --- /dev/null +++ b/vim/doc/EasyGrep.txt @@ -0,0 +1,580 @@ +*EasyGrep.txt* +============================================================================== + EasyGrep *EasyGrep* +============================================================================== + +Author: Dan Price vim@danprice.fastmail.net *EasyGrep_Author* + +Goal: To be an easy to use, powerful find and |EasyGrep_Motivation| + replace tool for users of all skill levels. +Version: 0.98 |EasyGrep_History| + +License: Public domain, no restrictions whatsoever |EasyGrep_License| +Contribute: Please report any bugs or suggestions |EasyGrep_Bugs| + to the address above. |EasyGrep_Future| + + +============================================================================== + Table of Contents *EasyGrep_Contents* +============================================================================== + + + 1. Motivation.................|EasyGrep_Motivation| + 2. Operation..................|EasyGrep_Operation| + 2.1 Modes..................|EasyGrep_OperationModes| + 3. Keymaps....................|EasyGrep_Keymaps| + 3.1 Option Mappings........|EasyGrep_KeymapsOptions| + 3.2 Mapping Customization..|EasyGrep_KeymapsCustomization| + 4. Commands...................|EasyGrep_Commands| + 5. Options....................|EasyGrep_Options| + 5.1 Summary...............|EasyGrep_OptionsSummary| + 5.2 Explorer..............|EasyGrep_OptionsExplorer| + 5.3 Details...............|EasyGrep_OptionsDetail| + 6. Bugs.......................|EasyGrep_Bugs| + 7. Future.....................|EasyGrep_Future| + 8. History....................|EasyGrep_History| + 9. License....................|EasyGrep_License| + + +============================================================================== + Motivation *EasyGrep_Motivation* +============================================================================== + +EasyGrep's main goal is to make search and replace in files easy. Other Vim +plugins provide similar functionality, but few provide the same level of +functionality with as little configuration as EasyGrep does. In the common +case, all it takes to search for a string across multiple files is three +keypresses: vv. No clicks, no commands, no project/tags setup -- just +three keys. When you need a substitution, it also takes the same number of +keys to start a replace in files. After using EasyGrep, you'll wonder at how +you got around without it. + +While EasyGrep's default configuration will satisfy many users, it provides +more than a dozen options for those who need more control |EasyGrep_Options|. +When you need to change options, EasyGrep provides an options explorer that +indicates which files will be searched and allows visual customization of its +options |EasyGrep_OptionsExplorer|. When this isn't fast enough, EasyGrep +provides key mappings for each option to toggle its value +|EasyGrep_KeymapsOptions|. If you can't find an option you need, contact me +|EasyGrep_Author| and if it doesn't already exist, we'll make it happen. + +I hope that EasyGrep makes Vim more fun, productive, and easy for you to use. + + Happy Vimming! + + +============================================================================== + Operation *EasyGrep_Operation* +============================================================================== + +EasyGrep makes using Vim's grep capabilities easier. When using EasyGrep, +searching for a word is as easy as typing a three keypress mapping +|EasyGrep_Keymaps|. In addition to keymaps, search and replace can be invoked +through commands |EasyGrep_Commands|. + +To determine which files to search, EasyGrep provides three modes, described +in the next section. + + +Search Modes |EasyGrep_OperationModes| + +All + All files will be searched (default). + +Buffers + Files currently open in vim will be searched. Recursion has no meaning in + this mode, and will be turned off. + +TrackExt + Files that match the extension of the currently opened file will be + searched. Additionally, this extension can be mapped to a user defined + set of extensions that will also be searched |EasyGrepFileAssociations|. + + For example: in the default configuration, when test.cpp is open, files + that match any one of + + *.cpp *.hpp *.cxx *.hxx *.cc *.c *.h + + will be searched when a Grep is initiated. I find this mode to be the + most useful. + +User + Specify a custom set of file extensions to search. + + +These modes can be quickly changed through the |EasyGrep_OptionsExplorer| or +|EasyGrep_KeymapsOptions|. + + +============================================================================== + Keymaps *EasyGrep_Keymaps* +============================================================================== + +EasyGrep uses Vim's leader key, which is by default '\'. For information on +this key, type ":help mapleader". + +vv - Grep for the word under the cursor, match all occurences, + like 'g*'. See ":help gstar". +vV - Grep for the word under the cursor, match whole word, like + '*'. See ":help star". +va - Like vv, but add to existing list. +vA - Like vV, but add to existing list. + +vr - Perform a global search on the word under the cursor + and prompt for a pattern with which to replace it. +vR - Like vr, but match whole word. + +Each of these commands has an 'all occurences' and 'whole word' option, +designated by the case of the last character. If you would prefer that these +be reversed, see |EasyGrepInvertWholeWord|. + +In addition to grepping the word under the cursor, text may be visually +selected and these mappings may be used analogously to as they are used above. +Visual selections will automatically be escaped so as not to confuse the +selection with a regular expression. + + e.g. Selecting the text inside the quotes here "/" will match + against "\" but not against "word". + +To search with a regular expression, see the :Grep command |EasyGrep_Commands| + +Each of the above commands will search files according to settings +controlled by: + +vo - Open an options explorer to select the files to search in and + set grep options. + +For the options provided, see |EasyGrep_Options|. + + + *EasyGrep_KeymapsOptions* + +For each of the options presented in the options explorer, there is a mapping +that allows a direct change of this option. The pattern is vy* , +where star is the value listed in the options window for each of the options. + + e.g. To toggle recursive mode, type '\vyr' + +See |EasyGrepOptionPrefix| to change the prefix from '\vy' or to turn these +keymappings off. + + + *EasyGrep_KeymapsCustomization* + +Beyond EasyGrepOptionPrefix, other keymaps may be remapped to your liking. +See the "Keymaps" section of EasyGrep.vim for the names of these items. + +Mappings take the form: + + map (keycombination) (MappingName) +e.g. + map ,op EgMapGrepOptions + + +============================================================================== + Commands *EasyGrep_Commands* +============================================================================== + +:Grep [arg] + Search for the specified arg, like vv. When an ! is added, + search like vV + +:GrepAdd [arg] + Search for the specified arg, add to existing file list, as in + va. When an ! is added, search like vA + + The Above commands can additionally accept command switches: + -r Perform a recursive search + -R Perform a recursive search + -i Perform a case-insensitive search + -I Perform a case-sensitive search + -m Specify the number of matches to get + +:Replace [target] [replacement] +:Replace /[target]/[replacement]/ + Perform a global search and replace. The function searches + the same set of files a grep for the desired target and opens a dialog to + confirm replacement. In the second, forward slash delineated form, back + and forward slashes must be explicitly escaped. + +:ReplaceUndo + Undoes the last :Replace operation. Does not stack successive + searches; only the last replace may be undone. This function may not + work well when edits are made between a call to Replace and a call to + ReplaceUndo. + +:GrepOptions + Open the options explorer to set options. + + +For each of the search and replace commands, searching with regular +expressions is supported. Note that regular expressions are handled as +indicated by the 'magic' option (see ":help 'magic'"). + +:FilterErrorlist [args] + Removes entries from the error list according to whether or not they match + a set of specified patterns. The default behaviour is to save all entries + that match one of the patterns and remove those that do not. + + The Above command can additionally accept command switches: + -v Switch the criteria for matching; remove entries matching one of the + specified patterns instead of saving them + -l Remove entries from the location list + + +============================================================================== + Options *EasyGrep_Options* +============================================================================== + +Options Summary *EasyGrep_OptionsSummary* + + Option Description +------------------------------------------------------------------------------ +|EasyGrepFileAssociations| Specifies the location of the EasyGrep + file associations +------------------------------------------------------------------------------ +|EasyGrepMode| Mode of operation +------------------------------------------------------------------------------ +|EasyGrepCommand| Whether to use vimgrep or grepprg +------------------------------------------------------------------------------ +|EasyGrepRecursive| Recursive searching +------------------------------------------------------------------------------ +|EasyGrepIgnoreCase| Case-sensitivity in searches +------------------------------------------------------------------------------ +|EasyGrepHidden| Include hidden files in searches +------------------------------------------------------------------------------ +|EasyGrepAllOptionsInExplorer| How many options to show in the explorer +------------------------------------------------------------------------------ +|EasyGrepWindow| Quickfix or location list +------------------------------------------------------------------------------ +|EasyGrepWindowPosition| Where the error list window is opened +------------------------------------------------------------------------------ +|EasyGrepOpenWindowOnMatch| Open grep window on successful match +------------------------------------------------------------------------------ +|EasyGrepEveryMatch| Match multiple times per line +------------------------------------------------------------------------------ +|EasyGrepJumpToMatch| Jump to first match +------------------------------------------------------------------------------ +|EasyGrepSearchCurrentBufferDir| Whether to search current buffers dir + in addition to working dir +------------------------------------------------------------------------------ +|EasyGrepInvertWholeWord| Invert the meaning of whole word for vv + and vV keymaps +------------------------------------------------------------------------------ +|EasyGrepFileAssociationsInExplorer| Whether to show the file associations + list in the options explorer +------------------------------------------------------------------------------ +|EasyGrepReplaceWindowMode| Controls whether to use tabs or splits + when replacing in files +------------------------------------------------------------------------------ +|EasyGrepReplaceAllPerFile| Replace on per file or global basis +------------------------------------------------------------------------------ +|EasyGrepOptionPrefix| Specify the keymap for toggling options +------------------------------------------------------------------------------ +|EasyGrepExtraWarnings| Whether to show extra warnings +------------------------------------------------------------------------------ + + +Options Explorer *EasyGrep_OptionsExplorer* + + To invoke the options explorer, type '\vo' (default). The options + explorer presents all of EasyGrep's customizable options and provides + information on the file patterns that will be searched when invoking a + Grep. + + A useful exercise for beginners is to toggle between EasyGrep's options + and modes (|EasyGrep_OperationModes|) and type 'e' to see which files will + be searched for a given configuration. + + +Options Details *EasyGrep_OptionsDetail* + +*EasyGrepFileAssociations* +Specifies the location of a file that contains groups of files that should be +associated with one another. When set to an empty string "", no file read +will be attempted. + +This file has a simple syntax used to logically link different files types. +A simple configuration is shown below: + + C=*.c *.h + C++=*.cpp *.hpp *.cxx *.hxx *.cc + VHDL=*.hdl *.vhd *.vhdl *.vbe *.vst + Web=*.htm *.html *.js + +For example, in this configuration, whenever the active file has the .c +extension, files with the .h extension will also be search. A special feature +of this syntax is the ability to link groups together. For example, the C++ +group links to all files that are in the C group. + + +*EasyGrepMode* +Specifies the mode in which to start. +0 - All files +1 - Open Buffers +2 - Track the current extension + +Note: I find option 2 to be the most powerful, but option 0 is activated by +default because it is the most intuitive for users who haven't take the +time to understand how the script works. See |EasyGrep_OperationModes|. + +*EasyGrepCommand* +Specifies the grep command to use. + +0 - vimgrep +1 - grep (follows grepprg) + +*EasyGrepRecursive* +Specifies that recursive search be activated on start. + +*EasyGrepIgnoreCase* +Specifies the case sensitivity of searches. Note that this can be further +overrided for vimgrep searches with \c and \C. + +*EasyGrepHidden* +Specifies that hidden files search be activated on start. Note that hidden +implies the unix meaning of those files that are prepended with a '.', and not +the Windows meaning of those files with a hidden attribute. + +*EasyGrepAllOptionsInExplorer* +Specifies that all options be included in the explorer window. + +Note: settting this option is very useful when you want to try out and +learn all of the options available in this script. + +*EasyGrepWindow* +Specifies the window to use for matches. +0 - quickfix +1 - location list + +*EasyGrepWindowPosition* +Specifies where the error list window is opened. The value of this option +must match one of Vim's splitting positional window commands, such as topleft +or botright. + +*EasyGrepOpenWindowOnMatch* +Specifies whether to open the with matches after a search. + +*EasyGrepEveryMatch* +Specifies that multiple matches on the same line be treated as different +matches, like the g option to vimgrep. + +*EasyGrepJumpToMatch* +Specifies that jump to first match be activated, like the j option to vimgrep. + +*EasyGrepSearchCurrentBufferDir* +Setting this option causes EasyGrep to search the current buffer's +directory in addition to the current working directory. + +*EasyGrepInvertWholeWord* +Specifies that the whole word search keys should be inverted from their +default meaning. For example, when this option is activated, vv +matches whole word, while vV matches everything that includes the +word. Note that this affects both keymappings and commands. + +*EasyGrepFileAssociationsInExplorer* +Specifies whether to show the file associations list in the options explorer +window. + +*EasyGrepOptionPrefix* +Specifies the prefix that is used when building keymaps for setting options +directly. To specify that no option keymaps be created, set this to the empty +string. + +Default: + let g:EasyGrepOptionPrefix='vy' +Custom: + let g:EasyGrepOptionPrefix=',oe' +None: + let g:EasyGrepOptionPrefix='' + + +*EasyGrepReplaceWindowMode* +Specifies the mode that the script will use when a buffer needs to be changed +while performing a global replace. +0 - Open a new tab for each window +1 - Perform a split of the current window with the next window +2 - autowriteall; create no new windows + +Note: Option 1 has the possibility of running out of vertical space to +split more windows. Actions are taken to make this a non-issue, but this +option can often be more clunky than other options. +Note: As a result of the limitation above, option 0 is the only mode that +won't require saving the files during a replace. + +*EasyGrepReplaceAllPerFile* +Specifies that selecting 'a' (for all) will apply the replacements on a per +file basis, as opposed to globally as is the default. + +*EasyGrepExtraWarnings* +Specifies that warnings be issued for conditions that may be valid but confuse +some users. + + +============================================================================== + Future *EasyGrep_Future* +============================================================================== + +------------------------------------------------------------------------------ +Show search progress? +------------------------------------------------------------------------------ +Allow entries in the file associations list to be regular expressions +------------------------------------------------------------------------------ +create capability to include paths other than the active directories in a +search. e.g. ../../include, $INCLUDE, etc. +------------------------------------------------------------------------------ +set file/directory exclusions +------------------------------------------------------------------------------ + +============================================================================== + Bugs *EasyGrep_Bugs* +============================================================================== + +If you discover any bugs not listed here, please contact the |EasyGrep_Author| + +------------------------------------------------------------------------------ +Successive warning messages can hide a previous message +------------------------------------------------------------------------------ +ReplaceUndo opens a window even if it is already open? +------------------------------------------------------------------------------ +Report that a swap file can't be opened +------------------------------------------------------------------------------ +Don't warn when the current file will actually be searched because recursion +is on and it is below the current directory +------------------------------------------------------------------------------ +Patterns with backslashes in them require double-backslash to be searched from +the command line. This behaviour matches the builtin / command but it may be +unintuitive. +------------------------------------------------------------------------------ + + + +============================================================================== + History *EasyGrep_History* +============================================================================== + + 0.98 + Highlight: The Replace and ReplaceUndo commands were reimplemented. The + granularity of matches inside of a Replace call were improved so that + you can now decide replacements individually per line. + Additionally, Complex operations such as replacing x[i][j][k] with + x(i,j,k) and following it up with a ReplaceUndo are now possible. + + e.g. + :Replace /x\[\([^]]\+\)\]\[\([^]]\+\)\]\[\([^]]\+\)\]/x(\1,\2,\3)/ + :ReplaceUndo + + Please report any regressions with either of these functions. + + Feature: Added count command line option (-m 4 or -4) + Feature: Improved Grep options window keybindings; searching within the + options explorer window is now possible + Feature: Expanded searches to include all of the active buffers' + directories + Bugfix: Fixed recursive operation and expanded search from reporting + duplicate results + Bugfix: Fixed and in replace mode + Feature: Added EasyGrepWindowPosition for specifying where the error + list window will be opened + Feature: Added FilterErrorlist command for filtering the results within + the quickfix or location list windows + Feature: Improved printout when no matches are found + Feature: Improved searching when an entire line is selected + 0.96 + Feature: Expanded upon the list of file associations + Feature: Expanded searches to the current buffer's directory + in addition to the current working directory + Feature: Added command line arguments to :Grep and :Replace for + recursive searches and case sensitivity + Feature: Added toggle for window replace mode + Feature: Added toggle for showing file associations list in options + explorer + Bugfix: Case insensitivity would fail in replacing some patterns + 0.95 + Feature: Added search and replace on visual selections + Feature: Improved Grepping for items that can be interpreted as regular + expressions. Selections are assumed to be literal, whereas explicit + commands are assumed to be regular expressions. + Feature: Removed option g:EasyGrepNoDirectMappings in favor of + g:EasyGrepOptionPrefix, which allows the option prefix to be changed. + Bugfix: The tracked extension would sometimes fail to be updated when + switching between buffers + Documentation: Split the documentation into its own file; greatly + expanded upon its contents + Change: Activating a mode that is already activated will no longer + deactivate it + Change: GrepOptions no longer accepts an argument; use user mode instead + Change: Clarified mapping names; custom mappings will need to + be reset. + 0.9 + Feature: Added forward slash delineated pattern to the Replace command + e.g. :Replace /target/replacement/ + that allows more complicated replacements; you can now work with + patterns that have spaces in them. + Bugfix: If cursorline is off at the start of a replace, now ensuring + that cursorline is turned off for all buffers, and not just the last one + Bugfix: fixed an issue with an extra tab being opened during a + replacement + 0.8 + Implemented case sensitivity that is independent of ignorecase, thanks + to Doro Wu for contributing to this functionality + Changed shortcut key for hidden files from 'i' to 'h' + 0.7 + Expanded search of EasyGrepFileAssociations list to every component of + 'runtimepath'. This solves a starting message for those who placed + EasyGrepFileAssociations in a location other than the first location in + 'runtimepath'. + 0.6 + Fixed paths with spaces in them + Folds will now be disabled where replacements are to be made + Fixed an error with checking for extra warnings + Better highlighting while replacing + Recursive mode can no longer be activated when Buffers mode is activated + 0.5 + Fixed an issue with tracking the file extension where sometimes the + desired extension wouldn't be registered. + Better reporting when no files match. + Now warning when searching from a working directory that doesn't match + the current file's directory. + Added g:EasyGrepExtraWarnings option. + 0.4 + Improved Replace and ReplaceUndo + Added two configurable modes for how the windows operate when doing a + global replace. + Fixed an issue with linked filetypes. + 0.3 + Added experimental :Replace and :ReplaceUndo commands; keymapped + vr for :Replace + Improved response when no matches + 0.2 + Added option to toggle showing fewer or more options; showing fewer + options by default. + Added option '?' to print the current configuration and save it to a + register. + Now creating direct mappings by default; see g:EasyGrepNoDirectMappings + to turn this off. + 0.1 + Initial version + + +============================================================================== + License *EasyGrep_License* +============================================================================== + + Public domain, no restrictions whatsoever + +When writing EasyGrep, I wanted it to be free in the broadest sense. Of +course, most (if not all) plugins for Vim are free, but I wanted mine to be +freer still: I've released EasyGrep in the public domain. It took a lot of +time and learning to get EasyGrep to work, and I want anyone to take advantage +of my contribution. If you see some (or many) snippets of EasyGrep's code +that you need, use it -- you don't need to ask me, think about any copyright, +worry about violating a license, or even note that the code came from me, just +use it. My only request is that if you are thinking of forking EasyGrep (or +enhancing, as some authors claim to do), please contact me to let me know what +you feel is lacking in EasyGrep, and I promise I'll be receptive to correcting +these issues. + + +============================================================================== +vim:tw=78:ts=4:ft=help:norl:fdm=marker diff --git a/vim/doc/tags b/vim/doc/tags index 51855bd..dc14ee3 100644 --- a/vim/doc/tags +++ b/vim/doc/tags @@ -22,6 +22,43 @@ ChangesPlugin-history ChangesPlugin.txt /*ChangesPlugin-history* ChangesPlugin-hlLine ChangesPlugin.txt /*ChangesPlugin-hlLine* ChangesPlugin-manual ChangesPlugin.txt /*ChangesPlugin-manual* ChangesPlugin.txt ChangesPlugin.txt /*ChangesPlugin.txt* +EasyGrep EasyGrep.txt /*EasyGrep* +EasyGrep.txt EasyGrep.txt /*EasyGrep.txt* +EasyGrepAllOptionsInExplorer EasyGrep.txt /*EasyGrepAllOptionsInExplorer* +EasyGrepCommand EasyGrep.txt /*EasyGrepCommand* +EasyGrepEveryMatch EasyGrep.txt /*EasyGrepEveryMatch* +EasyGrepExtraWarnings EasyGrep.txt /*EasyGrepExtraWarnings* +EasyGrepFileAssociations EasyGrep.txt /*EasyGrepFileAssociations* +EasyGrepFileAssociationsInExplorer EasyGrep.txt /*EasyGrepFileAssociationsInExplorer* +EasyGrepHidden EasyGrep.txt /*EasyGrepHidden* +EasyGrepIgnoreCase EasyGrep.txt /*EasyGrepIgnoreCase* +EasyGrepInvertWholeWord EasyGrep.txt /*EasyGrepInvertWholeWord* +EasyGrepJumpToMatch EasyGrep.txt /*EasyGrepJumpToMatch* +EasyGrepMode EasyGrep.txt /*EasyGrepMode* +EasyGrepOpenWindowOnMatch EasyGrep.txt /*EasyGrepOpenWindowOnMatch* +EasyGrepOptionPrefix EasyGrep.txt /*EasyGrepOptionPrefix* +EasyGrepRecursive EasyGrep.txt /*EasyGrepRecursive* +EasyGrepReplaceAllPerFile EasyGrep.txt /*EasyGrepReplaceAllPerFile* +EasyGrepReplaceWindowMode EasyGrep.txt /*EasyGrepReplaceWindowMode* +EasyGrepSearchCurrentBufferDir EasyGrep.txt /*EasyGrepSearchCurrentBufferDir* +EasyGrepWindow EasyGrep.txt /*EasyGrepWindow* +EasyGrepWindowPosition EasyGrep.txt /*EasyGrepWindowPosition* +EasyGrep_Author EasyGrep.txt /*EasyGrep_Author* +EasyGrep_Bugs EasyGrep.txt /*EasyGrep_Bugs* +EasyGrep_Commands EasyGrep.txt /*EasyGrep_Commands* +EasyGrep_Contents EasyGrep.txt /*EasyGrep_Contents* +EasyGrep_Future EasyGrep.txt /*EasyGrep_Future* +EasyGrep_History EasyGrep.txt /*EasyGrep_History* +EasyGrep_Keymaps EasyGrep.txt /*EasyGrep_Keymaps* +EasyGrep_KeymapsCustomization EasyGrep.txt /*EasyGrep_KeymapsCustomization* +EasyGrep_KeymapsOptions EasyGrep.txt /*EasyGrep_KeymapsOptions* +EasyGrep_License EasyGrep.txt /*EasyGrep_License* +EasyGrep_Motivation EasyGrep.txt /*EasyGrep_Motivation* +EasyGrep_Operation EasyGrep.txt /*EasyGrep_Operation* +EasyGrep_Options EasyGrep.txt /*EasyGrep_Options* +EasyGrep_OptionsDetail EasyGrep.txt /*EasyGrep_OptionsDetail* +EasyGrep_OptionsExplorer EasyGrep.txt /*EasyGrep_OptionsExplorer* +EasyGrep_OptionsSummary EasyGrep.txt /*EasyGrep_OptionsSummary* g:SuperTabCompletionContexts supertab.txt /*g:SuperTabCompletionContexts* g:SuperTabContextDefaultCompletionType supertab.txt /*g:SuperTabContextDefaultCompletionType* g:SuperTabCrMapping supertab.txt /*g:SuperTabCrMapping* diff --git a/vim/plugin/EasyGrep.vim b/vim/plugin/EasyGrep.vim new file mode 100644 index 0000000..3da8e59 --- /dev/null +++ b/vim/plugin/EasyGrep.vim @@ -0,0 +1,2478 @@ +" Title: EasyGrep +" Author: Dan Price vim@danprice.fastmail.net +" +" Goal: To be an easy to use, powerful find and replace resource for +" users of all skill levels. +" Usage: This file should reside in the plugin directory and be +" automatically sourced. +" +" License: Public domain, no restrictions whatsoever +" Documentation: type ":help EasyGrep" +" +" Version: 0.98 -- Programs can inspect g:EasyGrepVersion + +" Initialization {{{ +if exists("g:EasyGrepVersion") || &cp || !has("quickfix") + finish +endif +let g:EasyGrepVersion = ".98" +" Check for Vim version 700 or greater {{{ +if v:version < 700 + echo "Sorry, EasyGrep ".g:EasyGrepVersion."\nONLY runs with Vim 7.0 and greater." + finish +endif +" }}} +" }}} +" Helper Functions {{{ +" countstr {{{ +function! s:countstr(str, ele) + let end = len(a:str) + let c = 0 + let i = 0 + while i < end + if a:str[i] == a:ele + let c += 1 + endif + let i += 1 + endwhile + + return c +endfunction +"}}} +" unique {{{ +function! s:unique(lst) + if empty(a:lst) + return a:lst + endif + + let lst = a:lst + call sort(lst) + + let end = len(lst) + let i = 1 + let lastSeen = lst[0] + while i < end + if lst[i] == lastSeen + call remove(lst, i) + let end -= 1 + else + let i += 1 + endif + endwhile + + return lst +endfunction +"}}} +" BackToForwardSlash {{{ +function! s:BackToForwardSlash(arg) + return substitute(a:arg, '\\', '/', 'g') +endfunction +"}}} +" GetBuffersOutput {{{ +function! s:GetBuffersOutput() + redir => bufoutput + silent! buffers + " This echo clears a bug in printing that shows up when it is not present + silent! echo "" + redir END + + return bufoutput +endfunction +" }}} +" GetBufferIdList {{{ +function! s:GetBufferIdList() + let bufoutput = s:GetBuffersOutput() + + let bufids = [] + for i in split(bufoutput, "\n") + let s1 = 0 + while i[s1] == ' ' + let s1 += 1 + endwhile + + let s2 = stridx(i, ' ', s1) - 1 + let id = str2nr(i[s1 : s2]) + + call add(bufids, id) + endfor + + return bufids +endfunction +" }}} +" GetBufferNamesList {{{ +function! s:GetBufferNamesList() + let bufoutput = s:GetBuffersOutput() + + let bufNames = [] + for i in split(bufoutput, "\n") + let s1 = stridx(i, '"') + 1 + let s2 = stridx(i, '"', s1) - 1 + let str = i[s1 : s2] + + if str[0] == '[' && str[len(str)-1] == ']' + continue + endif + + call add(bufNames, str) + endfor + + return bufNames +endfunction +" }}} +" GetBufferDirsList {{{ +function! s:GetBufferDirsList() + let dirs = {} + let bufs = s:GetBufferNamesList() + for buf in bufs + let d = fnamemodify(expand(buf), ":.:h") + let dirs[d]=1 + endfor + return keys(dirs) +endfunction +" }}} +" GetVisibleBuffers {{{ +function! s:GetVisibleBuffers() + let tablist = [] + for i in range(tabpagenr('$')) + call extend(tablist, tabpagebuflist(i + 1)) + endfor + let tablist = s:unique(tablist) + return tablist +endfunction +" }}} +" EscapeList {{{ +function! s:FileEscape(item) + return escape(a:item, ' \') +endfunction +function! s:ShellEscape(item) + return shellescape(a:item, 1) +endfunction +function! s:DoEscapeList(lst, seperator, func) + let escapedList = [] + for item in a:lst + let e = a:func(item).a:seperator + call add(escapedList, e) + endfor + return escapedList +endfunction +function! s:EscapeList(lst, seperator) + return s:DoEscapeList(a:lst, a:seperator, function("s:FileEscape")) +endfunction +function! s:ShellEscapeList(lst, seperator) + return s:DoEscapeList(a:lst, a:seperator, function("s:ShellEscape")) +endfunction +"}}} +" Escape{{{ +function! s:Escape(str, lst) + let str = a:str + for i in a:lst + let str = escape(str, i) + endfor + return str +endfunction +"}}} +" EscapeSpecial {{{ +function! s:EscapeSpecial(str) + let lst = [ '\', '/', '$' ] + if &magic + let magicLst = [ '*', '.', '~', '[', ']' ] + call extend(lst, magicLst) + endif + return s:Escape(a:str, lst) +endfunction +"}}} +" GetSavedName {{{ +function! s:GetSavedName(var) + let var = a:var + if match(var, "g:") == 0 + let var = substitute(var, "g:", "g_", "") + endif + return "s:saved_".var +endfunction +" }}} +" SaveVariable {{{ +function! s:SaveVariable(var) + if empty(a:var) + return + endif + let savedName = s:GetSavedName(a:var) + if match(a:var, "g:") == 0 + execute "let ".savedName." = ".a:var + else + execute "let ".savedName." = &".a:var + endif +endfunction +" }}} +" RestoreVariable {{{ +" if a second variable is present, indicate no unlet +function! s:RestoreVariable(var, ...) + let doUnlet = a:0 == 1 + let savedName = s:GetSavedName(a:var) + if exists(savedName) + if match(a:var, "g:") == 0 + execute "let ".a:var." = ".savedName + else + execute "let &".a:var." = ".savedName + endif + if doUnlet + unlet savedName + endif + endif +endfunction +" }}} +" OnOrOff {{{ +function! s:OnOrOff(num) + return a:num == 0 ? 'off' : 'on' +endfunction +"}}} +" Trim {{{ +function! s:Trim(s) + let len = strlen(a:s) + + let beg = 0 + while beg < len + if a:s[beg] != " " && a:s[beg] != "\t" + break + endif + let beg += 1 + endwhile + + let end = len - 1 + while end > beg + if a:s[end] != " " && a:s[end] != "\t" + break + endif + let end -= 1 + endwhile + + return strpart(a:s, beg, end-beg+1) +endfunction +"}}} +" ClearNewline {{{ +function! s:ClearNewline(s) + if empty(a:s) + return a:s + endif + + let lastchar = strlen(a:s)-1 + if char2nr(a:s[lastchar]) == 10 + return strpart(a:s, 0, lastchar) + endif + + return a:s +endfunction +"}}} +" Warning/Error {{{ +function! s:Info(message) + echohl Normal | echomsg "[EasyGrep] ".a:message | echohl None +endfunction +function! s:Warning(message) + echohl WarningMsg | echomsg "[EasyGrep] Warning: ".a:message | echohl None +endfunction +function! s:Error(message) + echohl ErrorMsg | echomsg "[EasyGrep] Error: ".a:message | echohl None +endfunction +"}}} +" }}} +" Global Options {{{ +if !exists("g:EasyGrepMode") + let g:EasyGrepMode=0 + " 0 - All + " 1 - Buffers + " 2 - Track +else + if g:EasyGrepMode > 2 + call s:Error("Invalid value for g:EasyGrepMode") + let g:EasyGrepMode = 0 + endif +endif + +if !exists("g:EasyGrepCommand") + let g:EasyGrepCommand=0 +endif + +if !exists("g:EasyGrepRecursive") + let g:EasyGrepRecursive=0 +endif + +if !exists("g:EasyGrepIgnoreCase") + let g:EasyGrepIgnoreCase=&ignorecase +endif + +if !exists("g:EasyGrepHidden") + let g:EasyGrepHidden=0 +endif + +if !exists("g:EasyGrepAllOptionsInExplorer") + let g:EasyGrepAllOptionsInExplorer=0 +endif + +if !exists("g:EasyGrepWindow") + let g:EasyGrepWindow=0 +endif + +if !exists("g:EasyGrepOpenWindowOnMatch") + let g:EasyGrepOpenWindowOnMatch=1 +endif + +if !exists("g:EasyGrepEveryMatch") + let g:EasyGrepEveryMatch=0 +endif + +if !exists("g:EasyGrepJumpToMatch") + let g:EasyGrepJumpToMatch=1 +endif + +if !exists("g:EasyGrepSearchCurrentBufferDir") + let g:EasyGrepSearchCurrentBufferDir=1 +endif + +if !exists("g:EasyGrepInvertWholeWord") + let g:EasyGrepInvertWholeWord=0 +endif + +" GetAssociationFileList {{{ +function! s:GetFileAssociationList() + if exists("g:EasyGrepFileAssociations") + return g:EasyGrepFileAssociations + endif + + let VimfilesDirs=split(&runtimepath, ',') + for v in VimfilesDirs + let f = s:BackToForwardSlash(v)."/plugin/EasyGrepFileAssociations" + if filereadable(f) + let g:EasyGrepFileAssociations=f + return f + endif + endfor + + call s:Error("Grep Pattern file list can't be read") + let g:EasyGrepFileAssociations="" + return "" +endfunction +" }}} + +if !exists("g:EasyGrepFileAssociationsInExplorer") + let g:EasyGrepFileAssociationsInExplorer=0 +endif + +if !exists("g:EasyGrepOptionPrefix") + let g:EasyGrepOptionPrefix='vy' + " Note: The default option prefix vy because I find it easy to type. + " If you want a mnemonic for it, think of (y)our own +endif + +let s:NumReplaceModeOptions = 3 +if !exists("g:EasyGrepReplaceWindowMode") + let g:EasyGrepReplaceWindowMode=0 +else + if g:EasyGrepReplaceWindowMode >= s:NumReplaceModeOptions + call s:Error("Invalid value for g:EasyGrepReplaceWindowMode") + let g:EasyGrepReplaceWindowMode = 0 + endif +endif + +if !exists("g:EasyGrepReplaceAllPerFile") + let g:EasyGrepReplaceAllPerFile=0 +endif + +if !exists("g:EasyGrepExtraWarnings") + let g:EasyGrepExtraWarnings=1 +endif + +if !exists("g:EasyGrepWindowPosition") + let g:EasyGrepWindowPosition="" +else + let w = g:EasyGrepWindowPosition + if w != "" +\ && w != "vertical" +\ && w != "leftabove" +\ && w != "aboveleft" +\ && w != "rightbelow" +\ && w != "belowright" +\ && w != "topleft" +\ && w != "botright" + call s:Error("Invalid position specified in g:EasyGrepWindowPosition") + let g:EasyGrepWindowPosition="" + endif +endif + +"}}} + +" Internals {{{ +" Variables {{{ +let s:OptionsExplorerOpen = 0 + +let s:FilesToGrep="*" +let s:TrackedExt = "*" + +function! s:GetReplaceWindowModeString(mode) + if(a:mode < 0 || a:mode >= s:NumReplaceModeOptions) + return "invalid" + endif + let ReplaceWindowModeStrings = [ "New Tab", "Split Windows", "autowriteall" ] + return ReplaceWindowModeStrings[a:mode] +endfunction +let s:SortOptions = [ "Name", "Name Reversed", "Extension", "Extension Reversed" ] +let s:SortFunctions = [ "SortName", "SortNameReversed", "SortExtension", "SortExtensionReversed" ] +let s:SortChoice = 0 + +let s:Commands = [ "vimgrep", "grep" ] +let s:CommandChoice = g:EasyGrepCommand < len(s:Commands) ? g:EasyGrepCommand : 0 +let s:CurrentFileCurrentDirChecked = 0 + +" SetGatewayVariables {{{ +function! s:SetGatewayVariables() + echo + call s:SaveVariable("lazyredraw") + set lazyredraw +endfunction +" }}} +" ClearGatewayVariables {{{ +function! s:ClearGatewayVariables() + let s:CurrentFileCurrentDirChecked = 0 + call s:RestoreVariable("lazyredraw") +endfunction +" }}} + +" }}} +" Echo {{{ +function! Echo(message) + let str = "" + if !s:OptionsExplorerOpen + let str .= "[EasyGrep] " + endif + let str .= a:message + echo str +endfunction +"}}} +" OptionsExplorer {{{ +" OpenOptionsExplorer {{{ +function! s:OpenOptionsExplorer() + let s:OptionsExplorerOpen = 1 + + call s:CreateOptions() + + let windowLines = len(s:Options) + 1 + if g:EasyGrepFileAssociationsInExplorer + let windowLines += len(s:Dict) + else + let windowLines += s:NumSpecialOptions + endif + + " split the window; fit exactly right + exe "keepjumps botright ".windowLines."new" + + setlocal bufhidden=delete + setlocal buftype=nofile + setlocal nobuflisted + setlocal noswapfile + setlocal cursorline + + syn match Help /^".*/ + highlight def link Help Special + + syn match Activated /^>\w.*/ + highlight def link Activated Type + + syn match Selection /^\ \w.*/ + highlight def link Selection String + + nnoremap l + nnoremap q :call Quit() + + nnoremap a :call ActivateAll() + nnoremap b :call ActivateBuffers() + nnoremap t :call ActivateTracked() + nnoremap u :call ActivateUser() + + nnoremap c :call ToggleCommand() + nnoremap r :call ToggleRecursion() + nnoremap i :call ToggleIgnoreCase() + nnoremap h :call ToggleHidden() + nnoremap w :call ToggleWindow() + nnoremap o :call ToggleOpenWindow() + nnoremap g :call ToggleEveryMatch() + nnoremap p :call ToggleJumpToMatch() + nnoremap ! :call ToggleWholeWord() + nnoremap e :call EchoFilesSearched() + nnoremap s :call Sort() + nnoremap m :call ToggleReplaceWindowMode() + nnoremap \| :call EchoOptionsSet() + nnoremap * :call ToggleFileAssociationsInExplorer() + nnoremap ? :call ToggleOptionsDisplay() + nnoremap :call Select() + nnoremap : :call Echo("Type q to quit") + + call s:BuildPatternList() + call s:FillWindow() +endfunction +" }}} +" Options Explorer Mapped Functions {{{ +" EchoFilesSearched {{{ +function! EchoFilesSearched() + call s:BuildPatternList("\n") + + if s:IsModeBuffers() + let str = s:FilesToGrep + else + let str = "" + let patternList = split(s:FilesToGrep) + for p in patternList + let s = glob(p) + if !empty(s) + let fileList = split(s, "\n") + for f in fileList + if filereadable(f) + let str .= f."\n" + endif + endfor + endif + endfor + endif + + if !empty(str) + call s:Echo("Files that will be searched") + echo str + else + call s:Echo("No files match the current options") + endif + call s:BuildPatternList() +endfunction +"}}} +" EchoOptionsSet {{{ +function! EchoOptionsSet() + + let optList = [ + \ "g:EasyGrepFileAssociations", + \ "g:EasyGrepMode", + \ "g:EasyGrepCommand", + \ "g:EasyGrepRecursive", + \ "g:EasyGrepIgnoreCase", + \ "g:EasyGrepHidden", + \ "g:EasyGrepAllOptionsInExplorer", + \ "g:EasyGrepWindow", + \ "g:EasyGrepReplaceWindowMode", + \ "g:EasyGrepOpenWindowOnMatch", + \ "g:EasyGrepEveryMatch", + \ "g:EasyGrepJumpToMatch", + \ "g:EasyGrepInvertWholeWord", + \ "g:EasyGrepFileAssociationsInExplorer", + \ "g:EasyGrepOptionPrefix", + \ "g:EasyGrepReplaceAllPerFile" + \ ] + + let str = "" + for item in optList + let q = type(eval(item))==1 ? "'" : "" + let str .= "let ".item."=".q.eval(item).q."\n" + endfor + + call s:Warning("The following options will be saved in the e register; type \"ep to paste into your .vimrc") + redir @e + echo str + redir END + +endfunction + +"}}} +" Select {{{ +function! Select() + let pos = getpos(".") + let line = pos[1] + let choice = line - s:firstPatternLine + + call s:ActivateChoice(choice) +endfunction +" }}} +" ActivateAll {{{ +function! ActivateAll() + call s:ActivateChoice(s:allChoicePos) +endfunction +"}}} +" ActivateBuffers {{{ +function! ActivateBuffers() + call s:ActivateChoice(s:buffersChoicePos) +endfunction +"}}} +" ActivateTracked {{{ +function! ActivateTracked() + call s:ActivateChoice(s:trackChoicePos) +endfunction +"}}} +" ActivateUser {{{ +function! ActivateUser() + call s:ActivateChoice(s:userChoicePos) +endfunction +"}}} +" ActivateChoice {{{ +function! s:ActivateChoice(choice) + let choice = a:choice + + if choice < 0 || choice == s:NumSpecialOptions + return + endif + + if choice < 3 + let g:EasyGrepMode = choice + endif + + " handles the space in between the special options and file patterns + let choice -= choice >= s:NumSpecialOptions ? 1 : 0 + + let specialKeys = [ s:allChoicePos, s:buffersChoicePos, s:trackChoicePos, s:userChoicePos] + + let isActivated = (s:Dict[choice][2] == 0) + + let userStr = "" + if choice == s:userChoicePos + let userStr = input("Enter Grep Pattern: ", s:Dict[choice][1]) + if empty(userStr) + let s:Dict[choice][1] = "" + if isActivated + return + endif + else + let choice = s:GrepSetManual(userStr) + if choice == -1 + return + elseif choice == s:userChoicePos + let s:Dict[choice][1] = userStr + else + let isActivated = 1 + let s:Dict[s:userChoicePos][1] = "" + call s:ClearActivated() + call s:UpdateAll() + endif + endif + endif + + let allBecomesActivated = 0 + if isActivated + if choice == s:buffersChoicePos && g:EasyGrepRecursive == 1 + call s:Echo("Recursion turned off by Buffers Selection") + let g:EasyGrepRecursive = 0 + endif + + if count(specialKeys, choice) > 0 + call s:ClearActivated() + call s:UpdateAll() + else + for c in specialKeys + if s:Dict[c][2] == 1 + let s:Dict[c][2] = 0 + call s:UpdateChoice(c) + endif + endfor + endif + + let s:Dict[choice][2] = 1 + + else + if choice == s:allChoicePos || choice == s:buffersChoicePos || choice == s:trackChoicePos || (choice == s:userChoicePos && !empty(userStr)) + let isActivated = 1 + else + let s:Dict[choice][2] = 0 + let isActivated = 0 + if s:HasActivatedItem() == 0 + let allBecomesActivated = 1 + let s:Dict[s:allChoicePos][2] = 1 + call s:UpdateChoice(s:allChoicePos) + endif + endif + endif + + call s:BuildPatternList() + call s:UpdateOptions() + + call s:UpdateChoice(choice) + + let str = "" + if choice == s:allChoicePos + let str = "Activated (All)" + else + let e = isActivated ? "Activated" : "Deactivated" + + let keyName = s:Dict[choice][0] + let str = e." (".keyName.")" + if allBecomesActivated + let str .= " -> Activated (All)" + endif + endif + + call s:Echo(str) +endfunction +"}}} +" Sort {{{ +function! Sort() + let s:SortChoice += 1 + if s:SortChoice == len(s:SortOptions) + let s:SortChoice = 0 + endif + + let beg = s:NumSpecialOptions + let dictCopy = s:Dict[beg :] + call sort(dictCopy, s:SortFunctions[s:SortChoice]) + let s:Dict[beg :] = dictCopy + + call s:UpdateOptions() + call s:UpdateAll() + + call s:Echo("Set sort to (".s:SortOptions[s:SortChoice].")") +endfunction +" }}} +" Sort Functions {{{ +function! SortName(lhs, rhs) + return a:lhs[0] == a:rhs[0] ? 0 : a:lhs[0] > a:rhs[0] ? 1 : -1 +endfunction + +function! SortNameReversed(lhs, rhs) + let r = SortName(a:lhs, a:rhs) + return r == 0 ? 0 : r == -1 ? 1 : -1 +endfunction + +function! SortExtension(lhs, rhs) + return a:lhs[1] == a:rhs[1] ? 0 : a:lhs[1] > a:rhs[1] ? 1 : -1 +endfunction + +function! SortExtensionReversed(lhs, rhs) + let r = SortExtension(a:lhs, a:rhs) + return r == 0 ? 0 : r == -1 ? 1 : -1 +endfunction +" }}} +" ToggleCommand {{{ +function! ToggleCommand() + let s:CommandChoice += 1 + if s:CommandChoice == len(s:Commands) + let s:CommandChoice = 0 + endif + + call s:BuildPatternList() + call s:UpdateOptions() + + call s:Echo("Set command to (".s:Commands[s:CommandChoice].")") +endfunction +" }}} +" ToggleRecursion {{{ +function! ToggleRecursion() + if s:IsModeBuffers() + call s:Warning("Recursive mode cant' be set when *Buffers* is activated") + return + endif + + let g:EasyGrepRecursive = !g:EasyGrepRecursive + + call s:BuildPatternList() + call s:UpdateOptions() + + call s:Echo("Set recursive mode to (".s:OnOrOff(g:EasyGrepRecursive).")") +endfunction +" }}} +" ToggleIgnoreCase {{{ +function! ToggleIgnoreCase() + let g:EasyGrepIgnoreCase = !g:EasyGrepIgnoreCase + call s:UpdateOptions() + call s:Echo("Set ignore case to (".s:OnOrOff(g:EasyGrepIgnoreCase).")") +endfunction +" }}} +" ToggleHidden {{{ +function! ToggleHidden() + let g:EasyGrepHidden = !g:EasyGrepHidden + + call s:BuildPatternList() + call s:UpdateOptions() + + call s:Echo("Set hidden files included to (".s:OnOrOff(g:EasyGrepHidden).")") +endfunction +" }}} +" ToggleWindow {{{ +function! ToggleWindow() + let g:EasyGrepWindow = !g:EasyGrepWindow + call s:UpdateOptions() + + call s:Echo("Set window to (".s:GetErrorListName().")") +endfunction +"}}} +" ToggleOpenWindow {{{ +function! ToggleOpenWindow() + let g:EasyGrepOpenWindowOnMatch = !g:EasyGrepOpenWindowOnMatch + call s:UpdateOptions() + + call s:Echo("Set open window on match to (".s:OnOrOff(g:EasyGrepOpenWindowOnMatch).")") +endfunction +"}}} +" ToggleEveryMatch {{{ +function! ToggleEveryMatch() + let g:EasyGrepEveryMatch = !g:EasyGrepEveryMatch + call s:UpdateOptions() + + call s:Echo("Set seperate multiple matches to (".s:OnOrOff(g:EasyGrepEveryMatch).")") +endfunction +"}}} +" ToggleJumpToMatch {{{ +function! ToggleJumpToMatch() + let g:EasyGrepJumpToMatch = !g:EasyGrepJumpToMatch + call s:UpdateOptions() + + call s:Echo("Set jump to match to (".s:OnOrOff(g:EasyGrepJumpToMatch).")") +endfunction +"}}} +" ToggleWholeWord {{{ +function! ToggleWholeWord() + let g:EasyGrepInvertWholeWord = !g:EasyGrepInvertWholeWord + call s:UpdateOptions() + + call s:Echo("Set invert the meaning of whole word to (".s:OnOrOff(g:EasyGrepInvertWholeWord).")") +endfunction +"}}} +" ToggleReplaceWindowMode {{{ +function! ToggleReplaceWindowMode() + let g:EasyGrepReplaceWindowMode += 1 + if g:EasyGrepReplaceWindowMode == s:NumReplaceModeOptions + let g:EasyGrepReplaceWindowMode = 0 + endif + + call s:UpdateOptions() + + call s:Echo("Set replace window mode to (".s:GetReplaceWindowModeString(g:EasyGrepReplaceWindowMode).")") +endfunction +" }}} +" ToggleOptionsDisplay {{{ +function! ToggleOptionsDisplay() + let g:EasyGrepAllOptionsInExplorer = !g:EasyGrepAllOptionsInExplorer + + if s:OptionsExplorerOpen + let oldWindowLines = len(s:Options) + 1 + call s:FillWindow() + let newWindowLines = len(s:Options) + 1 + + let linesDiff = newWindowLines-oldWindowLines + if linesDiff > 0 + let linesDiff = "+".linesDiff + endif + + execute "resize ".linesDiff + normal zb + endif + + call s:Echo("Showing ". (g:EasyGrepAllOptionsInExplorer ? "more" : "fewer")." options") +endfunction +"}}} +" ToggleFileAssociationsInExplorer {{{ +function! ToggleFileAssociationsInExplorer() + let g:EasyGrepFileAssociationsInExplorer = !g:EasyGrepFileAssociationsInExplorer + + call s:FillWindow() + call s:UpdateOptions() + + if g:EasyGrepFileAssociationsInExplorer + execute "resize +".len(s:Dict) + else + let newSize = len(s:Options) + s:NumSpecialOptions + 1 + execute "resize ".newSize + endif + normal zb + + call s:Echo("Set file associations in explorer to (".s:OnOrOff(g:EasyGrepFileAssociationsInExplorer).")") +endfunction +"}}} +" Quit {{{ +function! Quit() + let s:OptionsExplorerOpen = 0 + echo "" + quit +endfunction +" }}} +"}}} +" UpdateOptions {{{ +function! s:UpdateOptions() + if !s:OptionsExplorerOpen + return + endif + + call s:CreateOptions() + + setlocal modifiable + + let lastLine = len(s:Options) + let line = 0 + while line < lastLine + call setline(line+1, s:Options[line]) + let line += 1 + endwhile + + setlocal nomodifiable +endfunction +" }}} +" UpdateAll {{{ +function! s:UpdateAll() + if g:EasyGrepFileAssociationsInExplorer + let numItems = len(s:Dict) + else + let numItems = s:NumSpecialOptions + endif + call s:UpdateRange(0, numItems) +endfunction +" }}} +" UpdateChoice {{{ +function! s:UpdateChoice(choice) + call s:UpdateRange(a:choice, a:choice+1) +endfunction +" }}} +" UpdateRange {{{ +function! s:UpdateRange(first, last) + if !s:OptionsExplorerOpen + return + endif + + setlocal modifiable + let i = a:first + while i < a:last + let indicator = s:Dict[i][2] == 1 ? '>' : ' ' + let str = indicator. s:Dict[i][0] . ': ' . s:Dict[i][1] + let lineOffset = i >= s:NumSpecialOptions ? 1 : 0 + call setline(s:firstPatternLine+i+lineOffset, str) + let i += 1 + endwhile + + setlocal nomodifiable +endfunction +" }}} +" FillWindow {{{ +function! s:FillWindow() + + setlocal modifiable + + " Clear the entire window + execute "silent %delete" + + call s:CreateOptions() + call append(0, s:Options) + let s:firstPatternLine = len(s:Options) + 1 + call s:UpdateOptions() + + setlocal modifiable + + if g:EasyGrepFileAssociationsInExplorer + let numItems = len(s:Dict) + else + let numItems = s:NumSpecialOptions + endif + + let i = 0 + while i < numItems + call append(s:firstPatternLine, "") + let i += 1 + endwhile + call s:UpdateAll() + setlocal nomodifiable + + " place the cursor at the start of the special options + execute "".len(s:Options)+1 +endfunction +" }}} +" }}} +" IsRecursive {{{ +function! s:IsRecursive(pattern) + return stridx(a:pattern, "\*\*\/") == 0 ? 1 : 0 +endfunction +" }}} +" IsModeAll {{{ +function! s:IsModeAll() + return s:Dict[s:allChoicePos][2] == 1 +endfunction +" }}} +" IsModeBuffers {{{ +function! s:IsModeBuffers() + return s:Dict[s:buffersChoicePos][2] == 1 +endfunction +" }}} +" IsModeTracked {{{ +function! s:IsModeTracked() + return s:Dict[s:trackChoicePos][2] == 1 +endfunction +" }}} +" IsModeUser {{{ +function! s:IsModeUser() + return s:Dict[s:userChoicePos][2] == 1 +endfunction +" }}} +" BreakDown {{{ +function! s:BreakDown(keyList) + + " Indicates which keys have already been parsed to avoid multiple entries + " and infinite recursion + let s:traversed = repeat([0], len(s:Dict)) + + let str = "" + for k in a:keyList + let str .= s:DoBreakDown(k)." " + endfor + unlet s:traversed + let str = s:Trim(str) + + return str +endfunction +"}}} +" DoBreakDown {{{ +function! s:DoBreakDown(key) + if s:traversed[a:key] == 1 + return "" + endif + let s:traversed[a:key] = 1 + + let str = "" + let patternList = split(s:Dict[a:key][1]) + for p in patternList + if s:IsLink(p) + let k = s:FindByKey(s:GetKeyFromLink(p)) + if k != -1 + let str .= s:DoBreakDown(k) + endif + else + let str .= p + endif + let str .= ' ' + endfor + return str +endfunction +"}}} +" GetPatternList {{{ +function! s:GetPatternList(sp, dopost) + let sp = a:sp + let dopost = a:dopost + if s:IsModeBuffers() + let filesToGrep = join(s:EscapeList(s:GetBufferNamesList(), " "), sp) + elseif s:IsModeTracked() + + let str = s:TrackedExt + let i = s:FindByPattern(s:TrackedExt) + if i != -1 + let keyList = [ i ] + let str = s:BreakDown(keyList) + endif + + if dopost + let filesToGrep = s:BuildPatternListPost(str, sp) + else + let filesToGrep = str + endif + else + let i = 0 + let numItems = len(s:Dict) + let keyList = [] + while i < numItems + if s:Dict[i][2] == 1 + call add(keyList, i) + endif + let i += 1 + endwhile + + if !empty(keyList) + let str = s:BreakDown(keyList) + else + echoerr "Inconsistency in EasyGrep script" + let str = "*" + endif + if dopost + let filesToGrep = s:BuildPatternListPost(str, sp) + else + let filesToGrep = str + endif + endif + + let filesToGrep = s:Trim(filesToGrep) + return filesToGrep +endfunction +" }}} +" BuildPatternList {{{ +function! s:BuildPatternList(...) + if a:0 > 0 + let sp = a:1 + else + let sp = " " + endif + let s:FilesToGrep = s:GetPatternList(sp, 1) +endfunction +" }}} +" AddBufferDirToPatternList {{{ +function! s:AddBufferDirToPatternList(str,sp) + let str = a:str + let sp = a:sp + + " Build a list of the directories in buffers + let dirs = s:GetBufferDirsList() + + let patternList = split(str, sp) + + let currDir = getcwd() + for key in sort(dirs) + let newDir = key + let addToList = 1 + if newDir == currDir || newDir == '.' + let addToList = 0 + elseif g:EasyGrepRecursive && match(newDir,currDir)==0 + let addToList = 0 + endif + if addToList + for p in patternList + let str = str.sp.newDir."/".p + endfor + endif + endfor + return str +endfunction +"}}} +" BuildPatternListPost {{{ +function! s:BuildPatternListPost(str, sp) + if empty(a:str) + return a:str + endif + + let str = a:str + let sp = a:sp + if !s:IsModeBuffers() && g:EasyGrepSearchCurrentBufferDir && !g:EasyGrepRecursive + let str = s:AddBufferDirToPatternList(str,sp) + endif + let patternList = split(str) + + if g:EasyGrepHidden + let i = 0 + let size = len(patternList) + while i < size + let item = patternList[i] + if stridx(item, '*') != -1 + let newItem = '.'.item + let i += 1 + let size += 1 + call insert(patternList, newItem, i) + endif + let i += 1 + endwhile + endif + + let str = "" + for item in patternList + if g:EasyGrepRecursive && s:CommandChoice == 0 + let str .= "**/" + endif + let str .= item.sp + endfor + + return str +endfunction +"}}} +" ClearActivated {{{ +function! s:ClearActivated() + let i = 0 + let numItems = len(s:Dict) + while i < numItems + let s:Dict[i][2] = 0 + let i += 1 + endwhile +endfunction +" }}} +" FindByKey {{{ +function! s:FindByKey(key) + let i = 0 + let numItems = len(s:Dict) + while i < numItems + if s:Dict[i][0] ==# a:key + return i + endif + let i += 1 + endwhile + return -1 +endfunction +" }}} +" FindByPattern {{{ +function! s:FindByPattern(pattern) + let pattern = a:pattern + let i = 0 + let numItems = len(s:Dict) + while i < numItems + let patterns = split(s:Dict[i][1]) + for p in patterns + if pattern ==# p + return i + endif + endfor + let i += 1 + endwhile + return -1 +endfunction +" }}} +" HasActivatedItem {{{ +function! s:HasActivatedItem() + let i = 0 + let numItems = len(s:Dict) + while i < numItems + if s:Dict[i][2] == 1 + return 1 + endif + let i += 1 + endwhile + return 0 +endfunction +" }}} +" HasFilesThatMatch{{{ +function! s:HasFilesThatMatch() + let saveFilesToGrep = s:FilesToGrep + + call s:BuildPatternList("\n") + let patternList = split(s:FilesToGrep, "\n") + for p in patternList + let p = s:Trim(p) + let fileList = split(glob(p), "\n") + for f in fileList + if filereadable(f) + let s:FilesToGrep = saveFilesToGrep + return 1 + endif + endfor + endfor + + let s:FilesToGrep = saveFilesToGrep + return 0 +endfunction +"}}} +" HasMatches{{{ +function! s:HasMatches() + return !empty(s:GetErrorList()) +endfunction +"}}} +" WarnNoMatches {{{ +function! s:WarnNoMatches(pattern) + if s:IsModeBuffers() + let fpat = "*Buffers*" + elseif s:IsModeAll() + let fpat = "*" + else + let fpat = s:GetPatternList(" ", 0) + endif + + let r = g:EasyGrepRecursive ? " (Recursive)" : "" + let h = g:EasyGrepHidden ? " (Hidden)" : "" + + call s:Warning("No matches for '".a:pattern."'") + call s:Warning("File Pattern: ".fpat.r.h) + if g:EasyGrepSearchCurrentBufferDir + let dirs = s:GetBufferDirsList() + else + let dirs = [ '.' ] + endif + let s = "Directories:" + for d in dirs + if d == "." + let d = getcwd() + endif + call s:Warning(s." ".d) + let s = " " + endfor +endfunction +" }}} +" GetErrorList {{{ +function! s:GetErrorList() + if g:EasyGrepWindow == 0 + return getqflist() + else + return getloclist(0) + endif +endfunction +"}}} +" GetErrorListName {{{ +function! s:GetErrorListName() + if g:EasyGrepWindow == 0 + return 'quickfix' + else + return 'location list' + endif +endfunction +"}}} +" FilterErrorlist {{{ +function! s:FilterErrorlist(...) + let ltype = 0 + let mode = 'g' + + let filterlist = [] + for s in a:000 + if s[0] == '-' + if s == '-v' + let mode = 'v' + elseif s == '-g' + if mode == 'v' + call s:Error("Multiple -v / -g arguments given") + return + endif + let mode = 'g' + elseif s == '-l' + let ltype = 1 + else + call s:Error("Invalid command line switch") + return + endif + else + call add(filterlist, s) + endif + endfor + + if empty(filterlist) + call s:Error("Missing pattern to filter") + return + endif + + if ltype == 0 + let lst = getqflist() + else + let lst = getloclist(0) + endif + + if empty(lst) + call s:Error("Error list is empty") + return + endif + + let newlst = [] + for d in lst + let matched = 0 + for f in filterlist + let r = match(d.text, f) + if mode == 'g' + let matched = (r != -1) + else + let matched = (r == -1) + endif + if matched == 1 + call add(newlst, d) + break + endif + endfor + endfor + + if ltype == 0 + call setqflist(newlst) + else + call getloclist(0,newlst) + endif +endfunction +"}}} +" CreateOptions {{{ +function! s:CreateOptions() + + let s:Options = [] + + call add(s:Options, "\"q: quit") + call add(s:Options, "\"r: recursive mode (".s:OnOrOff(g:EasyGrepRecursive).")") + call add(s:Options, "\"i: ignore case (".s:OnOrOff(g:EasyGrepIgnoreCase).")") + call add(s:Options, "\"h: hidden files included (".s:OnOrOff(g:EasyGrepHidden).")") + call add(s:Options, "\"e: echo files that would be searched") + if g:EasyGrepAllOptionsInExplorer + call add(s:Options, "\"c: change grep command (".s:Commands[s:CommandChoice].")") + call add(s:Options, "\"w: window to use (".s:GetErrorListName().")") + call add(s:Options, "\"m: replace window mode (".s:GetReplaceWindowModeString(g:EasyGrepReplaceWindowMode).")") + call add(s:Options, "\"o: open window on match (".s:OnOrOff(g:EasyGrepOpenWindowOnMatch).")") + call add(s:Options, "\"g: seperate multiple matches (".s:OnOrOff(g:EasyGrepEveryMatch).")") + call add(s:Options, "\"p: jump to match (".s:OnOrOff(g:EasyGrepJumpToMatch).")") + call add(s:Options, "\"!: invert the meaning of whole word (".s:OnOrOff(g:EasyGrepInvertWholeWord).")") + call add(s:Options, "\"*: show file associations list (".s:OnOrOff(g:EasyGrepFileAssociationsInExplorer).")") + if g:EasyGrepFileAssociationsInExplorer + call add(s:Options, "\"s: change file associations list sorting (".s:SortOptions[s:SortChoice].")") + endif + call add(s:Options, "") + call add(s:Options, "\"a: activate 'All' mode") + call add(s:Options, "\"b: activate 'Buffers' mode") + call add(s:Options, "\"t: activate 'TrackExt' mode") + call add(s:Options, "\"u: activate 'User' mode") + call add(s:Options, "") + call add(s:Options, "\"|: echo options that are set") + endif + call add(s:Options, "\"?: show ". (g:EasyGrepAllOptionsInExplorer ? "fewer" : "more")." options") + call add(s:Options, "") + call add(s:Options, "\"Current Directory: ".getcwd()) + call add(s:Options, "\"Grep Targets: ".s:FilesToGrep) + call add(s:Options, "") + +endfunction +"}}} +" CreateDict {{{ +function! s:CreateDict() + if exists("s:Dict") + return + endif + + let s:Dict = [ ] + call add(s:Dict, [ "All" , "*", g:EasyGrepMode==0 ? 1 : 0 ] ) + call add(s:Dict, [ "Buffers" , "*Buffers*", g:EasyGrepMode==1 ? 1 : 0 ] ) + call add(s:Dict, [ "TrackExt" , "*TrackExt*", g:EasyGrepMode==2 ? 1 : 0 ] ) + call add(s:Dict, [ "User" , "", 0 ] ) + + let s:allChoicePos = 0 + let s:buffersChoicePos = 1 + let s:trackChoicePos = 2 + let s:userChoicePos = 3 + + let s:NumSpecialOptions = len(s:Dict) + + call s:ParseFileAssociationList() + let s:NumFileAssociations = len(s:Dict) - s:NumSpecialOptions + +endfunction +" }}} +" IsInDict {{{ +function! s:IsInDict(pat) + let i = 0 + let numItems = len(s:Dict) + while i < numItems + if s:Dict[i][0] == a:pat + return 1 + endif + let i += 1 + endwhile + return 0 +endfunction +" }}} +" ParseFileAssociationList {{{ +function! s:ParseFileAssociationList() + let lst = s:GetFileAssociationList() + + if empty(lst) + return + endif + + if !filereadable(lst) + call s:Error("Grep Pattern file list can't be read") + return + endif + + let fileList = readfile(lst) + if empty(fileList) + call s:Error("Grep Pattern file list is empty") + return + endif + + let lineCounter = 0 + for line in fileList + let lineCounter += 1 + let line = s:Trim(line) + if empty(line) || line[0] == "\"" + continue + endif + + let keys = split(line, "=") + if len(keys) != 2 + call s:Warning("Invalid line: ".line) + continue + endif + + let keys[0] = s:Trim(keys[0]) + let keys[1] = s:Trim(keys[1]) + + if len(keys[0]) == 0 || len(keys[1]) == 0 + call s:Warning("Invalid line: ".line) + continue + endif + + " TODO: check that keys[0] is well-formed + + if s:IsInDict(keys[0]) + call s:Warning("Key already added: ".keys[0]) + continue + endif + + let pList = split(keys[1]) + for p in pList + + " check for invalid filesystem characters. + if match(p, "[/\\,;']") != -1 + call s:Warning("Invalid pattern (".p.") in line(".lineCounter.")") + continue + endif + + if match(p, '[<>]') != -1 + if s:countstr(p, '<') > 1 + \ || s:countstr(p, '>') > 1 + \ || p[0] != '<' + \ || p[len(p)-1] != '>' + call s:Warning("Invalid link (".p.") in line(".lineCounter.")") + continue + endif + endif + endfor + + call add(s:Dict, [ keys[0], keys[1], 0 ] ) + endfor + call s:CheckLinks() +endfunction +"}}} +" IsLink {{{ +function! s:IsLink(str) + return a:str[0] == '<' && a:str[len(a:str)-1] == '>' +endfunction +"}}} +" GetKeyFromLink {{{ +function! s:GetKeyFromLink(str) + return strpart(a:str, 1, len(a:str)-2) +endfunction +"}}} +" CheckLinks {{{ +function! s:CheckLinks() + let i = s:NumSpecialOptions + let end = len(s:Dict) + while i < end + let patterns = split(s:Dict[i][1]) + let j = 0 + for p in patterns + if s:IsLink(p) && s:FindByKey(s:GetKeyFromLink(p)) == -1 + call s:Warning("Key(".p.") links to a nonexistent key") + call remove(patterns, j) + let j -= 1 + endif + let j += 1 + endfor + + if len(patterns) == 0 + call s:Warning("Key(".s:Dict[i][0].") has no valid patterns or links") + call remove(s:Dict, i) + else + let s:Dict[i][1] = join(patterns) + endif + let i += 1 + endwhile +endfunction +"}}} +" SetCurrentExtension {{{ +function! s:SetCurrentExtension() + if !empty(&buftype) + return + endif + let fname = bufname("%") + if empty(fname) + return + endif + let ext = fnamemodify(fname, ":e") + if !empty(ext) + let ext = "*.".ext + else + let ext = fnamemodify(fname, ":p:t") + if(empty(ext)) + return + endif + endif + if !s:IsModeTracked() + " Always save the extension when not in tracked mode + let s:TrackedExt = ext + + " Note: this has a very, very, very, small issue (is it even an + " issue?) where if you're working with C++ files, and you switch to + " buffers mode, and then edit a file of another type, like .c (which + " should be in the C++ list), and then switch back to tracked mode, + " you will lose the C++ association and have to go back to a C++ + " file before being able to search them. + " This is so small of an issue that it's almost a non-issue, so I'm + " not going to bother fixing it + else + let tempList = split(s:FilesToGrep) + + " When in tracked mode, change the tracked extension if it isn't + " already in the list of files to be grepped + if index(tempList, ext) == -1 + let s:TrackedExt = ext + call s:BuildPatternList() + endif + endif +endfunction +"}}} +" SetWatchExtension {{{ +function! s:SetWatchExtension() + call s:CreateDict() + augroup EasyGrepAutocommands + au! + autocmd BufEnter * call s:SetCurrentExtension() + augroup END +endfunction +call s:SetWatchExtension() +"}}} +" CompareCurrentFileCurrentDirectory {{{ +function! s:CompareCurrentFileCurrentDirectory() + if !g:EasyGrepExtraWarnings || s:CurrentFileCurrentDirChecked + return 1 + endif + let s:CurrentFileCurrentDirChecked = 1 + if !empty(&buftype) " don't check for quickfix and others + return + endif + if !s:IsModeBuffers() + let currFile = bufname("%") + if empty(currFile) + call s:Warning("cannot search the current file because it is unnamed") + return 0 + endif + let fileDir = fnamemodify(currFile, ":p:h") + if !empty(fileDir) && !g:EasyGrepSearchCurrentBufferDir + let cwd = getcwd() + if fileDir != cwd + call s:Warning("current file not searched, its directory [".fileDir."] doesn't match the working directory [".cwd."]") + return 0 + endif + endif + endif + return 1 +endfunction +" }}} +" CreateOptionMappings {{{ +function! s:CreateOptionMappings() + if empty(g:EasyGrepOptionPrefix) + return + endif + + let p = g:EasyGrepOptionPrefix + + exe "nmap ".p."a :call ActivateAll()" + exe "nmap ".p."b :call ActivateBuffers()" + exe "nmap ".p."t :call ActivateTracked()" + exe "nmap ".p."u :call ActivateUser()" + + exe "nmap ".p."c :call ToggleCommand()" + exe "nmap ".p."r :call ToggleRecursion()" + exe "nmap ".p."i :call ToggleIgnoreCase()" + exe "nmap ".p."h :call ToggleHidden()" + exe "nmap ".p."w :call ToggleWindow()" + exe "nmap ".p."o :call ToggleOpenWindow()" + exe "nmap ".p."g :call ToggleEveryMatch()" + exe "nmap ".p."p :call ToggleJumpToMatch()" + exe "nmap ".p."! :call ToggleWholeWord()" + exe "nmap ".p."e :call EchoFilesSearched()" + exe "nmap ".p."s :call Sort()" + exe "nmap ".p."m :call ToggleReplaceWindowMode()" + exe "nmap ".p."? :call ToggleOptionsDisplay()" + exe "nmap ".p."\\| :call EchoOptionsSet()" + exe "nmap ".p."* :call ToggleFileAssociationsInExplorer()" +endfunction +"}}} +" GetCurrentWord {{{ +function! s:GetCurrentWord() + return expand("") +endfunction +" }}} +" GetCurrentSelection {{{ +function! s:GetCurrentSelection() + return s:ClearNewline(@") +endfunction +" }}} +" GrepOptions {{{ +function! GrepOptions() + call s:SetGatewayVariables() + call s:CreateDict() + call s:OpenOptionsExplorer() + return s:ClearGatewayVariables() +endfunction +" }}} +" GrepCurrentWord {{{ +function! GrepCurrentWord(add, whole) + call s:SetGatewayVariables() + let currWord=s:GetCurrentWord() + if empty(currWord) + call s:Warning("No current word") + return s:ClearGatewayVariables() + endif + + let sameDirectory = s:CompareCurrentFileCurrentDirectory() + let r = s:DoGrep(currWord, a:add, a:whole, "", 1) + return s:ClearGatewayVariables() +endfunction +" }}} +" GrepSelection {{{ +function! GrepSelection(add, whole) + call s:SetGatewayVariables() + let currSelection=s:GetCurrentSelection() + if empty(currSelection) + call s:Warning("No current selection") + return s:ClearGatewayVariables() + endif + call s:DoGrep(currSelection, a:add, a:whole, "", 1) + return s:ClearGatewayVariables() +endfunction +" }}} +" ParseCommandLine {{{ +function! s:ParseCommandLine(argv) + let opts = {} + let opts["recursive"] = 0 + let opts["case-insensitive"] = g:EasyGrepIgnoreCase + let opts["case-sensitive"] = 0 + let opts["count"] = 0 + let opts["pattern"] = "" + let opts["failedparse"] = "" + + if empty(a:argv) + return opts + endif + + let nextiscount = 0 + let tokens = split(a:argv, ' \zs') + let numtokens = len(tokens) + let j = 0 + while j < numtokens + let tok = tokens[j] + if tok[0] == '-' + let tok = s:Trim(tok) + if tok =~ '-[0-9]\+' + let opts["count"] = tok[1:] + else + let i = 1 + let end = len(tok) + while i < end + let c = tok[i] + if c == '-' + " ignore + elseif c ==# 'R' || c==# 'r' + let opts["recursive"] = 1 + elseif c ==# 'i' + let opts["case-insensitive"] = 1 + elseif c ==# 'I' + let opts["case-sensitive"] = 1 + elseif c ==# 'm' + let j += 1 + if j < numtokens + let tok = tokens[j] + let opts["count"] = tok + else + let opts["failedparse"] = "Missing argument to -m" + endif + else + let opts["failedparse"] = "Invalid option (".c.")" + endif + let i += 1 + endwhile + endif + else + let opts["pattern"] .= tok + endif + let j += 1 + endwhile + + if !empty(opts["failedparse"]) + return opts + endif + + if empty(opts["pattern"]) + let opts["failedparse"] = "missing pattern" + endif + + return opts +endfunction +" }}} +" SetCommandLineOptions {{{ +function! s:SetCommandLineOptions(opts) + let opts = a:opts + call s:SaveVariable("g:EasyGrepRecursive") + let g:EasyGrepRecursive = g:EasyGrepRecursive || opts["recursive"] + + call s:SaveVariable("g:EasyGrepIgnoreCase") + let g:EasyGrepIgnoreCase = (g:EasyGrepIgnoreCase || opts["case-insensitive"]) && !opts["case-sensitive"] +endfunction +" }}} +" RestoreCommandLineOptions {{{ +function! s:RestoreCommandLineOptions(opts) + let opts = a:opts + call s:RestoreVariable("g:EasyGrepRecursive") + call s:RestoreVariable("g:EasyGrepIgnoreCase") +endfunction +" }}} +" GrepCommandLine {{{ +function! s:GrepCommandLine(argv, add, bang) + call s:SetGatewayVariables() + let opts = s:ParseCommandLine(a:argv) + if !empty(opts["failedparse"]) + let errorstring="Invalid command: ".opts["failedparse"] + echo errorstring + else + call s:SetCommandLineOptions(opts) + call s:DoGrep(opts["pattern"], a:add, a:bang == "!" ? 1 : 0, opts["count"]>0 ? opts["count"] : "", 0) + call s:RestoreCommandLineOptions(opts) + endif + return s:ClearGatewayVariables() +endfunction +" }}} +" GrepSetManual {{{ +function! s:GrepSetManual(str) + call s:SetGatewayVariables() + let str = a:str + if s:IsRecursive(str) + call s:Error("User specified grep pattern may not have a recursive specifier") + return -1 + endif + let pos = s:userChoicePos + + let i = s:FindByPattern(str) + if i != -1 + let s2 = s:Dict[i][1] + if str == s2 + let pos = i + else + let msg = "Pattern '".s:Dict[i][0]."=".s:Dict[i][1]."' matches your input, use this?" + let response = confirm(msg, "&Yes\n&No") + if response == 1 + let pos = i + endif + endif + endif + + return pos +endfunction +"}}} +" ReplaceCurrentWord {{{ +function! ReplaceCurrentWord(whole) + call s:SetGatewayVariables() + let currWord=s:GetCurrentWord() + if empty(currWord) + call s:Warning("No current word") + return s:ClearGatewayVariables() + endif + + call s:ReplaceString(currWord, a:whole, 1) + return s:ClearGatewayVariables() +endfunction +"}}} +" ReplaceSelection {{{ +function! ReplaceSelection(whole) + call s:SetGatewayVariables() + let currSelection=s:GetCurrentSelection() + if empty(currSelection) + call s:Warning("No current selection") + return s:ClearGatewayVariables() + endif + + call s:ReplaceString(currSelection, a:whole, 1) + return s:ClearGatewayVariables() +endfunction +"}}} +" ReplaceString {{{ +function! s:ReplaceString(str, whole, escapeArgs) + call s:CompareCurrentFileCurrentDirectory() + let r = input("Replace '".a:str."' with: ") + if empty(r) + return + endif + + call s:DoReplace(a:str, r, a:whole, a:escapeArgs) +endfunction +"}}} +" Replace {{{ +function! s:Replace(whole, argv) + call s:SetGatewayVariables() + + let l = len(a:argv) + let invalid = 0 + + if l == 0 + let invalid = 1 + elseif l > 3 && a:argv[0] == '/' + let ph = tempname() + let ph = substitute(ph, '/', '_', 'g') + let temp = substitute(a:argv, '\\/', ph, "g") + let l = len(temp) + if temp[l-1] != '/' + call s:Error("Missing trailing /") + let invalid = 1 + elseif stridx(temp, '/', 1) == l-1 + call s:Error("Missing middle /") + let invalid = 1 + elseif s:countstr(temp, '/') > 3 + call s:Error("Too many /'s, escape these if necessary") + let invalid = 1 + else + let argv = split(temp, '/') + let i = 0 + while i < len(argv) + let argv[i] = substitute(argv[i], ph, '\\/', 'g') + let i += 1 + endwhile + endif + else + let argv = split(a:argv) + if len(argv) != 2 + call s:Error("Too many arguments") + let invalid = 1 + endif + endif + + if invalid + call s:Echo("usage: Replace /target/replacement/ --or-- Replace target replacement") + return + endif + + let target = argv[0] + let replacement = argv[1] + + call s:DoReplace(target, replacement, a:whole, 0) + return s:ClearGatewayVariables() +endfunction +"}}} +" ReplaceUndo {{{ +function! s:ReplaceUndo(bang) + call s:SetGatewayVariables() + if !exists("s:actionList") + call s:Error("No saved actions to undo") + return s:ClearGatewayVariables() + endif + + " If either of these variables exists, that means the last command was + " interrupted; give it another shot + if !exists(s:GetSavedName("switchbuf")) && !exists(s:GetSavedName("autowriteall")) + + call s:SaveVariable("switchbuf") + set switchbuf=useopen + if g:EasyGrepReplaceWindowMode == 2 + call s:SaveVariable("autowriteall") + set autowriteall + else + if g:EasyGrepReplaceWindowMode == 0 + set switchbuf+=usetab + else + set switchbuf+=split + endif + endif + endif + + if g:EasyGrepWindow == 0 + call setqflist(s:LastErrorList) + cfirst + else + call setloclist(0,s:LastErrorList) + lfirst + endif + + let bufList = s:GetVisibleBuffers() + + let i = 0 + let numItems = len(s:actionList) + let lastFile = -1 + + let finished = 0 + while !finished + try + while i < numItems + + let cc = s:actionList[i][0] + let off = s:actionList[i][1] + let target = s:actionList[i][2] + let replacement = s:actionList[i][3] + + if g:EasyGrepReplaceWindowMode == 0 + let thisFile = s:LastErrorList[cc].bufnr + if thisFile != lastFile + " only open a new tab when this window isn't already + " open + if index(bufList, thisFile) == -1 + if lastFile != -1 + tabnew + endif + if g:EasyGrepWindow == 0 + execute g:EasyGrepWindowPosition." copen" + else + execute g:EasyGrepWindowPosition." lopen" + endif + setlocal nofoldenable + endif + endif + let lastFile = thisFile + endif + + if g:EasyGrepWindow == 0 + execute "cc ".(cc+1) + else + execute "ll ".(cc+1) + endif + + " TODO: increase the granularity of the undo to be per-atom + " TODO: restore numbered sub-expressions + " TODO: check that replacement is at off + + let thisLine = getline(".") + let linebeg = strpart(thisLine, 0, off) + let lineend = strpart(thisLine, off) + let lineend = substitute(lineend, replacement, target, "") + let newLine = linebeg.lineend + + call setline(".", newLine) + + let i += 1 + endwhile + let finished = 1 + catch /^Vim(\a\+):E36:/ + call s:Warning("Ran out of room for more windows") + let finished = confirm("Do you want to save all windows and continue?", "&Yes\n&No")-1 + if finished == 1 + call s:Warning("To continue, save unsaved windows, make some room (try :only) and run ReplaceUndo again") + return + else + wall + only + endif + catch /^Vim:Interrupt$/ + call s:Warning("Undo interrupted by user; state is not guaranteed") + let finished = confirm("Are you sure you want to stop the undo?", "&Yes\n&No")-1 + let finished = !finished + catch + echo v:exception + call s:Warning("Undo interrupted; state is not guaranteed") + let finished = confirm("Do you want to continue undoing?", "&Yes\n&No")-1 + endtry + endwhile + + call s:RestoreVariable("switchbuf") + call s:RestoreVariable("autowriteall") + + unlet s:actionList + unlet s:LastErrorList + return s:ClearGatewayVariables() +endfunction +"}}} +" DoGrep {{{ +function! s:DoGrep(word, add, whole, count, escapeArgs) + call s:CreateDict() + + if s:OptionsExplorerOpen == 1 + call s:Error("Error: Can't Grep while options window is open") + return 0 + endif + + call s:CompareCurrentFileCurrentDirectory() + + let com = s:Commands[s:CommandChoice] + + let commandIsVimgrep = (com == "vimgrep") + let commandIsGrep = !commandIsVimgrep && (stridx(&grepprg, "grep ") == 0) + let commandIsFindstr = !commandIsVimgrep && (stridx(&grepprg, "findstr ") == 0) + + let s1 = "" + let s2 = "" + if commandIsVimgrep + let s1 = "/" + let s2 = "/" + + if g:EasyGrepEveryMatch + let s2 .= "g" + endif + + if g:EasyGrepJumpToMatch + let s2 .= "j" + endif + endif + + let opts = "" + + if g:EasyGrepInvertWholeWord + let whole = !a:whole + else + let whole = a:whole + endif + + let word = a:escapeArgs ? s:EscapeSpecial(a:word) : a:word + if whole + if commandIsVimgrep + let word = "\\<".word."\\>" + elseif commandIsGrep + let word = "-w ".word + elseif commandIsFindstr + let word = "\"\\<".word."\\>\"" + endif + endif + + if g:EasyGrepRecursive + if commandIsGrep + let opts .= "-R " + elseif commandIsFindstr + let opts .= "/S " + endif + endif + + if g:EasyGrepIgnoreCase + if commandIsGrep + let opts .= "-i " + elseif commandIsFindstr + let opts .= "/I " + endif + else + if commandIsFindstr + let opts .= "/i " + endif + endif + + call s:BuildPatternList() + + let filesToGrep = s:FilesToGrep + if commandIsVimgrep + call s:SaveVariable("ignorecase") + let &ignorecase = g:EasyGrepIgnoreCase + endif + if commandIsGrep + " We would like to use --include pattern for a grep command + let opts .= " " . join(map(split(filesToGrep, ' '), '"--include=" .v:val'), ' ') + endif + + if s:IsModeBuffers() && empty(filesToGrep) + call s:Warning("No saved buffers to explore") + return + endif + + if g:EasyGrepExtraWarnings && !g:EasyGrepRecursive + " Don't evaluate if in recursive mode, this will take too long + if !s:HasFilesThatMatch() + call s:Warning("No files match against ".filesToGrep) + return + endif + endif + + let win = g:EasyGrepWindow != 0 ? "l" : "" + + let failed = 0 + try + let grepCommand = a:count.win.com.a:add." ".opts." ".s1.word.s2." ".filesToGrep + silent execute grepCommand + catch + if v:exception != 'E480' + call s:WarnNoMatches(a:word) + try + " go to the last error list on no matches + if g:EasyGrepWindow == 0 + silent colder + else + silent lolder + endif + catch + endtry + else + call s:Error("FIXME: exception not caught ".v:exception) + endif + let failed = 1 + endtry + + call s:RestoreVariable("ignorecase") + if failed + return 0 + endif + + if s:HasMatches() + if g:EasyGrepOpenWindowOnMatch + if g:EasyGrepWindow == 0 + execute g:EasyGrepWindowPosition." copen" + else + execute g:EasyGrepWindowPosition." lopen" + endif + setlocal nofoldenable + endif + else + call s:WarnNoMatches(a:word) + return 0 + endif + + return 1 +endfunction +" }}} +" DoReplace {{{ +function! s:DoReplace(target, replacement, whole, escapeArgs) + + if !s:DoGrep(a:target, "", a:whole, "", a:escapeArgs) + return + endif + + let target = a:escapeArgs ? s:EscapeSpecial(a:target) : a:target + let replacement = a:escapeArgs ? s:EscapeSpecial(a:replacement) : a:replacement + + let s:LastTarget = target + let s:LastReplacement = replacement + + let s:LastErrorList = deepcopy(s:GetErrorList()) + let numMatches = len(s:LastErrorList) + + let s:actionList = [] + + call s:SaveVariable("switchbuf") + set switchbuf=useopen + if g:EasyGrepReplaceWindowMode == 2 + call s:SaveVariable("autowriteall") + set autowriteall + else + if g:EasyGrepReplaceWindowMode == 0 + set switchbuf+=usetab + else + set switchbuf+=split + endif + endif + + let opts = "" + if !g:EasyGrepEveryMatch + let opts .= "g" + endif + + let bufList = s:GetVisibleBuffers() + + if g:EasyGrepWindow == 0 + cfirst + else + lfirst + endif + + call s:SaveVariable("ignorecase") + let &ignorecase = g:EasyGrepIgnoreCase + + call s:SaveVariable("cursorline") + set cursorline + call s:SaveVariable("hlsearch") + set hlsearch + + if g:EasyGrepIgnoreCase + let case = '\c' + else + let case = '\C' + endif + + if g:EasyGrepInvertWholeWord + let whole = !a:whole + else + let whole = a:whole + endif + + if whole + let target = "\\<".target."\\>" + endif + + let finished = 0 + let lastFile = -1 + let doAll = 0 + let i = 0 + while i < numMatches && !finished + try + let pendingQuit = 0 + let doit = 1 + + let thisFile = s:LastErrorList[i].bufnr + if thisFile != lastFile + call s:RestoreVariable("cursorline", "no") + call s:RestoreVariable("hlsearch", "no") + if g:EasyGrepReplaceWindowMode == 0 + " only open a new tab when the window doesn't already exist + if index(bufList, thisFile) == -1 + if lastFile != -1 + tabnew + endif + if g:EasyGrepWindow == 0 + execute g:EasyGrepWindowPosition." copen" + else + execute g:EasyGrepWindowPosition." lopen" + endif + setlocal nofoldenable + endif + endif + if doAll && g:EasyGrepReplaceAllPerFile + let doAll = 0 + endif + endif + + if g:EasyGrepWindow == 0 + execute "cc ".(i+1) + else + execute "ll ".(i+1) + endif + + if thisFile != lastFile + set cursorline + set hlsearch + endif + let lastFile = thisFile + + if foldclosed(".") != -1 + foldopen! + endif + + let thisLine = getline(".") + let off = match(thisLine,case.target, 0) + while off != -1 + + " this highlights the match; it seems to be a simpler solution + " than matchadd() + let linebeg = strpart(thisLine, 0, off) + let m = matchstr(thisLine,case.target, off) + let lineafterm = strpart(thisLine, off+strlen(m)) + + let linebeg = s:EscapeSpecial(linebeg) + let m = s:EscapeSpecial(m) + let lineafterm = s:EscapeSpecial(lineafterm) + + silent exe "s/".linebeg."\\zs".case.m."\\ze".lineafterm."//ne" + + if !doAll + + redraw! + echohl Type | echo "replace with ".a:replacement." (y/n/a/q/l/^E/^Y)?"| echohl None + let ret = getchar() + + if ret == 5 + if winline() > &scrolloff+1 + normal  + endif + continue + elseif ret == 25 + if (winheight(0)-winline()) > &scrolloff + normal  + endif + continue + elseif ret == 27 + let doit = 0 + let pendingQuit = 1 + else + let ret = nr2char(ret) + + if ret == '' + continue + elseif ret == 'y' + let doit = 1 + elseif ret == 'n' + let doit = 0 + elseif ret == 'a' + let doit = 1 + let doAll = 1 + elseif ret == 'q' + let doit = 0 + let pendingQuit = 1 + elseif ret == 'l' + let doit = 1 + let pendingQuit = 1 + else + continue + endif + endif + endif + + if doit + let linebeg = strpart(thisLine, 0, off) + let lineend = strpart(thisLine, off) + let newend = substitute(lineend, target, replacement, "") + let newLine = linebeg.newend + call setline(".", newLine) + + let replacedText = matchstr(lineend, target) + let remainder = substitute(lineend, target, "", "") + let replacedWith = strpart(newend, 0, strridx(newend, remainder)) + + let action = [i, off, replacedText, replacedWith] + call add(s:actionList, action) + endif + + if pendingQuit + break + endif + + let thisLine = getline(".") + let m = matchstr(thisLine,target, off) + let off = match(thisLine,target,off+strlen(m)) + endwhile + + if pendingQuit + break + endif + + let i += 1 + + catch /^Vim(\a\+):E36:/ + call s:Warning("Ran out of room for more windows") + let finished = confirm("Do you want to save all windows and continue?", "&Yes\n&No")-1 + if finished == 1 + call s:Warning("To continue, save unsaved windows, make some room (try :only) and run Replace again") + else + wall + only + endif + catch /^Vim:Interrupt$/ + call s:Warning("Replace interrupted by user") + let finished = confirm("Are you sure you want to stop the replace?", "&Yes\n&No")-1 + let finished = !finished + catch + echo v:exception + call s:Warning("Replace interrupted") + let finished = confirm("Do you want to continue replace?", "&Yes\n&No")-1 + endtry + endwhile + + call s:RestoreVariable("switchbuf") + call s:RestoreVariable("autowriteall") + call s:RestoreVariable("cursorline") + call s:RestoreVariable("hlsearch") + call s:RestoreVariable("ignorecase") +endfunction +"}}} +" }}} + +" Commands {{{ +command! -bang -nargs=+ Grep :call s:GrepCommandLine( , "", "") +command! -bang -nargs=+ GrepAdd :call s:GrepCommandLine( , "add", "") +command! GrepOptions :call GrepOptions() + +command! -bang -nargs=+ Replace :call s:Replace("", ) +command! -bang ReplaceUndo :call s:ReplaceUndo("") + +command! -nargs=+ FilterErrorlist :call s:FilterErrorlist() +"}}} +" Keymaps {{{ +if !hasmapto("EgMapGrepOptions") + map vo EgMapGrepOptions +endif +if !hasmapto("EgMapGrepCurrentWord_v") + map vv EgMapGrepCurrentWord_v +endif +if !hasmapto("EgMapGrepSelection_v") + vmap vv EgMapGrepSelection_v +endif +if !hasmapto("EgMapGrepCurrentWord_V") + map vV EgMapGrepCurrentWord_V +endif +if !hasmapto("EgMapGrepSelection_V") + vmap vV EgMapGrepSelection_V +endif +if !hasmapto("EgMapGrepCurrentWord_a") + map va EgMapGrepCurrentWord_a +endif +if !hasmapto("EgMapGrepSelection_a") + vmap va EgMapGrepSelection_a +endif +if !hasmapto("EgMapGrepCurrentWord_A") + map vA EgMapGrepCurrentWord_A +endif +if !hasmapto("EgMapGrepSelection_A") + vmap vA EgMapGrepSelection_A +endif +if !hasmapto("EgMapReplaceCurrentWord_r") + map vr EgMapReplaceCurrentWord_r +endif +if !hasmapto("EgMapReplaceSelection_r") + vmap vr EgMapReplaceSelection_r +endif +if !hasmapto("EgMapReplaceCurrentWord_R") + map vR EgMapReplaceCurrentWord_R +endif +if !hasmapto("EgMapReplaceSelection_R") + vmap vR EgMapReplaceSelection_R +endif + +if !exists("g:EasyGrepMappingsSet") + nmap