Hi, EmacsConf 2025. My name is Ramin Honary,
and I'd like to talk to you today
about my project called Schemacs
which I presented last year.
Back then it was called "Gypsum"
and the name has since changed.
So my name is Ramin Honary.
I'm an Emacs enthusiast, have been since 2017 or so.
I'm a full stack software developer.
I love Haskell, Scheme,
anything functional programming related,
and of course Emacs.
I started learning Scheme about three years ago,
and this is my third time presenting
at EmacsConf.
So the Schemacs project that I'm talking to,
I'm talking about to you today,
was originally called "Gypsum".
The reason I did not call it "Schemacs"
was that the name "Schemacs" was taken on GitHub.
But in the past year,
I was able to get the permission
of the author of GitHub's Schemacs
project to name my project the same thing,
even though it's a very similar project.
So I changed the name.
Let me see if I can quickly show the screen.
So yeah, I have archived the old project.
It's still there, but there's an explanation in
the readme file and a screen grab
of the conversation I had
with the original author of GitHub Schemacs.
My Schemacs is not on GitHub at all.
It's only on Codeberg. So please don't get confused.
But yes, I received permission
to change the name and so I did.
And I would like to give a quick shout-out to
user "Tusharhero" for helping me with that.
This person really helped make that name change happen.
So back to the slides.
And so now I'd like to clarify the scope of the project.
I don't think I quite made it clear
well enough last year,
but... Although I'm definitely cloning
the Emacs Lisp programming language,
the actual scope of the Schemacs project
is to make an Emacs-like app platform for Scheme.
I don't consider Emacs to be a text editor.
I consider Emacs to be a Lisp app platform.
So it's similar to something like the
World Wide Web, or Microsoft's .NET app platform, or Java.
These are all examples of app platforms.
I would like Schemacs to make it easy
for not only people to use it for
things like editing text or, you know, for
using your computer through a command line
or manipulating your Git repository.
I'd also like you to be able to create simple
GUIs or TUIs using Scheme.
So that's also one of the goals of this project.
It will of course have an Emacs-like text editor,
and I will clone Emacs Lisp.
So hopefully GNU Emacs users
will feel comfortable moving over to Schemacs
because they'll be able to use your init.
You'll be able to use your init.el file.
So configuring and scripting Schemacs
should be done in Scheme.
I'd like to encourage scripting in Scheme
and creating new workflows and macros in Scheme.
It will support Emacs Lisp depending on
how much of the Emacs Lisp interpreter I can clone.
That will be supported but not encouraged.
But you should still be able to run your init.el.
And I would like it to be good enough,
this Emacs Lisp interpreter
should be good enough to run packages from ELPA.
Although it will probably be some time
before it will be able to run
something as large as Org Mode or Magit.
It is slightly different from the Guile-Emacs project.
This is the work of Robin Templeton
who presented last year.
Guile-Emacs links the Guile runtime
into the Emacs executable.
It's not a Scheme application. Emacs,
the core of Emacs is written in C.
Guile, the core of Guile is written in C.
What Robin Templeton has done is, at the C level, linked
"libguile.so" into Emacs and then provided
a programming layer where you can
call the Scheme interpreter from Emacs Lisp
so that you can run Scheme programs from within Emacs
without having to launch a separate process
and communicate over a channel such as a socket.
You won't need "SLIME" or anything.
The Guile interpreter is just right there inside of Emacs.
But my project is not like this at all.
Schemacs is written completely from the ground up
in R7RS-compliant Scheme. And because it's R7RS-compliant,
it's not bound to any one particular Scheme implementation,
although Guile is the reference implementation.
One goal of this project is to be able to run
Schemacs on any R7RS-compliant Scheme implementation.
The work that I've done this past year mostly is internal.
There's not much that you can see on the surface.
But the most... One of the most important things that I
did was I rewrote the parser in R7RS Scheme,
so it no longer depends on
the Guile regular expressions library.
The parser now also provides source locations,
so if an error occurs in Emacs Lisp,
there will be a stack trace
and it will show you where in the source code
the error occured. This was not possible last year.
And because it no longer depends on Guile,
I can make it work on multiple Scheme implementations.
So far, I've been able to get it to run on
the Chibi Scheme interpreter
and the Gauche Scheme interpreter, as well as
Guile, which is the reference implementation.
For a short time, it did work also on Chez Scheme,
the Chez Scheme compiler, using Gwen Weinholt's "Akku,"
which is a program that translates R7RS Scheme to R6RS Scheme.
And with that translation, because Chez Scheme
is pretty strictly an R6RS compiler,
the translation allows you to run R7RS programs.
But due to some change, I'm not sure where,
it may have been changed in the Schemacs source code,
or it may have been a change to Akku,
but it no longer builds on Chez.
It did at one point. I'd like to try to fix that.
The second most important thing that I've worked on is a
portable React-like GUI. And so React,
for anyone who has done web programming,
is a very popular framework for programming web applications.
And I've provided something
very similar to that in Scheme now.
So it works. I have constructed a DOM data structure
in Scheme. It's just an ordinary Scheme data structure.
It works like the web's "Document Object Model"
or the "DOM" data structure.
And then this Scheme DOM data structure can be rendered
using any GUI framework that is convenient
for the Scheme implementation that you're targeting.
And you should be able to implement
also rendering to a CLI as well.
The current reference implementation
is using a framework called Guile-GI.
This is the "GObject Introspection" framework.
It's a very simple
GObject Introspection framework for Guile,
and it binds to GTK3 on Linux.
There's a similar framework called G-Golf
which I'd like to begin using as well, also for Guile.
G-Golf seems to be a bit more well-maintained, a bit...
It has better features. G-Golf may be a
better rendering backend for the reference
implementation, but I would like to provide both.
I will give a demo of this now.
Unfortunately not a whole lot
to see compared to last year.
First thing I'd like to show is
that I now have a Makefile. You can look inside
this Makefile and if you're able to read a Makefile,
you can see that I have several targets now available.
You can build Schemacs for Guile,
you can build Schemacs for Gambit,
or Stklos, or Chicken, or Chez,
although none of these (except for Guile)
currently works. These targets will actually
build the source code, but then you would have to
load it into the REPL separately.
There are targets for launching
a Gauche REPL and a Chibi REPL.
You can also run the Emacs Lisp tests
in Gauche and Chibi.
You can also start a Guile REPL through this Makefile.
So I will do that right now in the shell.
(...make the text larger...there we go...)
OK, so we have this directory of the source code.
Let's just begin by running "guile.sh".
This will launch a REPL and you can load "main-guile".
This will launch the GUI. This is the basic
proof of concept GUI that uses Guile-GI.
So it may be hard to see.
I cannot change the size of the text yet.
I've implemented the M-: feature
where you can eval in a minibuffer some Scheme code.
(string-append "hello" ...)
It outputs the result in the buffer.
This is basically the "*Messages*" buffer.
And that's all the more that I have.
This is the same state it was in last year.
It hasn't changed a whole lot since back then.
But I have made additional changes.
So first of all, you can run
(let me just go back into the Guile)... you can
run the Emacs Lisp interpreter tests, so "elisp-tests".
As you can see, it gives you a stack trace.
So this is an error that I've been able to reproduce.
I know exactly what the cause of this error is.
It is not finding a variable
because the closure is not correctly
capturing its environment. So there should be a variable
in the closure, but that variable has not been captured
and so it is causing an error.
It is currently loading "byte-run.el".
Let me show you what code that is here.
So I've copied into the source repository
for Schemacs some of the Elisp code from GNU Emacs.
So I have this "subr.el".
This declares most of the core of Emacs Lisp
that's not written in C.
There's also "byte-run.el". Schemacs Emacs Lisp can now
evaluate this. This is where functions like "defun" are
defined, and "defmacro". So as you can see,
defun itself is a defmacro defined right here.
It's written in Emacs Lisp itself,
defined in terms of defalias.
So I can evaluate "byte-run",
I can evaluate "macroexp",
and the failure occurs somewhere in "subr.el".
Although if you look at the stack trace,
it doesn't provide all the necessary information.
So it appears to be happening in byte-run.el.
Really, it's an error that's occurring inside of a macro,
and the macro call site is somewhere in subr.el.
Anyway, take note of this stack trace.
This was run from within Guile.
Now what I've done this past year
is make it work on other Scheme implementations.
Use "make" to launch a Gauche REPL.
Now I'm inside of Gauche.
This is the command that
you would use to launch a Gauche REPL.
And I can load the same program (load "elisp-tests.scm").
You get the exact same result as Guile.
So we have two different Scheme implementations
producing the same result.
Let's try "make" a Chibi REPL. This is Chibi Scheme.
And you can (load "elisp-tests.scm").
Chibi is a bit slower, but you get the exact same result.
So we have three different Scheme implementations
all running Emacs Lisp,
and all producing the same result.
I think that's...
I'm fairly proud of that accomplishment.
I was able to get the code written to the point
where it actually runs on multiple implementations.
You can also try making it for other Scheme compilers
like "schemacs-mitscheme" for example,
but this will fail.
You can try building it for "schemacs-chez",
Let's try Chez... there we go.
And it will use Akku,
and it will fetch the necessary dependencies.
But it fails, and I haven't been able to
debug that quite yet.
Stklos fails for a similar reason.
Gambit... Chicken still doesn't build all the way yet.
The Makefile at least has places for it.
If anyone can help me out and get Schemacs to compile
on these other Scheme implementations,
I'd appreciate it.
I can probably figure it out myself,
but that will take more time.
And let me just show you quickly
the test program.
Basically this is the Emacs Lisp test program
that I was just running, and it produces an error.
All it does is it loads these files here in this order,
and it fails right around here.
So it's able to load these two.
And yeah, that's what I've accomplished
on the Emacs Lisp side of things.
The next thing I want to show you is the GUI framework
that I've written, which I'm fairly proud of so far.
So this is the GUI framework
(oops, I better launch it again, OK...)
and let me show you the tests.
So here in the tests, you can start to see
some examples of how you use it.
So here is a "counter" test, and this is kind of like
the "hello world" of reactive programming frameworks,
where you have a state variable,
sometimes called an "observable."
I'm calling it "number",
and it uses "=" to check if the state has updated.
If an update occurs and the new value is different
from the old value according to the "=" function,
then trigger a state update in the GUI as well.
Initialize to 0, bound to "number".
I have a "button" function which creates a simple button.
It takes a label and an action.
Right here you see the "div" command.
This is what creates a "div".
Using the properties, I describe that this div is a
push-button and the "on-button-push" is an action.
The action is to update the variable "number"
using whatever function or lambda was provided to it.
And then the content that you see on screen,
that you will see on screen when it runs,
is here. You create a "div-pack cut-vertical".
You declare two buttons and then you declare
this "use-vars" which will take the content
of this variable here, this observable,
and place it into the GUI next to the buttons here.
So what you will see on screen is
a "plus" button which increments,
here is the "increment" function,
a "minus" button which decrements,
and then the content of the variable that is
being incremented and decremented.
The advantage of these reactive frameworks is that
with very few lines of code
you can create fairly complex interfaces.
The less code you have to write,
the fewer chances you have to make mistakes.
So let's just run this program.
This was the "counter-test."
And that is the debug window. Here's the "counter."
I'm sorry it's not much larger than this.
But here's the "plus" button, the "minus" button,
and here's the "number", 0.
And I can increment or decrement as much as I like.
So yeah, that's kind of the hello world
of reactive programming. (I'll reboot the REPL...)
The next thing I want to show you is this layout test.
And I'll just run the test first.
So here we have basically
a tiling window manager kind of thing,
where you can resize the tiles
and then by clicking on these buttons here,
you can change the layout.
So you can do two on the right,
two up above, or three up above. So, yeah.
Those tiling windows, as you can see,
once I work this branch into the main branch of Schemacs,
I can use that to implement
the split window functionality for Schemacs,
the editor. So here's what this split...
Here's the layout test that you just saw.
Let me make it a bit smaller
so that it all fits on one screen.
So basically we have the "button" command again,
and then these are the button actions
which basically just changes the layout,
and then I have the layout. So this layout is a "div."
The first div just places three buttons in a row.
The next layout is a div within a div.
So we have one div which places the button
called "two right" buttons, and the div above it,
which places the "three in a row" button
or the "two above" buttons.
And here's the next... So there's three different
layouts, and clicking on one of their associated buttons
will just change the layout.
As you can see, very little code
to create a somewhat complex user interface.
That's the advantage of using reactive or declarative
UI programming paradigms.
So yeah, this has not been merged into Schemacs
at the time of this recording,
but will be soon hopefully.
So yeah, I think I've already gone on for 20 minutes.
So I guess I'll just end my presentation here.
I have lots more to talk about.
I guess I will say one last thing before I go:
that I would very much like for others
to try and contribute to this project.
I will do my best to try and help teach anybody
or work with anybody, especially even
if you don't have much experience with Scheme.
I'd like to help everybody try to contribute.
Basically I want to get this proof of concept working.
I want to get a stable user interface up and running,
and then we can start working on
improving the Emacs Lisp interpreter all together.
There are close to 1,400 built-in functions
which need to be implemented.
We don't need to get all of them
in order to be able to run probably most of ELPA,
but as much as possible.
We would like to clone Emacs Lisp and I need help.
So get a hold of me. My project is on Codeberg.
Well, (oh, I can't show this here),
but I will end it there. Thank you for listening.