Emacs: Making NeoTree work with Perspectives

I like NeoTree, it’s simple and does what I need in terms of side-bar file browsing. But it’s got a particularly annoying problem that I finally decided to take a stab at solving.

In day-to-day use of Emacs, I rely very heavily on projects and workspaces. These are at the very core of my workflow and navigation. I have many Git repositories that I operate in and move around. Those are translated to “projects” by Projectile, and in turn those projects are tied to “perspectives” (think workspaces/virtual desktops), provided by Perspective.

There’s some native integration from NeoTree so it plays nice with Projectile:

(setq projectile-switch-project-action ‘neotree-projectile-action)

This makes it so a NeoTree buffer spawns at the root of a project when you switch to it. Works nicely when you initially open a project. But, the niceties quickly subside when you then start switching between perspectives of your projects. You’ll find that your NeoTree buffer has retained its position from the last project/perspective.

So, say you’ve opened project a . You you’ve got a perspective now for a and a NeoTree buffer at the root of a . You then open project b . As this is the first visit, a NeoTree buffer is spawned at the root of b , within your new b perspective. Now you want to go back and work on a , so you switch perspectives to a . But you’ll find your NeoTree buffer has stayed at the root of b . Not ideal…

Here’s a handy little hack that will make your NeoTree buffer change based on your perspective when switching:

(defun my/persp-neo ()
"Make NeoTree follow the perspective"
(interactive)
(let ((cw (selected-window))
(path (buffer-file-name))) ;;save current window/buffer
(progn
(when (and (fboundp 'projectile-project-p)
(projectile-project-p)
(fboundp 'projectile-project-root))
(neotree-dir (projectile-project-root)))
(neotree-find path))
(select-window cw)))

It’s just a slightly modified neo-show function I borrowed from the NeoTree source.

You can then use this function with the persp-switch-hook to activate it as part of switching perspectives.

Here it is in my configuration, expressed using use-package:

(use-package perspective
:init (persp-mode)
:config
(defun my/persp-neo ()
"Make NeoTree follow the perspective"
(interactive)
(let ((cw (selected-window))
(path (buffer-file-name))) ;;save current window/buffer
(progn
(when (and (fboundp 'projectile-project-p)
(projectile-project-p)
(fboundp 'projectile-project-root))
(neotree-dir (projectile-project-root)))
(neotree-find path))
(select-window cw)))
  :hook
(persp-switch . my/persp-neo))

And that’s it! I hope this helped someone who was looking for a fix. With this configuration; you should find that when you switch perspectives, your NeoTree buffer has followed the perspective/project.

Happy Hacking 👋