I want to set the Vim file search path that is customised for each of my Java projects. To do this I search for a project-specific .vimrc file that contains the per-project settings and load this configuration file whenever I edit a Java source file in the project.

File search path

In Vim, the gf command will "edit the file whose name is under or after the cursor". This command depends on the path property having been set: the list of directories which will be searched when using gf.

For example, if I am editing the file net/gslsrc/example/MyClass.java which contains:

package net.gslsrc.example;

import net.gslsrc.example.other.OtherClass;
...

I can place the cursor anywhere on the import statement’s package name (but not on the semi-colon) and type gf to open the file net/gslsrc/example/other/OtherClass.java if I set the appropriate search path.

For me, using Linux, the default path value is ".,/usr/include,,". Path elements are separated by commas; the "dot" means "search relative to the current directory"; and the "double-commas" (or empty path element) means "search in the current directory".

For Java projects, this path is only useful for opening files in the same package (directory). Import statements use absolute, not relative names, so unless you are editing a file in the default package (unnamed) and import classes from named sub-packages, the relative search is of limited use.

What constitutes a useful search path will vary from project to project but in Java projects, I generally want to do an upward search in the directory (package) hierarchy to the root of my source directory (usually src/) from which I can then search down for classes in other packages. The upward search path element takes the form seek;stopdir where seek is the path fragment you are searching for and stopdir is the name of the directory at which you stop searching.

Consider the directory structure for the "dmex" project with two source "modules" (core and pdf):

Project directory structure
~/workspace/
 |
 :
 |-- dmex/
 |   |-- src/
 :       |-- core/
         |   `-- net/gslsrc/dmex/ ...
         `-- pdf/
             `-- net/gslsrc/dmex/pdf/ ...

If I am editing one of the classes under the src/pdf directory and want to open an imported class from src/core, the path I use is:

:set path=.,src/core;dmex,src/pdf;dmex,,

This path will search upwards for src/core and src/pdf, stopping when the dmex (project) directory is reached. The trailing "double-comma" means the current directory is also searched. (The "dot" for searching "relative" is possibly useful for opening non-source resources located in a sub-directory of the package.)

Setting the project search path

The path described above is only useful for the "dmex" project’s directory structure so I only want to apply this path when editing a Java source file in this project.

To set the search path, we can put a project-specific .vimrc in the project’s base directory (dmex/) and have our home .vimrc load this file whenever we edit a file in the project.

The Vim script I use is:

Load project .vimrc file
let s:wdir = $HOME."/workspace"
if match(getcwd(), s:wdir) != -1
    let s:project_vimrc=findfile(".vimrc", ".;workspace")
    if exists("s:project_vimrc") && filereadable(expand(s:project_vimrc))
        execute "source ".s:project_vimrc
    endif
endif

We are only interested in loading a project .vimrc if we are editing a file beneath the ~/workspace/ directory (where all my projects are located) hence we match the current directory (getcwd()) with the workspace path to determine if we are editing a file in the workspace. (This step is perhaps unnecessary due to the findfile() call (see below) but it is a simple way to avoid searching when there is no possibility of success.)

The findfile() function searches for the .vimrc file upwards from the location of the file being edited, stopping the search when it reaches the workspace/ directory.

Hence if I put my .vimrc in the ~/workspace/dmex/ directory and edit a file in or below the dmex/ directory, the .vimrc will be found. All I have to do is put my "dmex"-specific path value in the dmex/.vimrc file.

If I want to set the path (or perform other customisations) for all files I might edit in a project, I can put the script in my home ~/.vimrc file. Otherwise, if I only want to load project customisations for particular file types (eg., Java source files only), then I put the script in my ~/.vim/java.vim file with my other Java-specific settings (that are loaded via an autocmd in ~/.vimrc).