-
Notifications
You must be signed in to change notification settings - Fork 2
/
troncle.el
120 lines (102 loc) · 4.17 KB
/
troncle.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
;;; troncle.el --- Emacs convenience functions for tracing clojure code
;; Version: 0.1.2
;; Author: Alex Coventry
;; URL: https://github.com/coventry/troncle
;; Package-Requires: ((nrepl "0.2.0"))
;;; Commentary:
;; A library of functions for quickly wrapping and executing clojure
;; code with tracing instrumentation. See
;; https://github.com/coventry/troncle for usage and installation
;; instructions.
;;
;; This is a stub: To ensure that troncle's elisp and clojure logic
;; are compatible, the elisp for interaction with troncle is loaded
;; from the troncle jar file on the clojure side.
;;; Code:
(unless (require 'cider nil t)
(require 'nrepl))
(require 'clojure-mode)
;; cider.el/nrepl.el compatibility. Grr
(let ((prefix (if (featurep 'cider) "cider-" "nrepl-")))
(dolist (var '("send-op"
"current-ns"
"ido-read-var"
"ido-ns"))
(let ((aliased-var (intern (concat prefix var)))
(alias-sym (intern (concat "troncle--" var))))
(cond ((functionp aliased-var)
(defalias alias-sym aliased-var))
((boundp aliased-var)
(defvaralias alias-sym aliased-var))
('t (error "%S is not defined." aliased-var))))))
(defun str (&rest vals) (mapconcat (lambda (v) (pp-to-string v)) vals " "))
(defun troncle-op-handler (buffer)
"Return a handler for nrepl responses. Copied from
nrepl-discover's nrepl-discover-op-handler."
(lexical-let ((buffer buffer))
(lambda (response)
(nrepl-dbind-response response (message)
(when message (message message))
;; There is a bunch more I'm leaving out from
;; nrepl-discover-op-handler. Definitely want to go back and
;; look at how it handles overlays, when I get to that part.
))))
(defun troncle-toplevel-region-for-region ()
"Get all top-level forms contained in or neighbouring region
between point and mark."
(let ((start (save-excursion (goto-char (min (point) (mark)))
(beginning-of-defun) (point)))
(end (save-excursion (goto-char (max (point) (mark)))
(end-of-defun) (point))))
(list start end)))
(defun troncle-trace-region (rstart rend)
"Send top-level form point is in to troncle.emacs/trace-region
via nrepl protocol. The form is re-compiled, with all evaluable
forms in the current emacs region (between (point) and mark) are
instrumented wiht tracing. Then
troncle.traces/trace-execution-function is executed. (See
troncle-set-exec-var for a way to set this.)"
(interactive "r")
(save-excursion
(let* ((defun-region (troncle-toplevel-region-for-region))
(dstart (car defun-region)) (dend (car (cdr defun-region)))
(fn (buffer-file-name)))
(troncle--send-op "trace-region"
;; *-send-op can only handle strings
(list "source" (buffer-substring-no-properties
dstart dend)
"source-region" (str (cons fn defun-region))
"trace-region" (str (list fn rstart rend)))
(troncle-op-handler (current-buffer))))))
(defun troncle-discover-choose-var (ns exec-fn)
"Choose a var to be executed when forms are sent for tracing
instrumentation with troncle-trace-region. The var must be a fn
which takes no arguments. Invokes exec-fn with the fully
qualified var-name as string."
(lexical-let ((exec-fn exec-fn))
(troncle--ido-read-var (or ns "user")
(lambda (var)
(funcall exec-fn
(concat troncle--ido-ns "/"
var))))))
(defun troncle-send-var (opname)
"Get user to choose a var to send to OPNAME"
(lexical-let ((handler (troncle-op-handler (current-buffer)))
(opname opname))
(troncle-discover-choose-var
(clojure-find-ns)
(lambda (var)
(troncle--send-op opname (list "var" var) handler)))))
;;;###autoload
(defun troncle-set-exec-var ()
(interactive) (troncle-send-var "set-exec-var"))
;;;###autoload
(defun troncle-toggle-trace-var ()
(interactive) (troncle-send-var "toggle-trace-var"))
(eval-after-load 'clojure-mode
'(progn
(define-key clojure-mode-map (kbd "C-c t R") 'troncle-trace-region)
(define-key clojure-mode-map (kbd "C-c t E") 'troncle-set-exec-var)
(define-key clojure-mode-map (kbd "C-c t V") 'troncle-toggle-trace-var)))
(provide 'troncle)
;;; troncle.el ends here