Currently i am using the load-history variable to find the file from which a feature came from.
suppose to find the file the feature gnus came from.
I execute the following code in scratch buffer which prints filename and the symbols in separate lines consecutively.
(dolist (var load-history)
(princ (format "%s\n" (car var)))
(princ (format "\t%s\n" (cdr var))))
and then search for "(provide . gnus)" and then move the point to the start of line(Ctrl+A).
The file name in the previous line is the file from which the feature came from.
Is there any thing wrong with this method, or does a better method exist.
I don't really know what you're trying to do with this, but here are some notes.
Your method is fine. Any way to hack your own solution to a problem is good in my book.
@Tom is correct that you shouldn't really need to do this, because the problem is already solved for you by the help system. i.e. C-h f
But that's not so interesting. Let's say you really want an automatic, more elegant solution. You want a function -- locate-feature
with this signature:
(defun locate-feature (feature)
"Return file-name as string where `feature' was provided"
...)
Method 1 load-history
approach
I'll just describe the steps I took to solve this:
You've already got the most important part -- find the variable with the information you need.
I notice immediately that this variable has a lot of data. If I insert it into a buffer as a single line, Emacs will not be happy, because it's notoriously bad at handling long lines. I know that the prett-print package will be able to format this data nicely. So I open up my *scratch*
buffer and run
M-: (insert (pp-to-string load-history))
I can now see the data structure I'm dealing with. It seems to be (in pseudo code):
((file-name
((defun|t|provide . symbol)|symbol)*)
...)
Now I just write the function
(eval-when-compile (require 'cl))
(defun locate-feature (feature)
"Return file name as string where `feature' was provided"
(interactive "Sfeature: ")
(dolist (file-info load-history)
(mapc (lambda (element)
(when (and (consp element)
(eq (car element) 'provide)
(eq (cdr element) feature))
(when (called-interactively-p 'any)
(message "%s defined in %s" feature (car file-info)))
(return (car file-info))))
(cdr file-info))))
The code here is pretty straight forward. Ask Emacs about the functions you don't understand.
Method 2 help approach
Method one works for features. But what if by I want to know where any
available function is defined? Not just features.
C-h f already tells me that, but I want the file-name in a string, not all of the verbose help text. I want this:
(defun locate-function (func)
"Return file-name as string where `func' was defined or will be autoloaded"
...)
Here we go.
C-h f is my starting point, but I really want to read the code that defines describe-function
. I do this:
C-h k C-h f C-x o tab enter
Now I'm in help-fns.el
at the definition of describe-function
. I want to work only with this function definition. So narrowing is in order:
C-x n d
I have a hunch that the interesting command will have "find" or "locate" in its name, so I use occur
to search for interesting lines:
M-s o find\|locate
No matches. Hmmm. Not a lot of lines in this defun. describe-function-1
seems to be doing the real work, so we try that.
I can visit the definition of describe-function-1
via C-h f. But I already have the file open. imenu
is available now:
C-x n w M-x imenu desc*1 tab enter
Narrow and search again:
C-x n d M-s o up enter
I see find-lisp-object-file-name
which looks promising.
After reading C-h f find-lisp-object-file-name I come up with:
(defun locate-function (func)
"Return file-name as string where `func' was defined or will be autoloaded"
(interactive "Ccommand: ")
(let ((res (find-lisp-object-file-name func (symbol-function func))))
(when (called-interactively-p 'any)
(message "%s defined in %s" func res))
res))
Now go have some fun exploring Emacs.
Just use symbol-file
. It scan load-history
which has format:
Each entry has the form `(provide . FEATURE)',
`(require . FEATURE)', `(defun . FUNCTION)', `(autoload . SYMBOL)',
`(defface . SYMBOL)', or `(t . SYMBOL)'. Entries like `(t . SYMBOL)'
may precede a `(defun . FUNCTION)' entry, and means that SYMBOL was an
autoload before this file redefined it as a function. In addition,
entries may also be single symbols, which means that SYMBOL was
defined by `defvar' or `defconst'.
So call it as:
(symbol-file 'scheme 'provide) ; Who provide feature.
(symbol-file 'nxml-mode-hook 'defvar) ; Where variable defined.
(symbol-file 'message-send 'defun) ; Where function defined.
(symbol-file 'scheme) ; Look for symbol despite its type.
There is locate-library
for that.
Try...
M-: (locate-library "my-feature")
eg: (locate-library "gnus")
There is nothing wrong with it, but why is it simpler than getting help on a key or a function? If you use a gnus command for example and you want to know where it comes from then you can use C-h k
and it tells you from which elisp file its definition comes.