5

(I'm a rookie and I use Spacemacs)

I'm trying to find the source of a certain function*. I can find the .el file in which it's defined by using find-function, however the defun is created dynamically using a macro.

Is there some way to show the source of the function as it exists now, after the macro has created it?

(* Specifically though I don't think it matters: spacemacs/align-repeat-bar)

6

find-function won't find macro-generated function definitions due to limitations of Emacs load-history and the workarounds find-function has to resort to.

find-function has to explicitly search for the actual source code location of a function definition because Emacs only tracks the defining library but not the actual location of the definition during reading and evaluation. It uses the regular expression in find-function-regexp which matches a couple of known built-in forms that define functions but knows nothing of 3rd party libraries that might also define functions.

Naturally find-function will thus fail to find any defining form which doesn't match find-function-regexp, which implies that it fails for almost all 3rd party macros that define functions.

You can manually add these to find-function-regexp however.

More detailed background information follows:


To track where exactly symbol cells are filled (with function definitions for instance) Emacs would have to track source file positions in a way to preserve locations through reading up to eval which it currently simply doesn't do—just take a look at compiled byte code (i.e. after read, but before evaluation), there are no source positions.

To be able to track loads (and thus be able to unload features and find definitions) Emacs has a load-history instead where certain forms (such as defun) leave entries during evaluation. When Emacs loads a library it puts a new entry into load-history and all defun and related forms in the library being loaded add to that entry.

But in this way Emacs only knows about the library that defined a function but not about the actual position of the source of the function within the library. find-function has to workaround the lack of this information, and it does so in a very dumb way: It visits the source library file, goes to the beginning of the buffer… and runs a literal search for a pattern that could match the definition of the function. In other words it does C-s <THE-NAME-OF-THE-FUNCTION>, just with a slightly more sophisticated pattern which you can actually inspect—and change, fwiw—in find-function-regexp.

If you take a look at the pattern you'll see that it quite literally looks for certain known forms that define functions, including defun, define-minor-mode and a couple of related forms, and thus it'll fail to find functions defined by macros whose names don't match that pattern.

  • 1
    Awesome, didn't know about find-function-regexp! – wasamasa Aug 1 '16 at 19:49
0

Macros don't really work dynamically. Reader macros work at read time - reader transforms some reader macro call into code, and during compilation before application macros are replaced with code, creating "static" code - and the same static code is there after compilation.

But you can't really see the static code, because it isn't there: macro will create it. Also, you can't plug into the compilation after the code has been generated and check what's there; however, you can use macroexpand. I don't have spacemacs and can't test it, but I would guess that if you run (macroexpand (quote *your-macro-here*)) it should print you an expanded version.

  • 1
    Nitpick: It's certainly not at read-time, that's what reader macros are for. Lisp macros on the other hand are expanded at compile time and in interpreted code, before the application phase. – wasamasa Aug 1 '16 at 19:48
  • FYI, elisp doesn't facilitate reader macros. – phils Aug 2 '16 at 12:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.