2020-12-14, updated: 2024-03-12

Tested with Nyxt 2 Pre-release 5.

Tags: feature.

Universal package management

Universal package management

By Pierre Neidhardt

With pre-release 4 we included a universal package manager interface in Nyxt. Thus far, it only supports Guix. More package manager support will come in the future, contributions are welcome!

The package manager interface profits from the Nyxt minibuffer to allow for quick fuzzy-search and multi-selection actions.

Why in Nyxt?

One might wonder: why include a package manager interface in a web browser?

In short, a package manager allows us to integrate more easily with external programs and services. For instance, if we want to add an interface to IPFS, we can automatically install the required dependencies (after prompting the user of course).

With a functional package manager like Nix or Guix, it's even better, we can leverage the nix-shell and guix environment commands to run commands without installing them (i.e. without polluting the user environment).

Guix interface implementation details

Guix was the first interface we developed. This choice was made for two primary reasons:

This last point is key:

Guix has a guix repl command, which is an interpreter (just like the one you'd get when running sbcl or python). Our approach is to start the interpreter, send it some Guile code and read the result.

To start the process, we use

Note that the guix process will automatically terminate when its input stream gets closed (which happens when Nyxt terminates).

To simplify, we can send instructions to the Guix REPL by writing Scheme code to the input stream:

Then we read the result with:

This should get us the current Guix version. It is really that easy!

Now this is where it gets mind blowing: we can write Guile Scheme code directly in our Common Lisp code base! While the syntax is similar, it's not completely interchangeable and the Common Lisp compiler will choke on some Guile Scheme symbols like #t and #f (true and false, respectively). The solution is to write reader macros. This is made easy thanks to the named-readtables library which lets us effortlessly switch between Scheme and Common Lisp syntax whenever, and wherever we want.

This is what our function to list installed packages looks like:

Notice that it allows us to intertwine Common Lisp and Guile Scheme. We define a Common Lisp function which evaluates a bunch of Scheme expressions which themselves expand other Common Lisp expressions!

Future work

In addition to more package manager support (Nix, Dpkg, etc.), we would like to extend our Common Lisp "system" management to bring it under the same interface, thereby providing a uniform experience for the user (whether installing Lisp systems or system packages).

Quicklisp is a obvious target, and already partly implemented, but we are also considering CLPM integration for the added benefit of full system version control.

Addendum: our experience with the Guix REPL has paved the way for more REPL interactions. This means that we are very close to implementing a universal REPL interface (à la Emacs' comint-mode). This means supporting interpreters from programming languages such as Guile, or Python, and giving the user the possibility to fiddle with foreign code from within the browser itself!

Thanks for reading!

Did you enjoy this article? Register for our newsletter to receive the latest hacker news from the world of Lisp and browsers!