我想获取上次编写特定函数或宏定义的文件的名称,用于各种文档和测试目的?
在 PJB 在#CommonLisp (IRC.LIBERA.CHAT) 上的帮助下,我发布了一个对我来说效果很好的答案,但会接受任何提供不依赖 SWANK 的便携式解决方案的答案或提供有关如何在 LispWorks、ACL 等其他 IDE 中实现相同的功能。
我想获取上次编写特定函数或宏定义的文件的名称,用于各种文档和测试目的?
在 PJB 在#CommonLisp (IRC.LIBERA.CHAT) 上的帮助下,我发布了一个对我来说效果很好的答案,但会接受任何提供不依赖 SWANK 的便携式解决方案的答案或提供有关如何在 LispWorks、ACL 等其他 IDE 中实现相同的功能。
如果您寻求的是一种可移植的解决方案——一种用可移植 CL 编写的解决方案——那么答案就是定义用于定义表单的包装器,然后使用包装器。
(defvar *flocs* (make-hash-table :test #'equal))
(defgeneric function-location (f/name)
(:method ((name t))
(values (gethash name *flocs* nil) t))
(:method ((f function))
(multiple-value-bind (le cp nm) (function-lambda-expression f)
(declare (ignore le cp))
(if nm
(function-location nm)
(values nil nil)))))
(defmacro define-function (f args &body doc/decls/forms)
(when (or *load-pathname* *compile-file-pathname*)
;; Prefer *load-pathname*
(setf (gethash f *flocs*) (or *load-pathname* *compile-file-pathname*)))
`(defun ,f ,args ,@doc/decls/forms))
在现实生活中,您define-function
defun
当然会调用define-variable
etc,然后为 CL 构建一个管道包,该包导出所有 CL 符号,同时用这些符号替换定义形式。
如果您寻求的是一种可移植的解决方案,即它导出一些标准接口但具有不同的实现相关的后端,那么可能看看 SLY 或 SWANK 做什么是一个好的开始。在 LW 的情况下,您可能希望后端使用 DSPEC,这是它处理位置信息的方式:
> (dspec:dspec-definition-locations '(defun foo))
(((defun foo) :listener))
> (dspec:dspec-definition-locations '(defun needs))
(((defmacro needs)
#P"..."))
> (defclass foo () ())
#<standard-class foo 402000B763>
> (dspec:name-definition-locations dspec:*dspec-classes* 'foo)
(((defclass foo) :listener) ((defun foo) :listener))
#CommonLisp (IRC.LIBERA.CHAT) 上的 PJB 提供了极大的帮助并提供了以下答案(我已经解释过,所以任何错误都归我所有):
首先,CL 是一个 lisp-2(实际上是 lisp-∞),因此可能没有一个单一的定义附加到一个符号上。例如,foo
下面提到的是哪个?
(deftype foo () (member foo))
(defvar foo 'foo)
(defun foo () foo)
此外,作为一个例子,符号可以在 REPL 中定义(没有关联的文件名),所以这不是一个可以在不假设意图的情况下直接回答的问题。
现在,当 的行为M-.
满足您的要求时,您可以在 slime/swank 中查看实现特定 API 的用途。
这应该指向您swank:find-definition-for-emacs
,这可能是您所追求的:
(swank:find-definitions-for-emacs "foo") #| -->
(("#'foo"
(:location (:file "/private/tmp/foo.lisp")
(:position 50)
(:snippet "(defun foo () foo)")))
("(type foo)"
(:location (:file "/private/tmp/foo.lisp")
(:position 1)
(:snippet "(deftype foo () '(member foo))")))
("(variable foo)"
(:location (:file "/private/tmp/foo.lisp")
(:position 32)
(:snippet "(defvar foo 'foo)"))))
如果您想依赖上述内容,请确保将其swank
作为依赖项加载到您的文件中。.asd
编辑:我还发现以下内容非常有用(并且 swank 对于大多数实现都有类似的文件,所以只需浏览每个文件以查看它们的等价物):
https://github.com/slime/slime/blob/68c58c0194ff03cd147fcec99f0ee90ba9178875/swank/sbcl.lisp#L811
(sb-introspect:find-definition-sources-by-name name type)
假设您使用的是 SBCL,函数调用(名称是符号,类型是关键字,例如 :function - 请参阅上面的链接)返回存储定义的文件。更多 (SBCL) 细节也在:
https://github.com/sbcl/sbcl/blob/master/contrib/sb-introspect/introspect.lisp