Path: blob/master/elisp/slime/contrib/slime-enclosing-context.el
990 views
1(define-slime-contrib slime-enclosing-context2"Utilities on top of slime-parse."3(:authors "Tobias C. Rittweiler <[email protected]>")4(:license "GPL")5(:slime-dependencies slime-parse)6(:on-load (error "This contrib does not work at the moment.")))78(defvar slime-variable-binding-ops-alist9'((let &bindings &body)))1011(defvar slime-function-binding-ops-alist12'((flet &bindings &body)13(labels &bindings &body)14(macrolet &bindings &body)))1516(defun slime-lookup-binding-op (op &optional binding-type)17(flet ((lookup-in (list) (assoc* op list :test 'equalp :key 'symbol-name)))18(cond ((eq binding-type :variable) (lookup-in slime-variable-binding-ops-alist))19((eq binding-type :function) (lookup-in slime-function-binding-ops-alist))20(t (or (lookup-in slime-variable-binding-ops-alist)21(lookup-in slime-function-binding-ops-alist))))))2223(defun slime-binding-op-p (op &optional binding-type)24(and (slime-lookup-binding-op op binding-type) t))2526(defun slime-binding-op-body-pos (op)27(when-let (special-lambda-list (slime-lookup-binding-op op))28(position '&body special-lambda-list)))2930(defun slime-binding-op-bindings-pos (op)31(when-let (special-lambda-list (slime-lookup-binding-op op))32(position '&bindings special-lambda-list)))333435(defun slime-enclosing-bound-names ()36"Returns all bound function names as first value, and the37points where their bindings are established as second value."38(multiple-value-call #'slime-find-bound-names (slime-enclosing-form-specs)))3940(defun slime-find-bound-names (ops indices points)41(let ((binding-names) (binding-start-points))42(save-excursion43(loop for (op . nil) in ops44for index in indices45for point in points46do (when (and (slime-binding-op-p op)47;; Are the bindings of OP in scope?48(>= index (slime-binding-op-body-pos op)))49(goto-char point)50(forward-sexp (slime-binding-op-bindings-pos op))51(down-list)52(ignore-errors53(loop54(down-list)55(push (slime-symbol-at-point) binding-names)56(push (save-excursion (backward-up-list) (point))57binding-start-points)58(up-list)))))59(values (nreverse binding-names) (nreverse binding-start-points)))))606162(defun slime-enclosing-bound-functions ()63(multiple-value-call #'slime-find-bound-functions (slime-enclosing-form-specs)))6465(defun slime-find-bound-functions (ops indices points)66(let ((names) (arglists) (start-points))67(save-excursion68(loop for (op . nil) in ops69for index in indices70for point in points71do (when (and (slime-binding-op-p op :function)72;; Are the bindings of OP in scope?73(>= index (slime-binding-op-body-pos op)))74(goto-char point)75(forward-sexp (slime-binding-op-bindings-pos op))76(down-list)77;; If we're at the end of the bindings, an error will78;; be signalled by the `down-list' below.79(ignore-errors80(loop81(down-list)82(destructuring-bind (name arglist)83(slime-parse-sexp-at-point 2)84(assert (slime-has-symbol-syntax-p name)) (assert arglist)85(push name names)86(push arglist arglists)87(push (save-excursion (backward-up-list) (point))88start-points))89(up-list)))))90(values (nreverse names)91(nreverse arglists)92(nreverse start-points)))))939495(defun slime-enclosing-bound-macros ()96(multiple-value-call #'slime-find-bound-macros (slime-enclosing-form-specs)))9798(defun slime-find-bound-macros (ops indices points)99;; Kludgy!100(let ((slime-function-binding-ops-alist '((macrolet &bindings &body))))101(slime-find-bound-functions ops indices points)))102103;;; Tests104105(def-slime-test enclosing-context.1106(buffer-sexpr wished-bound-names wished-bound-functions)107"Check that finding local definitions work."108'(("(flet ((,nil ()))109(let ((bar 13)110(,foo 42))111*HERE*))"112;; We used to return ,foo here, but we do not anymore. We113;; still return ,nil for the `slime-enclosing-bound-functions',114;; though. The first one is used for local M-., whereas the115;; latter is used for local autodoc. It does not seem too116;; important for local M-. to work on such names. \(The reason117;; that it does not work anymore, is that118;; `slime-symbol-at-point' now does TRT and does not return a119;; leading comma anymore.\)120("bar" nil nil)121((",nil" "()")))122("(flet ((foo ()))123(quux)124(bar *HERE*))"125("foo")126(("foo" "()"))))127(slime-check-top-level)128(with-temp-buffer129(let ((tmpbuf (current-buffer)))130(lisp-mode)131(insert buffer-sexpr)132(search-backward "*HERE*")133(multiple-value-bind (bound-names points)134(slime-enclosing-bound-names)135(slime-check "Check enclosing bound names"136(loop for name in wished-bound-names137always (member name bound-names))))138(multiple-value-bind (fn-names fn-arglists points)139(slime-enclosing-bound-functions)140(slime-check "Check enclosing bound functions"141(loop for (name arglist) in wished-bound-functions142always (and (member name fn-names)143(member arglist fn-arglists)))))144)))145146(provide 'slime-enclosing-context)147148149