forked from xquery-mode/cider-any
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cider-any.el
163 lines (136 loc) · 4.86 KB
/
cider-any.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
;;; cider-any.el --- Evaluate any buffer in cider. -*- lexical-binding: t; -*-
;; Copyright (C) 2016 by Artem Malyshev
;; Author: Artem Malyshev <proofit404@gmail.com>
;; URL: https://github.com/xquery-mode/cider-any
;; Version: 0.0.1
;; Package-Requires: ((cider "0.13.0"))
;;; Commentary:
;;; Code:
(require 'cl-lib)
(require 'cider)
(defgroup cider-any nil
"Evaluate any buffer in cider."
:group 'cider)
(defcustom cider-any-backends nil
"The list of active backends.
Only one backend is used at a time. Each backend is a function
that takes a variable number of arguments. The first argument is
the command requested from the backend. It is one of the
following:
`check': The backend should return t in the case it can eval in
current context. Returning nil from this command passed control
to the next backend.
`init': Backend initialization form. Result should be a string
that contains a valid clojure form. This form will be evaluated
once in the user session.
`handle-init': Process initialization result. The second
argument will hold initialization form result calculated
asynchronously. It is list of strings.
`eval': Request to perform evaluation of current context. The
second argument is the context type passed as a symbol.
`buffer', `function', `line' and `region' are default context
types. Return value must be a string containing the clojure form
which can actually evaluate the given context. It can contain %s
signature which will be substituted with actual evaluation
content.
`handle': Handle evaluation result. The second argument will be
an evaluation result. As with `handle-init' result is
represented as list of strings."
:type '(repeat :tag "User defined" (function)))
(defvar cider-any-initiated-backends nil
"Keep initialized backends.")
(defvar cider-any-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-c C-c") 'cider-any-buffer)
(define-key map (kbd "C-M-x") 'cider-any-function)
(define-key map (kbd "C-c C-l") 'cider-any-line)
(define-key map (kbd "C-c C-r") 'cider-any-region)
map)
"Keymap for `cider-any-mode'.")
(defun cider-any-buffer ()
"Eval current buffer in cider."
(interactive)
(cider-any-eval 'buffer))
(defun cider-any-function ()
"Eval current function in cider."
(interactive)
(cider-any-eval 'function))
(defun cider-any-line ()
"Eval current line in cider."
(interactive)
(cider-any-eval 'line))
(defun cider-any-region ()
"Eval current region in cider."
(interactive)
(cider-any-eval 'region))
(defun cider-any-string (string)
"Eval string in cider."
(interactive "sString: ")
(cider-any-eval string))
(defun cider-any-eval-arg (context)
"Get eval substitution for CONTEXT."
(replace-regexp-in-string
"\\\""
"\\\\\""
(if (stringp context)
context
(apply
#'buffer-substring-no-properties
(cl-case context
(buffer `(,(point-min)
,(point-max)))
(function `(,(save-excursion
(beginning-of-defun)
(point))
,(save-excursion
(end-of-defun)
(point))))
(line `(,(line-beginning-position)
,(line-end-position)))
(region (if (not (region-active-p))
(error "Region is not marked")
`(,(region-beginning)
,(region-end)))))))))
(defun cider-any-eval-handler (backend eval-context)
"Make an interactive eval handler for BACKEND.
EVAL-CONTEXT is a BACKEND command which can be either a `handle'
or `handle-init'."
(nrepl-make-response-handler
(current-buffer)
(lambda (buffer value)
(with-current-buffer buffer
(apply backend `(,eval-context ,value))))
(lambda (_buffer out)
(cider-emit-interactive-eval-output out))
(lambda (_buffer err)
(cider-emit-interactive-eval-err-output err))
'()))
(defun cider-any-eval (context)
"Try to evaluate current CONTEXT."
(let ((backends cider-any-backends)
backend found)
(while (and (not found) backends)
(setq backend (car-safe backends)
backends (cdr-safe backends))
(when (apply backend '(check))
(setq found t)))
(if (not backend)
(error "Can not evaluate current %s" context)
(unless (memq backend cider-any-initiated-backends)
(push backend cider-any-initiated-backends)
(cider-interactive-eval
(apply backend '(init))
(cider-any-eval-handler backend 'handle-init)))
(cider-interactive-eval
(format
(apply backend '(eval context))
(cider-any-eval-arg context))
(cider-any-eval-handler backend 'handle)))))
;;;###autoload
(define-minor-mode cider-any-mode
"Evaluate any buffer in the cider.
\\{cider-any-mode-map}"
:lighter " Cider-Any"
:keymap cider-any-mode-map)
(provide 'cider-any)
;;; cider-any.el ends here