Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find which file provide(d) the feature in emacs elisp

Tags:

emacs

elisp

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.

like image 394
Talespin_Kit Avatar asked Mar 08 '12 11:03

Talespin_Kit


People also ask

What is Emacs load path?

The value of variable 'load-path' is a list of directories to search, in order, for EmacsLisp libraries that you load. If you do not alter it (directly or indirectly), by default it contains the Lisp source directories for the Emacs distribution.

How do I read a file in Emacs?

To read a disk file into an emacs buffer, type the command Control-X-Control-F. Emacs will ask you for the name of the file. As you type the name of the file, it will be displayed in the mini buffer.

What does require do in Emacs?

If you load a library repeatedly, that file will be read and its code evaluated repeatedly (each and every time you load it). If you require a library repeatedly, it will load the library once (at most -- and not at all if the library had already been loaded).


4 Answers

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:

  1. You've already got the most important part -- find the variable with the information you need.

  2. 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))

  3. 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)*)
     ...)
    
  4. 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.

  1. 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

  2. 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

  3. 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.

  4. 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

  5. Narrow and search again:

    C-x n d M-s o up enter

    I see find-lisp-object-file-name which looks promising.

  6. 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.

like image 124
event_jr Avatar answered Dec 07 '22 11:12

event_jr


There is locate-library for that.

Try... M-: (locate-library "my-feature")

eg: (locate-library "gnus")

like image 24
kindahero Avatar answered Dec 07 '22 11:12

kindahero


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.
like image 21
gavenkoa Avatar answered Dec 07 '22 12:12

gavenkoa


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.

like image 22
Tom Avatar answered Dec 07 '22 13:12

Tom