I wrote the following one-liner command.
command! -nargs=? Gfind execute "split | enew | cd `git-pwd` | read !git ls-files | grep " . expand("<args>") . " " <bar>
(
git-pwd returns the current get repo's root or './'
#!/bin/bash
git-pwd() {
local root=$(git rev-parse --show-cdup 2>&1 )
[[ "$root" == "" ]] && { echo "./" && return; }
[[ "$root" == fatal:* ]] { echo "./" && return 1; }
echo "$root"
}
[[ "$BASH_SOURCE" == "$0" ]] && git-pwd "$#"
)
It allows me to do :Gfind regex and a split window opens up with the list of files whose path/name matches the regex. That I can use for navigation with gf.
I wonder if there's an easy way to make the returned files in that window enterable like in cwindow or NERDTree.
Alternatives
Use :Gedit with completion abbreviated paths. e.g. :Gedit f/b/b<tab> which will expand to :Gedit foo/bar/baz (Requires fugitive.vim)
Glob with :Gedit. e.g. :Gedit **/baz<tab>
Use a fuzzy finder like CtrlP.vim to jump around your project.
Use something like projectionist.vim to build navigation commands for a well structured project.
There are low tech solutions that use :find and 'path':
set path=.,**
nnoremap <leader>f :find *
These are not mutually exclusive as you can use all these methods as each have their own pro's and con's. I personally use projectionist.vim as my main navigation method.
Answer to your question
I would imagine the best thing would be to use the QuickFix list. Your command would populate the quickfix list with the files matching your pattern and then you can use :copen to actually see the files and move between them or use :cnext/:cprev type commands to move between files.
Put the following in your ~/.vimrc file:
command! -nargs=? Gfind call s:gfind(<q-args>)
function! s:gfind(pat)
let grepprg = &grepprg
let errorformat = &errorformat
let &grepprg = 'cd ' . shellescape(fugitive#repo().dir()) . ' && git ls-files | grep '
let &errorformat = '%f'
execute 'grep ' . a:pat
cwindow
let &grepprg = grepprg
let &errorformat = errorformat
endfunction
Notes: I have not tested this code. It also uses fugitive.vim, but you can use your git-cwd trick if you rather. You may want to remove cwindow command to depending on your workflow.
Related
I have defined a function to search for filename (<C-P>), and a string (<C-F>) from git root directory asynchronously with fzf.vim plugin (I also have Ag installed). However, I can not manipulate the definition to ignore node_modules directory. The vim script is too hard to debug, there is no console to print anything.
Is there any expert in vim script that can help me sort this out. Many thanks in advance
let s:git_path = substitute(system("git rev-parse --show-toplevel 2>/dev/null"), '\n', '', '')
function! s:ag_git_root(query, ...)
if type(a:query) != type('')
return s:warn('Invalid query argument')
endif
let query = empty(a:query) ? '^(?=.)' : a:query
let args = copy(a:000)
let ag_opts = len(args) > 1 && type(args[0]) == s:TYPE.string ? remove(args, 0) : ''
let command = ag_opts . ' ' . fzf#shellescape(query) . ' ' . s:git_path
return call('fzf#vim#ag_raw', insert(args, command, 0))
endfunction
command! -bang -nargs=* A
\ call s:ag_git_root(<q-args>, <bang>0)
command! -bang -nargs=? F
\ call fzf#vim#files(s:git_path, <bang>0)
silent! nmap <C-P> :F<CR>
silent! nmap <C-F> :A<CR>
Finally, I figured out a workaround by replacing fzf#vim#files with :Gfiles
New configuration is silent! nmap <C-P> :GFiles<CR>
<C-F> mapping is kept the same as in the question.
The demerit of this :GFiles solution is that files not added to git (untracked files) are not included in the search results. They all can be added via git add . -A
The merit of this solution is that all files in .gitignore is ignored in the search results
I know how to use CtrlP. I type ctrl+p, then I start to write file name, ... and so on. But, ... I am very lazy developer. I want to directly send to CtrlP current word. I know how to get current word:
let l:currentWord = expand('<cword>')
In Vim Language, ... I How can I send l:currentWord to CtrlP?
map <F6> :call ComposerKnowWhereCurrentFileIs()<CR>
function! ComposerKnowWhereCurrentFileIs()
let l:currentWord = expand('<cword>')
let l:command = "grep " . l:currentWord . " ../path/to/composer -R | awk '{print $6}' | awk -F\\' '{print $2}'"
let l:commandFileFound = l:command . ' | wc -l'
let l:numberOfResults = system(l:commandFileFound)
if l:numberOfResults == 1
let l:fileName = system(l:command)
let l:openFileCommand = 'tabe /path/to/project' . l:fileName
exec l:openFileCommand
else
echo "Too many files :-( - use CtrlP ;-) "
endif
endfunction
<C-P><C-\>w
See :h ctrlp-mappings. You may map this combination:
map <F6> <C-P><C-\>w
In a function:
exe "normal \<C-P>" . expand('<cword>')
The whole point of CtrlP and similar plugins is to provide an alternative command-line where you can refine your search as you type.
If you don't need fuzzy search and you already have the filename under the cursor… why not simply use the built-in gf?
-- edit --
In the gif below:
I jump to /path/not/knowable/BlaBlaClassName.php with gf,
I jump back to the previous buffer with <C-^> (unrelated to your question),
I jump to the declaration of BlaBlaClassName in /path/not/knowable/BlaBlaClassName.php again with <C-]> thanks to a tagsfile generated with ctags.
function! LazyP()
let g:ctrlp_default_input = expand('<cword>')
CtrlP
let g:ctrlp_default_input = ''
endfunction
command! LazyP call LazyP()
nnoremap <C-P> :LazyP<CR>
(this could probably be simplified but I suck at vim syntax)
For that, you wouldn't use the <C-P> mapping, but the :CtrlP command, as that one takes parameters.
To build a mapping that passes the current word to the command, there are two approaches. Either directly insert the current word into the command-line (via :help c_CTRL-R_CTRL-W):
:nnoremap <Leader>p :CtrlP <C-r><C-p><CR>
Or, in order to use expand(), build the Ex command via :execute:
:nnoremap <Leader>p :execute 'CtrlP' expand('<cword>')<CR>
How can I access the arguments that were given to Vim on the command line under Windows?
I'm looking for the the equivalent to argv[] in C.
Under linux you can read /proc/self/cmdline.
Example:
vim -c ":echo split( readfile( \"/proc/self/cmdline\", 1 )[0], \"\n\" )"
print
[
'vim',
'-c',
':echo split( readfile( "/proc/self/cmdline", 1 )[0], "\n" )'
]
argc() and argv() don't work. They just return number of files.
Example:
vim -c ':echo "argc:" . argc() . ", argv:" . string( argv() )' file1 file2
print
argc:2, argv:['file1', 'file2']
:help argc()
:help argv()
:help argidx()
And maybe also :help argument-list, just to be sure.
Simple example:
for arg in argv()
echo arg
endfor
In the specific case of needing argv[0] (i.e., the name vim was called by), you can use v:progname.
in vim, when I use
:make
the output of make is displayed in a "external" window, I don't like this and I use this map
nnoremap <leader>m :w <bar> make<CR><CR><CR>:copen<CR>
but, in some case the output of make is
make: Nothing to be done for `all'.
how I can add a autoclose to copen when the copen have make: Nothing to be done for all. ?
You can check the contents of the quickfix list via getqflist(). Then, I would only conditionally open the quickfix window if the first line does not match the text you don't want to see:
nnoremap <leader>m :w <bar> make<CR><CR><CR>
\:if get(get(getqflist(), 0, {}), 'text', '') !~# 'Nothing to be done' <Bar>
\ copen <Bar>
\endif<CR>
The access via get() avoids errors when the list is empty.
You could also always open the list, and then use :cclose in the conditional, if that better fits your needs.
i have a vim script that helps me a lot:
first it saves the current edit window (if possible, won't work if read only)
then it runs make and redirects errors (stderr) to temp file (stdout is ignored)
if build failed then open quick fix windows and fill it with error messages.
delete temporary file
command! -nargs=* Build call s:RunBuild()
function! s:RunBuild()
let tmpfile = tempname()
"build and surpresses build status messages to stdout
"(stdout message are not very informative and may be very very long)
"Error messages are redirected to temporary file.
let buildcmd = "make -j 2> " . tmpfile . " >/dev/null"
let fname = expand("%")
if fname != ""
" save current buffer if possible (your bad if file is read only)
write
endif
" --- run build command ---
echo "Running make ... "
let cmd_output = system(buildcmd)
"if getfsize(tmpfile) == 0
if v:shell_error == 0
cclose
execute "silent! cfile " . tmpfile
echo "Build succeded"
else
let old_efm = &efm
set efm=%f:%l:%m
execute "silent! cfile " . tmpfile
let &efm = old_efm
botright copen
endif
call delete(tmpfile)
endfunction
Then i map the F5 key to do the build in each vim mode
"F5 - run make (in normal mode)
:nnoremap :Build
"F5 - run make (in visual mode)
:vnoremap :Build
"F5 - run make (in insert mode)
:inoremap :Build
In my vimrc I call Uncrustify by this command:
%!uncrustify -l CPP -c D:\uncrustify\default.cfg
After that on some code I get a Windows Fatal error:
But when I call uncrustify on the same code in the console using the -f option, there is no error.
How can I change my vimrc to avoid such errors in the future? What can invoke this error?
In order to integrate Uncrustify with Vim properly, add the following to your .vimrc:
" Restore cursor position, window position, and last search after running a
" command.
function! Preserve(command)
" Save the last search.
let search = #/
" Save the current cursor position.
let cursor_position = getpos('.')
" Save the current window position.
normal! H
let window_position = getpos('.')
call setpos('.', cursor_position)
" Execute the command.
execute a:command
" Restore the last search.
let #/ = search
" Restore the previous window position.
call setpos('.', window_position)
normal! zt
" Restore the previous cursor position.
call setpos('.', cursor_position)
endfunction
" Specify path to your Uncrustify configuration file.
let g:uncrustify_cfg_file_path =
\ shellescape(fnamemodify('~/.uncrustify.cfg', ':p'))
" Don't forget to add Uncrustify executable to $PATH (on Unix) or
" %PATH% (on Windows) for this command to work.
function! Uncrustify(language)
call Preserve(':silent %!uncrustify'
\ . ' -q '
\ . ' -l ' . a:language
\ . ' -c ' . g:uncrustify_cfg_file_path)
endfunction
Now you can either map this function (Uncrustify) to a combination of keys or you could do the convenient trick that I use. Create a file ~/.vim/after/ftplugin/cpp.vim where you can override any Vim settings particularly for C++ and add the following line there:
autocmd BufWritePre <buffer> :call Uncrustify('cpp')
This basically adds a pre-save hook. Now when you save the file with C++ code it will be automatically formatted by Uncrustify utilizing the configuration file you supplied earlier.
For example, the same could be done for Java: in ~/.vim/after/ftplugin/java.vim add:
autocmd BufWritePre <buffer> :call Uncrustify('java')
You got the point.
NOTE: Everything presented here is well-tested and used every day by me.
I have found the placing the following code into your .vimrc to be sufficient:
let g:uncrustifyCfgFile = '~/.uncrustify.cfg'
function! UncrustifyFunc(options) range
exec a:firstline.','.a:lastline.'!uncrustify '.a:options
\.' -c '.g:uncrustifyCfgFile.' -q -l '.&filetype
endfunction
command! -range=% UncrustifyRange <line1>,<line2>call UncrustifyFunc('--frag')
command! Uncrustify let s:save_cursor = getcurpos()
\| %call UncrustifyFunc('')
\| call setpos('.', s:save_cursor)
Note this does assume that you have "uncrustify" binary in your $PATH.
It also assumes your configure file is ~/.uncrustify.cfg however you can change that by modifiying the g:uncrustifyCfgFile variable.
To call run
:Uncrustify
It also works on ranges (which was what promoted me to make this function). Visual selection example:
:'<,'>UncrustifyRange
I have only tired it with C, CPP and JAVA (I assume others will work as well)
In addition to #Alexander Shukaev's answer, adding the following will perform a check for uncrustify config correctness and not auto format if error is detected:
let output = system('uncrustify -q -c ' . a:cfgfile)
if v:shell_error != 0
echo output
endif
return v:shell_error
endfunction
" Don't forget to add Uncrustify executable to $PATH (on Unix) or
" %PATH% (on Windows) for this command to work.
function! Uncrustify(language)
if CheckUncrustifyCfg(g:uncrustify_cfg_file_path)
echo "Config file" g:uncrustify_cfg_file_path "has errors"
echo "No formatting will be performed"
return
endif
call Preserve(':silent %!uncrustify'
\ . ' -q '
\ . ' -l ' . a:language
\ . ' -c ' . g:uncrustify_cfg_file_path)
endfunction