Klimi's new dotfiles with stow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1072 lines
46 KiB

5 years ago
  1. ;;; cider-mode.el --- Minor mode for REPL interactions -*- lexical-binding: t -*-
  2. ;; Copyright © 2012-2013 Tim King, Phil Hagelberg, Bozhidar Batsov
  3. ;; Copyright © 2013-2019 Bozhidar Batsov, Artur Malabarba and CIDER contributors
  4. ;;
  5. ;; Author: Tim King <kingtim@gmail.com>
  6. ;; Phil Hagelberg <technomancy@gmail.com>
  7. ;; Bozhidar Batsov <bozhidar@batsov.com>
  8. ;; Artur Malabarba <bruce.connor.am@gmail.com>
  9. ;; Hugo Duncan <hugo@hugoduncan.org>
  10. ;; Steve Purcell <steve@sanityinc.com>
  11. ;; This program is free software: you can redistribute it and/or modify
  12. ;; it under the terms of the GNU General Public License as published by
  13. ;; the Free Software Foundation, either version 3 of the License, or
  14. ;; (at your option) any later version.
  15. ;; This program is distributed in the hope that it will be useful,
  16. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. ;; GNU General Public License for more details.
  19. ;; You should have received a copy of the GNU General Public License
  20. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. ;; This file is not part of GNU Emacs.
  22. ;;; Commentary:
  23. ;; Minor mode for REPL interactions.
  24. ;;; Code:
  25. (require 'clojure-mode)
  26. (require 'cider-eval)
  27. (require 'cider-test) ; required only for the menu
  28. (require 'cider-eldoc)
  29. (require 'cider-resolve)
  30. (require 'cider-doc) ; required only for the menu
  31. (require 'cider-profile) ; required only for the menu
  32. (require 'cider-completion)
  33. (require 'subr-x)
  34. (require 'cider-compat)
  35. (defcustom cider-mode-line-show-connection t
  36. "If the mode-line lighter should detail the connection."
  37. :group 'cider
  38. :type 'boolean
  39. :package-version '(cider "0.10.0"))
  40. (defun cider--modeline-info ()
  41. "Return info for the cider mode modeline.
  42. Info contains the connection type, project name and host:port endpoint."
  43. (if-let* ((current-connection (ignore-errors (cider-current-repl))))
  44. (with-current-buffer current-connection
  45. (concat
  46. (symbol-name cider-repl-type)
  47. (when cider-mode-line-show-connection
  48. (format ":%s@%s:%s"
  49. (or (cider--project-name nrepl-project-dir) "<no project>")
  50. (pcase (car nrepl-endpoint)
  51. ("localhost" "")
  52. (x x))
  53. (cadr nrepl-endpoint)))))
  54. "not connected"))
  55. ;;;###autoload
  56. (defcustom cider-mode-line
  57. '(:eval (format " cider[%s]" (cider--modeline-info)))
  58. "Mode line lighter for cider mode.
  59. The value of this variable is a mode line template as in
  60. `mode-line-format'. See Info Node `(elisp)Mode Line Format' for details
  61. about mode line templates.
  62. Customize this variable to change how cider mode displays its status in the
  63. mode line. The default value displays the current connection. Set this
  64. variable to nil to disable the mode line entirely."
  65. :group 'cider
  66. :type 'sexp
  67. :risky t
  68. :package-version '(cider "0.7.0"))
  69. ;;; Switching between REPL & source buffers
  70. (defun cider--switch-to-repl-buffer (repl-buffer &optional set-namespace)
  71. "Select the REPL-BUFFER, when possible in an existing window.
  72. When SET-NAMESPACE is t, sets the namespace in the REPL buffer to
  73. that of the namespace in the Clojure source buffer."
  74. (let ((buffer (current-buffer)))
  75. ;; first we switch to the REPL buffer
  76. (if cider-repl-display-in-current-window
  77. (pop-to-buffer-same-window repl-buffer)
  78. (pop-to-buffer repl-buffer))
  79. ;; then if necessary we update its namespace
  80. (when set-namespace
  81. (cider-repl-set-ns (with-current-buffer buffer (cider-current-ns))))
  82. (goto-char (point-max))))
  83. (defun cider-switch-to-repl-buffer (&optional set-namespace)
  84. "Switch to current REPL buffer, when possible in an existing window.
  85. The type of the REPL is inferred from the mode of current buffer. With a
  86. prefix arg SET-NAMESPACE sets the namespace in the REPL buffer to that of
  87. the namespace in the Clojure source buffer"
  88. (interactive "P")
  89. (cider--switch-to-repl-buffer
  90. (cider-current-repl nil 'ensure)
  91. set-namespace))
  92. (declare-function cider-load-buffer "cider-eval")
  93. (defun cider-load-buffer-and-switch-to-repl-buffer (&optional set-namespace)
  94. "Load the current buffer into the matching REPL buffer and switch to it.
  95. When SET-NAMESPACE is true, we'll also set the REPL's ns to match that of the
  96. Clojure buffer."
  97. (interactive "P")
  98. (cider-load-buffer)
  99. (cider-switch-to-repl-buffer set-namespace))
  100. (defun cider-switch-to-last-clojure-buffer ()
  101. "Switch to the last Clojure buffer.
  102. The default keybinding for this command is
  103. the same as variable `cider-switch-to-repl-buffer',
  104. so that it is very convenient to jump between a
  105. Clojure buffer and the REPL buffer."
  106. (interactive)
  107. (if (derived-mode-p 'cider-repl-mode)
  108. (let* ((a-buf)
  109. (the-buf (let ((repl-type (cider-repl-type-for-buffer)))
  110. (seq-find (lambda (b)
  111. (unless (with-current-buffer b (derived-mode-p 'cider-repl-mode))
  112. (when-let* ((type (cider-repl-type-for-buffer b)))
  113. (unless a-buf
  114. (setq a-buf b))
  115. (or (eq type 'multi)
  116. (eq type repl-type)))))
  117. (buffer-list)))))
  118. (if-let* ((buf (or the-buf a-buf)))
  119. (if cider-repl-display-in-current-window
  120. (pop-to-buffer-same-window buf)
  121. (pop-to-buffer buf))
  122. (user-error "No Clojure buffer found")))
  123. (user-error "Not in a CIDER REPL buffer")))
  124. (defun cider-find-and-clear-repl-output (&optional clear-repl)
  125. "Find the current REPL buffer and clear it.
  126. With a prefix argument CLEAR-REPL the command clears the entire REPL
  127. buffer. Returns to the buffer in which the command was invoked. See also
  128. the related commands `cider-repl-clear-buffer' and
  129. `cider-repl-clear-output'."
  130. (interactive "P")
  131. (let ((origin-buffer (current-buffer)))
  132. (switch-to-buffer (cider-current-repl nil 'ensure))
  133. (if clear-repl
  134. (cider-repl-clear-buffer)
  135. (cider-repl-clear-output))
  136. (switch-to-buffer origin-buffer)))
  137. (defun cider-undef ()
  138. "Undefine a symbol from the current ns."
  139. (interactive)
  140. (cider-ensure-op-supported "undef")
  141. (cider-read-symbol-name
  142. "Undefine symbol: "
  143. (lambda (sym)
  144. (cider-nrepl-send-request
  145. `("op" "undef"
  146. "ns" ,(cider-current-ns)
  147. "symbol" ,sym)
  148. (cider-interactive-eval-handler (current-buffer))))))
  149. ;;; cider-run
  150. (defvar cider--namespace-history nil
  151. "History of user input for namespace prompts.")
  152. (defun cider--var-namespace (var)
  153. "Return the namespace of VAR.
  154. VAR is a fully qualified Clojure variable name as a string."
  155. (replace-regexp-in-string "\\(?:#'\\)?\\(.*\\)/.*" "\\1" var))
  156. (defun cider-run (&optional function)
  157. "Run -main or FUNCTION, prompting for its namespace if necessary.
  158. With a prefix argument, prompt for function to run instead of -main."
  159. (interactive (list (when current-prefix-arg (read-string "Function name: "))))
  160. (cider-ensure-connected)
  161. (let ((name (or function "-main")))
  162. (when-let* ((response (cider-nrepl-send-sync-request
  163. `("op" "ns-list-vars-by-name"
  164. "name" ,name))))
  165. (if-let* ((vars (split-string (substring (nrepl-dict-get response "var-list") 1 -1))))
  166. (cider-interactive-eval
  167. (if (= (length vars) 1)
  168. (concat "(" (car vars) ")")
  169. (let* ((completions (mapcar #'cider--var-namespace vars))
  170. (def (or (car cider--namespace-history)
  171. (car completions))))
  172. (format "(#'%s/%s)"
  173. (completing-read (format "Namespace (%s): " def)
  174. completions nil t nil
  175. 'cider--namespace-history def)
  176. name))))
  177. (user-error "No %s var defined in any namespace" (cider-propertize name 'fn))))))
  178. ;;; Insert (and eval) in REPL functionality
  179. (defvar cider-insert-commands-map
  180. (let ((map (define-prefix-command 'cider-insert-commands-map)))
  181. ;; single key bindings defined last for display in menu
  182. (define-key map (kbd "e") #'cider-insert-last-sexp-in-repl)
  183. (define-key map (kbd "d") #'cider-insert-defun-in-repl)
  184. (define-key map (kbd "r") #'cider-insert-region-in-repl)
  185. (define-key map (kbd "n") #'cider-insert-ns-form-in-repl)
  186. ;; duplicates with C- for convenience
  187. (define-key map (kbd "C-e") #'cider-insert-last-sexp-in-repl)
  188. (define-key map (kbd "C-d") #'cider-insert-defun-in-repl)
  189. (define-key map (kbd "C-r") #'cider-insert-region-in-repl)
  190. (define-key map (kbd "C-n") #'cider-insert-ns-form-in-repl)))
  191. (defcustom cider-switch-to-repl-after-insert-p t
  192. "Whether to switch to the repl after inserting a form into the repl."
  193. :type 'boolean
  194. :group 'cider
  195. :package-version '(cider . "0.18.0"))
  196. (define-obsolete-variable-alias
  197. 'cider-switch-to-repl-after-insert-p
  198. 'cider-switch-to-repl-on-insert
  199. "0.21.0")
  200. (defcustom cider-switch-to-repl-on-insert t
  201. "Whether to switch to the repl when inserting a form into the repl."
  202. :type 'boolean
  203. :group 'cider
  204. :package-version '(cider . "0.21.0"))
  205. (defcustom cider-invert-insert-eval-p nil
  206. "Whether to invert the behavior of evaling.
  207. Default behavior when inserting is to NOT eval the form and only eval with
  208. a prefix. This allows to invert this so that default behavior is to insert
  209. and eval and the prefix is required to prevent evaluation."
  210. :type 'boolean
  211. :group 'cider
  212. :package-version '(cider . "0.18.0"))
  213. (defun cider-insert-in-repl (form eval)
  214. "Insert FORM in the REPL buffer and switch to it.
  215. If EVAL is non-nil the form will also be evaluated. Use
  216. `cider-invert-insert-eval-p' to invert this behavior."
  217. (while (string-match "\\`[ \t\n\r]+\\|[ \t\n\r]+\\'" form)
  218. (setq form (replace-match "" t t form)))
  219. (when cider-switch-to-repl-on-insert
  220. (cider-switch-to-repl-buffer))
  221. (let ((repl (cider-current-repl)))
  222. (with-selected-window (or (get-buffer-window repl)
  223. (selected-window))
  224. (with-current-buffer repl
  225. (goto-char (point-max))
  226. (let ((beg (point)))
  227. (insert form)
  228. (indent-region beg (point))
  229. (cider--font-lock-ensure beg (point)))
  230. (when (if cider-invert-insert-eval-p
  231. (not eval)
  232. eval)
  233. (cider-repl-return))
  234. (goto-char (point-max))))))
  235. (defun cider-insert-last-sexp-in-repl (&optional arg)
  236. "Insert the expression preceding point in the REPL buffer.
  237. If invoked with a prefix ARG eval the expression after inserting it."
  238. (interactive "P")
  239. (cider-insert-in-repl (cider-last-sexp) arg))
  240. (defun cider-insert-defun-in-repl (&optional arg)
  241. "Insert the top level form at point in the REPL buffer.
  242. If invoked with a prefix ARG eval the expression after inserting it."
  243. (interactive "P")
  244. (cider-insert-in-repl (cider-defun-at-point) arg))
  245. (defun cider-insert-region-in-repl (start end &optional arg)
  246. "Insert the curent region in the REPL buffer.
  247. START and END represent the region's boundaries.
  248. If invoked with a prefix ARG eval the expression after inserting it."
  249. (interactive "rP")
  250. (cider-insert-in-repl
  251. (buffer-substring-no-properties start end) arg))
  252. (defun cider-insert-ns-form-in-repl (&optional arg)
  253. "Insert the current buffer's ns form in the REPL buffer.
  254. If invoked with a prefix ARG eval the expression after inserting it."
  255. (interactive "P")
  256. (cider-insert-in-repl (cider-ns-form) arg))
  257. ;;; The menu-bar
  258. (defconst cider-mode-menu
  259. `("CIDER"
  260. ["Start or connect to any REPL" cider
  261. :help "A simple wrapper around all commands for starting/connecting to a REPL."]
  262. ("Clojure"
  263. ["Start a Clojure REPL" cider-jack-in
  264. :help "Starts an nREPL server and connects a Clojure REPL to it."]
  265. ["Connect to a Clojure REPL" cider-connect
  266. :help "Connects to a REPL that's already running."])
  267. ("ClojureScript"
  268. ["Start a ClojureScript REPL" cider-jack-in-cljs
  269. :help "Starts an nREPL server and connects a ClojureScript REPL to it."]
  270. ["Connect to a ClojureScript REPL" cider-connect-clojurescript
  271. :help "Connects to a ClojureScript REPL that's already running."]
  272. ["Create a ClojureScript REPL from a Clojure REPL" cider-jack-in-sibling-clojurescript])
  273. "--"
  274. ["Quit" cider-quit :active (cider-connected-p)]
  275. ["Restart" cider-restart :active (cider-connected-p)]
  276. "--"
  277. ["Connection info" cider-describe-connection
  278. :active (cider-connected-p)]
  279. ["Select any CIDER buffer" cider-selector]
  280. "--"
  281. ["Configure CIDER" (customize-group 'cider)]
  282. "--"
  283. ["A sip of CIDER" cider-drink-a-sip]
  284. ["View manual online" cider-view-manual]
  285. ["View refcard online" cider-view-refcard]
  286. ["Report a bug" cider-report-bug]
  287. ["Version info" cider-version]
  288. "--"
  289. ["Close ancillary buffers" cider-close-ancillary-buffers
  290. :active (seq-remove #'null cider-ancillary-buffers)]
  291. ("nREPL" :active (cider-connected-p)
  292. ["Describe nrepl session" cider-describe-nrepl-session]
  293. ["Toggle message logging" nrepl-toggle-message-logging])
  294. "Menu for CIDER mode."))
  295. (defconst cider-mode-eval-menu
  296. '("CIDER Eval" :visible (cider-connected-p)
  297. ["Eval top-level sexp" cider-eval-defun-at-point]
  298. ["Eval top-level sexp to point" cider-eval-defun-up-to-point]
  299. ["Eval top-level sexp to comment" cider-eval-defun-to-comment]
  300. ["Eval top-level sexp and pretty-print to comment" cider-pprint-eval-defun-to-comment]
  301. "--"
  302. ["Eval current sexp" cider-eval-sexp-at-point]
  303. ["Eval current sexp to point" cider-eval-sexp-up-to-point]
  304. ["Eval current sexp in context" cider-eval-sexp-at-point-in-context]
  305. "--"
  306. ["Eval last sexp" cider-eval-last-sexp]
  307. ["Eval last sexp in context" cider-eval-last-sexp-in-context]
  308. ["Eval last sexp and insert" cider-eval-print-last-sexp
  309. :keys "\\[universal-argument] \\[cider-eval-last-sexp]"]
  310. ["Eval last sexp in popup buffer" cider-pprint-eval-last-sexp]
  311. ["Eval last sexp and replace" cider-eval-last-sexp-and-replace]
  312. ["Eval last sexp to REPL" cider-eval-last-sexp-to-repl]
  313. ["Eval last sexp and pretty-print to REPL" cider-pprint-eval-last-sexp-to-repl]
  314. ["Eval last sexp and pretty-print to comment" cider-pprint-eval-last-sexp-to-comment]
  315. "--"
  316. ["Eval selected region" cider-eval-region]
  317. ["Eval ns form" cider-eval-ns-form]
  318. "--"
  319. ["Interrupt evaluation" cider-interrupt]
  320. "--"
  321. ["Insert last sexp in REPL" cider-insert-last-sexp-in-repl]
  322. ["Insert top-level sexp in REPL" cider-insert-defun-in-repl]
  323. ["Insert region in REPL" cider-insert-region-in-repl]
  324. ["Insert ns form in REPL" cider-insert-ns-form-in-repl]
  325. "--"
  326. ["Load this buffer" cider-load-buffer]
  327. ["Load this buffer and switch to REPL" cider-load-buffer-and-switch-to-repl-buffer]
  328. ["Load another file" cider-load-file]
  329. ["Recursively load all files in directory" cider-load-all-files]
  330. ["Load all project files" cider-load-all-project-ns]
  331. ["Refresh loaded code" cider-ns-refresh]
  332. ["Require and reload" cider-ns-reload]
  333. ["Require and reload all" cider-ns-reload-all]
  334. ["Run project (-main function)" cider-run])
  335. "Menu for CIDER mode eval commands.")
  336. (defconst cider-mode-interactions-menu
  337. `("CIDER Interactions" :visible (cider-connected-p)
  338. ["Complete symbol" complete-symbol]
  339. "--"
  340. ("REPL"
  341. ["Set REPL to this ns" cider-repl-set-ns]
  342. ["Switch to REPL" cider-switch-to-repl-buffer]
  343. ["REPL Pretty Print" cider-repl-toggle-pretty-printing
  344. :style toggle :selected cider-repl-use-pretty-printing]
  345. ["Clear latest output" cider-find-and-clear-repl-output]
  346. ["Clear all output" (cider-find-and-clear-repl-output t)
  347. :keys "\\[universal-argument] \\[cider-find-and-clear-repl-output]"]
  348. "--"
  349. ["Configure the REPL" (customize-group 'cider-repl)])
  350. ,cider-doc-menu
  351. ("Find (jump to)"
  352. ["Find definition" cider-find-var]
  353. ["Find namespace" cider-find-ns]
  354. ["Find resource" cider-find-resource]
  355. ["Find keyword" cider-find-keyword]
  356. ["Go back" cider-pop-back])
  357. ("Xref"
  358. ["Find fn references" cider-xref-fn-refs]
  359. ["Find fn references and select" cider-xref-fn-refs-select]
  360. ["Find fn dependencies" cider-xref-fn-defs]
  361. ["Find fn dependencies and select" cider-xref-fn-defs-select])
  362. ("Browse"
  363. ["Browse namespace" cider-browse-ns]
  364. ["Browse all namespaces" cider-browse-ns-all]
  365. ["Browse spec" cider-browse-spec]
  366. ["Browse all specs" cider-browse-spec-all]
  367. ["Browse REPL input history" cider-repl-history]
  368. ["Browse classpath" cider-classpath]
  369. ["Browse classpath entry" cider-open-classpath-entry])
  370. ("Format"
  371. ["Format EDN last sexp" cider-format-edn-last-sexp]
  372. ["Format EDN region" cider-format-edn-region]
  373. ["Format EDN buffer" cider-format-edn-buffer])
  374. ("Macroexpand"
  375. ["Macroexpand-1" cider-macroexpand-1]
  376. ["Macroexpand-all" cider-macroexpand-all])
  377. ,cider-test-menu
  378. ("Debug"
  379. ["Inspect" cider-inspect]
  380. ["Toggle var tracing" cider-toggle-trace-var]
  381. ["Toggle ns tracing" cider-toggle-trace-ns]
  382. "--"
  383. ["Debug top-level form" cider-debug-defun-at-point
  384. :keys "\\[universal-argument] \\[cider-eval-defun-at-point]"]
  385. ["List instrumented defs" cider-browse-instrumented-defs]
  386. "--"
  387. ["Configure the Debugger" (customize-group 'cider-debug)])
  388. ,cider-profile-menu
  389. ("Misc"
  390. ["Clojure Cheatsheet" cider-cheatsheet]
  391. ["Flush completion cache" cider-completion-flush-caches]))
  392. "Menu for CIDER interactions.")
  393. (declare-function cider-ns-refresh "cider-ns")
  394. (declare-function cider-ns-reload "cider-ns")
  395. (declare-function cider-ns-reload-all "cider-ns")
  396. (declare-function cider-browse-ns "cider-browse-ns")
  397. (declare-function cider-eval-ns-form "cider-eval")
  398. (declare-function cider-repl-set-ns "cider-repl")
  399. (declare-function cider-find-ns "cider-find")
  400. (defvar cider-ns-map
  401. (let ((map (define-prefix-command 'cider-ns-map)))
  402. (define-key map (kbd "b") #'cider-browse-ns)
  403. (define-key map (kbd "M-b") #'cider-browse-ns)
  404. (define-key map (kbd "e") #'cider-eval-ns-form)
  405. (define-key map (kbd "M-e") #'cider-eval-ns-form)
  406. (define-key map (kbd "f") #'cider-find-ns)
  407. (define-key map (kbd "M-f") #'cider-find-ns)
  408. (define-key map (kbd "n") #'cider-repl-set-ns)
  409. (define-key map (kbd "M-n") #'cider-repl-set-ns)
  410. (define-key map (kbd "r") #'cider-ns-refresh)
  411. (define-key map (kbd "M-r") #'cider-ns-refresh)
  412. (define-key map (kbd "l") #'cider-ns-reload)
  413. (define-key map (kbd "M-l") #'cider-ns-reload-all)
  414. map)
  415. "CIDER NS keymap.")
  416. ;; Those declares are needed, because we autoload all those commands when first
  417. ;; used. That optimizes CIDER's initial load time.
  418. (declare-function cider-macroexpand-1 "cider-macroexpansion")
  419. (declare-function cider-macroexpand-all "cider-macroexpansion")
  420. (declare-function cider-selector "cider-selector")
  421. (declare-function cider-toggle-trace-ns "cider-tracing")
  422. (declare-function cider-toggle-trace-var "cider-tracing")
  423. (declare-function cider-find-resource "cider-find")
  424. (declare-function cider-find-keyword "cider-find")
  425. (declare-function cider-find-var "cider-find")
  426. (declare-function cider-find-dwim-at-mouse "cider-find")
  427. (defconst cider--has-many-mouse-buttons (not (memq window-system '(mac ns)))
  428. "Non-nil if system binds forward and back buttons to <mouse-8> and <mouse-9>.
  429. As it stands Emacs fires these events on <mouse-8> and <mouse-9> on 'x' and
  430. 'w32'systems while on macOS it presents them on <mouse-4> and <mouse-5>.")
  431. (defconst cider-mode-map
  432. (let ((map (make-sparse-keymap)))
  433. (define-key map (kbd "C-c C-d") 'cider-doc-map)
  434. (define-key map (kbd "M-.") #'cider-find-var)
  435. (define-key map (kbd (if cider--has-many-mouse-buttons "<mouse-8>" "<mouse-4>")) #'xref-pop-marker-stack)
  436. (define-key map (kbd (if cider--has-many-mouse-buttons "<mouse-9>" "<mouse-5>")) #'cider-find-dwim-at-mouse)
  437. (define-key map (kbd "C-c C-.") #'cider-find-ns)
  438. (define-key map (kbd "C-c C-:") #'cider-find-keyword)
  439. (define-key map (kbd "M-,") #'cider-pop-back)
  440. (define-key map (kbd "C-c M-.") #'cider-find-resource)
  441. (define-key map (kbd "M-TAB") #'complete-symbol)
  442. (define-key map (kbd "C-M-x") #'cider-eval-defun-at-point)
  443. (define-key map (kbd "C-c C-c") #'cider-eval-defun-at-point)
  444. (define-key map (kbd "C-x C-e") #'cider-eval-last-sexp)
  445. (define-key map (kbd "C-c C-e") #'cider-eval-last-sexp)
  446. (define-key map (kbd "C-c C-p") #'cider-pprint-eval-last-sexp)
  447. (define-key map (kbd "C-c C-f") #'cider-pprint-eval-defun-at-point)
  448. (define-key map (kbd "C-c C-v") 'cider-eval-commands-map)
  449. (define-key map (kbd "C-c C-j") 'cider-insert-commands-map)
  450. (define-key map (kbd "C-c M-;") #'cider-eval-defun-to-comment)
  451. (define-key map (kbd "C-c M-e") #'cider-eval-last-sexp-to-repl)
  452. (define-key map (kbd "C-c M-p") #'cider-insert-last-sexp-in-repl)
  453. (define-key map (kbd "C-c M-:") #'cider-read-and-eval)
  454. (define-key map (kbd "C-c C-u") #'cider-undef)
  455. (define-key map (kbd "C-c C-m") #'cider-macroexpand-1)
  456. (define-key map (kbd "C-c M-m") #'cider-macroexpand-all)
  457. (define-key map (kbd "C-c M-n") 'cider-ns-map)
  458. (define-key map (kbd "C-c M-i") #'cider-inspect)
  459. (define-key map (kbd "C-c M-t v") #'cider-toggle-trace-var)
  460. (define-key map (kbd "C-c M-t n") #'cider-toggle-trace-ns)
  461. (define-key map (kbd "C-c C-z") #'cider-switch-to-repl-buffer)
  462. (define-key map (kbd "C-c M-z") #'cider-load-buffer-and-switch-to-repl-buffer)
  463. (define-key map (kbd "C-c C-o") #'cider-find-and-clear-repl-output)
  464. (define-key map (kbd "C-c C-k") #'cider-load-buffer)
  465. (define-key map (kbd "C-c C-l") #'cider-load-file)
  466. (define-key map (kbd "C-c C-M-l") #'cider-load-all-files)
  467. (define-key map (kbd "C-c C-b") #'cider-interrupt)
  468. (define-key map (kbd "C-c ,") 'cider-test-commands-map)
  469. (define-key map (kbd "C-c C-t") 'cider-test-commands-map)
  470. (define-key map (kbd "C-c M-s") #'cider-selector)
  471. (define-key map (kbd "C-c M-d") #'cider-describe-connection)
  472. (define-key map (kbd "C-c C-=") 'cider-profile-map)
  473. (define-key map (kbd "C-c C-q") #'cider-quit)
  474. (define-key map (kbd "C-c M-r") #'cider-restart)
  475. (dolist (variable '(cider-mode-interactions-menu
  476. cider-mode-eval-menu
  477. cider-mode-menu))
  478. (easy-menu-do-define (intern (format "%s-open" variable))
  479. map
  480. (get variable 'variable-documentation)
  481. (cider--menu-add-help-strings (symbol-value variable))))
  482. map))
  483. ;; This menu works as an easy entry-point into CIDER. Even if cider.el isn't
  484. ;; loaded yet, this will be shown in Clojure buffers next to the "Clojure"
  485. ;; menu.
  486. ;;;###autoload
  487. (with-eval-after-load 'clojure-mode
  488. (easy-menu-define cider-clojure-mode-menu-open clojure-mode-map
  489. "Menu for Clojure mode.
  490. This is displayed in `clojure-mode' buffers, if `cider-mode' is not active."
  491. `("CIDER" :visible (not cider-mode)
  492. ["Start a Clojure REPL" cider-jack-in-clj
  493. :help "Starts an nREPL server and connects a Clojure REPL to it."]
  494. ["Connect to a Clojure REPL" cider-connect-clj
  495. :help "Connects to a REPL that's already running."]
  496. ["Start a ClojureScript REPL" cider-jack-in-cljs
  497. :help "Starts an nREPL server and connects a ClojureScript REPL to it."]
  498. ["Connect to a ClojureScript REPL" cider-connect-cljs
  499. :help "Connects to a ClojureScript REPL that's already running."]
  500. ["Start a Clojure REPL, and a ClojureScript REPL" cider-jack-in-clj&cljs
  501. :help "Starts an nREPL server, connects a Clojure REPL to it, and then a ClojureScript REPL."]
  502. "--"
  503. ["View manual online" cider-view-manual])))
  504. ;;; Dynamic indentation
  505. (defcustom cider-dynamic-indentation t
  506. "Whether CIDER should aid Clojure(Script) indentation.
  507. If non-nil, CIDER uses runtime information (such as the \":style/indent\"
  508. metadata) to improve standard `clojure-mode' indentation.
  509. If nil, CIDER won't interfere with `clojure-mode's indentation.
  510. Toggling this variable only takes effect after a file is closed and
  511. re-visited."
  512. :type 'boolean
  513. :package-version '(cider . "0.11.0")
  514. :group 'cider)
  515. (defun cider--get-symbol-indent (symbol-name)
  516. "Return the indent metadata for SYMBOL-NAME in the current namespace."
  517. (let* ((ns (let ((clojure-cache-ns t)) ; we force ns caching here for performance reasons
  518. ;; silence bytecode warning of unused lexical var
  519. (ignore clojure-cache-ns)
  520. (cider-current-ns))))
  521. (if-let* ((meta (cider-resolve-var ns symbol-name))
  522. (indent (or (nrepl-dict-get meta "style/indent")
  523. (nrepl-dict-get meta "indent"))))
  524. (let ((format (format ":indent metadata on ‘%s’ is unreadable! \nERROR: %%s"
  525. symbol-name)))
  526. (with-demoted-errors format
  527. (cider--deep-vector-to-list (read indent))))
  528. ;; There's no indent metadata, but there might be a clojure-mode
  529. ;; indent-spec with fully-qualified namespace.
  530. (when (string-match cider-resolve--prefix-regexp symbol-name)
  531. (when-let* ((sym (intern-soft (replace-match (save-match-data
  532. (cider-resolve-alias ns (match-string 1 symbol-name)))
  533. t t symbol-name 1))))
  534. (get sym 'clojure-indent-function))))))
  535. ;;; Dynamic font locking
  536. (defcustom cider-font-lock-dynamically '(macro core deprecated)
  537. "Specifies how much dynamic font-locking CIDER should use.
  538. Dynamic font-locking this refers to applying syntax highlighting to vars
  539. defined in the currently active nREPL connection. This is done in addition
  540. to `clojure-mode's usual (static) font-lock, so even if you set this
  541. variable to nil you'll still see basic syntax highlighting.
  542. The value is a list of symbols, each one indicates a different type of var
  543. that should be font-locked:
  544. `macro' (default): Any defined macro gets the `font-lock-keyword-face'.
  545. `function': Any defined function gets the `font-lock-function-face'.
  546. `var': Any non-local var gets the `font-lock-variable-name-face'.
  547. `deprecated' (default): Any deprecated var gets the `cider-deprecated-face'
  548. face.
  549. `core' (default): Any symbol from clojure.core (face depends on type).
  550. The value can also be t, which means to font-lock as much as possible."
  551. :type '(choice (set :tag "Fine-tune font-locking"
  552. (const :tag "Any defined macro" macro)
  553. (const :tag "Any defined function" function)
  554. (const :tag "Any defined var" var)
  555. (const :tag "Any defined deprecated" deprecated)
  556. (const :tag "Any symbol from clojure.core" core))
  557. (const :tag "Font-lock as much as possible" t))
  558. :group 'cider
  559. :package-version '(cider . "0.10.0"))
  560. (defcustom cider-font-lock-reader-conditionals t
  561. "Apply font-locking to unused reader conditional expressions depending on the buffer CIDER connection type."
  562. :type 'boolean
  563. :group 'cider
  564. :package-version '(cider . "0.15.0"))
  565. (defface cider-deprecated-face
  566. '((((background light)) :background "light goldenrod")
  567. (((background dark)) :background "#432"))
  568. "Face used on deprecated vars."
  569. :group 'cider)
  570. (defface cider-instrumented-face
  571. '((((type graphic)) :box (:color "#c00" :line-width -1))
  572. (t :underline t :background "#800"))
  573. "Face used to mark code being debugged."
  574. :group 'cider-debug
  575. :group 'cider
  576. :package-version '(cider . "0.10.0"))
  577. (defface cider-traced-face
  578. '((((type graphic)) :box (:color "cyan" :line-width -1))
  579. (t :underline t :background "#066"))
  580. "Face used to mark code being traced."
  581. :group 'cider
  582. :package-version '(cider . "0.11.0"))
  583. (defface cider-reader-conditional-face
  584. '((t (:inherit font-lock-comment-face)))
  585. "Face used to mark unused reader conditional expressions."
  586. :group 'cider
  587. :package-version '(cider . "0.15.0"))
  588. (defconst cider-reader-conditionals-regexp "\\(?:#\\?@?[[:space:]\n]*(\\)"
  589. "Regexp for matching reader conditionals with a non-capturing group.
  590. Starts from the reader macro characters to the opening parentheses.")
  591. (defvar cider--reader-conditionals-match-data (list nil nil)
  592. "Reusable list for `match-data` in reader conditionals font lock matchers.")
  593. (defun cider--search-reader-conditionals (limit)
  594. "Matcher for finding reader conditionals.
  595. Search is done with the given LIMIT."
  596. (when (and cider-font-lock-reader-conditionals
  597. (cider-connected-p))
  598. (when (search-forward-regexp cider-reader-conditionals-regexp limit t)
  599. (let ((start (match-beginning 0))
  600. (state (syntax-ppss)))
  601. (if (or (nth 3 state) (nth 4 state)) ; inside string or comment?
  602. (cider--search-reader-conditionals limit)
  603. (when (<= (point) limit)
  604. (ignore-errors
  605. (let ((md (match-data nil cider--reader-conditionals-match-data)))
  606. (setf (nth 0 md) start)
  607. (setf (nth 1 md) (point))
  608. (set-match-data md)
  609. t))))))))
  610. (defun cider--anchored-search-suppressed-forms-internal (repl-types limit)
  611. "Helper function for `cider--anchored-search-suppressed-forms`.
  612. REPL-TYPES is a list of strings repl-type strings. LIMIT is the same as
  613. the LIMIT in `cider--anchored-search-suppressed-forms`"
  614. (when (= (length repl-types) 1)
  615. (let ((type (car repl-types))
  616. (expr (read (current-buffer)))
  617. (start (save-excursion (backward-sexp) (point))))
  618. (when (<= (point) limit)
  619. (forward-sexp)
  620. (if (not (string-equal (symbol-name expr) (concat ":" type)))
  621. (ignore-errors
  622. (cl-assert (<= (point) limit))
  623. (let ((md (match-data nil cider--reader-conditionals-match-data)))
  624. (setf (nth 0 md) start)
  625. (setf (nth 1 md) (point))
  626. (set-match-data md)
  627. t))
  628. (cider--anchored-search-suppressed-forms-internal repl-types limit))))))
  629. (defun cider--anchored-search-suppressed-forms (limit)
  630. "Matcher for finding unused reader conditional expressions.
  631. An unused reader conditional expression is an expression for a platform
  632. that does not match the CIDER connection for the buffer. Search is done
  633. with the given LIMIT."
  634. (let ((repl-types (seq-uniq (seq-map
  635. (lambda (repl)
  636. (symbol-name (cider-repl-type repl)))
  637. (cider-repls))))
  638. (result 'retry))
  639. (while (and (eq result 'retry) (<= (point) limit))
  640. (condition-case condition
  641. (setq result
  642. (cider--anchored-search-suppressed-forms-internal
  643. repl-types limit))
  644. (invalid-read-syntax
  645. (setq result 'retry))
  646. (wrong-type-argument
  647. (setq result 'retry))
  648. (scan-error
  649. (setq result 'retry))
  650. (end-of-file
  651. (setq result nil))
  652. (error
  653. (setq result nil)
  654. (message
  655. "Error during fontification while searching for forms: %S"
  656. condition))))
  657. (if (eq result 'retry) (setq result nil))
  658. result))
  659. (defconst cider--reader-conditionals-font-lock-keywords
  660. '((cider--search-reader-conditionals
  661. (cider--anchored-search-suppressed-forms
  662. (save-excursion
  663. (let* ((state (syntax-ppss))
  664. (list-pt (nth 1 state)))
  665. (when list-pt
  666. (goto-char list-pt)
  667. (forward-list)
  668. (backward-char)
  669. (point))))
  670. nil
  671. (0 'cider-reader-conditional-face t))))
  672. "Font Lock keywords for unused reader conditionals in CIDER mode.")
  673. (defun cider--unless-local-match (value)
  674. "Return VALUE, unless `match-string' is a local var."
  675. (unless (or (get-text-property (point) 'cider-block-dynamic-font-lock)
  676. (member (match-string 0)
  677. (get-text-property (point) 'cider-locals)))
  678. value))
  679. (defun cider--compile-font-lock-keywords (symbols-plist core-plist)
  680. "Return a list of font-lock rules for the symbols in SYMBOLS-PLIST and CORE-PLIST."
  681. (let ((cider-font-lock-dynamically (if (eq cider-font-lock-dynamically t)
  682. '(function var macro core deprecated)
  683. cider-font-lock-dynamically))
  684. deprecated enlightened
  685. macros functions vars instrumented traced)
  686. (cl-labels ((handle-plist
  687. (plist)
  688. (let ((do-function (memq 'function cider-font-lock-dynamically))
  689. (do-var (memq 'var cider-font-lock-dynamically))
  690. (do-macro (memq 'macro cider-font-lock-dynamically))
  691. (do-deprecated (memq 'deprecated cider-font-lock-dynamically)))
  692. (while plist
  693. (let ((sym (pop plist))
  694. (meta (pop plist)))
  695. (pcase (nrepl-dict-get meta "cider/instrumented")
  696. (`nil nil)
  697. (`"\"breakpoint-if-interesting\""
  698. (push sym instrumented))
  699. (`"\"light-form\""
  700. (push sym enlightened)))
  701. ;; The ::traced keywords can be inlined by MrAnderson, so
  702. ;; we catch that case too.
  703. ;; FIXME: This matches values too, not just keys.
  704. (when (seq-find (lambda (k) (and (stringp k)
  705. (string-match (rx "clojure.tools.trace/traced" eos) k)))
  706. meta)
  707. (push sym traced))
  708. (when (and do-deprecated (nrepl-dict-get meta "deprecated"))
  709. (push sym deprecated))
  710. (cond ((and do-macro (nrepl-dict-get meta "macro"))
  711. (push sym macros))
  712. ((and do-function (or (nrepl-dict-get meta "fn")
  713. (nrepl-dict-get meta "arglists")))
  714. (push sym functions))
  715. (do-var (push sym vars))))))))
  716. (when (memq 'core cider-font-lock-dynamically)
  717. (let ((cider-font-lock-dynamically '(function var macro core deprecated)))
  718. (handle-plist core-plist)))
  719. (handle-plist symbols-plist))
  720. `(
  721. ,@(when macros
  722. `((,(concat (rx (or "(" "#'")) ; Can't take the value of macros.
  723. "\\(" (regexp-opt macros 'symbols) "\\)")
  724. 1 (cider--unless-local-match font-lock-keyword-face))))
  725. ,@(when functions
  726. `((,(regexp-opt functions 'symbols) 0
  727. (cider--unless-local-match font-lock-function-name-face))))
  728. ,@(when vars
  729. `((,(regexp-opt vars 'symbols) 0
  730. (cider--unless-local-match font-lock-variable-name-face))))
  731. ,@(when deprecated
  732. `((,(regexp-opt deprecated 'symbols) 0
  733. (cider--unless-local-match 'cider-deprecated-face) append)))
  734. ,@(when enlightened
  735. `((,(regexp-opt enlightened 'symbols) 0
  736. (cider--unless-local-match 'cider-enlightened-face) append)))
  737. ,@(when instrumented
  738. `((,(regexp-opt instrumented 'symbols) 0
  739. (cider--unless-local-match 'cider-instrumented-face) append)))
  740. ,@(when traced
  741. `((,(regexp-opt traced 'symbols) 0
  742. (cider--unless-local-match 'cider-traced-face) append))))))
  743. (defconst cider--static-font-lock-keywords
  744. (eval-when-compile
  745. `((,(regexp-opt '("#break" "#dbg" "#light") 'symbols) 0 font-lock-warning-face)))
  746. "Default expressions to highlight in CIDER mode.")
  747. (defvar-local cider--dynamic-font-lock-keywords nil)
  748. (defun cider-refresh-dynamic-font-lock (&optional ns)
  749. "Ensure that the current buffer has up-to-date font-lock rules.
  750. NS defaults to `cider-current-ns', and it can also be a dict describing the
  751. namespace itself."
  752. (interactive)
  753. (when (and cider-font-lock-dynamically
  754. font-lock-mode)
  755. (font-lock-remove-keywords nil cider--dynamic-font-lock-keywords)
  756. (when-let* ((ns (or ns (cider-current-ns)))
  757. (symbols (cider-resolve-ns-symbols ns)))
  758. (setq-local cider--dynamic-font-lock-keywords
  759. (cider--compile-font-lock-keywords
  760. symbols (cider-resolve-ns-symbols (cider-resolve-core-ns))))
  761. (font-lock-add-keywords nil cider--dynamic-font-lock-keywords 'end))
  762. (cider--font-lock-flush)))
  763. ;;; Detecting local variables
  764. (defun cider--read-locals-from-next-sexp ()
  765. "Return a list of all locals inside the next logical sexp."
  766. (save-excursion
  767. (ignore-errors
  768. (clojure-forward-logical-sexp 1)
  769. (let ((out nil)
  770. (end (point)))
  771. (forward-sexp -1)
  772. ;; FIXME: This returns locals found inside the :or clause of a
  773. ;; destructuring map.
  774. (while (search-forward-regexp "\\_<[^:&]\\(\\sw\\|\\s_\\)*\\_>" end 'noerror)
  775. (push (match-string-no-properties 0) out))
  776. out))))
  777. (defun cider--read-locals-from-bindings-vector ()
  778. "Return a list of all locals inside the next bindings vector."
  779. (save-excursion
  780. (ignore-errors
  781. (cider-start-of-next-sexp)
  782. (when (eq (char-after) ?\[)
  783. (forward-char 1)
  784. (let ((out nil))
  785. (setq out (append (cider--read-locals-from-next-sexp) out))
  786. (while (ignore-errors (clojure-forward-logical-sexp 3)
  787. (unless (eobp)
  788. (forward-sexp -1)
  789. t))
  790. (setq out (append (cider--read-locals-from-next-sexp) out)))
  791. out)))))
  792. (defun cider--read-locals-from-arglist ()
  793. "Return a list of all locals in current form's arglist(s)."
  794. (let ((out nil))
  795. (save-excursion
  796. (ignore-errors
  797. (cider-start-of-next-sexp)
  798. ;; Named fn
  799. (when (looking-at-p "\\s_\\|\\sw")
  800. (cider-start-of-next-sexp 1))
  801. ;; Docstring
  802. (when (eq (char-after) ?\")
  803. (cider-start-of-next-sexp 1))
  804. ;; Attribute map
  805. (when (eq (char-after) ?{)
  806. (cider-start-of-next-sexp 1))
  807. ;; The arglist
  808. (pcase (char-after)
  809. (?\[ (setq out (cider--read-locals-from-next-sexp)))
  810. ;; FIXME: This returns false positives. It takes all arglists of a
  811. ;; function and returns all args it finds. The logic should be changed
  812. ;; so that each arglist applies to its own scope.
  813. (?\( (ignore-errors
  814. (while (eq (char-after) ?\()
  815. (save-excursion
  816. (forward-char 1)
  817. (setq out (append (cider--read-locals-from-next-sexp) out)))
  818. (cider-start-of-next-sexp 1)))))))
  819. out))
  820. (defun cider--parse-and-apply-locals (end &optional outer-locals)
  821. "Figure out local variables between point and END.
  822. A list of these variables is set as the `cider-locals' text property over
  823. the code where they are in scope.
  824. Optional argument OUTER-LOCALS is used to specify local variables defined
  825. before point."
  826. (while (search-forward-regexp "(\\(ns\\_>\\|def\\|fn\\|for\\b\\|loop\\b\\|with-\\|do[a-z]+\\|\\([a-z]+-\\)?let\\b\\)"
  827. end 'noerror)
  828. (goto-char (match-beginning 0))
  829. (let ((sym (match-string 1))
  830. (sexp-end (save-excursion
  831. (or (ignore-errors (forward-sexp 1)
  832. (point))
  833. end))))
  834. ;; #1324: Don't do dynamic font-lock in `ns' forms, they are special
  835. ;; macros where nothing is evaluated, so we'd get a lot of false
  836. ;; positives.
  837. (if (equal sym "ns")
  838. (add-text-properties (point) sexp-end '(cider-block-dynamic-font-lock t))
  839. (forward-char 1)
  840. (forward-sexp 1)
  841. (let ((locals (append outer-locals
  842. (pcase sym
  843. ((or "fn" "def" "") (cider--read-locals-from-arglist))
  844. (_ (cider--read-locals-from-bindings-vector))))))
  845. (add-text-properties (point) sexp-end (list 'cider-locals locals))
  846. (clojure-forward-logical-sexp 1)
  847. (cider--parse-and-apply-locals sexp-end locals)))
  848. (goto-char sexp-end))))
  849. (defun cider--update-locals-for-region (beg end)
  850. "Update the `cider-locals' text property for region from BEG to END."
  851. (save-excursion
  852. (goto-char beg)
  853. ;; If the inside of a `ns' form changed, reparse it from the start.
  854. (when (and (not (bobp))
  855. (get-text-property (1- (point)) 'cider-block-dynamic-font-lock))
  856. (ignore-errors (beginning-of-defun)))
  857. (save-excursion
  858. ;; Move up until we reach a sexp that encloses the entire region (or
  859. ;; a top-level sexp), and set that as the new BEG.
  860. (goto-char end)
  861. (while (and (or (> (point) beg)
  862. (not (eq (char-after) ?\()))
  863. (condition-case nil
  864. (progn (backward-up-list) t)
  865. (scan-error nil))))
  866. (setq beg (min beg (point)))
  867. ;; If there are locals above the current sexp, reapply them to the
  868. ;; current sexp.
  869. (let ((locals-above (when (> beg (point-min))
  870. (get-text-property (1- beg) 'cider-locals))))
  871. (condition-case nil
  872. (clojure-forward-logical-sexp 1)
  873. (error (goto-char end)))
  874. (add-text-properties beg (point) `(cider-locals ,locals-above))
  875. ;; Extend the region being font-locked to include whole sexps.
  876. (setq end (max end (point)))
  877. (goto-char beg)
  878. (ignore-errors
  879. (cider--parse-and-apply-locals end locals-above))))))
  880. (defun cider--docview-as-string (sym info)
  881. "Return a string of what would be displayed by `cider-docview-render'.
  882. SYM and INFO is passed to `cider-docview-render'"
  883. (with-temp-buffer
  884. (cider-docview-render (current-buffer) sym info)
  885. (goto-char (point-max))
  886. (forward-line -1)
  887. (replace-regexp-in-string
  888. "[`']" "\\\\=\\&"
  889. (buffer-substring-no-properties (point-min) (1- (point))))))
  890. (defcustom cider-use-tooltips t
  891. "If non-nil, CIDER displays mouse-over tooltips."
  892. :group 'cider
  893. :type 'boolean
  894. :package-version '(cider "0.12.0"))
  895. (defvar cider--debug-mode-response)
  896. (defvar cider--debug-mode)
  897. (defun cider--help-echo (_ obj pos)
  898. "Return the help-echo string for OBJ at POS.
  899. See \(info \"(elisp) Special Properties\")"
  900. (while-no-input
  901. (when (and (bufferp obj)
  902. (cider-connected-p)
  903. cider-use-tooltips (not help-at-pt-display-when-idle))
  904. (with-current-buffer obj
  905. (ignore-errors
  906. (save-excursion
  907. (goto-char pos)
  908. (when-let* ((sym (cider-symbol-at-point)))
  909. (if (member sym (get-text-property (point) 'cider-locals))
  910. (concat (format "`%s' is a local" sym)
  911. (when cider--debug-mode
  912. (let* ((locals (nrepl-dict-get cider--debug-mode-response "locals"))
  913. (local-val (cadr (assoc sym locals))))
  914. (format " with value:\n%s" local-val))))
  915. (let* ((info (cider-sync-request:info sym))
  916. (candidates (nrepl-dict-get info "candidates")))
  917. (if candidates
  918. (concat "There were ambiguities resolving this symbol:\n\n"
  919. (mapconcat (lambda (x) (cider--docview-as-string sym x))
  920. candidates
  921. (concat "\n\n" (make-string 60 ?-) "\n\n")))
  922. (cider--docview-as-string sym info)))))))))))
  923. (defun cider--wrap-fontify-locals (func)
  924. "Return a function that will call FUNC after parsing local variables.
  925. The local variables are stored in a list under the `cider-locals' text
  926. property."
  927. (lambda (beg end &rest rest)
  928. (with-silent-modifications
  929. (remove-text-properties beg end '(cider-locals nil cider-block-dynamic-font-lock nil))
  930. (add-text-properties beg end '(help-echo cider--help-echo))
  931. (when cider-font-lock-dynamically
  932. (cider--update-locals-for-region beg end)))
  933. (apply func beg end rest)))
  934. ;;; Minor-mode definition
  935. (defvar x-gtk-use-system-tooltips)
  936. ;;;###autoload
  937. (define-minor-mode cider-mode
  938. "Minor mode for REPL interaction from a Clojure buffer.
  939. \\{cider-mode-map}"
  940. nil
  941. cider-mode-line
  942. cider-mode-map
  943. (if cider-mode
  944. (progn
  945. (setq-local sesman-system 'CIDER)
  946. (cider-eldoc-setup)
  947. (add-hook 'completion-at-point-functions #'cider-complete-at-point nil t)
  948. (font-lock-add-keywords nil cider--static-font-lock-keywords)
  949. (cider-refresh-dynamic-font-lock)
  950. (font-lock-add-keywords nil cider--reader-conditionals-font-lock-keywords)
  951. ;; `font-lock-mode' might get enabled after `cider-mode'.
  952. (add-hook 'font-lock-mode-hook #'cider-refresh-dynamic-font-lock nil 'local)
  953. (setq-local font-lock-fontify-region-function
  954. (cider--wrap-fontify-locals font-lock-fontify-region-function))
  955. ;; GTK tooltips look bad, and we have no control over the face.
  956. (setq-local x-gtk-use-system-tooltips nil)
  957. ;; `tooltip' has variable-width by default, which looks terrible.
  958. (set-face-attribute 'tooltip nil :inherit 'unspecified)
  959. (when cider-dynamic-indentation
  960. (setq-local clojure-get-indent-function #'cider--get-symbol-indent))
  961. (setq-local clojure-expected-ns-function #'cider-expected-ns)
  962. (setq next-error-function #'cider-jump-to-compilation-error))
  963. ;; Mode cleanup
  964. (mapc #'kill-local-variable '(completion-at-point-functions
  965. next-error-function
  966. x-gtk-use-system-tooltips
  967. font-lock-fontify-region-function
  968. clojure-get-indent-function))
  969. (remove-hook 'font-lock-mode-hook #'cider-refresh-dynamic-font-lock 'local)
  970. (font-lock-add-keywords nil cider--reader-conditionals-font-lock-keywords)
  971. (font-lock-remove-keywords nil cider--dynamic-font-lock-keywords)
  972. (font-lock-remove-keywords nil cider--static-font-lock-keywords)
  973. (cider--font-lock-flush)
  974. (remove-hook 'completion-at-point-functions #'cider-complete-at-point t)))
  975. (defun cider-set-buffer-ns (ns)
  976. "Set this buffer's namespace to NS and refresh font-locking."
  977. (setq-local cider-buffer-ns ns)
  978. (when (or cider-mode (derived-mode-p 'cider-repl-mode))
  979. (cider-refresh-dynamic-font-lock ns)))
  980. (provide 'cider-mode)
  981. ;;; cider-mode.el ends here