[clojure] Added support for joker linter and having mutliple active linters

The variable clojure-enable-linters can now be set to a list of linters:

'(clj-kondo joker)
  or
'(joker squiggly)
  or any other combination of the available linters.

In which case, all linters in the list will be active if they are
available to be. In that flycheck is configured so that each linter
in the list has as next-checker the next linter in the list.

The variable can also now be set to:

'joker

If only the newly added joker linter should be used.

This will pull down flycheck-joker and add Joker as a checker for
Clojure modes.

--

Implementation Details

The way it works is that for each Clojure linting mode, clj, cljc,
cljs and edn, a primary linter is chosen based on the order the
user specifies in clojure-enable-linters which support that mode.
It is made the primary linter for flycheck to use by being promoted
to the front of the flycheck-checkers list. All other linters specified
by the user which the mode also supports get added to it as a
next-checker.

Tested with clj-kondo, joker and squiggly. The only issue I saw was that
the way flycheck-clojure works, and the way I currently have setup the
logic for multiple checkers mean that we can't add to a mode multiple
checkers for the same linter. flycheck-clojure has eastwood, kibit and
core.typed. If you have it configured to use eastwood linter, then it
will all work, as eastwood gets added as the next-checker. But if you
have it disabled in flycheck-clojure, there won't be any
flycheck-clojure linters to activate. I'm not sure as of now how to best
support that. Ideally, we would not clubber linters into a single packge
like that, and so the layer would have instead of squiggly: eastwood,
kibit, core.typed. But that's not how flycheck-clojure works. Future
commit might be able to do something smarter about this.
This commit is contained in:
Didier A 2019-09-02 00:25:45 -07:00 committed by smile13241324
parent 1de8157a5c
commit 58dcd6320b
3 changed files with 124 additions and 15 deletions

View File

@ -1225,6 +1225,7 @@ Other:
- Added =sayid= debugger (thanks to Daniel Manila and Arne Brasseur)
- Added =flycheck-clojure= linters (thanks to Eugene Yaremenko)
- Added =clj-kondo= to Clojure linters (thanks to Luo Tian and John Stevenson)
- Added =flycheck-joker= to Clojure linters (thanks to didibus)
- Improvements:
- Stored cider REPL history in spacemacs cache (thanks to Ryan Fowler)
- Removed backtick from smartparens pairs for Clojure
@ -1240,6 +1241,8 @@ Other:
(thanks to Dieter Komendera)
- Improved spacemacs-jump-handlers (thanks to Ag Ibragimov)
- Autoscroll to end of REPL when sending buffer content (thanks to Vitaly Banchenko)
- Added ability to use multiple linters together (thanks to didibus)
>>>>>>> fa4786d5a... [clojure] Added support for joker linter and having mutliple active linters
- Key bindings:
- ~SPC m e ;~ to eval sexp and show result as comment
(thanks to John Stevenson)

View File

