12

I know I can complete filenames/paths from the current directory using Ctrl+X, Ctrl+F (compl-filename). That works great in combination with set autochdir, which changes the current directory to the directory of the active buffer.

However, I started using airblade/vim-rooter to make the current directory the "project" folder. Now filename completion always starts from the project folder.

The question: Is there a way to make the filename completion use the directory of the active buffer instead of the current directory? Or some other workaround?

1
  • 5
    C-xC-f always uses the current buffer's working directory, without any options to configure it (it doesn't support path either). It depends on what your intended use for vim-rooter is. Depending on what you want from it, we could use other plugins. Aside: I use youcompleteme, which completes paths from the directory of the current buffer if you start typing ./. See reddit.com/r/vim/comments/216jdd/…
    – muru
    Feb 11, 2016 at 9:25

1 Answer 1

7

As @muru mentioned, there are no options to configure the directory from which to complete path and file names. It always uses the working directory of the window.

I've written a couple of functions and mappings to help with this. Behind the scenes, they change the local working directory (using :lcd) temporarily, then restore the previous working directory when done.

Elephant

For reasons unknown to even me, I've called this micro-plugin Elephant.

Here's the code (copied from my Vim config on GitHub):

let g:elephant_map = {
    \ 'f': function('elephant#current_file'),
    \ 'p': function('elephant#vcs_project')
\ }

function! elephant#prompt(base)
    let l:Fcn = get(g:elephant_map, a:base, function('elephant#identity'))
    let l:basedir = l:Fcn()
    execute 'lcd' l:basedir
    let l:file = fnamemodify(input(l:basedir.'/', '', 'file'), ':p')
    lcd -
    return fnamemodify(l:file, ':.')
endfunction

function! s:elephant_init()
    let l:base = getchar()
    return elephant#prompt(nr2char(l:base))
endfunction

function! elephant#identity()
    return '.'
endfunction

function! elephant#vcs_project()
    return fnamemodify(finddir('.git', '.;'), ':h')
endfunction

function! elephant#current_file()
    return expand('%:h')
endfunction

inoremap <silent> <expr> <C-R><C-E> <SID>elephant_init()
cnoremap <silent> <C-R><C-E> <C-R>=<SID>elephant_init()<CR>

How to use it

Using these mappings happens in 3 steps.

1. Invoke the mapping

In Insert mode or Command-line mode, invoke the mapping using <C-R><C-E>.

2. Choose a directory

Type a single character to choose which root directory you want completion from. The code above provides two types of roots:

  • f - The directory that the current file (buffer) resides in
  • p - The base directory of the Git project the current file belongs to

3. Enter the path or file name

You will be prompted to enter the path or file name relative to the directory specified, with completion available. Press Enter when finished.

Some notes

  • This doesn't provide inline completion in Insert mode the way <C-X><C-F> does; instead, you will be typing the path or file name on the Command-line prompt (where : commands go). Upon pressing Enter, the path will be inserted into the buffer.
  • The same is true in Command-line mode, which can sometimes be confusing when you hit Enter and forget that you still have to hit Enter to issue whatever command you were just typing.
  • Other directory functions can be registered by adding them into g:elephant_map.
  • The path inserted will be the full, absolute path. The script can be tweaked to change that behaviour, but I haven't got around to it.
1
  • Didn't quite test the solution, but accepted it because of the completeness. Instead I used the suggest workaround: YouCompleteMe instead of ctrl+x, ctrl+f. Feb 24, 2016 at 14:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.