Emacs: Making NeoTree work with Perspectives

By Calum MacRae

February 9, 2019

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!

Posted on:
February 9, 2019
Length:
2 minute read, 411 words
Tags:
emacs workflow
See Also:
A Nix overlay for Emacs 27 with the 'emacs-mac' patches
E-mail in Emacs with mu4e on OS X
Blogging with org-page