I’ve been looking into some web programming with CL. There’s quite a lot of alternatives, even many options from a single author. I find Reblocks quite interesting, but I’m wondering if maybe Nyxt headless mode could be used for similar purpose?
This is a very intriguing idea. Of course you can imagine they dynamic nature of CL would allow you to do many things.
It definitely can be used for that purpose. We’ve thought of it, but haven’t actually done anything with that idea. So far we’ve sort of “reinvented” the wheel a little bit with our own UI framework, and that’s about it
I mean, we already have our own infrastructure for applications, consisting of:
- Internal pages as views (see
define-internal-page[-command[-global]]
,buffer-load-internal-page-focus
, and theinternal-page
class itself).- Panels as a type of internal pages too (see
define-panel-command[-global]
andpanel
class).
- Panels as a type of internal pages too (see
- Commands as controllers (see
define-command[-global]
,lambda[-mapped|-unmapped]-command
,run[-async]
, andcommand
class itself.- Also see
ffi-add-context-menu-command
. - Also see the FFI events, such as
on-signal-notify-uri
,on-signal-load-started
,on-signal-button-press
etc. - And, obviously, hooks like the essential
request-resource-hook
andbuffer-loaded-hook
.
- Also see
Then, what’s left for MVC (in case you prefer this application architecture) is the model, which might be anything. But what could work well is something like our REPL architecture with cell
class and cell actions
.
This framework works well with HTML/CSS/JS generators, like Spinneret (which we use and have a huge interface library for—see spinneret-tags.lisp in Nyxt checkout), CL-WHO, and others. But it might be too restrictive for full-blown web frameworks like Reblocks of CLOG. These I’m not sure how to approach, but it should be possible to instrumentalize Nyxt for them too!
Yes, looks like it works right out of the box!
(hunchentoot:define-easy-handler (nyxt-new :uri "/new") ()
(setf (hunchentoot:content-type*) "text/html")
(let* ((cmd (nyxt::find-command 'nyxt:new))
(buf (funcall cmd))
(model (nyxt:document-model buf)))
(plump:serialize model nil)))
That’s actually really cool. We could make a sort of demo and interactive manual that’s running on a real instance of Nyxt. People could hack with the REPL without even doing an installation. The possibilities…!
Yeah, it’s really cool! Need to experiment with command interactions, partial updates, security (e.g. using GitHub - kanru/cl-isolated: A restricted environment for Common Lisp code evaluation) and more. But I find it intriguing!
@simendsjo I’m amazed by your creativity everytime!
I believe this topic deserves an article on our website.
Looks like it’s only going to work for https, and not on Safari or most mobile browsers.
See Navigator: registerProtocolHandler() method - Web APIs | MDN
navigator.registerProtocolHandler(
"nyxt",
"https://whatever-site-we-are-on/command/%s"
);
But with this, I assume we should be able to click around in the new/tutorial etc.
I got some time to hack on this again. I do a regex replace for all nyxt: and nyxt-resource: into calls to the backend Hunchentoot server, so now I’m able to navigate and fetch resources.
pretty cool, do you have like a short video or something we can see?