1

Goal: To achieve filename/path completion relative to current file directory using file name completion CTRL-X CTRL-F.

I open all my files contained in a base directory such that :pwd in some_file outputs /some/path/to/base_directory. This lets me search for other files relative to base_directory, that I want.

The problem with using CTRL-X CTRL-F is that by default it prompts for filename/directory relative to base_directory. So, if one has to use a path name that is relative to current file directory, something like ../../../some_file pathname, one is out of luck, as this path name is of some_file in three directory level up from base_directory.

I am trying to write a mapping that can switch between base_directory and current file directory to make efficient use of CTRL-X CTRL-F.


Attempt:

" temporarily switch to current file directory
function! SwitchCwd()
  " on first execution of function from a window
  if exists("w:baseCwd")==0
    " store the base directory path in w:baseCwd
    let w:baseCwd=getcwd()
    let w:tmpCwd=expand("%:p:h")
    " when this mapping is run first time from a window, switch to current file directory
    lcd %:p:h
  elseif w:tmpCwd==expand("%:p:h")
    echo w:baseCwd
    " on subsequent executions of this function from same window
    w:tmpCwd=w:baseCwd
    " switch to base directory
    lcd w:baseCwd
  else
    echo "inside else"
    lcd %:p:h
  endif
endfunction

"Path prompt mapping
nnoremap <leader>cd :call SwitchCwd()<CR>

When I run this mapping with <leader>cd for the first time, vim successfully switches to current file directory.

Any subsequent command <leader>cd results in error:

Error detected while processing function SwitchCwd:
line   13:
E13: File exists (add ! to override)
line   14:
E344: Can't find directory "w:baseCwd" in cdpath
E472: Command failed

echo w:baseCwd in elseif outputs the correct absolute path of base_directory, but throws an error in assignment w:tmpCwd=w:baseCwd.

5
  • 1
    you need to use :execute to interpolate variables. This is likely a duplicate. Feb 17, 2020 at 16:12
  • How to implement :execute in this questions context? Feb 17, 2020 at 16:15
  • @HasloVardos use execute 'lcd' w:baseCwd for the command that goes back to the top directory...
    – filbranden
    Feb 17, 2020 at 17:39
  • @filbranden I replaced lcd w:baseCwd with execute 'lcd' w:baseCwd. This works during first execution of function and successfully changes :pwd to current file directory. During second execution it changes :pwd back to the top directory but also throws error: E13: File exists (add ! to override). It keeps on throwing this error in subsequent executions. Feb 17, 2020 at 17:55
  • 1
    More on execute: vi.stackexchange.com/q/21392/10604
    – D. Ben Knoble
    Feb 17, 2020 at 23:58

2 Answers 2

3

There are two separate issues in your code:

  1. In most situations, if you want to use the contents of a variable in a Vim command, you need to use :execute to achieve this. lcd w:baseCwd will attempt to change to a directory named w:baseCwd. To change to the directory currently stored in that variable, use :execute 'lcd' w:baseCwd.

  2. You cannot assign to a variable simply by writing x = y. You need to use :let. The line w:tmpCwd=w:baseCwd doesn't assign to a variable: it attempts to write the current buffer to the file :tmpCwd=w:baseCwd. The first time you do this, it will succeed. The second time you do it (with a different buffer) it will fail with the File Exists error you are seeing.

0

I guess this is what you are looking for:

" Toggles CWD with the currently opened file and base directory
function ToggleCWD()
    if !exists("w:actual_wd")
        let w:actual_wd = getcwd()
        lcd %:p:h
        pwd
    else
        execute "lcd" w:actual_wd
        unlet w:actual_wd
        pwd
    endif
endfunction
nnoremap <leader>cd :call ToggleCWD()<CR>
1

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.