junegunn / fzf.vim

fzf :heart: vim
MIT License
9.62k stars 584 forks source link

Rg from different directory #837

Closed drjosephliu closed 5 years ago

drjosephliu commented 5 years ago

After typing :Rg followed by <enter> I'd like to search for terms starting from the project root. At the moment it is only able to search in the current working directory.

I managed to implement this feature for :Files with the following code:

function! s:find_git_root()
    return system('git rev-parse --show-toplevel 2> /dev/null')[:-2]
endfunction
command! ProjectFiles execute 'Files' s:find_git_root()
nnoremap <C-p> :ProjectFiles<CR>

So I tried doing the same for Rg by creating a new command :ProjectRg:

command! ProjectRg execute 'Rg' s:find_git_root()
nnoremap <S-f> :ProjectRg<CR>

But had no luck. Any ideas on how to search project root for Rg?

junegunn commented 5 years ago

You can define your own version of :Rg using fzf#vim#grep function as shown in https://github.com/junegunn/fzf.vim#advanced-customization.

For example, you can pass dir option like so

command! -bang -nargs=* PRg
  \ call fzf#vim#grep("rg --column --line-number --no-heading --color=always --smart-case ".shellescape(<q-args>), 1, fzf#vim#with_preview({'dir': system('git rev-parse --show-toplevel 2> /dev/null')[:-2]}), <bang>0)
powelleric commented 4 years ago

Since this seems to be the top search result for this topic, I'll add a slight variation for those who might be interested. This will perform an Rg search from the project root of the current buffer (as opposed to the current working directory used by the variation above).

command! -bang -nargs=* PRg
  \ call fzf#vim#grep("rg --column --line-number --no-heading --color=always --smart-case ".shellescape(<q-args>), 1, {'dir': system('git -C '.expand('%:p:h').' rev-parse --show-toplevel 2> /dev/null')[:-2]}, <bang>0)
medwatt commented 4 years ago

I know this is a closed topic. But how can we use the Rg with a directory from files on your local drive, like we do with Files ?

begin29 commented 3 years ago

or even start from root and show with preview as described https://github.com/junegunn/fzf.vim

command! -bang -nargs=* GGrep
  \ call fzf#vim#grep(
  \   'git grep --line-number -- '.shellescape(<q-args>), 0,
  \   fzf#vim#with_preview({'dir': systemlist('git rev-parse --show-toplevel')[0]}), <bang>0)
JohanChane commented 3 years ago

for example

