doomemacs/modules/lang/clojure/config.el
Henrik Lissner 3239ab8b2e
nit(mu4e): neutralize comments
Some of our comments/docs can come off as disparaging or snide. They're
glimpses of unfiltered frustration or snarky rubber ducking gone too
far, something I can totally sympathize with, as a scatterbrained
tinkerer, unwittingly made responsible for a lot of work that isn't mine
because of Doom's position as a middleman. But now that Doom has a
veritable userbase, I'd like to hold it to a higher standard.

Light-hearted banter and aired grievances in our source code,
documentation, or community are fine if focused on the problem or the
personal/shared experiences of the community (things that offer value or
amusement to others), but it is never acceptable to attack people or
their efforts. Especially not the very people on whose shoulders Doom
stands.

I sincerely apologize if these have offended you.

Amend: b07614037f
2022-08-14 20:36:42 +02:00

260 lines
10 KiB
EmacsLisp

;;; lang/clojure/config.el -*- lexical-binding: t; -*-
(after! projectile
(pushnew! projectile-project-root-files "project.clj" "build.boot" "deps.edn"))
;; Large clojure buffers tend to be slower than large buffers of other modes, so
;; it should have a lower threshold too.
(add-to-list 'doom-large-file-size-alist '("\\.\\(?:clj[sc]?\\|dtm\\|edn\\)\\'" . 0.5))
;;
;;; Packages
(use-package! clojure-mode
:hook (clojure-mode . rainbow-delimiters-mode)
:config
(when (featurep! +lsp)
(add-hook! '(clojure-mode-local-vars-hook
clojurec-mode-local-vars-hook
clojurescript-mode-local-vars-hook)
:append
(defun +clojure-disable-lsp-indentation-h ()
(setq-local lsp-enable-indentation nil))
#'lsp!)
(after! lsp-clojure
(dolist (m '(clojure-mode
clojurec-mode
clojurescript-mode
clojurex-mode))
(add-to-list 'lsp-language-id-configuration (cons m "clojure"))))))
(use-package! cider
;; NOTE if `org-directory' doesn't exist, `cider-jack' in won't work
:hook (clojure-mode-local-vars . cider-mode)
:init
(after! clojure-mode
(set-repl-handler! '(clojure-mode clojurec-mode) #'+clojure/open-repl :persist t)
(set-repl-handler! 'clojurescript-mode #'+clojure/open-cljs-repl :persist t)
(set-eval-handler! '(clojure-mode clojurescript-mode clojurec-mode) #'cider-eval-region))
;; HACK Fix radian-software/radian#446: CIDER tries to calculate the frame's
;; background too early; sometimes before the initial frame has been
;; initialized, causing errors.
(defvar cider-docview-code-background-color nil)
(defvar cider-stacktrace-frames-background-color nil)
(add-transient-hook! #'cider-docview-fontify-code-blocks (cider--docview-adapt-to-theme))
(add-transient-hook! #'cider-stacktrace-render-cause (cider--stacktrace-adapt-to-theme))
:config
(add-hook 'cider-mode-hook #'eldoc-mode)
(unless (featurep! +lsp)
(set-lookup-handlers! '(cider-mode cider-repl-mode)
:definition #'+clojure-cider-lookup-definition
:documentation #'cider-doc))
(set-popup-rules!
'(("^\\*cider-error*" :ignore t)
("^\\*cider-repl" :quit nil :ttl nil)
("^\\*cider-repl-history" :vslot 2 :ttl nil)))
(setq nrepl-hide-special-buffers t
nrepl-log-messages nil
cider-font-lock-dynamically '(macro core function var deprecated)
cider-overlays-use-font-lock t
cider-prompt-for-symbol nil
cider-repl-history-display-duplicates nil
cider-repl-history-display-style 'one-line
cider-repl-history-file (concat doom-cache-dir "cider-repl-history")
cider-repl-history-highlight-current-entry t
cider-repl-history-quit-action 'delete-and-restore
cider-repl-history-highlight-inserted-item t
cider-repl-history-size 1000
cider-repl-result-prefix ";; => "
cider-repl-print-length 100
cider-repl-use-clojure-font-lock t
cider-repl-use-pretty-printing t
cider-repl-wrap-history nil
cider-stacktrace-default-filters '(tooling dup)
;; Don't focus the CIDER REPL when it starts. Since it can take so long
;; to start up, you either wait for a minute doing nothing or be
;; prepared for your cursor to suddenly change buffers without warning.
;; See https://github.com/clojure-emacs/cider/issues/1872
cider-repl-pop-to-buffer-on-connect 'display-only)
(when (featurep! +lsp)
(setq cider-eldoc-display-for-symbol-at-point nil
cider-font-lock-dynamically nil)
(add-hook! 'cider-mode-hook
(defun +clojure--cider-disable-completion ()
"Use lsp completion instead of cider."
(remove-hook 'completion-at-point-functions #'cider-complete-at-point t))))
;; UX: CIDER's error messages get quietly funneled into *nrepl-server*. That
;; sort of information would be more helpful displayed front and center when
;; opening a *cider-repl*.
(add-hook! 'cider-connected-hook
(defun +clojure--cider-dump-nrepl-server-log-h ()
"Copy contents of *nrepl-server* to beginning of *cider-repl*."
(when (buffer-live-p nrepl-server-buffer)
(save-excursion
(goto-char (point-min))
(insert
(with-current-buffer nrepl-server-buffer
(buffer-string)))))))
;; When in cider-debug-mode, override evil keys to not interfere with debug keys
(after! evil
(add-hook! cider--debug-mode
(defun +clojure--cider-setup-debug ()
"Setup cider debug to override evil keys cleanly"
(evil-make-overriding-map cider--debug-mode-map 'normal)
(evil-normalize-keymaps))))
(when (featurep! :ui modeline +light)
(defvar-local cider-modeline-icon nil)
(defun +clojure--cider-set-modeline (face label)
"Update repl icon on modeline with cider information."
(setq cider-modeline-icon (concat
" "
(+modeline-format-icon 'faicon "terminal" "" face label -0.0575)
" "))
(add-to-list 'global-mode-string
'(t (:eval cider-modeline-icon))
'append))
(add-hook! '(cider-connected-hook
cider-disconnected-hook
cider-mode-hook)
(defun +clojure--cider-connected-update-modeline ()
"Update modeline with cider connection state."
(let* ((connected (cider-connected-p))
(face (if connected 'warning 'breakpoint-disabled))
(label (if connected "Cider connected" "Cider disconnected")))
(+clojure--cider-set-modeline face label))))
(add-hook! '(cider-before-eval-hook)
(defun +clojure--cider-before-eval-hook-update-modeline ()
"Update modeline with cider state before eval."
(+clojure--cider-set-modeline 'warning "Cider evaluating")))
(add-hook! '(cider-after-eval-done-hook)
(defun +clojure--cider-after-eval-done-hook-update-modeline ()
"Update modeline with cider state after eval."
(+clojure--cider-set-modeline 'success "Cider syncronized")))
(add-hook! '(cider-file-loaded-hook)
(defun +clojure--cider-file-loaded-update-modeline ()
"Update modeline with cider file loaded state."
(+clojure--cider-set-modeline 'success "Cider syncronized"))))
;; Ensure that CIDER is used for sessions in org buffers.
(when (featurep! :lang org)
(after! ob-clojure
(setq! org-babel-clojure-backend 'cider)))
;; The CIDER welcome message obscures error messages that the above code is
;; supposed to be make visible.
(setq cider-repl-display-help-banner nil)
(map! (:localleader
(:map (clojure-mode-map clojurescript-mode-map clojurec-mode-map)
"'" #'cider-jack-in-clj
"\"" #'cider-jack-in-cljs
"c" #'cider-connect-clj
"C" #'cider-connect-cljs
"m" #'cider-macroexpand-1
"M" #'cider-macroexpand-all
(:prefix ("d" . "debug")
"d" #'cider-debug-defun-at-point)
(:prefix ("e" . "eval")
"b" #'cider-eval-buffer
"d" #'cider-eval-defun-at-point
"D" #'cider-insert-defun-in-repl
"e" #'cider-eval-last-sexp
"E" #'cider-insert-last-sexp-in-repl
"r" #'cider-eval-region
"R" #'cider-insert-region-in-repl
"u" #'cider-undef)
(:prefix ("g" . "goto")
"b" #'cider-pop-back
"g" #'cider-find-var
"n" #'cider-find-ns)
(:prefix ("h" . "help")
"n" #'cider-find-ns
"a" #'cider-apropos
"c" #'cider-clojuredocs
"d" #'cider-doc
"j" #'cider-javadoc
"w" #'cider-clojuredocs-web)
(:prefix ("i" . "inspect")
"e" #'cider-enlighten-mode
"i" #'cider-inspect
"r" #'cider-inspect-last-result)
(:prefix ("n" . "namespace")
"n" #'cider-browse-ns
"N" #'cider-browse-ns-all
"r" #'cider-ns-refresh)
(:prefix ("p" . "print")
"p" #'cider-pprint-eval-last-sexp
"P" #'cider-pprint-eval-last-sexp-to-comment
"d" #'cider-pprint-eval-defun-at-point
"D" #'cider-pprint-eval-defun-to-comment
"r" #'cider-pprint-eval-last-sexp-to-repl)
(:prefix ("r" . "repl")
"n" #'cider-repl-set-ns
"q" #'cider-quit
"r" #'cider-ns-refresh
"R" #'cider-restart
"b" #'cider-switch-to-repl-buffer
"B" #'+clojure/cider-switch-to-repl-buffer-and-switch-ns
"c" #'cider-find-and-clear-repl-output
"l" #'cider-load-buffer
"L" #'cider-load-buffer-and-switch-to-repl-buffer)
(:prefix ("t" . "test")
"a" #'cider-test-rerun-test
"l" #'cider-test-run-loaded-tests
"n" #'cider-test-run-ns-tests
"p" #'cider-test-run-project-tests
"r" #'cider-test-rerun-failed-tests
"s" #'cider-test-run-ns-tests-with-filters
"t" #'cider-test-run-test)))
(:when (featurep! :editor evil +everywhere)
:map cider-repl-mode-map
:i [S-return] #'cider-repl-newline-and-indent
:i [M-return] #'cider-repl-return
(:localleader
"n" #'cider-repl-set-ns
"q" #'cider-quit
"r" #'cider-ns-refresh
"R" #'cider-restart
"c" #'cider-repl-clear-buffer)
:map cider-repl-history-mode-map
:i [return] #'cider-repl-history-insert-and-quit
:i "q" #'cider-repl-history-quit
:i "l" #'cider-repl-history-occur
:i "s" #'cider-repl-history-search-forward
:i "r" #'cider-repl-history-search-backward
:i "U" #'cider-repl-history-undo-other-window)))
(use-package! clj-refactor
:hook (clojure-mode . clj-refactor-mode)
:config
(unless (featurep! +lsp)
(set-lookup-handlers! 'clj-refactor-mode
:references #'cljr-find-usages))
(when (featurep! +lsp)
(setq cljr-add-ns-to-blank-clj-files nil))
(map! :map clojure-mode-map
:localleader
:desc "refactor" "R" #'hydra-cljr-help-menu/body))
;; clojure-lsp already uses clj-kondo under the hood
(use-package! flycheck-clj-kondo
:when (and (featurep! :checkers syntax)
(not (featurep! +lsp)))
:after flycheck)