Some editors have the ability to visually swap common sequences of characters out for single symbols without changing the bytes that get saved on disk. The most famous use case is displaying "lambda" as 'λ' in Lisp contexts. In Emacs the feature is called prettify-symbols-mode; in Vim it's called conceal. I wanted to try it out, but I'm using Zed, and Zed doesn't currently support it.
Zed does support OpenType ligatures, and those are just prettify-symbols-mode done at the font level. Programming fonts usually use them to do things like render "!=" as a double-wide '≠', which has never been that compelling to me, but there's no rule that programming fonts have to be monospaced and there's no rule that ligatures have to keep text's width constant. I'm already using a proportional font. If we can create a compact symbol for .addEventListener or make .querySelector into a single-character space-age property access operator, I want that.
I started out by editing Noto Sans Math in FontForge. (Noto because it's my default font; Math because it includes most of the symbols I want to use.) FontForge's UI for editing ligaturization rules is a fairly direct representation of the tables stored in the font file, which is to say it's not easy for a beginner to figure out. I tried to read the relevant parts of the OpenType spec, but that thing is downright impenetrable. I eventually got a working prototype through trial and error.
It was a good day when I discovered there was a text-based format for authoring font features. You can run a command to turn what you've written into the proper flavors of binary structs and patch them into an existing .otf file. After reading the .fea format spec, I think I finally understand what all those different binary structs are meant to do.
These are the substitutions I'm using for vanilla web development:
== | ≡ |
=== | ≣ |
!= | ≠ |
!== | ≢ |
=> | ↦ |
<= | ≤ |
>= | ≥ |
&& | ∧ |
|| | ∨ |
function | λ |
return | ↑ |
export | ⇑ |
let | ■ |
const | □ |
var | ▣ |
for | ∀ |
while | ⟳ |
document | ◊ |
.querySelectorAll | ⟫ |
.querySelector | ⟩ |
.addEventListener | ⊷ |
addEventListener (on window) | ⧟ |
I've been using the prototype daily ∀ the last few months without major incident. My main complaint is that it misfires inside English text every once in a ⟳.
Earlier versions could give especially bad results when they picked a few ■ters out of a bigger word, but later I discovered that the OpenType λality that powers ligatures can express lookahead and lookbehind, so we can say something more like s/(?<![a-z])function(?![a-z])/λ/:
feature calt {
ignore sub [a-z A-Z] f' u' n' c' t' i' o' n';
ignore sub f' u' n' c' t' i' o' n' [a-z A-Z];
sub f' u' n' c' t' i' o' n' by lambda;
} calt;
The font became much nicer to use after I found that functionality.
In the course of polyfilling prettify-symbols-mode in Zed we've accidentally polyfilled it everywhere else that supports OpenType ligatures, too. Sublime unfortunately only supports ligatures in runs of punctuation characters, but plenty of apps have full support. For instance, your browser:
In the copy I use locally, I'm replacing "ctx.localize" with '⊕', which is the closest available symbol to a globe. Your i18n library's translation function will have a different overly long name that appears everywhere in your templates; adjust accordingly.
I want some way of hiding the "Math." in Math.sin et al. while still giving some indication that the prefix is there. Maybe "ₘsin"?
In HTML, we could rewrite "<div id='a' class='b c'>" to "<div #='a' .='b c'>", but the meager space savings aren't worth the overhead of keeping track of more abbreviations. If we could get all the way to "<div #a .b.c>" it would be tempting, but ligature lookaround can't reach through arbitrarily long sequences of characters. (There might be some brilliant hack that can accomplish this.)
It would feel natural to map true → '⊤', false → '⊥', null → '∅', and Infinity → '∞', but like before, the space savings aren't worth the overhead. Also JavaScript's null/undefined distinction doesn't map cleanly onto standard math symbols.
I keep trying to make symbols for if/else if/else. Maybe '⎧'/'⎬'/'⎩'? It feels excessive, it doesn't play well with putting else on the same line as the closing curly, and font engines don't like it when you try to ligaturize sequences that contain spaces. If font rendering played along, it might look like this:
⎧ (i % 15 === 0) {
console.log("FizzBuzz");
} ⎬ (i % 3 === 0) {
console.log("Fizz");
} ⎬ (i % 5 === 0) {
console.log("Buzz");
} ⎩ {
console.log(i);
}
It's not half bad in Python, though:
⎧ i % 15 == 0:
print("FizzBuzz")
⎬ i % 3 == 0:
print("Fizz")
⎬ i % 5 == 0:
print("Buzz")
⎩:
print(i)
2026-06-09
↑ Home
← I made an adblock filter list to remove logos from site headers