Apr
12
2025

SLip — a Lisp system in your browser

I've put some love into my browser-based Lisp system. This project is so old that I could actually say it's new and nobody would know. I just let it rot for something like 12 years, but since I revamped Ymacs recently, I wanted to fix the “IDE”, which was broken; and then I got carried away.

Before reading further, if you are familiar with Common Lisp and Emacs/SLIME, check out this fine REPL! There you'll also find an info file with some information about the environment. And here's the old “crazy clock demo”, which I showcased in a video when I first announced this project.

[ read more... ]


Feb
3
2025

Common Lisp socket client - reconnect on failure

I'm working on an IMAP client for Common Lisp. Details about that in a future post, but I'd like to share here a few bits of code that I had to dig for.

The CL socket tutorials that I could find focus on how to connect to a server, fetch some data and then disconnect. In my case, however, the connection is supposed to be long lived. There's a thread that continuously reads data from the server (it fetches new emails or flag changes and updates a local maildir). Of course, in the wild there is no such thing as a 100% live connection — it will go down for a variety of reasons out of our control, so we need to handle errors and reconnect.

Here is a simplified version of what I came up with. It's probably not perfect, but it works. If you have any ideas for improvements, or if you know some other tutorial about this, please drop me a note!

[ read more... ]


Sep
23
2024

Ymacs: Twig/Django mode and other news

As I find myself writing code in Ymacs sometimes, I wrote a mode suitable for editing Twig/Django templates. It can be enabled with M-x twig_html_mode (the dogfood init code will auto-enable it for buffers coming from web-mode if the filename contains .twig).

While working on this (in itself, of course) I fixed a bunch of other issues related to indentation and syntax highlighting. JS mode will now highlight class, method and function names, and given these changes, I'd like to start working on some imenu-like functionality. Although, to be honest, the current “parsing” system could best be described as “a mess that works”, even after the significant refactoring at the beginning of this year (2024). My efforts would probably be better spent adopting CodeMirror's excellent parser generator (Lezer). But oh well, for now stuff is good enough. 🥲

Here's a small demo with the new Twig mode on:

[ read more... ]


May
31
2024

Carriage return in SLIME output

Here is a small Emacs/SLIME tip, since I couldn't find it on Google and I had to come up with the solution myself. I'm working on a long running Common Lisp program and I print a dot every few thousand iterations, so that I know that something is happening; then every few hundred of thousands I want to replace those dots with some stats about the computation, so I'm writing a carriage return (char code 13) and the stats. On a normal terminal, the whole line of dots will be replaced by the new output, but Emacs just prints ^M and adds the stats on the same line.

Although SLIME seems to be derived from Comint mode, it doesn't use the same code for output (Comint already handles a bunch of caret movement codes, including CR). To make it work in SLIME, paste the following somewhere in your Emacs config (it probably needs SLIME to be already loaded for the advice to work; it is loaded in my case):

;; Interpret #\Return in SLIME output (carriage-return)
(defun my-slime-fix-output (orig-fun &rest args)
  (with-current-buffer (slime-output-buffer)
    (ignore-errors
     (let ((pos (marker-position slime-output-end)))
       (apply orig-fun args)
       (comint-carriage-motion pos (marker-position slime-output-end))))))

(advice-add 'slime-repl-emit :around 'my-slime-fix-output)

May
8
2024

Dogfooding Ymacs

I first learned the term dogfooding at Zimbra in 2005, where we were using the email server and client that we were developing. The internal domain name was dogfood.zimbra.com.

Why would I want to use Ymacs? Its purpose was to enable me to write code in a browser, but in the comfort of my desktop, I can use the real thing. And indeed, Emacs is almost irreplaceable, because it's not just about the editor itself, but the immense ecosystem around it. How can one program in an editor without Magit, for example?

