Commit 25dab0e
authored
fix(font): Rewrite constraint code for improved icon scaling/alignment (#8563)
> This PR will probably need a rebase on the final outcome of #8550 and
~#8552~ #8580, but I'm putting it out here so folks can begin taking a
look if they want.
This is a rewrite of the code that applies scaling and alignment
constraints. The main intention is to further improve how Nerd Font
icons are matched to the primary font. This PR aligns the calculations
more closely with how the Nerd Font `font-patcher` script works, except
in two cases where we can easily do something unambiguously better (one
because of what's arguably a bug in the script, and one because we do
multi-cell alignment with knowledge of the pixel-rounded cell grid).
A goal of the rewrite is to make the scaling and alignment calculations
as clear and easy to follow as possible.
I'll lead with some screenshots. First the status quo, then this PR.
<img width="505" height="357" alt="Screenshot 2025-09-07 at 17 23 51"
src="https://github.com/user-attachments/assets/8e3ff9fd-3b66-4d54-be38-d54cf3b6cc5b"
/><img width="505" height="357" alt="Screenshot 2025-09-07 at 17 20 39"
src="https://github.com/user-attachments/assets/84fbe076-2e3f-4879-b9b2-91ce86b9ef5f"
/>
Relevant specs: macOS; 1920x1080; Ghostty config:
```ini
font-family = "CommitMono"
font-size = "15"
adjust-cell-height = "+20%"
```
**Points to note**
* Icons are generally larger, making better use of the available space.
* Icons are aligned nearly a pixel lower, better matching the text. This
is because alignment is now calculated from face metrics/bearings, not
the pixel-rounded cell. (See more below.)
* Relative sizes are better matched. Note especially that tall and
narrow icons, like the git branch symbol and icons depicting sheets of
paper, look conspicuously small in the status quo. With this PR, they're
better matched to other icons.
* Look at the letter Z icon I use as prompt character for zsh. It's
_tiny_ in the status quo, but properly sized with this PR. This
demonstrates the most important and clear-cut improvement we make over
`font-patcher`. (See more below.)
* Icons wider than a single cell are now left-aligned rather than
centered across two cells. I think this is preferable and makes better
use of space in most relevant contexts.
- Consider a Neovim bufferline showing the buffer title as a filetype
icon followed by the file name. Padding on the left would be a waste of
space, but having that extra space on the right can improve legibility.
- In listings, such as in the screenshots, columns look tidier when
their left edges are straight rather than ragged.
- This is how `font-patcher` does alignment, and thus what Nerd Font
users and UI designers expect.
**Implementation details**
I won't get too deep in the weeds here; see the code and comments. In
brief:
* `size_horizontal` and `size_vertical` are combined to a single `size`,
which can be `.none, .stretch, .fit, .cover` or `.fit_cover1`. The
latter implements the `pa` rule from `font-patcher`, except it works
better for icons that are small before scaling, like the letter Z prompt
in the screenshots. In short, it preserves aspect ratio while clamping
the size such that the icon `.cover`s at least one cell and `.fit`s
within the available space. See code comments and
ryanoasis/nerd-fonts/pull/1926 for details.
* An alignment mode `.center1` is added, implementing the centering rule
from `font-patcher` that I explained/defended above. In short, we center
the icon _in the first cell_, even it's allowed to span multiple cells.
For icons wider than a single cell, the lower bound that prevents them
from protruding to the left kicks in and turns this into left-alignment.
We keep the regular `.center` rule around for use with emojis, et
cetera.
* Scaling and alignment calculations only use the unrounded face metrics
and bearings. This ensures that pixel rounding of the cell and baseline,
and `adjust-cell-{width,height}`, don't affect scaling or relative
alignment; the icons are always scaled and aligned to the _face_. (The
one place we need to use cell metrics in the calculations is when we use
`cell_width` to obtain the inter-cell padding needed to correctly center
or right-align a glyph across two cells.)
- We can do this with impunity because we're blessed with sprite glyphs
in place of the "icons" that are actually box drawing and block graphics
characters 🙌
**Guide**
The meat of the changes is 100 % in `src/font/face.zig` and
`src/font/nerd_font_codegen.py`. Changes to other files only amount to
a) adding/changing some struct fields to get numbers to where they need
to be (see `src/font/Metrics.zig`), and b) collateral updates to make
otherwise unchanged code and tests work with/take advantage of the
modified structs.
Most files should have a clear and friendly diff. The exception is the
bottom half of `src/font/face.zig`, where the diff is meaningless and
the new code should just be reviewed on its own merits. This is the part
where the `constrain` function is rewritten and refactored. Scarred by
countless hours perusing `font-patcher`, I tried hard to make the math
and logic easy to follow here. I hope I have succeeded 🤞File tree
10 files changed
+812
-821
lines changed- src
- config
- font
- face
- renderer
10 files changed
+812
-821
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
416 | 416 | | |
417 | 417 | | |
418 | 418 | | |
419 | | - | |
420 | | - | |
421 | | - | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
422 | 425 | | |
423 | 426 | | |
424 | 427 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1213 | 1213 | | |
1214 | 1214 | | |
1215 | 1215 | | |
| 1216 | + | |
| 1217 | + | |
| 1218 | + | |
1216 | 1219 | | |
1217 | 1220 | | |
1218 | 1221 | | |
| |||
1223 | 1226 | | |
1224 | 1227 | | |
1225 | 1228 | | |
1226 | | - | |
| 1229 | + | |
| 1230 | + | |
| 1231 | + | |
| 1232 | + | |
1227 | 1233 | | |
1228 | 1234 | | |
1229 | 1235 | | |
| |||
1240 | 1246 | | |
1241 | 1247 | | |
1242 | 1248 | | |
1243 | | - | |
| 1249 | + | |
| 1250 | + | |
| 1251 | + | |
| 1252 | + | |
1244 | 1253 | | |
1245 | 1254 | | |
1246 | 1255 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
36 | 36 | | |
37 | 37 | | |
38 | 38 | | |
39 | | - | |
| 39 | + | |
40 | 40 | | |
41 | | - | |
42 | | - | |
43 | | - | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
44 | 50 | | |
45 | 51 | | |
46 | 52 | | |
| |||
53 | 59 | | |
54 | 60 | | |
55 | 61 | | |
56 | | - | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
57 | 65 | | |
58 | 66 | | |
59 | 67 | | |
| |||
214 | 222 | | |
215 | 223 | | |
216 | 224 | | |
217 | | - | |
218 | | - | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
219 | 229 | | |
220 | 230 | | |
221 | 231 | | |
| |||
224 | 234 | | |
225 | 235 | | |
226 | 236 | | |
227 | | - | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
228 | 242 | | |
229 | 243 | | |
230 | 244 | | |
| |||
237 | 251 | | |
238 | 252 | | |
239 | 253 | | |
240 | | - | |
241 | | - | |
242 | | - | |
243 | | - | |
244 | | - | |
245 | | - | |
246 | | - | |
247 | | - | |
248 | | - | |
249 | | - | |
| 254 | + | |
| 255 | + | |
250 | 256 | | |
251 | 257 | | |
252 | 258 | | |
| |||
260 | 266 | | |
261 | 267 | | |
262 | 268 | | |
263 | | - | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
264 | 273 | | |
265 | 274 | | |
266 | 275 | | |
| |||
286 | 295 | | |
287 | 296 | | |
288 | 297 | | |
289 | | - | |
290 | | - | |
291 | | - | |
292 | | - | |
293 | | - | |
294 | 298 | | |
295 | 299 | | |
296 | 300 | | |
| |||
307 | 311 | | |
308 | 312 | | |
309 | 313 | | |
| 314 | + | |
310 | 315 | | |
311 | 316 | | |
312 | 317 | | |
| |||
315 | 320 | | |
316 | 321 | | |
317 | 322 | | |
| 323 | + | |
318 | 324 | | |
319 | 325 | | |
320 | 326 | | |
| |||
417 | 423 | | |
418 | 424 | | |
419 | 425 | | |
420 | | - | |
421 | | - | |
422 | | - | |
423 | | - | |
424 | | - | |
425 | | - | |
426 | | - | |
427 | | - | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
428 | 449 | | |
429 | | - | |
430 | | - | |
431 | | - | |
432 | | - | |
433 | | - | |
434 | | - | |
435 | | - | |
436 | | - | |
437 | | - | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
438 | 453 | | |
| 454 | + | |
439 | 455 | | |
440 | 456 | | |
441 | 457 | | |
| |||
481 | 497 | | |
482 | 498 | | |
483 | 499 | | |
484 | | - | |
| 500 | + | |
485 | 501 | | |
486 | 502 | | |
487 | 503 | | |
| |||
512 | 528 | | |
513 | 529 | | |
514 | 530 | | |
515 | | - | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
516 | 535 | | |
517 | 536 | | |
518 | 537 | | |
| |||
542 | 561 | | |
543 | 562 | | |
544 | 563 | | |
| 564 | + | |
545 | 565 | | |
546 | 566 | | |
547 | 567 | | |
548 | 568 | | |
549 | 569 | | |
550 | 570 | | |
551 | 571 | | |
| 572 | + | |
552 | 573 | | |
553 | 574 | | |
554 | 575 | | |
| |||
570 | 591 | | |
571 | 592 | | |
572 | 593 | | |
| 594 | + | |
573 | 595 | | |
574 | 596 | | |
575 | 597 | | |
576 | 598 | | |
577 | 599 | | |
578 | 600 | | |
579 | 601 | | |
| 602 | + | |
580 | 603 | | |
581 | 604 | | |
582 | 605 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
270 | 270 | | |
271 | 271 | | |
272 | 272 | | |
273 | | - | |
274 | | - | |
275 | | - | |
276 | | - | |
277 | | - | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
278 | 276 | | |
279 | 277 | | |
280 | 278 | | |
| |||
0 commit comments