:RgD -path= . -pattern=main
" ok. equivalent to `:Rg main\(`
:RgD -path= . -pattern=main\(
" ok. equivalent to `:Rg <whitespace>main\(<whitespace>`
:RgD -path= . -pattern=<whitespace>main\(<whitespace>
" ok. equivalent to `:Rg cmd -pattern=param`
:RgD -path= . -pattern=cmd -pattern=param
" ok
:RgD -path= ./Program Files -pattern=cmd -pattern=param

add to .vimrc

function! RgDir(isFullScreen, args)
    let l:restArgs = [a:args]

    let l:restArgs = split(l:restArgs[0], '-pattern=', 1)
    let l:pattern = join(l:restArgs[1:], '')

    let l:restArgs = split(l:restArgs[0], '-path=', 1)
    " Since 8.0.1630 vim has a built-in trim() function
    let l:path = trim(l:restArgs[1])

    call fzf#vim#grep("rg --column --line-number --no-heading --color=always --smart-case " .. shellescape(l:pattern), 1, {'dir': l:path}, a:isFullScreen)
endfunction

" the path param should not have `-pattern=`
command! -bang -nargs=+ -complete=dir RgD call RgDir(<bang>0, <q-args>)
nnoremap <leader>zd :RgD -path= . -pattern=
alexsmartens commented 2 years ago

Do you guys know how to search through the same files as :GFiles with :Rg?

I'm using :GFiles --cached --others --exclude-standard as a default command and absolutely love it. But :Rg searches through tons of "unrelated" files and I'd like it to search through the same files as my :GFiles command. Do you know how to make it work by any chance?

talmobi commented 2 years ago

@alexsmartens it's already answered in the first reply by Junegunn https://github.com/junegunn/fzf.vim/issues/837#issuecomment-509901611

[EDIT]: basically you can pass in any arbitrary dir or list of files -- and you can get all kinds of git specific files from git -- June gives an example of using git rev-parse --show-toplevel to get the git project root directory to start from -- you can customise this to your liking

ilidio commented 2 years ago

Rg2 [search] [folder]

command! -bang -nargs=* Rg2
  \ call fzf#vim#grep("rg --column --line-number --no-heading --color=always --smart-case ".<q-args>, 1, {'dir': system('git -C '.expand('%:p:h').' rev-parse --show-toplevel 2> /dev/null')[:-2]}, <bang>0)

Example:

:Rg2 apple ./folder_test
:Rg2 "apple teste" ./folder_test
:Rg2 --type=js "apple" 
:Rg2 --fixed-strings "apple"
:Rg2 -e -foo          
:Rg2 apple
:Rg2 '^port'                                       # Search for lines beginning with 'port'
:Rg2 '^\s*port'                                   # Search for lines beginning with 'port', possibly after initial whitespace
:Rg2 Apple --case-sensitive
:Rg2 Apple --sortr=created             #   (none, created, path, modified, accessed)   descending order
:Rg2 Apple --sort=created               #  (none, created, path, modified, accessed)   ascending order
:Rg2 --passthru 'blue' -r 'red' test.txt  > tmp.txt && mv tmp.txt test.txt                       #Replace example
:Rg2 --passthru 'blue' -r 'red' test.txt  | sponge test.txt                       # Replace example If you have moreutils installed
:Rg2 'port|http'                                     # Search for string 'port' OR string 'http':

Manual and examples you can use

Check: https://www.mankier.com/1/rg

Search Examples with rg : https://github.com/strindberg/rg/blob/master/EXAMPLES.md https://learnbyexample.github.io/substitution-with-ripgrep/

And you can add this all to Rg2

mb720 commented 1 year ago

This version is similar to JohanChane's but starts the fzf prompt immediately after calling the function.

See the mappings at the bottom for usage ideas.

" Gets the root of the Git repo or submodule, relative to the current buffer
function! GetGitRoot()
  return systemlist('git -C ' . shellescape(expand('%:p:h')) . ' rev-parse --show-toplevel')[0]
endfunction

" RgIn: Start ripgrep in the specified directory
"
" Usage
"   :RgIn start_dir search_term
"
" If the command was called with a bang ("RgIn!"), make the search window
" fullscreen
function! s:rg_in(showFullscreen, ...)
  let l:start_dir=expand(a:1)

  if !isdirectory(l:start_dir)
    throw 'not a valid directory: ' .. l:start_dir
  endif

  " a:000 contains the argument list → Join the arguments after the first one
  let l:pattern=(join(a:000[1:], ' '))

  let l:rg_cmd = "rg --color=always --line-number --no-heading --smart-case " .. shellescape(l:pattern)
  let l:has_column = 0
  call fzf#vim#grep(l:rg_cmd, l:has_column, {'dir': l:start_dir}, a:showFullscreen)

endfunction

" See this: https://vi.stackexchange.com/questions/13965/what-is-command-bang-nargs-in-a-vimrc-file
" -bang: The command can also be called as "RgIn!" to make the search window fullscreen
" <bang>0: If there is no bang, pass 0 to the function, otherwise 1
command! -bang -nargs=+ -complete=dir RgIn call s:rg_in(<bang>0, <f-args>)

" Search content from the root of the current Git repo
nmap <leader>o :RgIn `=GetGitRoot()`<cr>
" Search in a specified directory
nmap <leader>d :RgIn ~/docs<cr>
" Search current word in Git repo. Adapted from here: https://news.ycombinator.com/item?id=26634419#26635204
nnoremap <C-Space> yiw:RgIn `=GetGitRoot()` <C-r>"<cr>
" Search current selection in Git repo
vnoremap <C-Space> y:RgIn `=GetGitRoot()` <C-r>"<cr>
mikehaertl commented 1 year ago

@ilidio thanks a lot, your command is awesome.

I've pimped it a little to include preview and autocompletion of rg options (after -) and paths (after ./):

command! -bang -nargs=* -complete=custom,RgComplete Rgf
  \ call fzf#vim#grep(
  \   'rg --column --line-number --no-heading --color=always --smart-case '.<q-args>, 1,
  \   fzf#vim#with_preview({
  \     'dir': system('git -C '.expand('%:p:h').' rev-parse --show-toplevel 2> /dev/null')[:-2]
  \   }), <bang>0)

function RgComplete (A,L,P)
  echom a:A[0]
  if (a:A[0] == '-')
    return system("rg -h | grep '\\-.\\?[0-9A-Za-z-]*' -o | sort -u")
  endif
  if (a:A[0:1] == './')
    return globpath('.', a:A[2:]..'*')
  endif
endfunction

If all you want is file completion you can also leave away the RgComplete function and only use -complete=file in the command definition.