Hi stream, this is Yay Emacs number 11. I'm Sacha Chua
and today I will talk about how to fix find-function
for Emacs Lisp from Org Babel or the scratch buffer.
Quick question, where can you define an Emacs Lisp function
so that you can use find function to jump to it later?
Option A, in an indirect buffer
from an Org Mode source block
with your favorite eval function like eval-defun.
Let's try it out. Control, actually it's...
C-c ' (apostrophe) gets you this. I evaluate it.
I try to jump to the function.
Don't know where my test one is defined.
How about in an Org Mode file
by executing the block with C-c C-c?
Let's try that here. Can we find-function?
What's this called... my-test-2.
Nope, can't find it either.
In a .el file?
Let's say we have an Emacs Lisp file
that's got a defun in it.
We evaluate that. Can we find it again?
my-test-3. Yes, that one we can find.
Actually, we need to do a find-function
my-test-3, and that finds it.
How about in a scratch buffer?
Let's say, for example, you have your scratch buffer.
You've been defining a function. You want to test it out.
Can you find it again? I'm looking at it.
I'm saying my-test-4. Where is it?
Emacs doesn't know where it is.
So only option C works.
It's got to be in a .el file
in order for the find-function to find it.
I love jumping to function definitions using find-function
or lispy-goto-symbol
which replaces the xref-find-definitions on M-.
if you use lispy and set up lispy-mode.
It's a great way to look at things
or change how something works,
but it can be a little frustrating
when I try to jump to a definition
and it says, "Don't know where blah, blah, blah is defined."
I just defined it five minutes ago!
It's there in one of my other buffers.
Don't make me look for it myself.
Probably this will get fixed in Emacs core someday,
but no worries.
We can work around it today with a little bit of advice.
So I did some digging around the source code.
It turns out that symbol-file
can't find the function definition.
There's a load-history variable.
So find-function-search-for-symbol
gets called with nil for the library, which causes the error,
but you can work around that with advice.
And I've written something that searches
in all the open Emacs Lisp mode buffers
or in a list of other files,
like my Emacs configuration, for the function.
So this is how I activate it.
add this list of files to look at,
and I add some advice
to find-function-search-for-symbol.
So now, if I have a function,
I'm thinking, I want to change the way that this works,
I can jump into the function definition
with a handy dandy M-. command,
which in this case, I've got lispy-mode on,
it calls lispy-goto-symbol.
So assuming we've got the live demo working,
Ta-da! Look at this one.
So I defined this one inside the source buffer.
In fact, let's leave the source buffer open here.
And we've got our other source buffer over here.
So now, when I press M-.,
it jumps me to the source buffer
that I have open with that code in it,
instead of just complaining
about not being able to find the function.
And then if I have just executed the block
without going into the source buffer,
this advice also makes it so that
find-function works for that case as well.
In this case, instead of finding it
in one of the Emacs Lisp mode buffers,
it searches the list of the other files
like my Emacs configuration
for the function definition.
So if I say, for example, I'm somewhere else,
I say, okay, where's that function defined again?
I need to change something.
I can find it and go straight to my source code.
If I'm, for example, tangling things,
then at least I'm doing it in one place.
Naturally, the .el files still work,
so we didn't mess that up, thank goodness.
But if I define something in a scratch buffer...
Let me show you that with a scratch buffer here.
Just any buffer will do. I can say, defun my-test-5.
And let's go see if I can find that now.
find-function my-test-5.
It goes to the scratch buffer or wherever else.
In fact, this works even for pretty much,
you know, pretty much anything.
you can define it even in other places anyway.
So this is fun.
The way that it works
is there's some advice over here
that calls this function
sacha-elisp-find-function-search-for-symbol.
And when the library is nil,
that means that Emacs built-in find-function
couldn't find the file that's associated with this,
because maybe you're running it from a place
that doesn't have a file name,
or is not a .el file.
So if that's the case, then we go and we look for it
in all the different places that we can.
Here, this is a lambda
that basically searches through the buffer
that's been specified
or the file if it's passed a file name.
I basically took this code
from how find-function-search-for-symbol works
with a little bit of a modification
because this part over here, where was this?
This part over here needed some changing,
otherwise it was getting confused
with function calls that were one after the other.
Anyhow, what it does is it checks against
all of the Emacs Lisp mode buffers,
as well as the sacha-elisp-find-function-search-extra.
And the first buffer that has the definition wins.
So that's how I now have find-function
working for all my functions,
even the ones that I've defined
in my literate config or the ones that I've just put
in a scratch buffer somewhere
and totally haven't gotten around to saving to a file yet,
which is great because when I'm exploring things,
I'm often thinking, oh yeah, how does this one work again?
Or can I, can I get into it so I can edebug it?
And this one will now let me jump straight to the function
without having to worry about where and how I defined it.
So yeah. And I even wrote tests!
Yay. I think that still works.
Let me go see. Let's see if it still works.
Yay! Two tests. They both pass. So yeah, that's what I got.
If you look in yayemacs.com for Yay Emacs 11,
you'll find the source code and maybe future episodes.
Who knows? Anyway, that's what I got for now.
Thank you for dropping by. If you have any questions,
I will wave my hands around a little bit
until... Let me sort that out.
Ooh, I should actually maybe not overlap. Haha, wait.
Hang on a second, I can figure this out.
How do I resize this?
Look at that, I got like, chat on screen. Alright!
So stuff is over there.
I'm just going to keep this short.
If you have any questions or comments,
leave it in the place where the comments go
or email me!