Repository navigation
Width Policy
D2 Coding has exactly two advance widths for visible characters:
- 500 units (half width): Latin, digits, ASCII punctuation, Greek, Cyrillic, most symbols
- 1000 units (full width): Hangul, Hanja, kana, fullwidth forms, and the symbols listed below
One Hangul syllable is exactly two Latin columns wide. This is what keeps Korean comments and string literals aligned with code, and it is the one property every change has to preserve.
A text editor in a proportional layout just uses the advance widths from the font. A
terminal does not. It decides how many cells each character takes before it looks at
the font, usually with wcwidth(), which follows the Unicode
East Asian Width property:
| Class | Meaning | Terminal columns |
|---|---|---|
| W | Wide | 2 |
| F | Fullwidth | 2 |
| Na | Narrow | 1 |
| H | Halfwidth | 1 |
| N | Neutral (not East Asian) | 1 |
| A | Ambiguous | 1, or 2 if the terminal has an "ambiguous width is wide" setting turned on |
If the font's width and the terminal's column count disagree, the glyph either fills only the left half of its cell (font 500, terminal 2) or spills into the next cell (font 1000, terminal 1). So in practice the safe rule is:
- W and F: 1000. The terminal always gives them two columns.
- N, Na and H: 500. The terminal always gives them one column.
- A: leave as drawn. No setting works everywhere. Widening an Ambiguous character breaks it in most terminals, and it also widens curly quotes, dashes and the ellipsis inside Western text in an editor.
Counts of mapped code points in Regular, by class and advance width, in 1.3.5:
| Class | 500 | 1000 | Notes |
|---|---|---|---|
| W | 0 | 16,533 | all wide characters are full width since 1.3.4 |
| F | 0 | 101 | fullwidth forms such as ! (
|
| Na | 109 | 0 | ASCII |
| H | 1 | 0 |
₩ U+20A9 |
| N | 1,432 | 11 | the 11 are ➊ to ➓ and ʼ U+02BC |
| A | 629 | 1,118 | see below |
The 1,118 Ambiguous characters at 1000 are mostly private use area code points (about 980)
and the enclosed alphanumerics ① to ⑳ and friends in U+2460 to U+24FF (128). They were
drawn that way in the original font and are left alone. The 629 at 500 include § ° ± ×,
Greek and Cyrillic letters, arrows such as →, and symbols such as ★ ◆ ※.
-
1.3.4: 20 East Asian Wide characters drawn at 500 were widened to 1000:
◽ ◾ ☔ ☕ ♈ ♉ ♊ ♋ ♌ ♍ ♎ ♏ ♐ ♑ ♒ ♓ ♿ ⚓ ⚡and the wave dash〜(U+301C). The outlines were moved right by 250 units to sit centered, not scaled. The wave dash shared its glyph with∼(U+223C, Ambiguous), so it got a new glyphuni301Cat the end of the glyph order. - Not adopted: a community build (linked from issues #72 and #91) widened 578 symbols, including 444 Neutral and 115 Ambiguous ones, and scaled the outlines by about 1.7. It matches what some Windows applications with legacy Korean fonts expect, but it would overlap in terminals and make the widened symbols heavier than the text around them.
To check that nothing has slipped, this lists any Wide or Fullwidth character that is not 1000 units wide. It should print nothing:
import unicodedata
from fontTools.ttLib import TTFont
font = TTFont("fonts/ttf/D2Coding-Regular.ttf")
hmtx = font["hmtx"]
for cp, glyph in sorted(font.getBestCmap().items()):
if unicodedata.east_asian_width(chr(cp)) in "WF" and hmtx[glyph][0] != 1000:
print(f"U+{cp:04X} {chr(cp)} {hmtx[glyph][0]}")Python's unicodedata follows the Unicode version of the interpreter, so a newer Python can
report new Wide characters.
These follow directly from the 500/1000 grid. Changing them would break the 1:2 alignment.
- Half pixel widths at odd sizes. 500 units is 0.5 em, so at 13px a column is 6.5px. Some editors round the half pixel and leave a one pixel line at the end of a row (issue #82). Even sizes are always whole pixels. Most monospaced fonts are about 0.6 em wide and do not land on exact halves.
-
"Not really monospaced" checks. The maximum advance is 1000 and the average is 500.
fontconfig therefore classifies the font as
spacing: dual(90) rather thanmono(100), sofc-list :spacing=monodoes not list it (issue #76). neovim-qt compares the average and maximum width and prints "bad fixed pitch metrics" but still uses the font (issue #77). -
OS/2.xAvgCharWidthmust stay 500. Windows Notepad spaces characters by this value. OS/2 version 3 defines it as the average of all glyph widths, and font editors such as FontForge and FontLab recompute it on export. With 11,172 Hangul syllables at 1000 that average is far above 500, and Notepad then draws wide gaps between letters (issue #84). If you build or export the font with any tool, set this value back to 500 afterwards. -
post.isFixedPitchis 1 and PANOSE proportion is 9 (monospaced). Keep both; they are what tells applications that this is a monospaced font despite the two widths.
Maintainer notes
Repository