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... ]


May
9
2021

New server

“If you don't schedule time for maintenance, your equipment will schedule it for you”

So true! After almost ten years of continuous functioning, one of the hard drives failed and I was left with an unbootable server. Last time I checked it had more than five years uptime. I managed to backup, last minute, things that I should have backed up periodically, and I got a new server, also from Hetzner (whom I warmly recommend, without having any affiliation to them, other than the fact that they are my favorite host for the past 10 years or so).

Sysadmin work sucks. I only do it when the hard drive fails :) so that's about once every 10 years. Still, I was able to put back together my DNS server pretty quickly; also this website, because it's written in Common Lisp. 10 years old software, unchanged, compiled by bleeding edge SBCL running on bleeding edge Arch Linux; now that's stability.

Until the dust settles, comments will be disabled (missing a SMTP server for now). Permanent victims are my old Perl-based websites, including my old blog; I won't bother to get them back up, but there's the Internet Archive if you miss anything.

There'll be a new blog post soon, about Sudoku. I'm not dead yet. :)


« Before 9 May 2021