jEdit Macro for Opening the File Browser at Current Buffer's "Project Root" Directory

Filed under jEdit, Programming, Scripts

When I'm working with code in jEdit, my editor of choice, I like to keep the file browser open and docked to the left side of my editor window. When I'm switching between files -- often belonging to different projects -- I find myself reaching for the mouse in order to manually navigate the file browser to the root folder of the project the currently open file belongs to. I started doing this so often that I decided to whip up a small macro to do it for me.

Update (April 4, 2011): Set file browser to directory of current buffer if version control root cannot be found.

Since I don't use the ProjectViewer plugin this macro has to have its own logic for determining where the "project root" is. The way it works is that it tries to find the root folder of the current project by way of searching for version control system folders (i.e. .git, .hg, .bzr, _darcs, .svn or CVS). The assumption is that as the script traverses the file system folder structure from the buffer's location towards the root the first folder that has a Git, Mercurial, Bazaar or Darcs folder (or the last to have a Subversion or CVS folder) is the root. When the script finds the project root it switches the file browser to display it while keeping the UI focus in the editor field. If no project root can be found in this manner, the script sets the file browser to the directory that contains the currently open file.

Download the macro script itself here: Open_Root_of_Current_Project_in_File_Browser.bsh

You install it by dropping it into your jEdit user settings directory's /macros folder (select Utilities → Settings Directory from the jEdit menu to find this location) and then running Macros → Rescan Macros. You can set a keyboard shortcut for this via the Shortcuts section of jEdit's preferences and/or add a toolbar button via the Tool Bar section.

Here is the macro source:

 * Tries to find the root of the 'current project', assuming
 * all project files live under the same directory structure
 * and that they are all under the same version control
 * repository.
 * For Git, Mercurial and Bazaar (and it seems Darcs?) this is
 * easy since they only have their 'dot-directory' at the root
 * of the structure but Subversion (and I assume CVS) put them
 * everywhere so we have to find the _last_ directory to have
 * one.
String findProjectRoot()
	dir = new File(buffer.getDirectory());
	previousDir = null;
	boolean previousDirHasSvnDir = false;
	boolean previousDirHasCvsDir = false;
	while (dir != null)
		boolean hasSvnDir = false;
		boolean hasCvsDir = false;
		list = dir.list();
		for (childName : list)
			if (!hasSvnDir && childName.equals(".svn"))
				hasSvnDir = true;
			else if (!hasCvsDir && childName.equals("CVS"))
				hasCvsDir = true;
			else if (childName.equals(".git")
				|| childName.equals(".hg")
				|| childName.equals(".bzr")
				|| childName.equals("_darcs")
				return dir.getAbsolutePath();
		if (previousDir != null
			&& ((previousDirHasSvnDir && !hasSvnDir)
				|| (previousDirHasCvsDir && !hasCvsDir))
			return previousDir.getAbsolutePath();
		previousDirHasSvnDir = hasSvnDir;
		previousDirHasCvsDir = hasCvsDir;
		previousDir = dir;
		dir = dir.getParentFile();
	return null;

root = findProjectRoot();
if (root == null)
	VFSBrowser.browseDirectory(view, buffer.getDirectory());
	view.getStatus().setMessageAndClear("Browser directory set to current buffer's location (cannot find project root.).");
	VFSBrowser.browseDirectory(view, root);
	view.getStatus().setMessageAndClear("Project root guessed; browser directory set to it.");