Speed up and fix hangs when doing a large search and replace in vim

This commit is contained in:
Michael Campagnaro 2021-12-03 14:52:32 -05:00
parent 7c5dc3cd7c
commit 476a163236

64
vimrc
View File

@ -131,7 +131,7 @@ let g:campo_extensions_that_run_ctags = ['c','cpp','h','hpp','inc','cs','js','py
" Default files and directories that ctags should ignore when doing a " Default files and directories that ctags should ignore when doing a
" recursive crawl. " recursive crawl.
" @note The RunCtags function will always ignore .git and node_modules " @note The CreateCtags function will always ignore .git and node_modules
" regardless of this variable's value. " regardless of this variable's value.
let g:campo_ctags_exclude = ['*.txt', '*.config', '.cache'] let g:campo_ctags_exclude = ['*.txt', '*.config', '.cache']
@ -281,6 +281,9 @@ set numberwidth=5
set showtabline=2 set showtabline=2
set winwidth=79 set winwidth=79
" Use abbreviations.
set shortmess=a
" Remove gvim Menubar and Toolbar " Remove gvim Menubar and Toolbar
"set guioptions -=m "set guioptions -=m
"set guioptions -=T "set guioptions -=T
@ -530,7 +533,7 @@ augroup campoCmds
autocmd BufWritePost *.vim source $MYVIMRC autocmd BufWritePost *.vim source $MYVIMRC
autocmd BufWritePost ~/.vimrc.private source $MYVIMRC autocmd BufWritePost ~/.vimrc.private source $MYVIMRC
function! s:RunCtags() function! s:CreateCtags()
" Only allow one instance of ctags to run in this directory at any given time. " Only allow one instance of ctags to run in this directory at any given time.
let l:lock_file = "ctags.lock" let l:lock_file = "ctags.lock"
if filereadable(l:lock_file) || filereadable("newtags") if filereadable(l:lock_file) || filereadable("newtags")
@ -581,7 +584,7 @@ augroup campoCmds
endfun endfun
" Generate ctags on save. " Generate ctags on save.
autocmd BufWritePost * call s:RunCtags() autocmd BufWritePost * call s:CreateCtags()
" Remove trailing whitespace when saving any file. " Remove trailing whitespace when saving any file.
function! s:StripTrailingWhitespaces() function! s:StripTrailingWhitespaces()
@ -979,7 +982,7 @@ function! CenterPane()
" Taken from https://dev.to/vinneycavallo/easily-center-content-in-vim " Taken from https://dev.to/vinneycavallo/easily-center-content-in-vim
lefta vnew lefta vnew
wincmd w wincmd w
exec 'vertical resize '. string(&columns * 0.75) exec 'vertical resize' string(&columns * 0.75)
endfunction endfunction
nnoremap <leader>c :call CenterPane()<cr> nnoremap <leader>c :call CenterPane()<cr>
@ -1029,7 +1032,7 @@ function! ChangeBgTheme(bg, onlySetTheme)
endif endif
if !a:onlySetTheme if !a:onlySetTheme
exec ':AirlineTheme ' . a:bg exec 'AirlineTheme' a:bg
endif endif
endfunction endfunction
@ -1218,27 +1221,18 @@ nnoremap <expr> p (&buftype is# "quickfix" ? "<CR>\|:copen<CR>" : "p")
" SEARCH & REPLACE " SEARCH & REPLACE
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" argdo wrapper that will disable all events for read/save. This significantly " Replace text in a git repo's committed files.
" speeds up GlobalReplaceIt(). " The range identifier allows us to run this once when multiple lines are selected in a file.
command! -nargs=? Argdo call Argdo(<q-args>) function! GlobalReplaceIt(confirm_replacement) range
function! Argdo(command)
set eventignore=all
exec 'noautocmd argdo '. a:command . ' | update'
set eventignore=
endfunction
" Replace the selected text in all files within the repo.
function! GlobalReplaceIt(confirm_replacement)
if exists(':Ggrep') if exists(':Ggrep')
call inputsave() call inputsave()
if a:confirm_replacement if a:confirm_replacement
let l:term = input('Enter search term (w/ confirmation): ') let l:term = input('Enter search term (w/ confirmation): ')
else else
let l:term = input('Enter search term (no confirmation): ') let l:term = input('Enter search term (no confirmation): ')
endif endif
call inputrestore() call inputrestore()
if empty(l:term) if empty(l:term)
return return
endif endif
@ -1251,14 +1245,34 @@ function! GlobalReplaceIt(confirm_replacement)
endif endif
if a:confirm_replacement if a:confirm_replacement
let l:confirm_opt = 'c' let l:confirm = 'c'
else else
let l:confirm_opt = 'e' let l:confirm = 'e'
endif endif
exec 'Ggrep '.l:term " Capture opened buffers and windows so that we can restore everything after running cdo.
exec 'Qargs | Argdo %s/'.l:term.'/'.l:replacement.'/g'.l:confirm_opt exec 'mksession! _replace_session.vim'
call s:RunCtags() " Regen ctags.
" Search all committed files in the current directory
" Ignoring binary files (-I)
" Only including a matching filename once (--name-only)
exec 'Ggrep --threads 4 -I --name-only' l:term '.'
" cdo will run the command foreach file in the grep results. It opens
" the file in a window so we immediately write the changes and then
" wipe the buffer (closing the window). If we don't close it then vim
" will run out of space when modifying a lot of files. This will
" likely close buffers that were open before running the replace, but
" we will restore them below from the saved session file.
" Note that we don't run autocommands for optimization purposes!
:noautocmd exec 'cdo' '%s/'.l:term.'/'.l:replacement.'/g'.l:confirm '| write | bwipe'
" Restore the session.
if filereadable('_replace_session.vim')
silent! exec 'source _replace_session.vim | !rm _replace_session.vim &>/dev/null'
endif
call s:CreateCtags()
else else
call PrintError("Unable to search since you're not in a git repo!") call PrintError("Unable to search since you're not in a git repo!")
endif endif
@ -1274,8 +1288,8 @@ function! RenameFile()
let l:old_name = expand('%') let l:old_name = expand('%')
let l:new_name = input('New file name: ', expand('%'), 'file') let l:new_name = input('New file name: ', expand('%'), 'file')
if l:new_name != '' && l:new_name != l:old_name if l:new_name != '' && l:new_name != l:old_name
exec ':saveas ' . l:new_name exec 'saveas' l:new_name
exec ':silent !rm ' . l:old_name exec '!rm' l:old_name
redraw! redraw!
endif endif
endfunction endfunction