Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
marvel
GitHub Repository: marvel/qnf
Path: blob/master/elisp/slime/contrib/slime-enclosing-context.el
990 views
1
2
(define-slime-contrib slime-enclosing-context
3
"Utilities on top of slime-parse."
4
(:authors "Tobias C. Rittweiler <[email protected]>")
5
(:license "GPL")
6
(:slime-dependencies slime-parse)
7
(:on-load (error "This contrib does not work at the moment.")))
8
9
(defvar slime-variable-binding-ops-alist
10
'((let &bindings &body)))
11
12
(defvar slime-function-binding-ops-alist
13
'((flet &bindings &body)
14
(labels &bindings &body)
15
(macrolet &bindings &body)))
16
17
(defun slime-lookup-binding-op (op &optional binding-type)
18
(flet ((lookup-in (list) (assoc* op list :test 'equalp :key 'symbol-name)))
19
(cond ((eq binding-type :variable) (lookup-in slime-variable-binding-ops-alist))
20
((eq binding-type :function) (lookup-in slime-function-binding-ops-alist))
21
(t (or (lookup-in slime-variable-binding-ops-alist)
22
(lookup-in slime-function-binding-ops-alist))))))
23
24
(defun slime-binding-op-p (op &optional binding-type)
25
(and (slime-lookup-binding-op op binding-type) t))
26
27
(defun slime-binding-op-body-pos (op)
28
(when-let (special-lambda-list (slime-lookup-binding-op op))
29
(position '&body special-lambda-list)))
30
31
(defun slime-binding-op-bindings-pos (op)
32
(when-let (special-lambda-list (slime-lookup-binding-op op))
33
(position '&bindings special-lambda-list)))
34
35
36
(defun slime-enclosing-bound-names ()
37
"Returns all bound function names as first value, and the
38
points where their bindings are established as second value."
39
(multiple-value-call #'slime-find-bound-names (slime-enclosing-form-specs)))
40
41
(defun slime-find-bound-names (ops indices points)
42
(let ((binding-names) (binding-start-points))
43
(save-excursion
44
(loop for (op . nil) in ops
45
for index in indices
46
for point in points
47
do (when (and (slime-binding-op-p op)
48
;; Are the bindings of OP in scope?
49
(>= index (slime-binding-op-body-pos op)))
50
(goto-char point)
51
(forward-sexp (slime-binding-op-bindings-pos op))
52
(down-list)
53
(ignore-errors
54
(loop
55
(down-list)
56
(push (slime-symbol-at-point) binding-names)
57
(push (save-excursion (backward-up-list) (point))
58
binding-start-points)
59
(up-list)))))
60
(values (nreverse binding-names) (nreverse binding-start-points)))))
61
62
63
(defun slime-enclosing-bound-functions ()
64
(multiple-value-call #'slime-find-bound-functions (slime-enclosing-form-specs)))
65
66
(defun slime-find-bound-functions (ops indices points)
67
(let ((names) (arglists) (start-points))
68
(save-excursion
69
(loop for (op . nil) in ops
70
for index in indices
71
for point in points
72
do (when (and (slime-binding-op-p op :function)
73
;; Are the bindings of OP in scope?
74
(>= index (slime-binding-op-body-pos op)))
75
(goto-char point)
76
(forward-sexp (slime-binding-op-bindings-pos op))
77
(down-list)
78
;; If we're at the end of the bindings, an error will
79
;; be signalled by the `down-list' below.
80
(ignore-errors
81
(loop
82
(down-list)
83
(destructuring-bind (name arglist)
84
(slime-parse-sexp-at-point 2)
85
(assert (slime-has-symbol-syntax-p name)) (assert arglist)
86
(push name names)
87
(push arglist arglists)
88
(push (save-excursion (backward-up-list) (point))
89
start-points))
90
(up-list)))))
91
(values (nreverse names)
92
(nreverse arglists)
93
(nreverse start-points)))))
94
95
96
(defun slime-enclosing-bound-macros ()
97
(multiple-value-call #'slime-find-bound-macros (slime-enclosing-form-specs)))
98
99
(defun slime-find-bound-macros (ops indices points)
100
;; Kludgy!
101
(let ((slime-function-binding-ops-alist '((macrolet &bindings &body))))
102
(slime-find-bound-functions ops indices points)))
103
104
;;; Tests
105
106
(def-slime-test enclosing-context.1
107
(buffer-sexpr wished-bound-names wished-bound-functions)
108
"Check that finding local definitions work."
109
'(("(flet ((,nil ()))
110
(let ((bar 13)
111
(,foo 42))
112
*HERE*))"
113
;; We used to return ,foo here, but we do not anymore. We
114
;; still return ,nil for the `slime-enclosing-bound-functions',
115
;; though. The first one is used for local M-., whereas the
116
;; latter is used for local autodoc. It does not seem too
117
;; important for local M-. to work on such names. \(The reason
118
;; that it does not work anymore, is that
119
;; `slime-symbol-at-point' now does TRT and does not return a
120
;; leading comma anymore.\)
121
("bar" nil nil)
122
((",nil" "()")))
123
("(flet ((foo ()))
124
(quux)
125
(bar *HERE*))"
126
("foo")
127
(("foo" "()"))))
128
(slime-check-top-level)
129
(with-temp-buffer
130
(let ((tmpbuf (current-buffer)))
131
(lisp-mode)
132
(insert buffer-sexpr)
133
(search-backward "*HERE*")
134
(multiple-value-bind (bound-names points)
135
(slime-enclosing-bound-names)
136
(slime-check "Check enclosing bound names"
137
(loop for name in wished-bound-names
138
always (member name bound-names))))
139
(multiple-value-bind (fn-names fn-arglists points)
140
(slime-enclosing-bound-functions)
141
(slime-check "Check enclosing bound functions"
142
(loop for (name arglist) in wished-bound-functions
143
always (and (member name fn-names)
144
(member arglist fn-arglists)))))
145
)))
146
147
(provide 'slime-enclosing-context)
148
149