But there are reasons. First, to me, there's this pleasure of using a tool that I created. Then, I'm a strong believer in manual testing — the only way to ensure it's reasonably stable is to actually use it (yes, I'm typing in Ymacs right now). Then, some things might even be better than in Emacs, depending on case and setup — for example I noticed that Emacs with js2-mode (that's what I use) will mismatch quotes of nested template strings. That works properly in Ymacs (including indentation in nested expressions).

I thought that if I could quickly switch between the two, I could use Ymacs for editing work, and go to Emacs for anything else, like Magit. Thus came the idea of a dogfood server — Ymacs would connect to a running Emacs instance, and provide a way to load/save buffers via Emacs. That was pretty easy to write. Yes of course there is a HTTP server for Emacs.

[ read more... ]


Apr
19
2024

Ymacs Reloaded

Hello. Here's an Ymacs update, after 12 years. Remember Ymacs? It's an Emacs-like editor that works in the browser. Here is what's new.

  • Zero dependencies. Ymacs no longer requires my old DynarchLIB toolkit. The minified and gzipped payload is under 50K, which is pretty small by today standards. Along with this change I modernized the code to use ES6 features (e.g. classes, modules), improved theming and added a simple build system based on Parcel.

  • Improved isearch, query-replace. This took a surprising amount of fiddling, but finally, it's Good™. It has “lazy highlighting”, stats (current/count), regexp, word, case folding, lax whitespace. Query-replace is new (old Ymacs didn't have it). Supports similar-case in replacements, regexp replacement variables, bound to selection when active, etc. — with the standard Emacs keybindings, except for C-w 😢 which see below.

[ read more... ]


Aug
15
2023

Get image dimensions (PNG/JPG) without loading the file in Common Lisp

Hey Common Lispers! Why are we so few, when this language, and tooling, is so amazing and fabulous? :)

Today I added PhotoSwipe on a website I'm working on for a friend. The backend is written in Common Lisp, because life's too short. PhotoSwipe is a wonderful library, It Just Works™, but it has this minor-yet-inconvenient requirement — you have to declare the image size (width and height) for each thumbnail, in some data attributes. I've searched for some Common Lisp code that could fetch an image dimensions from the file, and I couldn't find any. There are image manipulation libraries, alright, but they parse and decode the whole file (and that's slow), when I only need the dimensions. Those could be fetched from the headers, reading just a few bytes and consing nothing at all (or almost nothing).

Following research, since I couldn't find any code that does that, I wrote my own. I hope it will be useful for someone else too. Pasting it below, or get it from this GitHub gist. It should work okay for PNG, JPEG and GIF. I'm not so sure about WEBP. Any comments or improvements are welcome!

Update: I added a proper parser to figure out orientation from the Exif block (which is really a TIFF header).

[ read more... ]


Oct
21
2022

Always choose simple

Today I was tasked with something rather trivial at work, and I wrote the simplest, dumbest code possible to solve the problem. A colleague of mine was surprised looking at my patch, she said it's so simple and beautiful, as she expected some more involved cleanup or refactoring. This brought to mind a little story I'd like to share.

[ read more... ]


Jun
30
2021

No hover please

Ever watch videos online? Ha ha, of course you do. Now here's what bothers me. I set the video — for example eurosportplayer.com — in full-screen, on a desktop, but I don't really watch continuously, I let it play and come back to it every now and then. Whenever I switch back to that desktop, a gross overlay with the video controls shadows the media for like 5 seconds. Even the slightest mouse movement brings on that despicable thing.

If this is pissing you off too, and if you are using Linux + Xorg/X11, then I have a solution. It's called nohoverplease but feel free to name it whatever you like, like fuckyouroverlay or something. It's an empty and fully transparent window that does nothing at all, it just sits there, maximized, on top of the browser, and won't let it know it's visible or catch mouse movements, so the damn overlay won't show up. I do have bigger problems in life, but it feels good to solve at least the little ones.

[ read more... ]


May
15
2021

JavaScript Sudoku solver

My wife has developed a passion for Sudoku. I do not share it, I've always thought that this is a problem for computers, not humans, so I've never tried to solve one by hand. However, even if it's a high school problem, I thought it'd be a cute little program to work on. This is the obligatory blog post about it.

Update: see bestest version.

[ read more... ]


« Before 15 May 2021