dsh-diff-approval 0.28.0 → 0.29.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/README.zh.md +12 -0
- package/assets/fonts/FONTLOG.md +55 -0
- package/assets/fonts/OFL.txt +95 -0
- package/assets/fonts/README.md +123 -0
- package/assets/fonts/manifest.json +1784 -0
- package/assets/fonts/regular-cjk-punctuation.woff2 +0 -0
- package/assets/fonts/regular-hanzi-000.woff2 +0 -0
- package/assets/fonts/regular-hanzi-001.woff2 +0 -0
- package/assets/fonts/regular-hanzi-002.woff2 +0 -0
- package/assets/fonts/regular-hanzi-003.woff2 +0 -0
- package/assets/fonts/regular-hanzi-004.woff2 +0 -0
- package/assets/fonts/regular-hanzi-005.woff2 +0 -0
- package/assets/fonts/regular-hanzi-006.woff2 +0 -0
- package/assets/fonts/regular-hanzi-007.woff2 +0 -0
- package/assets/fonts/regular-hanzi-008.woff2 +0 -0
- package/assets/fonts/regular-hanzi-009.woff2 +0 -0
- package/assets/fonts/regular-hanzi-010.woff2 +0 -0
- package/assets/fonts/regular-hanzi-011.woff2 +0 -0
- package/assets/fonts/regular-hanzi-012.woff2 +0 -0
- package/assets/fonts/regular-hanzi-013.woff2 +0 -0
- package/assets/fonts/regular-hanzi-014.woff2 +0 -0
- package/assets/fonts/regular-hanzi-015.woff2 +0 -0
- package/assets/fonts/regular-hanzi-016.woff2 +0 -0
- package/assets/fonts/regular-hanzi-017.woff2 +0 -0
- package/assets/fonts/regular-hanzi-018.woff2 +0 -0
- package/assets/fonts/regular-hanzi-019.woff2 +0 -0
- package/assets/fonts/regular-hanzi-020.woff2 +0 -0
- package/assets/fonts/regular-hanzi-021.woff2 +0 -0
- package/assets/fonts/regular-hanzi-022.woff2 +0 -0
- package/assets/fonts/regular-hanzi-023.woff2 +0 -0
- package/assets/fonts/regular-hanzi-024.woff2 +0 -0
- package/assets/fonts/regular-hanzi-025.woff2 +0 -0
- package/assets/fonts/regular-hanzi-026.woff2 +0 -0
- package/assets/fonts/regular-hanzi-027.woff2 +0 -0
- package/assets/fonts/regular-hanzi-028.woff2 +0 -0
- package/assets/fonts/regular-hanzi-029.woff2 +0 -0
- package/assets/fonts/regular-hanzi-030.woff2 +0 -0
- package/assets/fonts/regular-hanzi-031.woff2 +0 -0
- package/assets/fonts/regular-hanzi-032.woff2 +0 -0
- package/assets/fonts/regular-hanzi-033.woff2 +0 -0
- package/assets/fonts/regular-hanzi-034.woff2 +0 -0
- package/assets/fonts/regular-hanzi-035.woff2 +0 -0
- package/assets/fonts/regular-hanzi-036.woff2 +0 -0
- package/assets/fonts/regular-hanzi-037.woff2 +0 -0
- package/assets/fonts/regular-hanzi-038.woff2 +0 -0
- package/assets/fonts/regular-hanzi-039.woff2 +0 -0
- package/assets/fonts/regular-hanzi-040.woff2 +0 -0
- package/assets/fonts/regular-hanzi-041.woff2 +0 -0
- package/assets/fonts/regular-hanzi-042.woff2 +0 -0
- package/assets/fonts/regular-hanzi-043.woff2 +0 -0
- package/assets/fonts/regular-hanzi-044.woff2 +0 -0
- package/assets/fonts/regular-hanzi-045.woff2 +0 -0
- package/assets/fonts/regular-hanzi-046.woff2 +0 -0
- package/assets/fonts/regular-hanzi-047.woff2 +0 -0
- package/assets/fonts/regular-hanzi-048.woff2 +0 -0
- package/assets/fonts/regular-hanzi-049.woff2 +0 -0
- package/assets/fonts/regular-hanzi-050.woff2 +0 -0
- package/assets/fonts/regular-hanzi-051.woff2 +0 -0
- package/assets/fonts/regular-hanzi-052.woff2 +0 -0
- package/assets/fonts/regular-hanzi-053.woff2 +0 -0
- package/assets/fonts/regular-hanzi-054.woff2 +0 -0
- package/assets/fonts/regular-hanzi-055.woff2 +0 -0
- package/assets/fonts/regular-hanzi-056.woff2 +0 -0
- package/assets/fonts/regular-hanzi-057.woff2 +0 -0
- package/assets/fonts/regular-hanzi-058.woff2 +0 -0
- package/assets/fonts/regular-hanzi-059.woff2 +0 -0
- package/assets/fonts/regular-hanzi-060.woff2 +0 -0
- package/assets/fonts/regular-hanzi-061.woff2 +0 -0
- package/assets/fonts/regular-hanzi-062.woff2 +0 -0
- package/assets/fonts/regular-hanzi-063.woff2 +0 -0
- package/assets/fonts/regular-hanzi-064.woff2 +0 -0
- package/assets/fonts/regular-latin.woff2 +0 -0
- package/assets/fonts/regular-punctuation.woff2 +0 -0
- package/assets/fonts/regular-symbols.woff2 +0 -0
- package/assets/fonts/semibold-cjk-punctuation.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-000.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-001.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-002.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-003.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-004.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-005.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-006.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-007.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-008.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-009.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-010.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-011.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-012.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-013.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-014.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-015.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-016.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-017.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-018.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-019.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-020.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-021.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-022.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-023.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-024.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-025.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-026.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-027.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-028.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-029.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-030.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-031.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-032.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-033.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-034.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-035.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-036.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-037.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-038.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-039.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-040.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-041.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-042.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-043.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-044.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-045.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-046.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-047.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-048.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-049.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-050.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-051.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-052.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-053.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-054.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-055.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-056.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-057.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-058.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-059.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-060.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-061.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-062.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-063.woff2 +0 -0
- package/assets/fonts/semibold-hanzi-064.woff2 +0 -0
- package/assets/fonts/semibold-latin.woff2 +0 -0
- package/assets/fonts/semibold-punctuation.woff2 +0 -0
- package/assets/fonts/semibold-symbols.woff2 +0 -0
- package/lib/client.js +577 -266
- package/lib/index.js +180 -2
- package/lib/types/client/code-font.d.ts +70 -0
- package/lib/types/client/locales.d.ts +12 -0
- package/lib/types/client/settings.d.ts +15 -0
- package/lib/types/comment-skill.d.ts +1 -1
- package/lib/types/font-slices.d.ts +58 -0
- package/lib/types/index.d.ts +46 -0
- package/package.json +8 -1
package/README.md
CHANGED
|
@@ -92,4 +92,16 @@ corepack pnpm install
|
|
|
92
92
|
pnpm run typecheck # tsc over both faces
|
|
93
93
|
pnpm run build # emits lib/index.js and lib/client.js
|
|
94
94
|
pnpm test
|
|
95
|
+
pnpm run fonts:check # the bundled code font: 138 slices, every range covered exactly once
|
|
96
|
+
pnpm run fonts:plan # what a page actually downloads, by how many hanzi it shows
|
|
95
97
|
```
|
|
98
|
+
|
|
99
|
+
The bundled font is [JetBrains Maple Mono](https://github.com/SpaceTimee/Fusion-JetBrainsMapleMono) (SIL OFL 1.1), subset and sliced by `scripts/fonts` — see [`assets/fonts/README.md`](assets/fonts/README.md) for the pipeline, the licence and what the slices cost.
|
|
100
|
+
|
|
101
|
+
A `file:` profile install copies what the package's `files` list named *at install time*, so a checkout whose list grew needs a refresh before the host can hand the new files out:
|
|
102
|
+
|
|
103
|
+
```sh
|
|
104
|
+
npx @deepseek-ai/dsh plugin --profile web install # then restart `dsh web`
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Only the client half reloads on its own (its bundle is watched), so a client change shows up on a page refresh while a host-half change — like the route that serves the font — waits for the restart.
|
package/README.zh.md
CHANGED
|
@@ -92,4 +92,16 @@ corepack pnpm install
|
|
|
92
92
|
pnpm run typecheck # 两个编译面的 tsc
|
|
93
93
|
pnpm run build # 产出 lib/index.js 与 lib/client.js
|
|
94
94
|
pnpm test
|
|
95
|
+
pnpm run fonts:check # 内置代码字体:138 个切片,每个码位恰好被覆盖一次
|
|
96
|
+
pnpm run fonts:plan # 页面上出现多少汉字时实际会下载多少
|
|
95
97
|
```
|
|
98
|
+
|
|
99
|
+
内置字体是 [JetBrains Maple Mono](https://github.com/SpaceTimee/Fusion-JetBrainsMapleMono)(SIL OFL 1.1),由 `scripts/fonts` 子集化并切片——流水线、许可证与各切片的体积见 [`assets/fonts/README.md`](assets/fonts/README.md)。
|
|
100
|
+
|
|
101
|
+
`file:` 方式安装的 profile 只复制**安装当时** `files` 列出的文件,所以本地 checkout 后来新增的文件(如 `assets/fonts`)必须先刷新安装,宿主才拿得到:
|
|
102
|
+
|
|
103
|
+
```sh
|
|
104
|
+
npx @deepseek-ai/dsh plugin --profile web install # 然后重启 `dsh web`
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
客户端那半会自己热更新(它的 bundle 被监听),所以客户端改动刷新页面即可;宿主那半的改动(例如提供字体的这条路由)要等重启才生效。
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# FONTLOG
|
|
2
|
+
|
|
3
|
+
What the bundled font is, where it came from, and what was done to it. The
|
|
4
|
+
licence text is in `OFL.txt` next to this file; the machine-readable record of
|
|
5
|
+
the exact upstream build and every slice is in `manifest.json`.
|
|
6
|
+
|
|
7
|
+
## Upstream
|
|
8
|
+
|
|
9
|
+
- **JetBrains Maple Mono 1.2304.79** — <https://github.com/SpaceTimee/Fusion-JetBrainsMapleMono>
|
|
10
|
+
- archive `JetBrainsMapleMono-XX-XX-XX-XX.zip`, sha256
|
|
11
|
+
`1998cf7047be954c781510d5a651e9d57fadb2ee00bebd80a0719d49eaa50513`
|
|
12
|
+
- the plain build: no Nerd Font icons (`XX`), no narrowed CJK (`XX` — that
|
|
13
|
+
variant is documented as breaking the 2:1 ratio), no hinting (`XX`)
|
|
14
|
+
- itself a fusion of **JetBrains Mono 2.304** (all non-CJK outlines) and
|
|
15
|
+
**Maple Mono 7.9** (the CJK outlines), assembled by FontForge
|
|
16
|
+
- CJK designs ultimately from Resource Han Rounded and Source Han Sans
|
|
17
|
+
- Licence of everything above: **SIL Open Font License 1.1**, with no Reserved
|
|
18
|
+
Font Name declared by any of the three copyright holders. `OFL.txt` carries
|
|
19
|
+
JetBrains Mono (2020), Maple Mono (2022) and Space Time (2025) notices.
|
|
20
|
+
|
|
21
|
+
## What this repository does to it
|
|
22
|
+
|
|
23
|
+
A **modification** in OFL terms, and therefore recorded here:
|
|
24
|
+
|
|
25
|
+
1. **Renamed** to `JetBrains Maple Mono for DSH` (the family the CSS declares).
|
|
26
|
+
The name says which face it is; the `for DSH` marker keeps it from colliding
|
|
27
|
+
with a copy of the upstream font the reader may have installed — a locally
|
|
28
|
+
installed font wins over a webfont of the same name, which would leave these
|
|
29
|
+
slices unused and render someone else's build. It also keeps the upstream
|
|
30
|
+
names out of a user-visible primary name, which is what the OFL asks of a
|
|
31
|
+
modified version (Maple Mono declares `Maple Mono` as a Reserved Font Name).
|
|
32
|
+
2. **Subset** to the characters a code diff can render: Latin and Latin-1,
|
|
33
|
+
Latin Extended-A, general punctuation, arrows, box drawing, geometric shapes
|
|
34
|
+
and dingbats, CJK punctuation and fullwidth forms, and the 20,992 hanzi of
|
|
35
|
+
U+4E00-9FFF. Uncovered on purpose: Korean, CJK Ext-A/B, compatibility
|
|
36
|
+
ideographs — those fall back to the system stack.
|
|
37
|
+
3. **Sliced** into woff2 files by frequency, so a page fetches the few hundred
|
|
38
|
+
kilobytes it needs instead of the whole block. The order is frozen in
|
|
39
|
+
`ranked-hanzi.txt`; the rule is in `scripts/fonts/build.py`.
|
|
40
|
+
4. **Converted** to woff2 and stripped of hinting (`--no-hinting`), keeping every
|
|
41
|
+
OpenType feature (`--layout-features='*'`).
|
|
42
|
+
|
|
43
|
+
Both weights are cut from the same slices: Regular for code, SemiBold for
|
|
44
|
+
emphasis, matching `font-weight: 400` and `600`.
|
|
45
|
+
|
|
46
|
+
## Reproducing
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
python -m scripts.fonts.build --download --extract
|
|
50
|
+
python -m scripts.fonts.build
|
|
51
|
+
python -m scripts.fonts.build --check
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`--download` verifies the sha256 above before unpacking, so the slices cannot
|
|
55
|
+
silently come from a different build of the font.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)
|
|
2
|
+
Copyright 2022 The Maple Mono Project Authors (https://github.com/subframe7536/maple-font)
|
|
3
|
+
Copyright 2025 Space Time (https://github.com/SpaceTimee/Fusion-JetBrainsMapleMono)
|
|
4
|
+
|
|
5
|
+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
|
6
|
+
This license is copied below, and is also available with a FAQ at:
|
|
7
|
+
https://openfontlicense.org
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
-----------------------------------------------------------
|
|
11
|
+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
|
12
|
+
-----------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
PREAMBLE
|
|
15
|
+
The goals of the Open Font License (OFL) are to stimulate worldwide
|
|
16
|
+
development of collaborative font projects, to support the font creation
|
|
17
|
+
efforts of academic and linguistic communities, and to provide a free and
|
|
18
|
+
open framework in which fonts may be shared and improved in partnership
|
|
19
|
+
with others.
|
|
20
|
+
|
|
21
|
+
The OFL allows the licensed fonts to be used, studied, modified and
|
|
22
|
+
redistributed freely as long as they are not sold by themselves. The
|
|
23
|
+
fonts, including any derivative works, can be bundled, embedded,
|
|
24
|
+
redistributed and/or sold with any software provided that any reserved
|
|
25
|
+
names are not used by derivative works. The fonts and derivatives,
|
|
26
|
+
however, cannot be released under any other type of license. The
|
|
27
|
+
requirement for fonts to remain under this license does not apply
|
|
28
|
+
to any document created using the fonts or their derivatives.
|
|
29
|
+
|
|
30
|
+
DEFINITIONS
|
|
31
|
+
"Font Software" refers to the set of files released by the Copyright
|
|
32
|
+
Holder(s) under this license and clearly marked as such. This may
|
|
33
|
+
include source files, build scripts and documentation.
|
|
34
|
+
|
|
35
|
+
"Reserved Font Name" refers to any names specified as such after the
|
|
36
|
+
copyright statement(s).
|
|
37
|
+
|
|
38
|
+
"Original Version" refers to the collection of Font Software components as
|
|
39
|
+
distributed by the Copyright Holder(s).
|
|
40
|
+
|
|
41
|
+
"Modified Version" refers to any derivative made by adding to, deleting,
|
|
42
|
+
or substituting -- in part or in whole -- any of the components of the
|
|
43
|
+
Original Version, by changing formats or by porting the Font Software to a
|
|
44
|
+
new environment.
|
|
45
|
+
|
|
46
|
+
"Author" refers to any designer, engineer, programmer, technical
|
|
47
|
+
writer or other person who contributed to the Font Software.
|
|
48
|
+
|
|
49
|
+
PERMISSION & CONDITIONS
|
|
50
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
51
|
+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
|
52
|
+
redistribute, and sell modified and unmodified copies of the Font
|
|
53
|
+
Software, subject to the following conditions:
|
|
54
|
+
|
|
55
|
+
1) Neither the Font Software nor any of its individual components,
|
|
56
|
+
in Original or Modified Versions, may be sold by itself.
|
|
57
|
+
|
|
58
|
+
2) Original or Modified Versions of the Font Software may be bundled,
|
|
59
|
+
redistributed and/or sold with any software, provided that each copy
|
|
60
|
+
contains the above copyright notice and this license. These can be
|
|
61
|
+
included either as stand-alone text files, human-readable headers or
|
|
62
|
+
in the appropriate machine-readable metadata fields within text or
|
|
63
|
+
binary files as long as those fields can be easily viewed by the user.
|
|
64
|
+
|
|
65
|
+
3) No Modified Version of the Font Software may use the Reserved Font
|
|
66
|
+
Name(s) unless explicit written permission is granted by the corresponding
|
|
67
|
+
Copyright Holder. This restriction only applies to the primary font name as
|
|
68
|
+
presented to the users.
|
|
69
|
+
|
|
70
|
+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
|
71
|
+
Software shall not be used to promote, endorse or advertise any
|
|
72
|
+
Modified Version, except to acknowledge the contribution(s) of the
|
|
73
|
+
Copyright Holder(s) and the Author(s) or with their explicit written
|
|
74
|
+
permission.
|
|
75
|
+
|
|
76
|
+
5) The Font Software, modified or unmodified, in part or in whole,
|
|
77
|
+
must be distributed entirely under this license, and must not be
|
|
78
|
+
distributed under any other license. The requirement for fonts to
|
|
79
|
+
remain under this license does not apply to any document created
|
|
80
|
+
using the Font Software.
|
|
81
|
+
|
|
82
|
+
TERMINATION
|
|
83
|
+
This license becomes null and void if any of the above conditions are
|
|
84
|
+
not met.
|
|
85
|
+
|
|
86
|
+
DISCLAIMER
|
|
87
|
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
88
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
|
89
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
90
|
+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
|
91
|
+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
92
|
+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
93
|
+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
94
|
+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
|
95
|
+
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# The bundled code font
|
|
2
|
+
|
|
3
|
+
The panel renders code and Chinese comments on one character grid, which needs a
|
|
4
|
+
font where one CJK glyph is exactly twice one Latin glyph. No system stack does
|
|
5
|
+
that on Windows or Android: the shell's own code font is
|
|
6
|
+
`"SF Mono", "JetBrains Mono", …, "PingFang SC", "Microsoft YaHei"`, so Latin
|
|
7
|
+
comes from a monospace face and hanzi from a proportional one, and every
|
|
8
|
+
Chinese comment drifts out of column.
|
|
9
|
+
|
|
10
|
+
So the font ships with the plugin. It is
|
|
11
|
+
[JetBrains Maple Mono](https://github.com/SpaceTimee/Fusion-JetBrainsMapleMono)
|
|
12
|
+
(JetBrains Mono for Latin, Maple Mono for CJK, fused upstream so the 2:1 ratio
|
|
13
|
+
holds by construction), subset into sliced woff2 files and served by the host.
|
|
14
|
+
|
|
15
|
+
## What is committed
|
|
16
|
+
|
|
17
|
+
| path | what it is |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| `ranked-hanzi.txt` | the 20,992 hanzi of U+4E00-9FFF in frequency order — the input the slice plan is built on |
|
|
20
|
+
| `regular-*.woff2`, `semibold-*.woff2` | the slices themselves (`regular-latin.woff2`, `regular-hanzi-000.woff2`, …) |
|
|
21
|
+
| `manifest.json` | every slice's `unicode-range`, byte size, weight, and the pinned upstream archive |
|
|
22
|
+
| `OFL.txt` | the font's licence, which must travel with it |
|
|
23
|
+
|
|
24
|
+
The full TTFs and the upstream archive are **not** committed: they are 17 MB and
|
|
25
|
+
141 MB, they are reproducible from the pinned URL and checksum in
|
|
26
|
+
`manifest.json`, and `scripts/fonts/build.py` fetches them into `vendor/`
|
|
27
|
+
(git-ignored) on demand. Keeping the whole font locally is still the point of
|
|
28
|
+
that cache — re-slicing must never require a network round trip, and after one
|
|
29
|
+
`--download` it does not.
|
|
30
|
+
|
|
31
|
+
## Rebuilding
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
python -m pip install fonttools brotli wordfreq jieba
|
|
35
|
+
python -m scripts.fonts.build --download --extract # once: fills assets/fonts/vendor
|
|
36
|
+
python -m scripts.fonts.build # writes the slices + manifest
|
|
37
|
+
python -m scripts.fonts.build --check # ranges cover U+4E00-9FFF exactly once
|
|
38
|
+
python -m scripts.fonts.build --plan # what a page actually pulls
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`--download` verifies the archive's sha256 before unpacking, so a re-slice
|
|
42
|
+
cannot silently pick up a different font. `--check` is what CI-able confidence
|
|
43
|
+
looks like here: it re-reads the committed manifest, re-derives the covered
|
|
44
|
+
codepoints from every `unicode-range`, and fails on a gap, an overlap, or a byte
|
|
45
|
+
size that no longer matches the file on disk.
|
|
46
|
+
|
|
47
|
+
The frequency order is a separate, frozen input:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
python -m scripts.fonts.rank --out assets/fonts/ranked-hanzi.txt # regenerate (deliberate)
|
|
51
|
+
python -m scripts.fonts.rank --check assets/fonts/ranked-hanzi.txt # verify coverage
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Why the slices look like this
|
|
55
|
+
|
|
56
|
+
A browser downloads a whole `@font-face` slice as soon as **one** character in
|
|
57
|
+
its `unicode-range` appears on the page. Measured on this font:
|
|
58
|
+
|
|
59
|
+
- the whole hanzi block as one slice: **5,431,736 B** — one Chinese comment would
|
|
60
|
+
cost 5.4 MB;
|
|
61
|
+
- four equal quarters by codepoint: **~5.8 MB total, and no better per page** —
|
|
62
|
+
the 60 commonest hanzi are scattered across all four, because codepoint order
|
|
63
|
+
has nothing to do with how often a character is used;
|
|
64
|
+
- frequency order plus a byte cap: a page using the commonest 200 hanzi pulls
|
|
65
|
+
**one small slice** (the seed), a page using 3,000 pulls a few, and one rare
|
|
66
|
+
character costs at most one capped slice (120 KB).
|
|
67
|
+
|
|
68
|
+
So the plan is a small seed slice (the 300 commonest hanzi) followed by slices
|
|
69
|
+
capped at 120,000 B each. Both numbers live in `scripts/fonts/build.py`; raising
|
|
70
|
+
the cap means fewer files, lowering it means a cheaper worst case. Changing
|
|
71
|
+
either re-slices the same frozen order, which is the point of committing it.
|
|
72
|
+
|
|
73
|
+
## What the CSS does with it
|
|
74
|
+
|
|
75
|
+
One rule in `src/client/code-font.ts`: `.lines{font-family:<the bundled family>, <the
|
|
76
|
+
shell's stack>}`. `.lines` is the diff's code table, so the grid lands on the code
|
|
77
|
+
and nothing else — comment bubbles, the file list and the panel's chrome keep the
|
|
78
|
+
shell's font stack.
|
|
79
|
+
|
|
80
|
+
**Off until asked for.** The switch is in the plugin's DSH Settings section
|
|
81
|
+
(`等宽 CJK 字体` / "Monospaced CJK font"), stored as `diff-approval:code-font`, and
|
|
82
|
+
it defaults to off because the slices are traffic the reader pays for: tens of
|
|
83
|
+
kilobytes for ordinary Chinese, at most ~120 KB per slice for a rare character,
|
|
84
|
+
33 KB for pure ASCII. Off means nothing is fetched at all — no manifest request,
|
|
85
|
+
no `@font-face` — so the default panel is exactly what it was before this
|
|
86
|
+
existed. A browser fetches a `@font-face` only when a rule uses it, which is what
|
|
87
|
+
keeps an enabled pure-ASCII file down to the one Latin slice.
|
|
88
|
+
|
|
89
|
+
`font-display: swap` rather than `block`: the code is readable in the system font
|
|
90
|
+
immediately, and swapping when the slices land changes the column width, never
|
|
91
|
+
the row height that the virtual window and the jump math are built on.
|
|
92
|
+
|
|
93
|
+
## Two things the font forces on the build
|
|
94
|
+
|
|
95
|
+
- **The full feature set is kept when slicing.** `pyftsubset`'s default prunes a
|
|
96
|
+
code font down to `calt` and `locl` and drops GPOS entirely, which would take
|
|
97
|
+
the slashed zero (`zero`), the character variants (`cv*`, `ss*`) and accent
|
|
98
|
+
composition with it. `--layout-features='*'` costs ~20% on the Latin slice and
|
|
99
|
+
is why `scripts/fonts/build.py` does not use the defaults.
|
|
100
|
+
- **The family name is our own** (`DSH Code Mono`), declared by
|
|
101
|
+
`src/font-slices.ts`. Two reasons: the upstream name embeds the JetBrains
|
|
102
|
+
trademark, which OFL does not grant rights to; and a separately installed copy
|
|
103
|
+
of the upstream font would otherwise win over the webfont, silently replacing
|
|
104
|
+
the slices the panel counts on. The copyright lines and the OFL text still
|
|
105
|
+
travel with the files.
|
|
106
|
+
|
|
107
|
+
The face keeps its own `calt`, so `->` and `=>` draw as arrows — the same thing
|
|
108
|
+
JetBrains Mono already does everywhere else in the UI. The upstream project also
|
|
109
|
+
ships a no-ligature build (`…-NL-…`) if that ever changes; using it means
|
|
110
|
+
re-slicing, not a CSS override, because `calt` is what carries the arrows.
|
|
111
|
+
|
|
112
|
+
Unhinted on purpose: Windows browser rendering goes through DirectWrite, where
|
|
113
|
+
Google Fonts ships unhinted too, and dropping `cvt `/`fpgm`/`prep` makes every
|
|
114
|
+
slice smaller.
|
|
115
|
+
|
|
116
|
+
## Licence
|
|
117
|
+
|
|
118
|
+
SIL Open Font License 1.1, no Reserved Font Name declared by any of the three
|
|
119
|
+
copyright holders (JetBrains Mono, Maple Mono, and the fusion project), so
|
|
120
|
+
subsetting and redistribution are permitted provided `OFL.txt` and the
|
|
121
|
+
copyright notices travel with the files — which is why `OFL.txt` sits here.
|
|
122
|
+
`fontTools.subset` strips the license name records out of a woff2, so the file
|
|
123
|
+
is not optional: the slices do not carry the notice themselves.
|