featurep! will be renamed modulep! in the future, so it's been deprecated. They have identical interfaces, and can be replaced without issue. featurep! was never quite the right name for this macro. It implied that it had some connection to featurep, which it doesn't (only that it was similar in purpose; still, Doom modules are not features). To undo such implications and be consistent with its namespace (and since we're heading into a storm of breaking changes with the v3 release anyway), now was the best opportunity to begin the transition.
260 lines
10 KiB
EmacsLisp
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 (modulep! +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 (modulep! +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 (modulep! +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 (modulep! :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 (modulep! :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 (modulep! :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 (modulep! +lsp)
|
|
(set-lookup-handlers! 'clj-refactor-mode
|
|
:references #'cljr-find-usages))
|
|
(when (modulep! +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 (modulep! :checkers syntax)
|
|
(not (modulep! +lsp)))
|
|
:after flycheck)
|