PageRenderTime 61ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/elpa/cider-20131221.1231/cider-interaction.el

https://github.com/elegoff/emacs-conf
Emacs Lisp | 1211 lines | 1009 code | 147 blank | 55 comment | 46 complexity | a3fbadee2a6c4ebe6dc87b8f0eb1257c MD5 | raw file
Possible License(s): GPL-3.0
  1. ;;; cider-interaction.el --- IDE for Clojure
  2. ;; Copyright © 2012-2013 Tim King, Phil Hagelberg
  3. ;; Copyright © 2013 Bozhidar Batsov, Hugo Duncan, Steve Purcell
  4. ;;
  5. ;; Author: Tim King <kingtim@gmail.com>
  6. ;; Phil Hagelberg <technomancy@gmail.com>
  7. ;; Bozhidar Batsov <bozhidar@batsov.com>
  8. ;; Hugo Duncan <hugo@hugoduncan.org>
  9. ;; Steve Purcell <steve@sanityinc.com>
  10. ;; This program is free software: you can redistribute it and/or modify
  11. ;; it under the terms of the GNU General Public License as published by
  12. ;; the Free Software Foundation, either version 3 of the License, or
  13. ;; (at your option) any later version.
  14. ;; This program is distributed in the hope that it will be useful,
  15. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ;; GNU General Public License for more details.
  18. ;; You should have received a copy of the GNU General Public License
  19. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. ;; This file is not part of GNU Emacs.
  21. ;;; Commentary:
  22. ;; Provides an Emacs Lisp client to connect to Clojure nREPL servers.
  23. ;;; Code:
  24. (require 'cider-client)
  25. (require 'cider-util)
  26. (require 'clojure-mode)
  27. (require 'dash)
  28. (require 'thingatpt)
  29. (require 'etags)
  30. (require 'arc-mode)
  31. (require 'ansi-color)
  32. (require 'cl-lib)
  33. (require 'compile)
  34. (require 'tramp)
  35. (defconst cider-error-buffer "*cider-error*")
  36. (defconst cider-doc-buffer "*cider-doc*")
  37. (defconst cider-src-buffer "*cider-src*")
  38. (defconst cider-result-buffer "*cider-result*")
  39. (defcustom cider-use-local-resources t
  40. "Use local resources under HOME if possible."
  41. :type 'boolean
  42. :group 'cider)
  43. (defcustom cider-popup-stacktraces t
  44. "Non-nil means pop-up error stacktraces for evaluation errors.
  45. Nil means show only an error message in the minibuffer. See also
  46. `cider-repl-popup-stacktraces', which overrides this setting
  47. for REPL buffers."
  48. :type 'boolean
  49. :group 'cider)
  50. (defcustom cider-popup-on-error t
  51. "When `cider-popup-on-error' is set to t, stacktraces will be displayed.
  52. When set to nil, stactraces will not be displayed, but will be available
  53. in the `cider-error-buffer', which defaults to *cider-error*."
  54. :type 'boolean
  55. :group 'cider)
  56. (defcustom cider-auto-select-error-buffer nil
  57. "Controls whether to auto-select the error popup buffer."
  58. :type 'boolean
  59. :group 'cider)
  60. (defface cider-error-highlight-face
  61. '((((supports :underline (:style wave)))
  62. (:underline (:style wave :color "red") :inherit unspecified))
  63. (t (:inherit font-lock-warning-face :underline t)))
  64. "Face used to highlight compilation errors in Clojure buffers."
  65. :group 'cider)
  66. (defface cider-warning-highlight-face
  67. '((((supports :underline (:style wave)))
  68. (:underline (:style wave :color "yellow") :inherit unspecified))
  69. (t (:inherit font-lock-warning-face :underline (:color "yellow"))))
  70. "Face used to highlight compilation warnings in Clojure buffers."
  71. :group 'cider)
  72. ;;; Connection info
  73. (defun cider--clojure-version ()
  74. "Retrieve the underlying connection's Clojure version."
  75. (cider-eval-and-get-value "(clojure-version)"))
  76. (defun cider--backend-version ()
  77. "Retrieve the underlying connection's nREPL version."
  78. (cider-eval-and-get-value "(:version-string clojure.tools.nrepl/version)"))
  79. (defun cider--connection-info (nrepl-connection-buffer)
  80. "Return info about NREPL-CONNECTION-BUFFER.
  81. Info contains project name, current REPL namespace, host:port endpoint and Clojure version."
  82. (with-current-buffer (get-buffer nrepl-connection-buffer)
  83. (format "Active nREPL connection: %s:%s, %s:%s (Clojure %s, nREPL %s)"
  84. (or (nrepl--project-name nrepl-project-dir) "<no project>")
  85. nrepl-buffer-ns
  86. (car nrepl-endpoint)
  87. (cadr nrepl-endpoint)
  88. (cider--clojure-version)
  89. (cider--backend-version))))
  90. (defun cider-display-current-connection-info ()
  91. "Display information about the current connection."
  92. (interactive)
  93. (message (cider--connection-info (nrepl-current-connection-buffer))))
  94. (defun cider-rotate-connection ()
  95. "Rotate and display the current nREPL connection."
  96. (interactive)
  97. (setq nrepl-connection-list
  98. (append (cdr nrepl-connection-list)
  99. (list (car nrepl-connection-list))))
  100. (message (cider--connection-info (car nrepl-connection-list))))
  101. ;;; Switching between REPL & source buffers
  102. (make-variable-buffer-local
  103. (defvar cider-last-clojure-buffer nil
  104. "A buffer-local variable holding the last Clojure source buffer.
  105. `cider-switch-to-last-clojure-buffer' uses this variable to jump
  106. back to last Clojure source buffer."))
  107. (defvar cider-current-clojure-buffer nil
  108. "This variable holds current buffer temporarily when connecting to a REPL.
  109. It is set to current buffer when `nrepl' or `cider-jack-in' is called.
  110. After the REPL buffer is created, the value of this variable is used
  111. to call `cider-remember-clojure-buffer'.")
  112. (defun cider-remember-clojure-buffer (buffer)
  113. "Try to remember the BUFFER from which the user jumps.
  114. The BUFFER needs to be a Clojure buffer and current major mode needs
  115. to be `cider-repl-mode'. The user can use `cider-switch-to-last-clojure-buffer'
  116. to jump back to the last Clojure source buffer."
  117. (when (and buffer
  118. (with-current-buffer buffer
  119. (derived-mode-p 'clojure-mode))
  120. (derived-mode-p 'cider-repl-mode))
  121. (setq cider-last-clojure-buffer buffer)))
  122. (defun cider-switch-to-repl-buffer (&optional arg)
  123. "Select the REPL buffer, when possible in an existing window.
  124. Hint: You can use `display-buffer-reuse-frames' and
  125. `special-display-buffer-names' to customize the frame in which
  126. the buffer should appear.
  127. With a prefix ARG sets the name of the REPL buffer to the one
  128. of the current source file."
  129. (interactive "P")
  130. (if (not (cider-connected-p))
  131. (message "No active nREPL connection.")
  132. (let ((buffer (current-buffer)))
  133. (when arg
  134. (cider-repl-set-ns (cider-current-ns)))
  135. (pop-to-buffer (cider-find-or-create-repl-buffer))
  136. (cider-remember-clojure-buffer buffer)
  137. (goto-char (point-max)))))
  138. (defun cider-switch-to-relevant-repl-buffer (arg)
  139. "Select the REPL buffer, when possible in an existing window.
  140. The buffer chosen is based on the file open in the current buffer.
  141. Hint: You can use `display-buffer-reuse-frames' and
  142. `special-display-buffer-names' to customize the frame in which
  143. the buffer should appear.
  144. With a prefix ARG sets the name of the REPL buffer to the one
  145. of the current source file.
  146. With a second prefix ARG the chosen REPL buffer is based on a
  147. supplied project directory."
  148. (interactive "P")
  149. (if (not (cider-connected-p))
  150. (message "No active nREPL connection.")
  151. (let ((project-directory
  152. (or (when arg
  153. (ido-read-directory-name "Project: "))
  154. (nrepl-project-directory-for (nrepl-current-dir)))))
  155. (if project-directory
  156. (let ((buf (car (-filter
  157. (lambda (conn)
  158. (let ((conn-proj-dir (with-current-buffer (get-buffer conn)
  159. nrepl-project-dir)))
  160. (when conn-proj-dir
  161. (equal (file-truename project-directory)
  162. (file-truename conn-proj-dir)))))
  163. nrepl-connection-list))))
  164. (if buf
  165. (setq nrepl-connection-list
  166. (cons buf (delq buf nrepl-connection-list)))
  167. (message "No relevant nREPL connection found. Switching to default connection.")))
  168. (message "No project directory found. Switching to default nREPL connection.")))
  169. (cider-switch-to-repl-buffer '())))
  170. (defun cider-switch-to-last-clojure-buffer ()
  171. "Switch to the last Clojure buffer.
  172. The default keybinding for this command is
  173. the same as `cider-switch-to-repl-buffer',
  174. so that it is very convenient to jump between a
  175. Clojure buffer and the REPL buffer."
  176. (interactive)
  177. (if (and (derived-mode-p 'cider-repl-mode)
  178. (buffer-live-p cider-last-clojure-buffer))
  179. (pop-to-buffer cider-last-clojure-buffer)
  180. (message "Don't know the original Clojure buffer")))
  181. (defun cider-find-and-clear-repl-buffer ()
  182. "Find the current REPL buffer and clear it.
  183. Returns to the buffer in which the command was invoked."
  184. (interactive)
  185. (let ((origin-buffer (current-buffer)))
  186. (switch-to-buffer (cider-current-repl-buffer))
  187. (cider-repl-clear-buffer)
  188. (switch-to-buffer origin-buffer)))
  189. ;;; Minibuffer eval
  190. (defvar cider-minibuffer-history '()
  191. "History list of expressions read from the minibuffer.")
  192. (defvar cider-minibuffer-map
  193. (let ((map (make-sparse-keymap)))
  194. (set-keymap-parent map minibuffer-local-map)
  195. (define-key map "TAB" 'complete-symbol)
  196. (define-key map "M-TAB" 'complete-symbol)
  197. map)
  198. "Minibuffer keymap used for reading Clojure expressions.")
  199. (defun cider-read-from-minibuffer (prompt &optional initial-value history)
  200. "Read a string from the minibuffer, prompting with PROMPT.
  201. If INITIAL-VALUE is non-nil, it is inserted into the minibuffer before
  202. reading input."
  203. (minibuffer-with-setup-hook
  204. (lambda ()
  205. (add-hook 'completion-at-point-functions
  206. #'cider-complete-at-point nil t)
  207. (run-hooks 'eval-expression-minibuffer-setup-hook))
  208. (read-from-minibuffer prompt initial-value
  209. cider-minibuffer-map nil
  210. 'cider-minibuffer-history)))
  211. (defun cider-read-and-eval ()
  212. "Read a sexp from the minibuffer and output its result to the echo area."
  213. (interactive)
  214. (cider-interactive-eval (cider-read-from-minibuffer "CIDER Eval: ")))
  215. ;;; Eval
  216. (defun cider-eval-region (start end)
  217. "Evaluate the region.
  218. The two arguments START and END are character positions;
  219. they can be in either order."
  220. (interactive "r")
  221. (cider-interactive-eval (buffer-substring-no-properties start end)))
  222. (defun cider-eval-buffer ()
  223. "Evaluate the current buffer."
  224. (interactive)
  225. (cider-eval-region (point-min) (point-max)))
  226. (defun cider-defun-at-point ()
  227. "Return the text of the top-level sexp at point."
  228. (apply #'buffer-substring-no-properties
  229. (cider--region-for-defun-at-point)))
  230. (defun cider--region-for-defun-at-point ()
  231. "Return the start and end position of defun at point."
  232. (save-excursion
  233. (save-match-data
  234. (end-of-defun)
  235. (let ((end (point)))
  236. (beginning-of-defun)
  237. (list (point) end)))))
  238. (defun cider-eval-defun-at-point (&optional prefix)
  239. "Evaluate the current toplevel form, and print result in the minibuffer.
  240. With a PREFIX argument, print the result in the current buffer."
  241. (interactive "P")
  242. (let ((form (cider-defun-at-point)))
  243. (if prefix
  244. (cider-interactive-eval-print form)
  245. (cider-interactive-eval form))))
  246. (define-obsolete-function-alias
  247. 'cider-eval-expression-at-point
  248. 'cider-eval-defun-at-point)
  249. (defun cider-eval-ns-form ()
  250. "Evaluate the current buffer's namespace form."
  251. (interactive)
  252. (when (clojure-find-ns)
  253. (save-excursion
  254. (goto-char (match-beginning 0))
  255. (cider-eval-defun-at-point))))
  256. (defun cider-bounds-of-sexp-at-point ()
  257. "Return the bounds sexp at point as a pair (or nil)."
  258. (or (and (equal (char-after) ?\()
  259. (member (char-before) '(?\' ?\, ?\@))
  260. ;; hide stuff before ( to avoid quirks with '( etc.
  261. (save-restriction
  262. (narrow-to-region (point) (point-max))
  263. (bounds-of-thing-at-point 'sexp)))
  264. (bounds-of-thing-at-point 'sexp)))
  265. (defun cider-symbol-at-point ()
  266. "Return the name of the symbol at point, otherwise nil."
  267. (let ((str (substring-no-properties (or (thing-at-point 'symbol) ""))))
  268. (and str
  269. (not (equal str (concat (cider-find-ns) "> ")))
  270. (not (equal str ""))
  271. (substring-no-properties str))))
  272. (defun cider-sexp-at-point ()
  273. "Return the sexp at point as a string, otherwise nil."
  274. (let ((bounds (cider-bounds-of-sexp-at-point)))
  275. (if bounds
  276. (buffer-substring-no-properties (car bounds)
  277. (cdr bounds)))))
  278. (defun cider-sexp-at-point-with-bounds ()
  279. "Return a list containing the sexp at point and its bounds."
  280. (let ((bounds (cider-bounds-of-sexp-at-point)))
  281. (if bounds
  282. (let ((start (car bounds))
  283. (end (cdr bounds)))
  284. (list (buffer-substring-no-properties start end)
  285. (cons (set-marker (make-marker) start)
  286. (set-marker (make-marker) end)))))))
  287. (defun cider-last-sexp ()
  288. "Return the last sexp."
  289. (buffer-substring-no-properties
  290. (save-excursion (backward-sexp) (point))
  291. (point)))
  292. ;;;
  293. (defun cider-tramp-prefix ()
  294. "Top element on `find-tag-marker-ring' used to determine Clojure host."
  295. (let ((jump-origin (buffer-file-name
  296. (marker-buffer
  297. (ring-ref find-tag-marker-ring 0)))))
  298. (when (tramp-tramp-file-p jump-origin)
  299. (let ((vec (tramp-dissect-file-name jump-origin)))
  300. (tramp-make-tramp-file-name (tramp-file-name-method vec)
  301. (tramp-file-name-user vec)
  302. (tramp-file-name-host vec)
  303. nil)))))
  304. (defun cider-home-prefix-adjustment (resource)
  305. "System-dependent HOME location will be adjusted in RESOURCE.
  306. Removes any leading slash if on Windows."
  307. (save-match-data
  308. (cond ((string-match "^\\/\\(Users\\|home\\)\\/\\w+\\(\\/.+\\)" resource)
  309. (concat (getenv "HOME") (match-string 2 resource)))
  310. ((and (eq system-type 'windows-nt)
  311. (string-match "^/" resource)
  312. (not (tramp-tramp-file-p resource)))
  313. (substring resource 1))
  314. (t
  315. resource))))
  316. (defun cider-emacs-or-clojure-side-adjustment (resource)
  317. "Fix the RESOURCE path depending on `cider-use-local-resources`."
  318. (let ((resource (cider-home-prefix-adjustment resource))
  319. (clojure-side-res (concat (cider-tramp-prefix) resource))
  320. (emacs-side-res resource))
  321. (cond ((equal resource "") resource)
  322. ((and cider-use-local-resources
  323. (file-exists-p emacs-side-res))
  324. emacs-side-res)
  325. ((file-exists-p clojure-side-res)
  326. clojure-side-res)
  327. (t
  328. resource))))
  329. (defun cider-find-file (filename)
  330. "Switch to a buffer visiting FILENAME.
  331. Adjusts for HOME location using `cider-home-prefix-adjustment'.
  332. Uses `find-file'."
  333. (find-file (cider-emacs-or-clojure-side-adjustment filename)))
  334. (defun cider-find-resource (resource)
  335. "Find and display RESOURCE."
  336. (cond ((string-match "^file:\\(.+\\)" resource)
  337. (cider-find-file (match-string 1 resource)))
  338. ((string-match "^\\(jar\\|zip\\):file:\\(.+\\)!/\\(.+\\)" resource)
  339. (let* ((jar (match-string 2 resource))
  340. (path (match-string 3 resource))
  341. (buffer-already-open (get-buffer (file-name-nondirectory jar))))
  342. (cider-find-file jar)
  343. (goto-char (point-min))
  344. (search-forward path)
  345. (let ((opened-buffer (current-buffer)))
  346. (archive-extract)
  347. (unless buffer-already-open
  348. (kill-buffer opened-buffer)))))
  349. (t (error "Unknown resource path %s" resource))))
  350. (defun cider-jump-to-def-for (location)
  351. "Jump to LOCATION's definition in the source code."
  352. ;; ugh; elisp destructuring doesn't work for vectors
  353. (let ((resource (aref location 0))
  354. (path (aref location 1))
  355. (line (aref location 2)))
  356. (if (and path (file-exists-p path))
  357. (find-file path)
  358. (cider-find-resource resource))
  359. (goto-char (point-min))
  360. (forward-line (1- line))))
  361. (defun cider-jump-to-def-handler (buffer)
  362. "Create a handler for jump-to-def in BUFFER."
  363. ;; TODO: got to be a simpler way to do this
  364. (nrepl-make-response-handler buffer
  365. (lambda (buffer value)
  366. (with-current-buffer buffer
  367. (ring-insert find-tag-marker-ring (point-marker)))
  368. (cider-jump-to-def-for
  369. (car (read-from-string value))))
  370. (lambda (buffer out) (message out))
  371. (lambda (buffer err) (message err))
  372. nil))
  373. (defun cider-jump-to-def (var)
  374. "Jump to the definition of the VAR at point."
  375. (let ((form (format "(let [ns-symbol '%s
  376. ns-var '%s
  377. ns-file (clojure.core/comp :file
  378. clojure.core/meta
  379. clojure.core/second
  380. clojure.core/first
  381. clojure.core/ns-publics)
  382. resource-str (clojure.core/comp clojure.core/str
  383. clojure.java.io/resource
  384. ns-file)
  385. file-str (clojure.core/comp clojure.core/str
  386. clojure.java.io/file
  387. ns-file)]
  388. (cond ((clojure.core/ns-aliases ns-symbol) ns-var)
  389. (let [resolved-ns ((clojure.core/ns-aliases ns-symbol) ns-var)]
  390. [(resource-str resolved-ns)
  391. (file-str resolved-ns)
  392. 1])
  393. (find-ns ns-var)
  394. [(resource-str ns-var)
  395. (file-str ns-var)
  396. 1]
  397. (clojure.core/ns-resolve ns-symbol ns-var)
  398. ((clojure.core/juxt
  399. (clojure.core/comp clojure.core/str
  400. clojure.java.io/resource
  401. :file)
  402. (clojure.core/comp clojure.core/str
  403. clojure.java.io/file
  404. :file)
  405. :line)
  406. (clojure.core/meta (clojure.core/ns-resolve ns-symbol ns-var)))))"
  407. (cider-current-ns) var)))
  408. (cider-tooling-eval form
  409. (cider-jump-to-def-handler (current-buffer))
  410. nrepl-buffer-ns)))
  411. (defun cider-jump (query)
  412. "Jump to the definition of QUERY."
  413. (interactive "P")
  414. (cider-read-symbol-name "Symbol: " 'cider-jump-to-def query))
  415. (defalias 'cider-jump-back 'pop-tag-mark)
  416. (defun cider-completion-complete-core-fn (str)
  417. "Return a list of completions for STR using complete.core/completions."
  418. (cider-eval-and-get-value
  419. (format "(clojure.core/require 'complete.core) (complete.core/completions \"%s\" *ns*)" str)
  420. nrepl-buffer-ns
  421. (nrepl-current-tooling-session)))
  422. (defun cider-completion-complete-op-fn (str)
  423. "Return a list of completions for STR using the nREPL \"complete\" op."
  424. (let ((strlst (plist-get
  425. (nrepl-send-request-sync
  426. (list "op" "complete"
  427. "session" (nrepl-current-tooling-session)
  428. "ns" nrepl-buffer-ns
  429. "symbol" str))
  430. :value)))
  431. (when strlst
  432. (car strlst))))
  433. (defun cider-dispatch-complete-symbol (str)
  434. "Return a list of completions for STR.
  435. Dispatch to the nREPL \"complete\" op if supported,
  436. otherwise dispatch to internal completion function."
  437. (if (nrepl-op-supported-p "complete")
  438. (cider-completion-complete-op-fn str)
  439. (cider-completion-complete-core-fn str)))
  440. (defun cider-complete-at-point ()
  441. "Complete the symbol at point."
  442. (let ((sap (symbol-at-point)))
  443. (when (and sap (not (in-string-p)))
  444. (let ((bounds (bounds-of-thing-at-point 'symbol)))
  445. (list (car bounds) (cdr bounds)
  446. (completion-table-dynamic #'cider-dispatch-complete-symbol))))))
  447. ;;; JavaDoc Browsing
  448. ;;; Assumes local-paths are accessible in the VM.
  449. (defvar cider-javadoc-local-paths nil
  450. "List of paths to directories with Javadoc.")
  451. (defun cider-javadoc-op (symbol-name)
  452. "Invoke the nREPL \"javadoc\" op on SYMBOL-NAME."
  453. (cider-send-op
  454. "javadoc"
  455. `("symbol" ,symbol-name "ns" ,nrepl-buffer-ns
  456. "local-paths" ,(mapconcat #'identity cider-javadoc-local-paths " "))
  457. (nrepl-make-response-handler
  458. (current-buffer)
  459. (lambda (buffer url)
  460. (if url
  461. (browse-url url)
  462. (error "No javadoc url for %s" symbol-name)))
  463. nil nil nil)))
  464. (defun cider-javadoc-handler (symbol-name)
  465. "Invoke the nREPL \"javadoc\" op on SYMBOL-NAME if available."
  466. (when symbol-name
  467. (let ((bounds (bounds-of-thing-at-point 'symbol)))
  468. (if (nrepl-op-supported-p "javadoc")
  469. (cider-javadoc-op symbol-name)
  470. (message "No Javadoc middleware available")))))
  471. (defun cider-javadoc (query)
  472. "Browse Javadoc on the Java class QUERY at point."
  473. (interactive "P")
  474. (cider-read-symbol-name "Javadoc for: " 'cider-javadoc-handler query))
  475. (defun cider-stdin-handler (buffer)
  476. "Make a stdin response handler for BUFFER."
  477. (nrepl-make-response-handler buffer
  478. (lambda (buffer value)
  479. (cider-repl-emit-result buffer value t))
  480. (lambda (buffer out)
  481. (cider-repl-emit-output buffer out t))
  482. (lambda (buffer err)
  483. (cider-repl-emit-output buffer err t))
  484. nil))
  485. (defun cider-insert-eval-handler (buffer)
  486. "Make a nREPL evaluation handler for the BUFFER.
  487. The handler simply inserts the result value in BUFFER."
  488. (nrepl-make-response-handler buffer
  489. (lambda (buffer value)
  490. (with-current-buffer buffer
  491. (insert value)))
  492. (lambda (buffer out)
  493. (cider-repl-emit-interactive-output out))
  494. (lambda (buffer err)
  495. (message "%s" err)
  496. (cider-highlight-compilation-errors
  497. buffer err))
  498. '()))
  499. (defun cider-interactive-eval-handler (buffer)
  500. "Make an interactive eval handler for BUFFER."
  501. (nrepl-make-response-handler buffer
  502. (lambda (buffer value)
  503. (message "%s" value))
  504. (lambda (buffer value)
  505. (cider-repl-emit-interactive-output value))
  506. (lambda (buffer err)
  507. (message "%s" err)
  508. (cider-highlight-compilation-errors
  509. buffer err))
  510. '()))
  511. (defun cider-load-file-handler (buffer)
  512. "Make a load file handler for BUFFER."
  513. (let (current-ns (cider-current-ns))
  514. (nrepl-make-response-handler buffer
  515. (lambda (buffer value)
  516. (message "%s" value)
  517. (with-current-buffer buffer
  518. (setq nrepl-buffer-ns (clojure-find-ns))
  519. (run-hooks 'cider-file-loaded-hook)))
  520. (lambda (buffer value)
  521. (cider-repl-emit-interactive-output value))
  522. (lambda (buffer err)
  523. (message "%s" err)
  524. (cider-highlight-compilation-errors
  525. buffer err))
  526. '()
  527. (lambda (buffer ex root-ex session)
  528. (let ((cider-popup-on-error nil))
  529. (funcall nrepl-err-handler
  530. buffer ex root-ex session))))))
  531. (defun cider-interactive-eval-print-handler (buffer)
  532. "Make a handler for evaluating and printing result in BUFFER."
  533. (nrepl-make-response-handler buffer
  534. (lambda (buffer value)
  535. (with-current-buffer buffer
  536. (insert (format "%s" value))))
  537. '()
  538. (lambda (buffer err)
  539. (message "%s" err))
  540. '()))
  541. (defun cider-popup-eval-print-handler (buffer)
  542. "Make a handler for evaluating and printing result in popup BUFFER."
  543. (nrepl-make-response-handler buffer
  544. (lambda (buffer str)
  545. (cider-emit-into-popup-buffer buffer str))
  546. '()
  547. (lambda (buffer str)
  548. (cider-emit-into-popup-buffer buffer str))
  549. '()))
  550. (defun cider-popup-eval-out-handler (buffer)
  551. "Make a handler for evaluating and printing stdout/stderr in popup BUFFER."
  552. (nrepl-make-response-handler buffer
  553. '()
  554. (lambda (buffer str)
  555. (cider-emit-into-popup-buffer buffer str))
  556. (lambda (buffer str)
  557. (cider-emit-into-popup-buffer buffer str))
  558. '()))
  559. (defun cider-visit-error-buffer ()
  560. "Visit the `cider-error-buffer' (usually *cider-error*) if it exists."
  561. (interactive)
  562. (let ((buffer (get-buffer cider-error-buffer)))
  563. (when buffer
  564. (cider-popup-buffer-display buffer))))
  565. (defun cider-find-property (property &optional backward)
  566. "Find the next text region which has the specified PROPERTY.
  567. If BACKWARD is t, then search backward.
  568. Returns the position at which PROPERTY was found, or nil if not found."
  569. (let ((p (if backward
  570. (previous-single-char-property-change (point) property)
  571. (next-single-char-property-change (point) property))))
  572. (when (and (not (= p (point-min))) (not (= p (point-max))))
  573. p)))
  574. (defun cider-jump-to-compilation-error (&optional arg reset)
  575. "Jump to the line causing the current compilation error.
  576. ARG and RESET are ignored, as there is only ever one compilation error.
  577. They exist for compatibility with `next-error'."
  578. (interactive)
  579. (cl-labels ((goto-next-note-boundary
  580. ()
  581. (let ((p (or (cider-find-property 'cider-note-p)
  582. (cider-find-property 'cider-note-p t))))
  583. (when p
  584. (goto-char p)
  585. (message (get-char-property p 'cider-note))))))
  586. ;; if we're already on a compilation error, first jump to the end of
  587. ;; it, so that we find the next error.
  588. (when (get-char-property (point) 'cider-note-p)
  589. (goto-next-note-boundary))
  590. (goto-next-note-boundary)))
  591. (defun cider-default-err-handler (buffer ex root-ex session)
  592. "Make an error handler for BUFFER, EX, ROOT-EX and SESSION."
  593. ;; TODO: use ex and root-ex as fallback values to display when pst/print-stack-trace-not-found
  594. (let ((replp (with-current-buffer buffer (derived-mode-p 'cider-repl-mode))))
  595. (if (or (and cider-repl-popup-stacktraces replp)
  596. (and cider-popup-stacktraces (not replp)))
  597. (lexical-let ((cider-popup-on-error cider-popup-on-error))
  598. (with-current-buffer buffer
  599. (cider-eval "(if-let [pst+ (clojure.core/resolve 'clj-stacktrace.repl/pst+)]
  600. (pst+ *e) (clojure.stacktrace/print-stack-trace *e))"
  601. (nrepl-make-response-handler
  602. (cider-make-popup-buffer cider-error-buffer)
  603. nil
  604. (lambda (buffer value)
  605. (cider-emit-into-color-buffer buffer value)
  606. (when cider-popup-on-error
  607. (cider-popup-buffer-display buffer cider-auto-select-error-buffer)))
  608. nil nil) nil session))
  609. (with-current-buffer cider-error-buffer
  610. (compilation-minor-mode +1))))))
  611. (defvar cider-compilation-regexp
  612. '("\\(?:.*\\(warning, \\)\\|.*?\\(, compiling\\):(\\)\\([^:]*\\):\\([[:digit:]]+\\)\\(?::\\([[:digit:]]+\\)\\)?\\(\\(?: - \\(.*\\)\\)\\|)\\)" 3 4 5 (1))
  613. "Specifications for matching errors and warnings in Clojure stacktraces.
  614. See `compilation-error-regexp-alist' for help on their format.")
  615. (add-to-list 'compilation-error-regexp-alist-alist
  616. (cons 'cider cider-compilation-regexp))
  617. (add-to-list 'compilation-error-regexp-alist 'cider)
  618. (defun cider-extract-error-info (regexp message)
  619. "Extract error information with REGEXP against MESSAGE."
  620. (let ((file (nth 1 regexp))
  621. (line (nth 2 regexp))
  622. (col (nth 3 regexp))
  623. (type (nth 4 regexp))
  624. (pat (car regexp)))
  625. (when (string-match pat message)
  626. ;; special processing for type (1.2) style
  627. (setq type (if (consp type)
  628. (or (and (car type) (match-end (car type)) 1)
  629. (and (cdr type) (match-end (cdr type)) 0)
  630. 2)))
  631. (list
  632. (when file
  633. (let ((val (match-string-no-properties file message)))
  634. (unless (string= val "NO_SOURCE_PATH") val)))
  635. (when line (string-to-number (match-string-no-properties line message)))
  636. (when col
  637. (let ((val (match-string-no-properties col message)))
  638. (when val (string-to-number val))))
  639. (aref [cider-warning-highlight-face
  640. cider-warning-highlight-face
  641. cider-error-highlight-face]
  642. (or type 2))
  643. message))))
  644. (defun cider-highlight-compilation-errors (buffer message)
  645. "Highlight compilation error line in BUFFER, using MESSAGE."
  646. (with-current-buffer buffer
  647. (let ((info (cider-extract-error-info cider-compilation-regexp message)))
  648. (when info
  649. (let ((file (nth 0 info))
  650. (line (nth 1 info))
  651. (col (nth 2 info))
  652. (face (nth 3 info))
  653. (note (nth 4 info)))
  654. (save-excursion
  655. ;; when we don't have a filename the line number
  656. ;; is relative to form start
  657. (if file
  658. (goto-char (point-min)) ; start of file
  659. (beginning-of-defun))
  660. (forward-line (1- line))
  661. ;; if have column, highlight sexp at that point otherwise whole line.
  662. (move-to-column (or col 0))
  663. (let ((begin (progn (if col (backward-up-list) (back-to-indentation)) (point)))
  664. (end (progn (if col (forward-sexp) (move-end-of-line nil)) (point))))
  665. (let ((overlay (make-overlay begin end)))
  666. (overlay-put overlay 'cider-note-p t)
  667. (overlay-put overlay 'face face)
  668. (overlay-put overlay 'cider-note note)
  669. (overlay-put overlay 'help-echo note)))))))))
  670. (defun cider-need-input (buffer)
  671. "Handle an need-input request from BUFFER."
  672. (with-current-buffer buffer
  673. (nrepl-send-stdin (concat (read-from-minibuffer "Stdin: ") "\n")
  674. (cider-stdin-handler buffer))))
  675. ;;;; Popup buffers
  676. (define-minor-mode cider-popup-buffer-mode
  677. "Mode for CIDER popup buffers"
  678. nil
  679. (" cider-tmp")
  680. '(("q" . cider-popup-buffer-quit-function)))
  681. (make-variable-buffer-local
  682. (defvar cider-popup-buffer-quit-function 'cider-popup-buffer-quit
  683. "The function that is used to quit a temporary popup buffer."))
  684. (defun cider-popup-buffer-quit-function (&optional kill-buffer-p)
  685. "Wrapper to invoke the function `cider-popup-buffer-quit-function'.
  686. KILL-BUFFER-P is passed along."
  687. (interactive)
  688. (funcall cider-popup-buffer-quit-function kill-buffer-p))
  689. (defun cider-popup-buffer (name &optional select)
  690. "Create new popup buffer called NAME.
  691. If SELECT is non-nil, select the newly created window"
  692. (with-current-buffer (cider-make-popup-buffer name)
  693. (setq buffer-read-only t)
  694. (cider-popup-buffer-display (current-buffer) select)))
  695. (defun cider-popup-buffer-display (popup-buffer &optional select)
  696. "Display POPUP-BUFFER.
  697. If SELECT is non-nil, select the newly created window"
  698. (with-current-buffer popup-buffer
  699. (let ((new-window (display-buffer (current-buffer))))
  700. (set-window-point new-window (point))
  701. (when select
  702. (select-window new-window))
  703. (current-buffer))))
  704. (defun cider-popup-buffer-quit (&optional kill-buffer-p)
  705. "Quit the current (temp) window and bury its buffer using `quit-window'.
  706. If prefix argument KILL-BUFFER-P is non-nil, kill the buffer instead of burying it."
  707. (interactive)
  708. (quit-window kill-buffer-p (selected-window)))
  709. (defun cider-make-popup-buffer (name)
  710. "Create a temporary buffer called NAME."
  711. (with-current-buffer (get-buffer-create name)
  712. (kill-all-local-variables)
  713. (setq buffer-read-only nil)
  714. (erase-buffer)
  715. (set-syntax-table clojure-mode-syntax-table)
  716. (cider-popup-buffer-mode 1)
  717. (current-buffer)))
  718. (defun cider-emit-into-popup-buffer (buffer value)
  719. "Emit into BUFFER the provided VALUE."
  720. (with-current-buffer buffer
  721. (let ((inhibit-read-only t)
  722. (buffer-undo-list t))
  723. (insert (format "%s" value))
  724. (indent-sexp)
  725. (font-lock-fontify-buffer))))
  726. (defun cider-emit-into-color-buffer (buffer value)
  727. "Emit into color BUFFER the provided VALUE."
  728. (with-current-buffer buffer
  729. (let ((inhibit-read-only t)
  730. (buffer-undo-list t))
  731. (goto-char (point-max))
  732. (insert (format "%s" value))
  733. (ansi-color-apply-on-region (point-min) (point-max)))
  734. (goto-char (point-min))))
  735. ;;; Namespace handling
  736. (defun cider-find-ns ()
  737. "Return the ns of the current buffer.
  738. For Clojure buffers the ns is extracted from the ns header. If
  739. it's missing \"user\" is used as fallback."
  740. (cond
  741. ((derived-mode-p 'clojure-mode)
  742. (or (save-restriction
  743. (widen)
  744. (clojure-find-ns))
  745. "user"))
  746. ((derived-mode-p 'cider-repl-mode)
  747. nrepl-buffer-ns)))
  748. (defun cider-current-ns ()
  749. "Return the ns in the current context.
  750. If `nrepl-buffer-ns' has a value then return that, otherwise
  751. search for and read a `ns' form."
  752. (let ((ns nrepl-buffer-ns))
  753. (or (and (string= ns "user")
  754. (cider-find-ns))
  755. ns)))
  756. ;;; Evaluation
  757. (defun cider-popup-eval-print (form)
  758. "Evaluate the given FORM and print value in current buffer."
  759. (let ((buffer (current-buffer)))
  760. (cider-eval form
  761. (cider-popup-eval-print-handler buffer)
  762. (cider-current-ns))))
  763. (defun cider-interactive-eval-print (form)
  764. "Evaluate the given FORM and print value in current buffer."
  765. (let ((buffer (current-buffer)))
  766. (cider-eval form
  767. (cider-interactive-eval-print-handler buffer)
  768. (cider-current-ns))))
  769. (defun cider-interactive-eval (form)
  770. "Evaluate the given FORM and print value in minibuffer."
  771. (remove-overlays (point-min) (point-max) 'cider-note-p t)
  772. (let ((buffer (current-buffer)))
  773. (cider-eval form
  774. (cider-interactive-eval-handler buffer)
  775. (cider-current-ns))))
  776. (defun cider-interactive-eval-to-repl (form)
  777. "Evaluate the given FORM and print it's value in REPL buffer."
  778. (let ((buffer (cider-current-repl-buffer)))
  779. (cider-eval form
  780. (cider-insert-eval-handler buffer)
  781. (cider-current-ns))))
  782. (defun cider-eval-last-sexp (&optional prefix)
  783. "Evaluate the expression preceding point.
  784. If invoked with a PREFIX argument, print the result in the current buffer."
  785. (interactive "P")
  786. (if prefix
  787. (cider-interactive-eval-print (cider-last-sexp))
  788. (cider-interactive-eval (cider-last-sexp))))
  789. (define-obsolete-function-alias
  790. 'cider-eval-last-expression
  791. 'cider-eval-last-sexp)
  792. (defun cider-eval-last-sexp-and-replace ()
  793. "Evaluate the expression preceding point and replace it with its result."
  794. (interactive)
  795. (let ((last-sexp (cider-last-sexp)))
  796. ;; we have to be sure the evaluation won't result in an error
  797. (cider-eval-and-get-value last-sexp)
  798. ;; seems like the sexp is valid, so we can safely kill it
  799. (backward-kill-sexp)
  800. (cider-interactive-eval-print last-sexp)))
  801. (defun cider-eval-last-sexp-to-repl (&optional prefix)
  802. "Evaluate the expression preceding point and insert its result in the REPL.
  803. If invoked with a PREFIX argument, switch to the REPL buffer."
  804. (interactive "P")
  805. (cider-interactive-eval-to-repl (cider-last-sexp))
  806. (when prefix
  807. (cider-switch-to-repl-buffer)))
  808. (defun cider-eval-print-last-sexp ()
  809. "Evaluate the expression preceding point.
  810. Print its value into the current buffer"
  811. (interactive)
  812. (cider-interactive-eval-print (cider-last-sexp)))
  813. (defun cider-pprint-eval-last-sexp ()
  814. "Evaluate the expression preceding point and pprint its value in a popup buffer."
  815. (interactive)
  816. (let ((form (cider-last-sexp))
  817. (result-buffer (cider-popup-buffer cider-result-buffer nil)))
  818. (cider-tooling-eval (format "(clojure.pprint/pprint %s)" form)
  819. (cider-popup-eval-out-handler result-buffer)
  820. (cider-current-ns))))
  821. (defun cider-insert-last-sexp-in-repl (&optional arg)
  822. "Insert the expression preceding point in the REPL buffer.
  823. If invoked with a prefix ARG eval the expression after inserting it."
  824. (interactive "P")
  825. (let ((form (cider-last-sexp))
  826. (start-pos (point)))
  827. (with-current-buffer (cider-current-repl-buffer)
  828. (insert form)
  829. (indent-region start-pos (point))
  830. (when arg
  831. (cider-repl-return))))
  832. (cider-switch-to-repl-buffer))
  833. (defun cider-ping ()
  834. "Check that communication with the server works."
  835. (interactive)
  836. (message "%s" (cider-eval-and-get-value "\"PONG\"")))
  837. (defun clojure-enable-cider ()
  838. "Turn on CIDER mode (see command `cider-mode').
  839. Useful in hooks."
  840. (cider-mode 1)
  841. (setq next-error-function 'cider-jump-to-compilation-error))
  842. (defun clojure-disable-cider ()
  843. "Turn off CIDER mode (see command `cider-mode').
  844. Useful in hooks."
  845. (cider-mode -1))
  846. (defun cider-connected-p ()
  847. "Return t if CIDER is currently connected, nil otherwise."
  848. (condition-case nil
  849. (nrepl-current-connection-buffer)
  850. (error nil)))
  851. (defun cider-enable-on-existing-clojure-buffers ()
  852. "Enable interaction mode on existing Clojure buffers.
  853. See command `cider-mode'."
  854. (interactive)
  855. (add-hook 'clojure-mode-hook 'clojure-enable-cider)
  856. (dolist (buffer (cider-util--clojure-buffers))
  857. (with-current-buffer buffer
  858. (clojure-enable-cider))))
  859. (defun cider-disable-on-existing-clojure-buffers ()
  860. "Disable `cider-mode' on existing Clojure buffers.
  861. See command `cider-mode'."
  862. (interactive)
  863. (dolist (buffer (cider-util--clojure-buffers))
  864. (with-current-buffer buffer
  865. (setq nrepl-buffer-ns "user")
  866. (clojure-disable-cider))))
  867. (defun cider-possibly-disable-on-existing-clojure-buffers ()
  868. "If not connected, disable `cider-mode' on existing Clojure buffers."
  869. (unless (cider-connected-p)
  870. (cider-disable-on-existing-clojure-buffers)))
  871. ;; this is horrible, but with async callbacks we can't rely on dynamic scope
  872. (defvar cider-ido-ns nil)
  873. (defvar cider-ido-var-callback nil)
  874. (defun cider-ido-form (ns)
  875. "Construct a Clojure form for ido read using NS."
  876. `(concat (if (find-ns (symbol ,ns))
  877. (map name (concat (keys (ns-interns (symbol ,ns)))
  878. (keys (ns-refers (symbol ,ns))))))
  879. (if (not= "" ,ns) [".."])
  880. (->> (all-ns)
  881. (map (fn [n]
  882. (re-find (re-pattern (str "^" (if (not= ,ns "")
  883. (str ,ns "\\."))
  884. "[^\\.]+"))
  885. (str n))))
  886. (filter identity)
  887. (map (fn [n] (str n "/")))
  888. (into (hash-set)))))
  889. (defun cider-ido-up-ns (ns)
  890. "Perform up using NS."
  891. (mapconcat 'identity (butlast (split-string ns "\\.")) "."))
  892. (defun cider-ido-var-select (selected targets)
  893. "Peform ido select using SELECTED and TARGETS."
  894. ;; TODO: immediate RET gives "" as selected for some reason
  895. ;; this is an OK workaround though
  896. (cond ((equal "" selected)
  897. (cider-ido-var-select (car targets) targets))
  898. ((equal "/" (substring selected -1)) ; selected a namespace
  899. (cider-ido-read-var (substring selected 0 -1) cider-ido-var-callback))
  900. ((equal ".." selected)
  901. (cider-ido-read-var (cider-ido-up-ns cider-ido-ns) cider-ido-var-callback))
  902. ;; non ido variable selection techniques don't return qualified symbols, so this shouldn't either
  903. (t (funcall cider-ido-var-callback selected))))
  904. (defun cider-ido-read-sym-handler (label ido-select buffer)
  905. "Create an ido read var handler with IDO-SELECT for BUFFER."
  906. (lexical-let ((ido-select ido-select)
  907. (label label))
  908. (nrepl-make-response-handler buffer
  909. (lambda (buffer value)
  910. ;; make sure to eval the callback in the buffer that the symbol was requested from so we get the right namespace
  911. (with-current-buffer buffer
  912. (let* ((targets (car (read-from-string value)))
  913. (selected (ido-completing-read label targets nil t)))
  914. (funcall ido-select selected targets))))
  915. nil nil nil)))
  916. (defun cider-ido-read-var (ns ido-callback)
  917. "Perform ido read var in NS using IDO-CALLBACK."
  918. ;; Have to be stateful =(
  919. (setq cider-ido-ns ns)
  920. (setq cider-ido-var-callback ido-callback)
  921. (cider-tooling-eval (prin1-to-string (cider-ido-form cider-ido-ns))
  922. (cider-ido-read-sym-handler "Var:" 'cider-ido-var-select (current-buffer))
  923. nrepl-buffer-ns))
  924. (defun cider-ido-fns-form (ns)
  925. "Construct a Clojure form for reading fns using supplied NS."
  926. (format "(let [fn-pred (fn [[k v]] (and (fn? (.get v))
  927. (not (re-find #\"clojure.\" (str v)))))]
  928. (sort
  929. (map (comp name key)
  930. (filter fn-pred
  931. (concat
  932. (ns-interns '%s)
  933. (ns-refers '%s))))))" ns ns))
  934. (defun cider-ido-fn-callback (f targets)
  935. (with-current-buffer (cider-current-repl-buffer)
  936. (cider-repl--replace-input (format "(%s)" f))
  937. (goto-char (- (point-max) 1))))
  938. (defun cider-load-fn-into-repl-buffer ()
  939. "Browse functions available in current repl buffer using ido.
  940. Once selected, the name of the fn will appear in the repl buffer in parens
  941. ready to call."
  942. (interactive)
  943. (cider-tooling-eval (cider-ido-fns-form (cider-current-ns))
  944. (cider-ido-read-sym-handler (format "Fn: %s/" nrepl-buffer-ns)
  945. 'cider-ido-fn-callback (current-buffer))
  946. nrepl-buffer-ns))
  947. (defun cider-read-symbol-name (prompt callback &optional query)
  948. "Either read a symbol name using PROMPT or choose the one at point.
  949. Use CALLBACK as the ido read var callback.
  950. The user is prompted with PROMPT if a prefix argument is in effect,
  951. if there is no symbol at point, or if QUERY is non-nil."
  952. (let ((symbol-name (cider-symbol-at-point)))
  953. (cond ((not (or current-prefix-arg query (not symbol-name)))
  954. (funcall callback symbol-name))
  955. (ido-mode (cider-ido-read-var nrepl-buffer-ns callback))
  956. (t (funcall callback (read-from-minibuffer prompt symbol-name))))))
  957. (defun cider-doc-handler (symbol)
  958. "Create a handler to lookup documentation for SYMBOL."
  959. (let ((form (format "(clojure.repl/doc %s)" symbol))
  960. (doc-buffer (cider-popup-buffer cider-doc-buffer t)))
  961. (cider-tooling-eval form
  962. (cider-popup-eval-out-handler doc-buffer)
  963. nrepl-buffer-ns)))
  964. (defun cider-doc (query)
  965. "Open a window with the docstring for the given QUERY.
  966. Defaults to the symbol at point. With prefix arg or no symbol
  967. under point, prompts for a var."
  968. (interactive "P")
  969. (cider-read-symbol-name "Symbol: " 'cider-doc-handler query))
  970. (defun cider-src-handler (symbol)
  971. "Create a handler to lookup source for SYMBOL."
  972. (let ((form (format "(clojure.repl/source %s)" symbol))
  973. (src-buffer (cider-popup-buffer cider-src-buffer t)))
  974. (with-current-buffer src-buffer
  975. (clojure-mode)
  976. (cider-popup-buffer-mode +1))
  977. (cider-tooling-eval form
  978. (cider-popup-eval-out-handler src-buffer)
  979. nrepl-buffer-ns)))
  980. (defun cider-src (query)
  981. "Open a window with the source for the given QUERY.
  982. Defaults to the symbol at point. With prefix arg or no symbol
  983. under point, prompts for a var."
  984. (interactive "P")
  985. (cider-read-symbol-name "Symbol: " 'cider-src-handler query))
  986. ;; TODO: implement reloading ns
  987. (defun cider-eval-load-file (form)
  988. "Load FORM."
  989. (let ((buffer (current-buffer)))
  990. (cider-eval form (cider-interactive-eval-handler buffer))))
  991. (defun cider-file-string (file)
  992. "Read the contents of a FILE and return as a string."
  993. (with-current-buffer (find-file-noselect file)
  994. (buffer-string)))
  995. (defun cider-load-file-op (filename)
  996. "Send \"load-file\" op for FILENAME."
  997. (cider-send-load-file (cider-file-string filename)
  998. filename
  999. (file-name-nondirectory filename)))
  1000. (defun cider-load-file (filename)
  1001. "Load the Clojure file FILENAME."
  1002. (interactive (list
  1003. (read-file-name "Load file: " nil nil
  1004. nil (if (buffer-file-name)
  1005. (file-name-nondirectory
  1006. (buffer-file-name))))))
  1007. (remove-overlays (point-min) (point-max) 'cider-note-p t)
  1008. (cider-load-file-op filename)
  1009. (message "Loading %s..." filename))
  1010. (defun cider-load-current-buffer ()
  1011. "Load current buffer's file."
  1012. (interactive)
  1013. (check-parens)
  1014. (unless buffer-file-name
  1015. (error "Buffer %s is not associated with a file" (buffer-name)))
  1016. (when (and (buffer-modified-p)
  1017. (y-or-n-p (format "Save file %s? " (buffer-file-name))))
  1018. (save-buffer))
  1019. (cider-load-file (buffer-file-name)))
  1020. ;;; interrupt evaluation
  1021. (defun cider-interrupt-handler (buffer)
  1022. "Create an interrupt response handler for BUFFER."
  1023. (nrepl-make-response-handler buffer nil nil nil nil))
  1024. ;;; quiting
  1025. (defun cider--close-buffer (buffer)
  1026. "Close the BUFFER and kill its associated process (if any)."
  1027. (when (get-buffer-process buffer)
  1028. (delete-process (get-buffer-process buffer)))
  1029. (when (get-buffer buffer)
  1030. (kill-buffer buffer)))
  1031. (defvar cider-ancilliary-buffers
  1032. (list cider-error-buffer
  1033. cider-doc-buffer
  1034. cider-src-buffer
  1035. nrepl-event-buffer-name))
  1036. (defun cider-close-ancilliary-buffers ()
  1037. "Close buffers that are shared across connections."
  1038. (interactive)
  1039. (dolist (buf-name cider-ancilliary-buffers)
  1040. (cider--close-buffer buf-name)))
  1041. (defun cider-quit ()
  1042. "Quit CIDER.
  1043. Quitting closes all active nREPL connections and kills all CIDER buffers."
  1044. (interactive)
  1045. (when (y-or-n-p "Are you sure you want to quit CIDER? ")
  1046. (dolist (connection nrepl-connection-list)
  1047. (when connection
  1048. (nrepl-close connection)))
  1049. (message "All active nREPL connections were closed")
  1050. (cider-close-ancilliary-buffers)))
  1051. (defun cider-restart (&optional prompt-project)
  1052. "Quit CIDER and restart it.
  1053. If PROMPT-PROJECT is t, then prompt for the project in which to
  1054. restart the server."
  1055. (interactive)
  1056. (cider-quit)
  1057. (cider-jack-in current-prefix-arg))
  1058. (add-hook 'nrepl-connected-hook 'cider-enable-on-existing-clojure-buffers)
  1059. (add-hook 'nrepl-disconnected-hook
  1060. 'cider-possibly-disable-on-existing-clojure-buffers)
  1061. (provide 'cider-interaction)
  1062. ;;; cider-interaction.el ends here