didibus / anakondo

Minor mode for Clojure[Script] completion powered by clj-kondo.
MIT License
114 stars 1 forks source link

background static analysis for multiple projects loaded on Emacs startup #1

Open practicalli-johnny opened 4 years ago

practicalli-johnny commented 4 years ago

When using anakondo with Spacemacs (develop) and multiple projects are re-opened on restarting, interaction with Spacemacs is blocked until static analysis is complete.

To reproduce:

  1. Add anakondo as described in the Spacemacs configuration below
  2. Add several Clojure projects (or one very large one) to emacs using projectile or layouts
  3. Restart Spacemacs so existing projects reload
  4. Wait as anakondo statically analyses all project. I have 13 Clojure projects and have to wait approximately 60 seconds for the analysis (12 thread i7 cpu).
  5. Once analysis of all projects is complete, Spacemacs responds to key presses.

Spacemacs configuration anakondo is added to the dotspacemacs-additional-packages '(anakondo) list which downloads the package.

anakondo is enabled by including the following in dotspacemacs/user-config

  ;; Lazy load of anakondo until Clojure buffer is used
  (autoload 'anakondo-minor-mode "anakondo")
  ;;
  ;; Enable anakondo-minor-mode in all Clojure buffers
  (add-hook 'clojure-mode-hook #'anakondo-minor-mode)
  ;; Enable anakondo-minor-mode in all ClojureScript buffers
  (add-hook 'clojurescript-mode-hook #'anakondo-minor-mode)
  ;; Enable anakondo-minor-mode in all cljc buffers
  (add-hook 'clojurec-mode-hook #'anakondo-minor-mode)
practicalli-johnny commented 4 years ago

Spacemacs also blocked when loading in a perspectives file that contains multiple Clojure projects, until static analysis has completed.

practicalli-johnny commented 4 years ago

For the moment, I have commented out the code in dotspacemacs/user-config and simply include anakondo in the dotspacemacs-additional-packages.

SPC SPC anakondo-minor-mode then enables the package and starts the static analysis just for that specific project (which is usually just a few seconds or less).

didibus commented 4 years ago

Making analysis happen async in the background is still a goal of mine. But it requires a certain level of refactor and adds a bit of complexity.

I'm thinking an alternate solution that gives us 80% of the benefits is to cache the analysis to a file. I'm thinking I can key the cache on the deps.edn last modified timestamp. So if you haven't changed your dependencies, it won't need to rerun analysis. Source code changes, if they are all made inside Emacs with anakondo turned on should automatically update the cache. Right now it does so when you call for completion, but I could make it more robust and have it re-run per-file when the buffer is saved as well. Single file analysis is really quick, so users wouldn't even notice this happens after save.

So the issues with this would be:

  1. Can get out of sync with source code if source files are added or changed outside of anakondo buffers.

  2. When source files are removed, it won't get synced. This shouldn't be a big deal, since people will most likely remove the require as well. But could cause a little be of drift.

  3. Can get out of sync if dependencies use snapshot release, and so changes can be pulled in without touching the deps.edn file.

Whenever the user feels things are out of sync, they can force refresh the cache with anakondo-refresh-project-cache command. So since I expect it to be rare, I think this is a good 80/20 rule solution.

I think implementing this wouldn't take me very long, compared to async analysis, so I might start with it, and postpone the work for async analysis.

One more consideration:

Another consideration, where to put the cache directory or file? Options are:

andreyorst commented 3 years ago

Another consideration, where to put the cache directory or file?

Some projects use .cache directory under emacs-user-directory. I think clj-kondo directory is okay too, unless this cache will not interfere with clj-kondo's own cache and produce errors or make either of projects behave incorrectly