init-clojure.el 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. ;;; init-clojure.el --- Clojure Configuration File -*- lexical-binding: t -*-
  2. ;;; Commentary:
  3. ;;; Code:
  4. ;(require 'init-lisp)
  5. (use-package yasnippet
  6. :diminish yas-minor-mode)
  7. (use-package flycheck-clj-kondo)
  8. (use-package clojure-mode
  9. :config
  10. (require 'flycheck-clj-kondo)
  11. (define-abbrev-table 'clojure-mode-abbrev-table
  12. '(("scs" "#sc/spy")
  13. ("scp" "#spy/p")
  14. ("scd" "#spy/d")
  15. ("sct" "#spy/t")
  16. ("ms" "(miracle.save/save)" backward-char)
  17. ("ddb" "#d/dbg")
  18. ("db" "#d/dbg")
  19. ("dbn" "#d/dbgn")
  20. ("ddn" "#d/dbgn")
  21. ("sc" "#sc/spy")
  22. ("sd" "#spy/d")
  23. ("sp" "#spy/p")
  24. ("st" "#spy/t")))
  25. (defalias 'cape-clojure (cape-capf-super #'cider-complete-at-point
  26. #'lsp-completion-at-point
  27. #'cape-dabbrev))
  28. (defun set-clojure-capf ()
  29. (add-hook 'completion-at-point-functions #'cape-clojure -99 t))
  30. (defun clojure-mode-hook-fn ()
  31. (set-clojure-capf)
  32. (subword-mode +1))
  33. ;; https://github.com/weavejester/compojure/wiki/Emacs-indentation
  34. (define-clojure-indent
  35. (defroutes 'defun)
  36. (GET 2)
  37. (POST 2)
  38. (PUT 2)
  39. (DELETE 2)
  40. (HEAD 2)
  41. (ANY 2)
  42. (OPTIONS 2)
  43. (PATCH 2)
  44. (rfn 2)
  45. (let-routes 1)
  46. (context 2))
  47. ;; https://github.com/magnars/.emacs.d/blob/04426922530edc3ebe9bae7a86632e3b1956049d/settings/setup-clojure-mode.el#L494-L537
  48. (defun my/cider-looking-at-lets? ()
  49. (or (looking-at "(let ")
  50. (looking-at "(letfn ")
  51. (looking-at "(when-let ")
  52. (looking-at "(if-let ")))
  53. (defun my/cider-collect-lets (&optional max-point)
  54. (let* ((beg-of-defun (save-excursion (beginning-of-defun) (point)))
  55. (lets nil))
  56. (save-excursion
  57. (while (not (= (point) beg-of-defun))
  58. (paredit-backward-up 1)
  59. (when (my/cider-looking-at-lets?)
  60. (save-excursion
  61. (let ((beg (point)))
  62. (paredit-forward-down 1)
  63. (paredit-forward 2)
  64. (when (and max-point (< max-point (point)))
  65. (goto-char max-point))
  66. (setq lets (cons (concat (buffer-substring-no-properties beg (point))
  67. (if max-point "]" ""))
  68. lets))))))
  69. lets)))
  70. (defun my/inside-let-block? ()
  71. (save-excursion
  72. (paredit-backward-up 2)
  73. (my/cider-looking-at-lets?)))
  74. (defun my/cider-eval-including-lets (&optional output-to-current-buffer)
  75. "Evaluates the current sexp form, wrapped in all parent lets."
  76. (interactive "P")
  77. (let* ((beg-of-sexp (save-excursion (paredit-backward 1) (point)))
  78. (code (buffer-substring-no-properties beg-of-sexp (point)))
  79. (lets (my/cider-collect-lets (when (my/inside-let-block?)
  80. (save-excursion (paredit-backward 2) (point)))))
  81. (code (concat (s-join " " lets)
  82. " " code
  83. (s-repeat (length lets) ")"))))
  84. (cider-interactive-eval code
  85. (when output-to-current-buffer
  86. (cider-eval-print-handler))
  87. nil
  88. (cider--nrepl-pr-request-map))))
  89. :init
  90. ;; Always show more of the path in clj buffer names.
  91. ;; Using setq-local in clojure-mode-hook is not enough, as it runs too late
  92. (defun clj-uniquify-get-proposed-name (orig base dirname &optional depth original-dirname)
  93. (when (and (> (length base) 4)
  94. (string= ".clj" (substring base -4))
  95. (not (string= "project.clj" base)))
  96. (setq-local uniquify-min-dir-content 3))
  97. (funcall orig base dirname depth original-dirname))
  98. (advice-add 'uniquify-get-proposed-name :around 'clj-uniquify-get-proposed-name)
  99. :hook
  100. (clojure-mode . clojure-mode-hook-fn))
  101. (use-package clj-refactor
  102. :diminish
  103. :bind ("C-c @" . hydra-cljr-help-menu/body)
  104. :custom
  105. (cljr-suppress-no-project-warning t)
  106. (cljr-add-ns-to-blank-clj-files nil) ; disable clj-refactor adding ns to blank files
  107. (cljr-slash-uses-suggest-libspec t)
  108. :config
  109. (cljr-add-keybindings-with-prefix "C-c C-m")
  110. (defun clj-refactor-hook-fn ()
  111. (clj-refactor-mode 1)
  112. (yas-minor-mode 1))
  113. :hook
  114. (clojure-mode . clj-refactor-hook-fn))
  115. (use-package cider
  116. :diminish
  117. :config
  118. (cider-enable-flex-completion)
  119. (defvar cider-main-function "-main")
  120. (defun cider-repl-mode-hook-fn ()
  121. (display-line-numbers-mode -1)
  122. (subword-mode +1))
  123. (defun cider-mode-hook-fn ()
  124. (eldoc-mode 1)
  125. ;; Remove this, as we use cape-clojure (in init-clojure.el), which includes
  126. ;; cider-complete-at-point
  127. (remove-hook 'completion-at-point-functions #'cider-complete-at-point t))
  128. (defun run-and-unhook ()
  129. (remove-hook 'cider-connected-hook 'run-and-unhook)
  130. (run-main))
  131. (defun run-main ()
  132. (interactive)
  133. (cider-insert-in-repl (concat "(" cider-main-function ")") t))
  134. (defun cider-jack-in-and-run-main (arg &rest params)
  135. (interactive "P")
  136. (add-hook 'cider-connected-hook 'run-and-unhook)
  137. (cider-jack-in params))
  138. (defun load-debug-namespaces ()
  139. (interactive)
  140. (cider-interactive-eval "(require 'snitch.core)" nil nil (cider--nrepl-pr-request-map))
  141. (cider-interactive-eval "(require 'miracle.save)" nil nil (cider--nrepl-pr-request-map))
  142. (cider-interactive-eval "(require 'sc.api)" nil nil (cider--nrepl-pr-request-map))
  143. (cider-interactive-eval "(require '[debux.cs.core :refer [dbg dbgn dbgt]])" nil nil (cider--nrepl-pr-request-map)))
  144. (defun cider-toggle-boolean ()
  145. (interactive)
  146. (let ((opposite (pcase (cider-symbol-at-point)
  147. ("false" "true")
  148. ("true" "false"))))
  149. (when opposite
  150. (pcase-let ((`(,start . ,end) (bounds-of-thing-at-point 'symbol)))
  151. (delete-region start end))
  152. (insert opposite))))
  153. (define-abbrev-table 'cider-repl-mode-abbrev-table
  154. '(("scl" "(eval `(sc.api/defsc ~(sc.api/last-ep-id)))" cider-repl-return)
  155. ("scs" "(sc.api/defsc*)" cider-repl-return)
  156. ("scd" "(sc.api/defsc)" backward-char)
  157. ("ms" "(use 'miracle.save)" cider-repl-return)
  158. ("ld" "(ld)" backward-char)
  159. ("ps" "(print-saves)" backward-char)
  160. ("sv" "(save-var*)" backward-char)
  161. ("usv" "(unsave-var*)" backward-char)
  162. ("sn" "(save-ns*)" backward-char)
  163. ("usn" "(unsave-ns*)" backward-char)
  164. ("fs" "@f-saves")
  165. ("ldf" "(ld)" backward-char)
  166. ("pfs" "(print-f-saves)" backward-char)
  167. ("scr" "(use 'spyscope.repl)" cider-repl-return)))
  168. (setq cider-repl-pop-to-buffer-on-connect 'display-only
  169. cider-repl-display-help-banner nil
  170. cider-repl-history-highlight-current-entry t
  171. cider-repl-history-highlight-inserted-item t
  172. cider-repl-use-clojure-font-lock t
  173. cider-repl-use-pretty-printing t
  174. cider-save-file-on-load t
  175. cider-test-show-report-on-success t
  176. ;; cider-invert-insert-eval-p t
  177. ;; cider-switch-to-repl-on-insert nil
  178. cider-xref-fn-depth 90
  179. cider-repl-history-file ".cider-repl-history"
  180. ;; nrepl-log-messages t
  181. cider-connection-message-fn nil
  182. cider-show-error-buffer 'except-in-repl
  183. cider-test-fail-fast nil
  184. clojure-toplevel-inside-comment-form t)
  185. (setq cider-clojure-compilation-error-phases nil)
  186. (setq-default cider-use-overlays t)
  187. (unbind-key "C-c C-l" cider-mode-map)
  188. (unbind-key "C-c C-b" cider-mode-map)
  189. (unbind-key "C-c C-b" cider-repl-mode-map)
  190. (defun fix-duplicate-windows ()
  191. "When all windows are the same, delete all of them except the current one."
  192. (when (apply #'eq (mapcar 'window-buffer (window-list)))
  193. (delete-other-windows)))
  194. (advice-add #'cider-close-ancillary-buffers :after #'fix-duplicate-windows)
  195. :bind
  196. (:map cider-mode-map
  197. ("C-c M-l" . cider-load-file)
  198. ("C-c M-b" . cider-interrupt)
  199. ("C-x M-i e" . cider-inspect-last-sexp)
  200. ("C-x M-i f" . cider-inspect-defun-at-point)
  201. ("C-x M-i l" . cider-inspect-last-result)
  202. ("C-x M-i v" . cider-inspect-expr))
  203. (:map cider-repl-mode-map
  204. ("C-c M-b" . cider-interrupt)
  205. ;; sp commands sometimes behave strangely in the cider repl buffer
  206. ("M-d" . paredit-forward-kill-word)
  207. ("M-DEL" . paredit-backward-kill-word)
  208. ("C-k" . paredit-kill)
  209. ("C-x M-i e" . cider-inspect-last-sexp)
  210. ("C-x M-i f" . cider-inspect-defun-at-point)
  211. ("C-x M-i l" . cider-inspect-last-result)
  212. ("C-x M-i v" . cider-inspect-expr))
  213. (:map cider-start-map
  214. ("C-c C-M-j" . cider-jack-in-and-run-main))
  215. (:map clojure-mode-map
  216. ("C-c C-r C-m" . run-main)
  217. ("C-c C-r C-d" . load-debug-namespaces)
  218. ("C-c C-M-j" . cider-jack-in-and-run-main)
  219. ("C-x p q" . project-clojure-test-switch)
  220. ("C-c C-M-c" . (lambda () (interactive) (cider-clear-compilation-highlights t)))
  221. ("C-c C->" . cider-find-dwim)
  222. ("C-x 4 C->" . cider-find-dwim-other-window))
  223. :hook
  224. (cider-repl-mode . cider-repl-mode-hook-fn)
  225. (cider-mode . cider-mode-hook-fn))
  226. (use-package babashka)
  227. (use-package jet
  228. :bind ("C-c j" . jet))
  229. (provide 'init-clojure)
  230. ;;; init-clojure.el ends here