@ -13,7 +13,9 @@
- [[#enabling-sayid-or-clj-refactor][Enabling sayid or clj-refactor]]
- [[#enabling-automatic-linting][Enabling Automatic Linting]]
- [[#enable-clj-kondo-linter][Enable clj-kondo linter]]
- [[#enable-joker-linter][Enable joker linter]]
- [[#enable-squiggly-linter][Enable Squiggly linter]]
- [[#enable-multiple-linters][Enable multiple linters]]
- [[#starting-clojure-manually-outside-of-emacs][Starting Clojure manually (outside of Emacs)]]
- [[#quick-start-with-boot][Quick Start with boot]]
- [[#quick-start-with-lein][Quick Start with lein]]
@ -53,7 +55,7 @@ This layer adds support for [[https://clojure.org/][Clojure]] language using [[h
- REPL via [[https://github.com/clojure-emacs/cider][CIDER]]
- Code formatting via [[https://github.com/clojure-emacs/cider][CIDER]] using [[https://github.com/weavejester/cljfmt][Cljfmt]]
- Refactoring via [[https://github.com/clojure-emacs/clj-refactor.el][clj-refactor]]
- Linting via [[https://github.com/clojure-emacs/squiggly-clojure][squiggly-clojure]]
- Linting via [[https://github.com/clojure-emacs/squiggly-clojure][squiggly-clojure]], [[https://github.com/borkdude/clj-kondo][clj-kondo]] or [[https://github.com/candid82/joker][joker]]
- Aligning of code forms via [[https://github.com/clojure-emacs/clojure-mode][clojure-mode]]
- Debugging with [[https://github.com/clojure-emacs/sayid][sayid]]
- Clojure cheatsheet
@ -111,20 +113,17 @@ Enabling either of these packages will cause extra nREPL middleware to be
injected when jacking in CIDER.
** Enabling Automatic Linting
[[https://github.com/borkdude/clj-kondo][clj-kondo]] and [[https://github.com/clojure-emacs/squiggly-clojure][squiggly-clojure]] provide automated linting via =flycheck=.
These packages disabled by default as they require the relevant linter binaries
[[https://github.com/borkdude/clj-kondo][clj-kondo]], [[https://github.com/candid82/joker][joker]] and [[https://github.com/clojure-emacs/squiggly-clojure][squiggly-clojure]] provide automated linting via =flycheck=.
These packages are disabled by default as they require the relevant linter binaries
to be installed locally.
The recommended linter is [[https://github.com/borkdude/clj-kondo][clj-kondo]]
The recommended linter is to use [[https://github.com/borkdude/clj-kondo][clj-kondo]] in combination with [[https://github.com/candid82/joker][joker]]. Together they catch the most issues while both running extremely quickly.
squiggly reloads your code on every change which gives unexpected results if
your code is not re-loadable. squiggly also requires =org.clojure/core.typed= be
added to the development dependencies of your projects or build tool when using
=cider-connect=.
Joker is a Clojure linter written in Go and is available separately via the
[[https://github.com/n2o/clojure-lint-spacemacs-layer][unofficial clojure-lint layer]]
*** Enable clj-kondo linter
This linter based on static syntax checking and requires the [[https://github.com/borkdude/clj-kondo][clj-kondo]] binary
installed on the system PATH that =spacemacs.env= includes. Please read the
@ -149,6 +148,30 @@ to your Spacemacs configuration:
)
#+END_SRC
*** Enable joker linter
This linter is based on static syntax checking and requires the [[https://github.com/candid82/joker][joker]] binary
installed on the system PATH that =spacemacs.env= includes. Please read the
[[https://github.com/candid82/joker#installation][joker binary installation instructions]]
Enable the joker automatic linter in Spacemacs by adding a =:variables= option
to your Spacemacs configuration:
#+BEGIN_SRC emacs-lisp
;; Witout any variables your configuration would just include clojure
dotspacemacs-configuration-layers
'(...
clojure
)
;; to use joker as a linter, add this variable to the clojure layer
;; wrapping the clojure layer in a list
dotspacemacs-configuration-layers
'(...
(clojure :variables
clojure-enable-linters 'joker)
)
#+END_SRC
*** Enable Squiggly linter
[[https://github.com/clojure-emacs/squiggly-clojure][squiggly-clojure]] uses [[https://github.com/jonase/eastwood][Eastwood]] and [[https://github.com/jonase/kibit][Kibit]] for linting. Please install these projects
before configuring Spacemacs with =squiggly=.
@ -157,8 +180,7 @@ Make sure to read the [[https://github.com/clojure-emacs/squiggly-clojure#warnin
Please read the section on [[https://github.com/clojure-emacs/squiggly-clojure#dependencies-in-clojure][squiggly dependencies]] if you are using =cider-connect=
Enable the clj-kondo automatic linter in Spacemacs by adding a =:variables= option
to your Spacemacs configuration:
Enable the squiggly (eastwood, kibit and core.typed) automatic linter in Spacemacs by adding a =:variables= option to your Spacemacs configuration:
#+BEGIN_SRC emacs-lisp
;; Without any variables your configuration would just include Clojure
@ -179,6 +201,29 @@ to your Spacemacs configuration:
Troubleshooting: please read [[https://github.com/clojure-emacs/squiggly-clojure#debugging-and-bug-reporting][debugging and bug reporting]] and try to reproduce using the [[https://github.com/clojure-emacs/squiggly-clojure/tree/master/sample-project][sample project]].
*** Enable multiple linters
You can choose to enable multiple linters and have them all run together. This gives you better linting coverage, as they don't catch all the same issues.
You will need to follow their individual install instructions first, to get all their necessary binaries and configs on the system PATH that =spacemacs.env= includes. Please refer to their individual Enable ... linter section respectively.
Once all the linters you want to enable are installed, you simply need to specify a list of them in the =:variables= option to your Spacemacs configuration:
#+BEGIN_SRC emacs-lisp
;; Witout any variables your configuration would just include clojure
dotspacemacs-configuration-layers
'(...
clojure
)
;; to enable multiple linters, say clj-kondo and joker, add a list variable to the clojure layer
;; listing each one in the order you want them running, wrapping the clojure layer in a list
dotspacemacs-configuration-layers
'(...
(clojure :variables
clojure-enable-linters '(clj-kondo joker))
)
#+END_SRC
** Starting Clojure manually (outside of Emacs)
CIDER communicates with your Clojure process through nREPL, and for CIDER to
function correctly extra nREPL middleware needs to be present

View File

@ -20,8 +20,15 @@
eldoc
evil-cleverparens
flycheck
(flycheck-clojure :toggle (eq clojure-enable-linters 'squiggly))
(flycheck-clj-kondo :toggle (eq clojure-enable-linters 'clj-kondo))
(flycheck-clojure :toggle (memq 'squiggly (if (listp clojure-enable-linters)
clojure-enable-linters
(list clojure-enable-linters))))
(flycheck-clj-kondo :toggle (memq 'clj-kondo (if (listp clojure-enable-linters)
clojure-enable-linters
(list clojure-enable-linters))))
(flycheck-joker :toggle (memq 'joker (if (listp clojure-enable-linters)
clojure-enable-linters
(list clojure-enable-linters))))
ggtags
counsel-gtags
helm-gtags
@ -173,9 +180,6 @@
;; add support for golden-ratio
(with-eval-after-load 'golden-ratio
(add-to-list 'golden-ratio-extra-commands 'cider-popup-buffer-quit-function))
;; setup linters. NOTE: It must be done after both CIDER and Flycheck are loaded.
(when (eq clojure-enable-linters 'squiggly)
(with-eval-after-load 'flycheck (flycheck-clojure-setup)))
;; add support for evil
(evil-set-initial-state 'cider-stacktrace-mode 'motion)
(evil-set-initial-state 'cider-popup-buffer-mode 'motion)
@ -435,13 +439,70 @@
(add-hook 'clojure-mode-hook 'parinfer-mode))
(defun clojure/post-init-flycheck ()
;; When user has chosen to use multiple linters.
(when (> (safe-length clojure-enable-linters) 1)
;; If adding a linter, you must add to checkers-per-mode for each mode
;; it can support the mapping from the linter name in clojure-enable-linters
;; to the flycheck checker to use to add to flycheck.
(let* ((checkers-per-mode '((clj . ((clj-kondo . clj-kondo-clj)
(joker . clojure-joker)
(squiggly . clojure-cider-eastwood)))
(cljc . ((clj-kondo . clj-kondo-cljc)
(joker . clojure-joker)))
(cljs . ((clj-kondo . clj-kondo-cljs)
(joker . clojurescript-joker)))
(edn . ((clj-kondo . clj-kondo-edn)
(joker . edn-joker))))))
;; For each checker mode
(dolist (mode-checkers checkers-per-mode)
;; We find the first checker in order from the user configured linters which
;; the mode supports and make it the primary-linter. All other linters after that
;; the mode support is made a next-linter. Finally, we extract the checkers of the
;; primary linter and the next linters.
(let* ((checkers (cdr mode-checkers))
(primary-linter (seq-find (lambda (l)
(assq l checkers))
clojure-enable-linters))
(primary-checker (cdr (assq primary-linter checkers)))
(next-linters (seq-filter (lambda (l)
(and (not (eq l primary-linter))
(assq l checkers)))
clojure-enable-linters))
(next-checkers (mapcar (lambda (l)
(cdr (assq l checkers)))
next-linters)))
;; Move primary checker to the front of flycheck lists of checkers so that
;; it is used as the primary checker, because flycheck picks the first one
;; it finds.
(delq primary-checker flycheck-checkers)
(push primary-checker flycheck-checkers)
;; For every checker, set their next checkers, starting with the primary
;; checker which has all others has a next-checker, and then the next
;; one has all the ones after it, and so on, until the last one which
;; has no next-checker to be added. This is because flycheck next-checkers
;; must be nested if we want more than two to run. It will pick the first
;; available next-checker from next-checkers and run that after. If we want
;; a checker after that one, it must also have next-checkers configured.
(let ((checkers-to-add next-checkers))
(dolist (checker (cons primary-checker next-checkers))
(dolist (next-checker checkers-to-add)
(flycheck-add-next-checker checker next-checker t))
(setq checkers-to-add (cdr checkers-to-add))))))))
(spacemacs|forall-clojure-modes m
(spacemacs/enable-flycheck m)))
(defun clojure/init-flycheck-clojure ()
(use-package flycheck-clojure
:if (configuration-layer/package-usedp 'flycheck)))
:if (configuration-layer/package-usedp 'flycheck)
:config (progn
(flycheck-clojure-setup)
(with-eval-after-load 'cider
(flycheck-clojure-inject-jack-in-dependencies)))))
(defun clojure/init-flycheck-clj-kondo ()
(use-package flycheck-clj-kondo
:if (configuration-layer/package-usedp 'flycheck)))
(defun clojure/init-flycheck-joker ()
(use-package flycheck-joker
:if (configuration-layer/package-usedp 'flycheck)))