Nice to have you here on this talk.
This is my second talk this year.
First one was on things that I've done to Org Mode.
Just as a side note, this presentation
that I'm going to share with you
about my work on Corfu and Yasnippet.
I've prepared that on Org Mode
and exported that with a work I've been doing
to the latest exporter.
Anyhow, what is my talk going to be about?
It's going to be about Corfu and Yasnippet,
which I thought would be difficult to integrate,
and it was much easier than I thought.
So just a short outline, my motivation,
step-by-step of the things that I've been investigating,
and some takeaways.
So my motivation, yasnippet is old.
So I've tried another. I've tried Tempel
and other template management packages,
but it was really not my cup of tea. So mainly why?
Mainly because I have a nice base of yasnippets
I have generated for my needs.
So it's not that I've been importing snippets
from packages which are out there.
No, they are my snippets. I'm used to them.
And of course, migration counts as a cost.
I've been using Company as my completion point function GUI for years,
but with the time coming in features and so on,
it was not as easy to set up as I wanted for my needs.
So I had been working,
I've been playing with Eglot already some time
for a language server protocol.
I had read about how easy it was to integrate with Corfu,
which was really nice, and I had given it a try,
but I'm using both graphical user interface mode in Emacs
and text mode,
and for text mode you need corfu-terminal,
which was yet another package that I didn't download.
Well, and I didn't really find a quick way
to get rid of company to get yasnippet.
So at the end, when, at the beginning,
when I was using Corfu and Eglot,
I also needed to load company
to have yasnippet support,
which was really like sort of weird
because I wanted to get rid of yasnippet.
Anyhow, while I try now, I'm following the mailing list,
the development mailing list,
and I got interested when I heard something about
TTY child frames being announced for master.
That would mean less packages to download
because I thought I could get rid of Corfu,
and I wanted to try if I could get rid of corfu-terminal
and run Corfu without that.
So, there were some hints there in that mailing list
that made it interesting for me.
And at the end, I'm also like a "why not try"ing man,
so I said, let's give it a try.
My requirements, I'm working always on a new Emacs,
a decently new Emacs, normally from master, vanilla,
completely vanilla, and I don't have any extras
like Doom or things like that.
So I'm only vanilla. And one of the things
that I don't want is that on this vanilla recent Emacs,
I don't want a corfu-terminal. I need yasnippet.
I'm basically an old man.
Old dog doesn't do new tricks and snippets must,
in my way of working, must be easy and quick to configure,
and tempel or others that I've seen are not.
I don't want any reminiscence of company in my setup.
And of course, don't forget that I've embraced
the language protocol implementations and basically Eglot.
My main focus now is Python and LaTeX,
and I have pylsp and texlab.
I don't want to have to stop using them.
So basic setup for Corfu and Eglot.
You can find it everywhere you look for it.
It's really easy.
And actually, I also do something somehow naughty,
which is to set this variable,
the corfu-auto variable to true,
although I know it's not recommended, blah, blah, blah.
But I use that because I'm a bit lazy in that.
So next step was looking at completion at point functions.
So the information there, if you go through, is scattered
and sometimes a bit cryptic.
At the end I came up with something like the thing
that you see there on the screen.
It's a function for yas-completion-at-point.
I need my list of keywords,
so that I'm going to be talking later,
and I have my bounds, which is normally a word,
and from that, I get the start and the end
of the thing that I want to
be my seed for looking and bringing up Corfu,
and of course, I need some completion properties here.
This looked like this is what you need to do,
but I had to dig quite deep
to create a yasnippet keyword test
and to understand the completion props.
And as an update of what I've been doing in the last weeks,
I've created a bound of things at point for me
with a different thing
that doesn't skip over non-blank characters,
that only skips over non-blank characters.
Why? Because 'word was confusing LaTeX,
because the backslash,
like in the example for the teletype text,
was not taken into account by 'word.
So I had to create my own one,
which was a bounds-of-thing-at-point,
and then my thing is non-blanks.
Completion at point properties, what are they?
They allow Emacs to know how to handle the information
for a specific completion time.
So you normally will have an annotation,
which then can disappear if you use nerd-icons-corfu,
which is what I'm doing currently,
but I keep it commented just in case I get tired of Corfu
and I want to have my completion function.
Then the :company-kind is actually not something
that comes from the company package, but does not require.
And that's going to allow nerd-icons-corfu to identify
and put the right icon there in the completion list,
as you will see in a couple of minutes.
So it's a snippet key.
So basically what this is telling you
is that this is a snippet keyword.
These two lines, either line,
tell you that this is a snippet keyword,
and that it should be added to the other completions
that you already have in your list.
Problems. Looking... Now, next step,
once I had the completion props
which was relatively easy was to go
and get the keyword list right.
I've been looking at pre-existing solutions
like, for example, how the menu
is built in by yasnippet
and it looked a bit like Mission Impossible,
because the approach by all the things
that I have seen and I have examined
is to get the keys and the names
and then further process them.
My take was, do I really need both?
At the end, if I use my own snippets,
I'm going to be using something
I would call meaningful keys for them,
or at least meaningful for... These keys are meaningful for me,
and I try not to repeat them,
because it makes little sense to repeat a keyword.
So why not center everything around the keys only,
and can that help simplify my code?
So I started to dive into yasnippet
and I found a lot of useful semi-hidden functions there.
I discovered that getting the list,
the list of keys for a given mode was not that difficult.
And at the end, what I started doing
is get all the snippet tables used by a major mode
and get the lists of the keys that you have in each table.
Sometimes the list is empty
so it's going to return a nil and that you have to discard.
When you're using structured snippets
like snippets and submenus and so on
to get a structured menu.
You also get some non-strings that you need to filter out
in order to get a workable keyword list.
At the end of the day, what I had was something like this.
I have, for a mode, I went through all modes.
through all modes associated to that, and then I went,
I got my results from all the tables that I had
for a given time, for a given table.
So what you do is you get the tables
that are associated to a mode, because, surprise, surprise,
some modes have more than one table.
And then what you do is you filter out all non strings
from each of the keys list that you have for each table.
So as you see, it's a 1, 2, 3, 4, 5, 6, 7 liner,
which was not too much.
By the way, if someone from Yasnippet is around,
I sent a pull request to include this
as a public function in Yasnipit
because it might be nice to have it in the package
in order to do this kind of things.
So fine-tuning. Just adding a yas completion
to the completion point functions was not enough.
I don't really know,
but :exclusive no didn't seem to work how I wanted
so I needed to escape... Sorry. Yeah.
I was saying I was getting rid of packages,
and I had to add one package
in order to get a function, which is very, very, nice,
and which is part of the cape function of the cape package,
and that's cape-capf-super.
So at the end, using that, you define an alias,
which, for that, where you use cape-capf-super
to have a list of what you want...
So in this case, for example, for the demo
I'm going to make, I'm using yas completion
and then the elisp-completion-at-point function
provided by Emacs.
I combine them using cape-capf-super,
and with that, I create a completion point,
a new completion point function which I call cape-lisp-mode,
and then I add this alias to the completion functions list,
and with that, it is enough.
Snippet expansion.
If you want to have your snippets expanded automatically,
you have to add an exit function to the, I'm sorry,
to the completion properties.
Yet another functionality you have to add.
And to avoid this automatic selection to be too eager,
you need to add this setq corfu-on-exact-match to nil
because otherwise, you will always get the snippet expanded,
even if you don't want it. Basically, why?
Basically, because this would be suboptimal
because the key can appear as part of a variable name.
Another nice thing, I'm also creating my own themes.
I'm trying to have very sleek themes
that only cover the modes that I use
and for that I have my own theme creator fork
from the original theme creator.
In my personal fork that I'm running at home,
I only have the faces for the modes I use.
I don't want to overload the thing
with too much different things.
Looking at this, I really didn't need, as you will see now,
I don't need to add anything to my themes,
because the default faces for Corfu
adapt quite well to most of the themes.
So if I go back to my checklist,
decently new Emacs, yes,
compiled. The one you'll see
in the demo I'm doing is a master
compiled the day before yesterday
and I don't need corfu-terminal there.
I need yasnippet,
and you're going to see that in a second
with a couple of snippets that I can expand here.
I don't want any reminiscence of a company in my setup,
and there's none. Well, actually, :company-kind is there
you see the company there,
but it isn't defined by company strictly speaking,
and for... I don't want... I need Eglot integration
which I will also be showing you.
Takeaways from all this,
if you accept the extra burden
of corfu-terminal for Emacs 30 or earlier Emacs 30s,
it's not too difficult to get this set up running.
Corfu was easier to integrate and configure than Company,
and it's much lighter in terms
of number of lines, et cetera. I learned a lot.
Well, actually, yes, with the help of Cape,
but it is much lighter and much easier
to integrate and configure.
I've learned a lot about computational functions in the process,
which is, something that is always nice to learn new things
and the nerd-icons-corfu makes the...
at least, at this point in time... I might get tired of it,
but at this point in time, it makes
a very nice overall look and feel for Emacs.
Requests (to whom it may concern): cape has nice features
that maybe could make their way into emacs.
I'm thinking basically about
this super cape functionality
which is very nice, and overcomes the problem of linking,
and this :exclusive and all this kind of things
that we have currently in Corfu
with the completion-at-point functions.
Corfu is also really nice to have, and it's not too big.
So is there any possibility
that it makes its way into Emacs?
Please keep yasnippet alive.
I'm not saying here that my pull request should be there,
but it would be nice if someone took a look
and made it part of Yasnippet.
And P.S., currently on master,
there's a lot of semantic highlighting going on,
which is very, very nice. No criticism on that.
But you may need to add to your snippet hook
this simple local value for elisp-fontify-semantically,
because at least in my case, I felt that
the faces were a bit too pushy,
so I had to make the snippet mode
use the old Emacs Lisp fontification.
This would be my talk.
Any initial reactions to this? There's a question here.
Someone asked, did you try yasnippet-capf?
If so, what did you miss from this approach? I tried that.
And it's not that I missed anything.
It was more or less that I wanted to do it myself.
So I wanted to see what was behind it. That's my answer.
There are lots of packages there,
but I try to keep learning. So, this was a nice objective
to learn a bit more about Emacs. And now, just a second.
Now, a small demo. This is the interaction.
And as you see, I have the snippet there.
and I have a couple of snippets.
So, for example, if I would like to say
I want to define a function, I can go like this.
And what you see here is that
I have two snippets appearing and then some variables.
So, I could go for defun or if I want a key map, for def-keymap,
which would be something like this.
And then when I press enter, I get directly into the map
and I could say like, show off map.
Then it sets out directly a :prefix t,
which is something that I asked for in Emacs master.
So with :prefix t, for those who prefix it true,
for those who don't know it,
it makes integrating this into keymaps
in use-package much easier.
So the next thing would be,
I would like to write a description,
like, for example, a cool show-off keymap,
and then my keys are my functions, and that would be it.
Of course, you also have like this define function.
And of course you can say, that's nice,
but you're not showing the integration
with Eglot, and you're right.
So I'm going just to open up a small program
that I'm currently developing in Python.
This is a tool to do things in MP3.
And here I would have, like, all these things.
As you see here in the bottom,
server is running, file is local, eglot is active.
So I have my eglot stop and then I go down.
And I want to add a new argument here.
I would go like for it. I would go like add flag.
For example, I would add a flag
and I would get a new flag to add here.
Oops. Of course, this is integrated into Eglot,
so I'm getting your information about what I have.
I could... I don't have os, so I would need to import here,
but I can go up just to see...
If I would like to, for example,
create a new regular expression,
I'm getting this information that you see right now on call.
I'm getting that from Eglot.
So you see there's the integration
with Eglot too in Python.
I have Eglot, and as you've seen
I also have the... and all these are snippets. Fine.
More reactions and questions?
Because that would be my show off here.
Any questions? Any more questions on the pad?
but anyhow I'm going to try,
I'm going to try yasnippet too
and I'm going to be answering this question more
yeah time is good okay fine
so I would be done if there's no more reactions...
Thank you so much. You're welcome.
If you have any other questions, folks,
you can always follow up on the pad.
That was a great demonstration, and I'm sure lots of people
are looking forward to trying it out.
Oh, I see some questions coming in now.
You may go ahead if you like.
Okay, fine. There's someone asking:
Do special characters in your snippets work well too?
what kind of... I don't use special characters in the key name,
so in this case everything works quite nicely,
and then I'm passing, I'm passing the control to yasnippet,
so if there's any problem in yasnippet
with special characters,
that, I don't know. I don't use that as a key.
I'm just using for key names.
I normally use a... I only use letters, but that should work.
I mean, let's, uh, let's give it a trial.
Let's kill here. Yes. I don't want, I don't want to touch this.
Ugh. Let's go into this one.
Let's say I'm going to define this, for example, like this,
and I'm going to create a new snippet.
I'm going to create a new snippet
and use this. For example, when you look at this,
if you have the new way of the new Emacs
semantical highlighting working,
this would be quite cramped. This is why I'm using,
this is why I said the snippet, the...
So is this more or less what you're talking about?
This is what you're talking about. Snippet. Save the snippet.
Snippet, load and put window.
Enable interaction mode. Yes, I'm going to save.
And I'm going to save that as fd test in the file.
No, I'm going to save this. Load. Load input window.
I'm going to put this in Emacs Lisp mode. I want to save it. No.
I'm going to write that directly into Emacs Lisp mode.
Going to go back into scratch buffer,
and here I have it. We have it here. But anyhow...
And I'm just going to try to see, if I feel like...
Empty? Of course, there's only one.
It will not show in Corfu.
but I mean, I don't have any problems
with that, as you see. Was that what you were meaning?
Yeah, I guess that works. Fine.
All right, shall we wrap up here
so that you can have supper
and have lunch and other things? Okay, fine for me.
I was hoping to see the drop down. Just a second.
I think we can do that too. Two seconds.
How can we do that with a drop down?
Yeah, if I say something like this.
And then I go and save it.
And I'm going to go and write this
into, with a second, fine.
And now I need to quit here, sorry.
And I'm going to come back in a second with another remark.
Well, I'm bringing back and now let's see.
Let's see what we have in yasnippet.
It's not there. Why not? Just a second. Let's see if I go.
I don't know if it matters that the name was
that didn't have the characters in the beginning.
Just a second. I think I know what is happening here.
Do I have them? I'm going to clean.
[Sacha]: Oh, you're back in your home directories is why.
cd - to get back in.
Yeah. That's right.
So you see how the name also has...
it doesn't have the same as the keys.
I don't know if that affects what shows up.
[Pedro]: Yeah, we we can try that.
That's a quick one. This is my...
Fine, now that I have this,
which is going to be quicker, we check again.
They both seem to be the same now
and I don't know if that affects, but anyhow, let's try it.
I go and then I look at the yasnippet, if it's there.
Yes, it is.
[Sacha]: Yeah, it's there.
[Pedro]: And then if I say there, there you are. Oh, look at that.
It doesn't seem to be affecting.
[Sacha]: Fantastic.
[Pedro]: And by the way, it is there.
[Sacha]: Yeah, I really should spend time
getting more templates set up with yasnippet.
I really love the fact that
you can evaluate Emacs Lisp in it too.
[Pedro]: Yeah, I mean, just to make it bigger,
try that because if I go into my, for example,
into my org mode stuff
and in my org mode, I go to the article,
which is one of the big ones.
I have things like, for example,
I defined a couple of functions here to do if it's empty,
if that is empty, just add a white space.
If one is empty, add a white space.
add a white space here so it becomes a comment.
I have functions to do more things on that,
and I also have menus to see
what language I want to choose for
my spell checking and so on.
And that's all... As you see,
this is Lisp being evaluated.
So yes, do. I really encourage you
[Sacha]: I've also heard people use it,
like, especially if they're working
in different programming languages,
so they can just have the syntax
for the different languages
be condensed into a consistent abbreviation.
[Pedro]: Yeah. And look, this is my article. I have another.
This is when I'm writing articles. I have another one.
I have another one for writing letters
in org mode and so on. So, it's like letter, block,
and you have the complete infrastructure
and you don't have to type it by hand.
So, it's really, really nice.
[Sacha]: Hmm, I think it might be nice to have
a future Emacs carnival, you know,
shared blogging theme thing be around
having people share their snippets.
[Pedro]: Yasnippets and other things. Like for example,
this is something stupid.
I'm switching my themes. All right.
And of course, there you see,
I have also, this is also with,
this is my way of switching buffers,
which is with the shift control and tab,
I can switch different families
and then when I'm in a family,
I can go and switch with control tab between the different,
I'm using tab line by the way. I'm not using the other one.
I'm using the old plain tab line with my themes.
So that's more or less everything.
[Sacha]: Thank you for the peek into your workflow.
I will work on getting the recordings for the live talks
sorted out at some point very soon.
I might even be able to get them out next week.
So thanks again. All right. Have a nice supper.
[Pedro]: Same to you.