vim: search files under the current working directory with denite & defx without changing the actual working directory
Tags: vim, neovim, defx, denite
Published: 2020-05-06 10:57:05

I'm using [defx](https://github.com/Shougo/defx.nvim) as filer, and [denite](https://github.com/Shougo/denite.nvim) and [ag](https://github.com/ggreer/the_silver_searcher) to search files on Neovim.
My current configuration searches files under the current working directory.
defx supports `auto-cd` option which changes the working directory automatically while navigating with it.
It allows you to quickly search files under the directory where you are viewing on defx, which is handy because you don't need to filter files in other directories which you are not currently interested in.
It basically works great, but my problem is that tools that work in the project root directory don't work when the current directory got changed.
In my case, `eslint` and `flow` can't be invoked via [coc.nvim](https://github.com/neoclide/coc.nvim), causing error like this:

```
[coc.nvim] Definition provider not found for current document
```

So, I want to search files under the directory I am currently working without changing the actual working directory.

![defx](https://dev-to-uploads.s3.amazonaws.com/i/q0jbt8b2dct3kf1uety3.png)

*Fig. using defx*

## Use `defx#get_candidate()` to get the currently selected file path

First off, I need to know the path where defx is displaying.
I found that `defx#get_candidate()` returns the information about currently selected item like so:

```vim
echo defx#get_candidate()
"{'word': 'native-base-theme/', 'is_directory': v:true, 'action__path': '/foo/bar.txt', 'level': 0, 'is_opened_tree': v:false}
```

Seems like you can use `action__path` to know where you are as following:

```vim
let l:path = expand('%:p:h')
if has_key(defx#get_candidate(), 'action__path')
  let l:path = fnamemodify(defx#get_candidate()['action__path'], ':p:h')
endif 
```

If defx is not opened, it uses the parent path of the currently editing file instead, so you can quickly search sibling files without opening up defx.

## vim config

So, I've update my vim config like so:

```vim
" use floating
let s:denite_win_width_percent = 0.8
let s:denite_win_height_percent = 0.7
let s:denite_default_options = {
    \ 'split': 'floating',
    \ 'winwidth': float2nr(&columns * s:denite_win_width_percent),
    \ 'wincol': float2nr((&columns - (&columns * s:denite_win_width_percent)) / 2),
    \ 'winheight': float2nr(&lines * s:denite_win_height_percent),
    \ 'winrow': float2nr((&lines - (&lines * s:denite_win_height_percent)) / 2),
    \ 'highlight_filter_background': 'DeniteFilter',
    \ 'prompt': 'Œª ',
    \ 'start_filter': v:true,
    \ }
let s:denite_option_array = []
for [key, value] in items(s:denite_default_options)
  call add(s:denite_option_array, '-'.key.'='.value)
endfor
call denite#custom#option('default', s:denite_default_options)

" Ag command on grep source
call denite#custom#var('grep', 'command', ['ag'])
call denite#custom#var('grep', 'default_opts', ['-i', '--vimgrep'])
call denite#custom#var('grep', 'recursive_opts', [])
call denite#custom#var('grep', 'pattern_opt', [])
call denite#custom#var('grep', 'separator', ['--'])
call denite#custom#var('grep', 'final_opts', [])

" grep
command! -nargs=? Dgrep call s:Dgrep(<f-args>)
function s:Dgrep(...)
  if a:0 > 0
    execute(':Denite -buffer-name=grep-buffer-denite grep -path='.a:1)
  else
    let l:path = expand('%:p:h')
    if has_key(defx#get_candidate(), 'action__path')
      let l:path = fnamemodify(defx#get_candidate()['action__path'], ':p:h')
    endif 
    execute(':Denite -buffer-name=grep-buffer-denite -no-empty '.join(s:denite_option_array, ' ').' grep -path='.l:path)
  endif
endfunction

" show Denite grep results
command! Dresume execute(':Denite -resume -buffer-name=grep-buffer-denite '.join(s:denite_option_array, ' ').'')

nnoremap <silent> ;r :<C-u>Dgrep<CR>
```

Works like a charm!

![End result](https://dev-to-uploads.s3.amazonaws.com/i/rqt167c8odr5gwfnwyqg.png)