buninu-linux 0.3.0 → 0.4.0
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/LICENSES/Apache-2.0.txt +202 -0
- package/LICENSES/BSD-3-Clause-Skia.txt +29 -0
- package/LICENSES/Bitstream-Vera.txt +44 -0
- package/LICENSES/MIT-xterm.js.txt +21 -0
- package/LICENSES/OFL-1.1.txt +91 -0
- package/NOTICE.md +18 -1
- package/README.md +226 -22
- package/fetch-alpine.sh +9 -4
- package/graphics.md +213 -0
- package/initramfs/bin/bunterm +66 -0
- package/initramfs/bin/ip +2 -1
- package/initramfs/bin/mount +2 -1
- package/initramfs/bin/poweroff +6 -27
- package/initramfs/bin/ps +256 -0
- package/initramfs/bin/reboot +10 -0
- package/initramfs/bin/tar +169 -0
- package/initramfs/bin/top +129 -0
- package/initramfs/bin/umount +2 -1
- package/initramfs/buninu/CHANGELOG.md +40 -0
- package/initramfs/buninu/apps/bunmsh/CHANGELOG.md +36 -0
- package/initramfs/buninu/apps/bunmsh/README.md +7 -0
- package/initramfs/buninu/apps/bunmsh/package.json +1 -1
- package/initramfs/buninu/apps/bunmsh/src/fancy-ls.js +29 -14
- package/initramfs/buninu/apps/bunmsh/src/line-edit.js +43 -0
- package/initramfs/buninu/apps/bunmsh/src/main.js +15 -1
- package/initramfs/buninu/apps/bunmsh/src/mouse.js +29 -4
- package/initramfs/buninu/apps/bunmsh/src/shell.js +9 -1
- package/initramfs/buninu/apps/bunmsh/test/shell1.test.js +70 -0
- package/initramfs/buninu/apps/jsgotty/gotty.js +4 -3
- package/initramfs/buninu/apps/jsgotty/package.json +1 -1
- package/initramfs/buninu/apps/jsmdcui/CHANGELOG.md +10 -0
- package/initramfs/buninu/apps/jsmdcui/README.md +2 -0
- package/initramfs/buninu/apps/jsmdcui/package.json +1 -1
- package/initramfs/buninu/apps/jsmdcui/runtime/help/commands.md +4 -1
- package/initramfs/buninu/apps/jsmdcui/runtime/help/help.md +2 -0
- package/initramfs/buninu/apps/jsmdcui/src/index.js +40 -13
- package/initramfs/buninu/package.json +1 -1
- package/initramfs/init.js +6 -0
- package/initramfs/lib/bunterm/glyphs.js +446 -0
- package/initramfs/lib/bunterm/images.js +225 -0
- package/initramfs/lib/bunterm/input.js +140 -0
- package/initramfs/lib/bunterm/renderer.js +424 -0
- package/initramfs/lib/bunterm/terminal.js +203 -0
- package/initramfs/lib/canvas.js +181 -0
- package/initramfs/lib/canvaskit/LICENSE +29 -0
- package/initramfs/lib/canvaskit/canvaskit.js +264 -0
- package/initramfs/lib/canvaskit/canvaskit.wasm +0 -0
- package/initramfs/lib/dlopen.js +14 -11
- package/initramfs/lib/document.js +6 -0
- package/initramfs/lib/fbdev.js +581 -0
- package/initramfs/lib/power.js +35 -0
- package/initramfs/lib/xterm/LICENSE +21 -0
- package/initramfs/lib/xterm/addon-unicode-graphemes.mjs +44 -0
- package/initramfs/lib/xterm/xterm-headless.mjs +46 -0
- package/initramfs/usr/share/doc/buninu-linux/bunterm.md +83 -0
- package/initramfs/usr/share/doc/buninu-linux/canvas.md +91 -0
- package/initramfs/usr/share/doc/buninu-linux/fbdev.md +113 -0
- package/initramfs/usr/share/doc/buninu-linux/ps.md +94 -0
- package/initramfs/usr/share/doc/buninu-linux/reboot.md +15 -0
- package/initramfs/usr/share/doc/buninu-linux/tar.md +73 -0
- package/initramfs/usr/share/doc/buninu-linux/top.md +23 -0
- package/initramfs/usr/share/fonts/DejaVuSansMono-Bold.ttf +0 -0
- package/initramfs/usr/share/fonts/DejaVuSansMono.ttf +0 -0
- package/initramfs/usr/share/fonts/LICENSE-Apache-2.0.txt +202 -0
- package/initramfs/usr/share/fonts/LICENSE-DejaVu.txt +44 -0
- package/initramfs/usr/share/fonts/LICENSE-OFL-1.1.txt +91 -0
- package/initramfs/usr/share/fonts/NotoColorEmoji.ttf +0 -0
- package/initramfs/usr/share/fonts/NotoColorEmojiFlags.ttf +0 -0
- package/initramfs/usr/share/fonts/NotoSansCJK-Regular.ttc +0 -0
- package/initramfs/usr/share/fonts/NotoSansSymbols-Regular-Subsetted.ttf +0 -0
- package/initramfs/usr/share/fonts/NotoSansSymbols-Regular-Subsetted2.ttf +0 -0
- package/initramfs/usr/share/fonts/Roboto-Regular.ttf +0 -0
- package/initramfs/usr/share/fonts/fonts.json +28 -0
- package/package.json +2 -2
- package/run-qemu.sh +1 -1
|
@@ -793,6 +793,8 @@ selection, search, and copy remain available.
|
|
|
793
793
|
| `Ctrl-F` | Search; use `Ctrl-N` and `Ctrl-P` for the next and previous match. |
|
|
794
794
|
| `Ctrl-G` | Open the editor help. |
|
|
795
795
|
| `Alt-G` | Show or hide the shortcut bar. |
|
|
796
|
+
| `Ctrl-W` | Switch to the next pane in the current tab. |
|
|
797
|
+
| `Ctrl-W` twice quickly | Switch to the next tab like `Alt-T`. At the rightmost tab, if every tab contains only terminal panes, create a new editor tab instead of cycling back. |
|
|
796
798
|
| `Ctrl-Q` or `Alt-Q` | Close the current UI. |
|
|
797
799
|
|
|
798
800
|
To preview another color theme, press `Ctrl-E` or click on `€`, type `theme `, then use `Tab`
|
|
@@ -151,7 +151,10 @@ quotes here but these are not necessary when entering the command in micro.
|
|
|
151
151
|
|
|
152
152
|
* `term ['exec']`: Open a terminal emulator running the given executable. If no
|
|
153
153
|
executable is given, this will open the default shell in the terminal
|
|
154
|
-
emulator.
|
|
154
|
+
emulator. `Ctrl-W` switches panes in both editor and terminal panes. Press
|
|
155
|
+
it twice quickly to cycle to the next tab like `Alt-T`; at the rightmost
|
|
156
|
+
tab, if every tab is a terminal, this creates a new editor tab instead of
|
|
157
|
+
cycling back.
|
|
155
158
|
|
|
156
159
|
---
|
|
157
160
|
|
|
@@ -793,6 +793,8 @@ selection, search, and copy remain available.
|
|
|
793
793
|
| `Ctrl-F` | Search; use `Ctrl-N` and `Ctrl-P` for the next and previous match. |
|
|
794
794
|
| `Ctrl-G` | Open the editor help. |
|
|
795
795
|
| `Alt-G` | Show or hide the shortcut bar. |
|
|
796
|
+
| `Ctrl-W` | Switch to the next pane in the current tab. |
|
|
797
|
+
| `Ctrl-W` twice quickly | Switch to the next tab like `Alt-T`. At the rightmost tab, if every tab contains only terminal panes, create a new editor tab instead of cycling back. |
|
|
796
798
|
| `Ctrl-Q` or `Alt-Q` | Close the current UI. |
|
|
797
799
|
|
|
798
800
|
To preview another color theme, press `Ctrl-E` or click on `€`, type `theme `, then use `Tab`
|
|
@@ -2796,6 +2796,8 @@ class App {
|
|
|
2796
2796
|
this.tabRects = [];
|
|
2797
2797
|
this._escBuf = null; // pending lone ESC bytes waiting for alt-key combo
|
|
2798
2798
|
this._escTimer = null;
|
|
2799
|
+
this._ctrlWTime = 0;
|
|
2800
|
+
this._ctrlWTimer = null;
|
|
2799
2801
|
this._suggestionsRow = null;
|
|
2800
2802
|
this._suggestionRects = [];
|
|
2801
2803
|
this._acHScroll = 0;
|
|
@@ -3790,7 +3792,7 @@ class App {
|
|
|
3790
3792
|
const titleStyle = { ...defaultStyle, reverse: true };
|
|
3791
3793
|
const scrollMsg = vt && vt.scrollOffset > 0
|
|
3792
3794
|
? ` -- SCROLLBACK (${vt.scrollOffset}/${vt.scrollback.length}) wheel↑↓ to browse, any key to return`
|
|
3793
|
-
: (isActive ? " [Esc
|
|
3795
|
+
: (isActive ? " [Esc=close,Ctrl-W/*2=Next Pane/Tab]" : "");
|
|
3794
3796
|
putText(this.screen, pane.x, pane.y, ` Terminal${scrollMsg}`.padEnd(pane.w), titleStyle, pane.w);
|
|
3795
3797
|
if (!vt) return;
|
|
3796
3798
|
const renderRows = pane.h - 1;
|
|
@@ -4228,14 +4230,12 @@ class App {
|
|
|
4228
4230
|
this.render();
|
|
4229
4231
|
return;
|
|
4230
4232
|
}
|
|
4231
|
-
// Ctrl-W: switch pane focus without closing
|
|
4233
|
+
// Ctrl-W: switch pane focus without closing. A quick second Ctrl-W
|
|
4234
|
+
// cycles tabs, with an editor-tab escape hatch when every tab is a
|
|
4235
|
+
// terminal and the current one is already the rightmost tab.
|
|
4232
4236
|
if (text === "\x17") {
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
const idx = panes.indexOf(this.tab.activePane);
|
|
4236
|
-
this.tab.activePane = panes[(idx + 1) % panes.length];
|
|
4237
|
-
this.render();
|
|
4238
|
-
}
|
|
4237
|
+
await this.handleCtrlW();
|
|
4238
|
+
this.render();
|
|
4239
4239
|
return;
|
|
4240
4240
|
}
|
|
4241
4241
|
|
|
@@ -4525,11 +4525,7 @@ class App {
|
|
|
4525
4525
|
await runAction("AddTab", this);
|
|
4526
4526
|
break;
|
|
4527
4527
|
case "ctrl-w": { //switchPane
|
|
4528
|
-
|
|
4529
|
-
if (panes.length > 1) {
|
|
4530
|
-
const idx = panes.indexOf(this.tab.activePane);
|
|
4531
|
-
this.tab.activePane = panes[(idx + 1) % panes.length];
|
|
4532
|
-
}
|
|
4528
|
+
await this.handleCtrlW();
|
|
4533
4529
|
break;
|
|
4534
4530
|
}
|
|
4535
4531
|
case "ctrl-y": //redo
|
|
@@ -5403,6 +5399,37 @@ class App {
|
|
|
5403
5399
|
return this.setActiveTab((this.activeTabIdx + 1) % this.tabs.length);
|
|
5404
5400
|
}
|
|
5405
5401
|
|
|
5402
|
+
_clearCtrlW() {
|
|
5403
|
+
if (this._ctrlWTimer) clearTimeout(this._ctrlWTimer);
|
|
5404
|
+
this._ctrlWTimer = null;
|
|
5405
|
+
this._ctrlWTime = 0;
|
|
5406
|
+
}
|
|
5407
|
+
|
|
5408
|
+
async handleCtrlW() {
|
|
5409
|
+
const now = Date.now();
|
|
5410
|
+
const isDouble = this._ctrlWTime > 0 && now - this._ctrlWTime < 400;
|
|
5411
|
+
this._clearCtrlW();
|
|
5412
|
+
|
|
5413
|
+
if (isDouble) {
|
|
5414
|
+
const atRightmostTab = this.activeTabIdx === this.tabs.length - 1;
|
|
5415
|
+
const allTabsAreTerminal = this.tabs.every((tab) =>
|
|
5416
|
+
tab.panes().length > 0 && tab.panes().every((pane) => pane.type === "term")
|
|
5417
|
+
);
|
|
5418
|
+
if (atRightmostTab && allTabsAreTerminal) await this.addTab();
|
|
5419
|
+
else this.nextTab();
|
|
5420
|
+
return;
|
|
5421
|
+
}
|
|
5422
|
+
|
|
5423
|
+
this._ctrlWTime = now;
|
|
5424
|
+
this._ctrlWTimer = setTimeout(() => this._clearCtrlW(), 400);
|
|
5425
|
+
|
|
5426
|
+
const panes = this.tab.panes();
|
|
5427
|
+
if (panes.length > 1) {
|
|
5428
|
+
const idx = panes.indexOf(this.tab.activePane);
|
|
5429
|
+
this.tab.activePane = panes[(idx + 1) % panes.length];
|
|
5430
|
+
}
|
|
5431
|
+
}
|
|
5432
|
+
|
|
5406
5433
|
async handlePrompt(text) {
|
|
5407
5434
|
const key = parseKey(text);
|
|
5408
5435
|
|
package/initramfs/init.js
CHANGED
|
@@ -341,6 +341,12 @@ const launchBunmsh = () => {
|
|
|
341
341
|
|
|
342
342
|
const launchBuninu = () => {
|
|
343
343
|
|
|
344
|
+
console.log(`
|
|
345
|
+
Type bunterm in bunmsh: Graphical Terminal
|
|
346
|
+
Shows Emojis, CJK chars
|
|
347
|
+
Supports Kitty Graphics Protocol
|
|
348
|
+
`)
|
|
349
|
+
|
|
344
350
|
const entry = `/buninu/bin/init.js`;
|
|
345
351
|
console.log(`buninu: Starting ${entry} --local`);
|
|
346
352
|
const shell = Bun.spawnSync([
|
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
// /lib/bunterm/glyphs.js — box drawing, block, shade, Powerline and legacy
|
|
2
|
+
// computing characters drawn as vectors instead of font glyphs, so they meet
|
|
3
|
+
// their neighbours exactly at every cell size.
|
|
4
|
+
//
|
|
5
|
+
// The shape tables are ported from xterm.js's addon-webgl CustomGlyphs.ts
|
|
6
|
+
// (Copyright (c) 2021 The xterm.js authors, MIT License; see /lib/xterm/
|
|
7
|
+
// LICENSE). The SVG-style path strings are kept as they are there; only the
|
|
8
|
+
// drawing side is rewritten for Skia.
|
|
9
|
+
|
|
10
|
+
// Block elements: rectangles on an 8x8 grid of the cell.
|
|
11
|
+
const blockElementDefinitions = {
|
|
12
|
+
"▀": [{ x: 0, y: 0, w: 8, h: 4 }],
|
|
13
|
+
"▁": [{ x: 0, y: 7, w: 8, h: 1 }],
|
|
14
|
+
"▂": [{ x: 0, y: 6, w: 8, h: 2 }],
|
|
15
|
+
"▃": [{ x: 0, y: 5, w: 8, h: 3 }],
|
|
16
|
+
"▄": [{ x: 0, y: 4, w: 8, h: 4 }],
|
|
17
|
+
"▅": [{ x: 0, y: 3, w: 8, h: 5 }],
|
|
18
|
+
"▆": [{ x: 0, y: 2, w: 8, h: 6 }],
|
|
19
|
+
"▇": [{ x: 0, y: 1, w: 8, h: 7 }],
|
|
20
|
+
"█": [{ x: 0, y: 0, w: 8, h: 8 }],
|
|
21
|
+
"▉": [{ x: 0, y: 0, w: 7, h: 8 }],
|
|
22
|
+
"▊": [{ x: 0, y: 0, w: 6, h: 8 }],
|
|
23
|
+
"▋": [{ x: 0, y: 0, w: 5, h: 8 }],
|
|
24
|
+
"▌": [{ x: 0, y: 0, w: 4, h: 8 }],
|
|
25
|
+
"▍": [{ x: 0, y: 0, w: 3, h: 8 }],
|
|
26
|
+
"▎": [{ x: 0, y: 0, w: 2, h: 8 }],
|
|
27
|
+
"▏": [{ x: 0, y: 0, w: 1, h: 8 }],
|
|
28
|
+
"▐": [{ x: 4, y: 0, w: 4, h: 8 }],
|
|
29
|
+
"▔": [{ x: 0, y: 0, w: 8, h: 1 }],
|
|
30
|
+
"▕": [{ x: 7, y: 0, w: 1, h: 8 }],
|
|
31
|
+
"▖": [{ x: 0, y: 4, w: 4, h: 4 }],
|
|
32
|
+
"▗": [{ x: 4, y: 4, w: 4, h: 4 }],
|
|
33
|
+
"▘": [{ x: 0, y: 0, w: 4, h: 4 }],
|
|
34
|
+
"▙": [{ x: 0, y: 0, w: 4, h: 8 }, { x: 0, y: 4, w: 8, h: 4 }],
|
|
35
|
+
"▚": [{ x: 0, y: 0, w: 4, h: 4 }, { x: 4, y: 4, w: 4, h: 4 }],
|
|
36
|
+
"▛": [{ x: 0, y: 0, w: 4, h: 8 }, { x: 4, y: 0, w: 4, h: 4 }],
|
|
37
|
+
"▜": [{ x: 0, y: 0, w: 8, h: 4 }, { x: 4, y: 0, w: 4, h: 8 }],
|
|
38
|
+
"▝": [{ x: 4, y: 0, w: 4, h: 4 }],
|
|
39
|
+
"▞": [{ x: 4, y: 0, w: 4, h: 4 }, { x: 0, y: 4, w: 4, h: 4 }],
|
|
40
|
+
"▟": [{ x: 4, y: 0, w: 4, h: 8 }, { x: 0, y: 4, w: 8, h: 4 }],
|
|
41
|
+
// Legacy computing: vertical and horizontal one eighth blocks
|
|
42
|
+
"\u{1FB70}": [{ x: 1, y: 0, w: 1, h: 8 }],
|
|
43
|
+
"\u{1FB71}": [{ x: 2, y: 0, w: 1, h: 8 }],
|
|
44
|
+
"\u{1FB72}": [{ x: 3, y: 0, w: 1, h: 8 }],
|
|
45
|
+
"\u{1FB73}": [{ x: 4, y: 0, w: 1, h: 8 }],
|
|
46
|
+
"\u{1FB74}": [{ x: 5, y: 0, w: 1, h: 8 }],
|
|
47
|
+
"\u{1FB75}": [{ x: 6, y: 0, w: 1, h: 8 }],
|
|
48
|
+
"\u{1FB76}": [{ x: 0, y: 1, w: 8, h: 1 }],
|
|
49
|
+
"\u{1FB77}": [{ x: 0, y: 2, w: 8, h: 1 }],
|
|
50
|
+
"\u{1FB78}": [{ x: 0, y: 3, w: 8, h: 1 }],
|
|
51
|
+
"\u{1FB79}": [{ x: 0, y: 4, w: 8, h: 1 }],
|
|
52
|
+
"\u{1FB7A}": [{ x: 0, y: 5, w: 8, h: 1 }],
|
|
53
|
+
"\u{1FB7B}": [{ x: 0, y: 6, w: 8, h: 1 }],
|
|
54
|
+
"\u{1FB7C}": [{ x: 0, y: 0, w: 1, h: 8 }, { x: 0, y: 7, w: 8, h: 1 }],
|
|
55
|
+
"\u{1FB7D}": [{ x: 0, y: 0, w: 1, h: 8 }, { x: 0, y: 0, w: 8, h: 1 }],
|
|
56
|
+
"\u{1FB7E}": [{ x: 7, y: 0, w: 1, h: 8 }, { x: 0, y: 0, w: 8, h: 1 }],
|
|
57
|
+
"\u{1FB7F}": [{ x: 7, y: 0, w: 1, h: 8 }, { x: 0, y: 7, w: 8, h: 1 }],
|
|
58
|
+
"\u{1FB80}": [{ x: 0, y: 0, w: 8, h: 1 }, { x: 0, y: 7, w: 8, h: 1 }],
|
|
59
|
+
"\u{1FB81}": [{ x: 0, y: 0, w: 8, h: 1 }, { x: 0, y: 2, w: 8, h: 1 }, { x: 0, y: 4, w: 8, h: 1 }, { x: 0, y: 7, w: 8, h: 1 }],
|
|
60
|
+
"\u{1FB82}": [{ x: 0, y: 0, w: 8, h: 2 }],
|
|
61
|
+
"\u{1FB83}": [{ x: 0, y: 0, w: 8, h: 3 }],
|
|
62
|
+
"\u{1FB84}": [{ x: 0, y: 0, w: 8, h: 5 }],
|
|
63
|
+
"\u{1FB85}": [{ x: 0, y: 0, w: 8, h: 6 }],
|
|
64
|
+
"\u{1FB86}": [{ x: 0, y: 0, w: 8, h: 7 }],
|
|
65
|
+
"\u{1FB87}": [{ x: 6, y: 0, w: 2, h: 8 }],
|
|
66
|
+
"\u{1FB88}": [{ x: 5, y: 0, w: 3, h: 8 }],
|
|
67
|
+
"\u{1FB89}": [{ x: 3, y: 0, w: 5, h: 8 }],
|
|
68
|
+
"\u{1FB8A}": [{ x: 2, y: 0, w: 6, h: 8 }],
|
|
69
|
+
"\u{1FB8B}": [{ x: 1, y: 0, w: 7, h: 8 }],
|
|
70
|
+
"\u{1FB95}": [
|
|
71
|
+
{ x: 0, y: 0, w: 2, h: 2 }, { x: 4, y: 0, w: 2, h: 2 },
|
|
72
|
+
{ x: 2, y: 2, w: 2, h: 2 }, { x: 6, y: 2, w: 2, h: 2 },
|
|
73
|
+
{ x: 0, y: 4, w: 2, h: 2 }, { x: 4, y: 4, w: 2, h: 2 },
|
|
74
|
+
{ x: 2, y: 6, w: 2, h: 2 }, { x: 6, y: 6, w: 2, h: 2 },
|
|
75
|
+
],
|
|
76
|
+
"\u{1FB96}": [
|
|
77
|
+
{ x: 2, y: 0, w: 2, h: 2 }, { x: 6, y: 0, w: 2, h: 2 },
|
|
78
|
+
{ x: 0, y: 2, w: 2, h: 2 }, { x: 4, y: 2, w: 2, h: 2 },
|
|
79
|
+
{ x: 2, y: 4, w: 2, h: 2 }, { x: 6, y: 4, w: 2, h: 2 },
|
|
80
|
+
{ x: 0, y: 6, w: 2, h: 2 }, { x: 4, y: 6, w: 2, h: 2 },
|
|
81
|
+
],
|
|
82
|
+
"\u{1FB97}": [{ x: 0, y: 2, w: 8, h: 2 }, { x: 0, y: 6, w: 8, h: 2 }],
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// Shade characters: a repeating pixel pattern (1 = filled).
|
|
86
|
+
const patternDefinitions = {
|
|
87
|
+
"░": [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0]],
|
|
88
|
+
"▒": [[1, 0], [0, 0], [0, 1], [0, 0]],
|
|
89
|
+
"▓": [[0, 1], [1, 1], [1, 0], [1, 1]],
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const Shapes = {
|
|
93
|
+
TOP_TO_BOTTOM: "M.5,0 L.5,1",
|
|
94
|
+
LEFT_TO_RIGHT: "M0,.5 L1,.5",
|
|
95
|
+
TOP_TO_RIGHT: "M.5,0 L.5,.5 L1,.5",
|
|
96
|
+
TOP_TO_LEFT: "M.5,0 L.5,.5 L0,.5",
|
|
97
|
+
LEFT_TO_BOTTOM: "M0,.5 L.5,.5 L.5,1",
|
|
98
|
+
RIGHT_TO_BOTTOM: "M0.5,1 L.5,.5 L1,.5",
|
|
99
|
+
MIDDLE_TO_TOP: "M.5,.5 L.5,0",
|
|
100
|
+
MIDDLE_TO_LEFT: "M.5,.5 L0,.5",
|
|
101
|
+
MIDDLE_TO_RIGHT: "M.5,.5 L1,.5",
|
|
102
|
+
MIDDLE_TO_BOTTOM: "M.5,.5 L.5,1",
|
|
103
|
+
T_TOP: "M0,.5 L1,.5 M.5,.5 L.5,0",
|
|
104
|
+
T_LEFT: "M.5,0 L.5,1 M.5,.5 L0,.5",
|
|
105
|
+
T_RIGHT: "M.5,0 L.5,1 M.5,.5 L1,.5",
|
|
106
|
+
T_BOTTOM: "M0,.5 L1,.5 M.5,.5 L.5,1",
|
|
107
|
+
CROSS: "M0,.5 L1,.5 M.5,0 L.5,1",
|
|
108
|
+
TWO_DASHES_HORIZONTAL: "M.1,.5 L.4,.5 M.6,.5 L.9,.5",
|
|
109
|
+
THREE_DASHES_HORIZONTAL: "M.0667,.5 L.2667,.5 M.4,.5 L.6,.5 M.7333,.5 L.9333,.5",
|
|
110
|
+
FOUR_DASHES_HORIZONTAL: "M.05,.5 L.2,.5 M.3,.5 L.45,.5 M.55,.5 L.7,.5 M.8,.5 L.95,.5",
|
|
111
|
+
TWO_DASHES_VERTICAL: "M.5,.1 L.5,.4 M.5,.6 L.5,.9",
|
|
112
|
+
THREE_DASHES_VERTICAL: "M.5,.0667 L.5,.2667 M.5,.4 L.5,.6 M.5,.7333 L.5,.9333",
|
|
113
|
+
FOUR_DASHES_VERTICAL: "M.5,.05 L.5,.2 M.5,.3 L.5,.45 L.5,.55 M.5,.7 L.5,.95",
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const NORMAL = 1;
|
|
117
|
+
const BOLD = 3;
|
|
118
|
+
|
|
119
|
+
// Box drawing: per line weight, a path string or a function of the double
|
|
120
|
+
// line spacing (xp, yp) that returns one.
|
|
121
|
+
const S = Shapes;
|
|
122
|
+
const boxDrawingDefinitions = {
|
|
123
|
+
"─": { [NORMAL]: S.LEFT_TO_RIGHT },
|
|
124
|
+
"━": { [BOLD]: S.LEFT_TO_RIGHT },
|
|
125
|
+
"│": { [NORMAL]: S.TOP_TO_BOTTOM },
|
|
126
|
+
"┃": { [BOLD]: S.TOP_TO_BOTTOM },
|
|
127
|
+
"┌": { [NORMAL]: S.RIGHT_TO_BOTTOM },
|
|
128
|
+
"┏": { [BOLD]: S.RIGHT_TO_BOTTOM },
|
|
129
|
+
"┐": { [NORMAL]: S.LEFT_TO_BOTTOM },
|
|
130
|
+
"┓": { [BOLD]: S.LEFT_TO_BOTTOM },
|
|
131
|
+
"└": { [NORMAL]: S.TOP_TO_RIGHT },
|
|
132
|
+
"┗": { [BOLD]: S.TOP_TO_RIGHT },
|
|
133
|
+
"┘": { [NORMAL]: S.TOP_TO_LEFT },
|
|
134
|
+
"┛": { [BOLD]: S.TOP_TO_LEFT },
|
|
135
|
+
"├": { [NORMAL]: S.T_RIGHT },
|
|
136
|
+
"┣": { [BOLD]: S.T_RIGHT },
|
|
137
|
+
"┤": { [NORMAL]: S.T_LEFT },
|
|
138
|
+
"┫": { [BOLD]: S.T_LEFT },
|
|
139
|
+
"┬": { [NORMAL]: S.T_BOTTOM },
|
|
140
|
+
"┳": { [BOLD]: S.T_BOTTOM },
|
|
141
|
+
"┴": { [NORMAL]: S.T_TOP },
|
|
142
|
+
"┻": { [BOLD]: S.T_TOP },
|
|
143
|
+
"┼": { [NORMAL]: S.CROSS },
|
|
144
|
+
"╋": { [BOLD]: S.CROSS },
|
|
145
|
+
"╴": { [NORMAL]: S.MIDDLE_TO_LEFT },
|
|
146
|
+
"╸": { [BOLD]: S.MIDDLE_TO_LEFT },
|
|
147
|
+
"╵": { [NORMAL]: S.MIDDLE_TO_TOP },
|
|
148
|
+
"╹": { [BOLD]: S.MIDDLE_TO_TOP },
|
|
149
|
+
"╶": { [NORMAL]: S.MIDDLE_TO_RIGHT },
|
|
150
|
+
"╺": { [BOLD]: S.MIDDLE_TO_RIGHT },
|
|
151
|
+
"╷": { [NORMAL]: S.MIDDLE_TO_BOTTOM },
|
|
152
|
+
"╻": { [BOLD]: S.MIDDLE_TO_BOTTOM },
|
|
153
|
+
// Double
|
|
154
|
+
"═": { [NORMAL]: (xp, yp) => `M0,${.5 - yp} L1,${.5 - yp} M0,${.5 + yp} L1,${.5 + yp}` },
|
|
155
|
+
"║": { [NORMAL]: (xp) => `M${.5 - xp},0 L${.5 - xp},1 M${.5 + xp},0 L${.5 + xp},1` },
|
|
156
|
+
"╒": { [NORMAL]: (xp, yp) => `M.5,1 L.5,${.5 - yp} L1,${.5 - yp} M.5,${.5 + yp} L1,${.5 + yp}` },
|
|
157
|
+
"╓": { [NORMAL]: (xp) => `M${.5 - xp},1 L${.5 - xp},.5 L1,.5 M${.5 + xp},.5 L${.5 + xp},1` },
|
|
158
|
+
"╔": { [NORMAL]: (xp, yp) => `M1,${.5 - yp} L${.5 - xp},${.5 - yp} L${.5 - xp},1 M1,${.5 + yp} L${.5 + xp},${.5 + yp} L${.5 + xp},1` },
|
|
159
|
+
"╕": { [NORMAL]: (xp, yp) => `M0,${.5 - yp} L.5,${.5 - yp} L.5,1 M0,${.5 + yp} L.5,${.5 + yp}` },
|
|
160
|
+
"╖": { [NORMAL]: (xp) => `M${.5 + xp},1 L${.5 + xp},.5 L0,.5 M${.5 - xp},.5 L${.5 - xp},1` },
|
|
161
|
+
"╗": { [NORMAL]: (xp, yp) => `M0,${.5 + yp} L${.5 - xp},${.5 + yp} L${.5 - xp},1 M0,${.5 - yp} L${.5 + xp},${.5 - yp} L${.5 + xp},1` },
|
|
162
|
+
"╘": { [NORMAL]: (xp, yp) => `M.5,0 L.5,${.5 + yp} L1,${.5 + yp} M.5,${.5 - yp} L1,${.5 - yp}` },
|
|
163
|
+
"╙": { [NORMAL]: (xp) => `M1,.5 L${.5 - xp},.5 L${.5 - xp},0 M${.5 + xp},.5 L${.5 + xp},0` },
|
|
164
|
+
"╚": { [NORMAL]: (xp, yp) => `M1,${.5 - yp} L${.5 + xp},${.5 - yp} L${.5 + xp},0 M1,${.5 + yp} L${.5 - xp},${.5 + yp} L${.5 - xp},0` },
|
|
165
|
+
"╛": { [NORMAL]: (xp, yp) => `M0,${.5 + yp} L.5,${.5 + yp} L.5,0 M0,${.5 - yp} L.5,${.5 - yp}` },
|
|
166
|
+
"╜": { [NORMAL]: (xp) => `M0,.5 L${.5 + xp},.5 L${.5 + xp},0 M${.5 - xp},.5 L${.5 - xp},0` },
|
|
167
|
+
"╝": { [NORMAL]: (xp, yp) => `M0,${.5 - yp} L${.5 - xp},${.5 - yp} L${.5 - xp},0 M0,${.5 + yp} L${.5 + xp},${.5 + yp} L${.5 + xp},0` },
|
|
168
|
+
"╞": { [NORMAL]: (xp, yp) => `${S.TOP_TO_BOTTOM} M.5,${.5 - yp} L1,${.5 - yp} M.5,${.5 + yp} L1,${.5 + yp}` },
|
|
169
|
+
"╟": { [NORMAL]: (xp) => `M${.5 - xp},0 L${.5 - xp},1 M${.5 + xp},0 L${.5 + xp},1 M${.5 + xp},.5 L1,.5` },
|
|
170
|
+
"╠": { [NORMAL]: (xp, yp) => `M${.5 - xp},0 L${.5 - xp},1 M1,${.5 + yp} L${.5 + xp},${.5 + yp} L${.5 + xp},1 M1,${.5 - yp} L${.5 + xp},${.5 - yp} L${.5 + xp},0` },
|
|
171
|
+
"╡": { [NORMAL]: (xp, yp) => `${S.TOP_TO_BOTTOM} M0,${.5 - yp} L.5,${.5 - yp} M0,${.5 + yp} L.5,${.5 + yp}` },
|
|
172
|
+
"╢": { [NORMAL]: (xp) => `M0,.5 L${.5 - xp},.5 M${.5 - xp},0 L${.5 - xp},1 M${.5 + xp},0 L${.5 + xp},1` },
|
|
173
|
+
"╣": { [NORMAL]: (xp, yp) => `M${.5 + xp},0 L${.5 + xp},1 M0,${.5 + yp} L${.5 - xp},${.5 + yp} L${.5 - xp},1 M0,${.5 - yp} L${.5 - xp},${.5 - yp} L${.5 - xp},0` },
|
|
174
|
+
"╤": { [NORMAL]: (xp, yp) => `M0,${.5 - yp} L1,${.5 - yp} M0,${.5 + yp} L1,${.5 + yp} M.5,${.5 + yp} L.5,1` },
|
|
175
|
+
"╥": { [NORMAL]: (xp) => `${S.LEFT_TO_RIGHT} M${.5 - xp},.5 L${.5 - xp},1 M${.5 + xp},.5 L${.5 + xp},1` },
|
|
176
|
+
"╦": { [NORMAL]: (xp, yp) => `M0,${.5 - yp} L1,${.5 - yp} M0,${.5 + yp} L${.5 - xp},${.5 + yp} L${.5 - xp},1 M1,${.5 + yp} L${.5 + xp},${.5 + yp} L${.5 + xp},1` },
|
|
177
|
+
"╧": { [NORMAL]: (xp, yp) => `M.5,0 L.5,${.5 - yp} M0,${.5 - yp} L1,${.5 - yp} M0,${.5 + yp} L1,${.5 + yp}` },
|
|
178
|
+
"╨": { [NORMAL]: (xp) => `${S.LEFT_TO_RIGHT} M${.5 - xp},.5 L${.5 - xp},0 M${.5 + xp},.5 L${.5 + xp},0` },
|
|
179
|
+
"╩": { [NORMAL]: (xp, yp) => `M0,${.5 + yp} L1,${.5 + yp} M0,${.5 - yp} L${.5 - xp},${.5 - yp} L${.5 - xp},0 M1,${.5 - yp} L${.5 + xp},${.5 - yp} L${.5 + xp},0` },
|
|
180
|
+
"╪": { [NORMAL]: (xp, yp) => `${S.TOP_TO_BOTTOM} M0,${.5 - yp} L1,${.5 - yp} M0,${.5 + yp} L1,${.5 + yp}` },
|
|
181
|
+
"╫": { [NORMAL]: (xp) => `${S.LEFT_TO_RIGHT} M${.5 - xp},0 L${.5 - xp},1 M${.5 + xp},0 L${.5 + xp},1` },
|
|
182
|
+
"╬": { [NORMAL]: (xp, yp) => `M0,${.5 + yp} L${.5 - xp},${.5 + yp} L${.5 - xp},1 M1,${.5 + yp} L${.5 + xp},${.5 + yp} L${.5 + xp},1 M0,${.5 - yp} L${.5 - xp},${.5 - yp} L${.5 - xp},0 M1,${.5 - yp} L${.5 + xp},${.5 - yp} L${.5 + xp},0` },
|
|
183
|
+
// Diagonal
|
|
184
|
+
"╱": { [NORMAL]: "M1,0 L0,1" },
|
|
185
|
+
"╲": { [NORMAL]: "M0,0 L1,1" },
|
|
186
|
+
"╳": { [NORMAL]: "M1,0 L0,1 M0,0 L1,1" },
|
|
187
|
+
// Mixed weight
|
|
188
|
+
"╼": { [NORMAL]: S.MIDDLE_TO_LEFT, [BOLD]: S.MIDDLE_TO_RIGHT },
|
|
189
|
+
"╽": { [NORMAL]: S.MIDDLE_TO_TOP, [BOLD]: S.MIDDLE_TO_BOTTOM },
|
|
190
|
+
"╾": { [NORMAL]: S.MIDDLE_TO_RIGHT, [BOLD]: S.MIDDLE_TO_LEFT },
|
|
191
|
+
"╿": { [NORMAL]: S.MIDDLE_TO_BOTTOM, [BOLD]: S.MIDDLE_TO_TOP },
|
|
192
|
+
"┍": { [NORMAL]: S.MIDDLE_TO_BOTTOM, [BOLD]: S.MIDDLE_TO_RIGHT },
|
|
193
|
+
"┎": { [NORMAL]: S.MIDDLE_TO_RIGHT, [BOLD]: S.MIDDLE_TO_BOTTOM },
|
|
194
|
+
"┑": { [NORMAL]: S.MIDDLE_TO_BOTTOM, [BOLD]: S.MIDDLE_TO_LEFT },
|
|
195
|
+
"┒": { [NORMAL]: S.MIDDLE_TO_LEFT, [BOLD]: S.MIDDLE_TO_BOTTOM },
|
|
196
|
+
"┕": { [NORMAL]: S.MIDDLE_TO_TOP, [BOLD]: S.MIDDLE_TO_RIGHT },
|
|
197
|
+
"┖": { [NORMAL]: S.MIDDLE_TO_RIGHT, [BOLD]: S.MIDDLE_TO_TOP },
|
|
198
|
+
"┙": { [NORMAL]: S.MIDDLE_TO_TOP, [BOLD]: S.MIDDLE_TO_LEFT },
|
|
199
|
+
"┚": { [NORMAL]: S.MIDDLE_TO_LEFT, [BOLD]: S.MIDDLE_TO_TOP },
|
|
200
|
+
"┝": { [NORMAL]: S.TOP_TO_BOTTOM, [BOLD]: S.MIDDLE_TO_RIGHT },
|
|
201
|
+
"┞": { [NORMAL]: S.RIGHT_TO_BOTTOM, [BOLD]: S.MIDDLE_TO_TOP },
|
|
202
|
+
"┟": { [NORMAL]: S.TOP_TO_RIGHT, [BOLD]: S.MIDDLE_TO_BOTTOM },
|
|
203
|
+
"┠": { [NORMAL]: S.MIDDLE_TO_RIGHT, [BOLD]: S.TOP_TO_BOTTOM },
|
|
204
|
+
"┡": { [NORMAL]: S.MIDDLE_TO_BOTTOM, [BOLD]: S.TOP_TO_RIGHT },
|
|
205
|
+
"┢": { [NORMAL]: S.MIDDLE_TO_TOP, [BOLD]: S.RIGHT_TO_BOTTOM },
|
|
206
|
+
"┥": { [NORMAL]: S.TOP_TO_BOTTOM, [BOLD]: S.MIDDLE_TO_LEFT },
|
|
207
|
+
"┦": { [NORMAL]: S.LEFT_TO_BOTTOM, [BOLD]: S.MIDDLE_TO_TOP },
|
|
208
|
+
"┧": { [NORMAL]: S.TOP_TO_LEFT, [BOLD]: S.MIDDLE_TO_BOTTOM },
|
|
209
|
+
"┨": { [NORMAL]: S.MIDDLE_TO_LEFT, [BOLD]: S.TOP_TO_BOTTOM },
|
|
210
|
+
"┩": { [NORMAL]: S.MIDDLE_TO_BOTTOM, [BOLD]: S.TOP_TO_LEFT },
|
|
211
|
+
"┪": { [NORMAL]: S.MIDDLE_TO_TOP, [BOLD]: S.LEFT_TO_BOTTOM },
|
|
212
|
+
"┭": { [NORMAL]: S.RIGHT_TO_BOTTOM, [BOLD]: S.MIDDLE_TO_LEFT },
|
|
213
|
+
"┮": { [NORMAL]: S.LEFT_TO_BOTTOM, [BOLD]: S.MIDDLE_TO_RIGHT },
|
|
214
|
+
"┯": { [NORMAL]: S.MIDDLE_TO_BOTTOM, [BOLD]: S.LEFT_TO_RIGHT },
|
|
215
|
+
"┰": { [NORMAL]: S.LEFT_TO_RIGHT, [BOLD]: S.MIDDLE_TO_BOTTOM },
|
|
216
|
+
"┱": { [NORMAL]: S.MIDDLE_TO_RIGHT, [BOLD]: S.LEFT_TO_BOTTOM },
|
|
217
|
+
"┲": { [NORMAL]: S.MIDDLE_TO_LEFT, [BOLD]: S.RIGHT_TO_BOTTOM },
|
|
218
|
+
"┵": { [NORMAL]: S.TOP_TO_RIGHT, [BOLD]: S.MIDDLE_TO_LEFT },
|
|
219
|
+
"┶": { [NORMAL]: S.TOP_TO_LEFT, [BOLD]: S.MIDDLE_TO_RIGHT },
|
|
220
|
+
"┷": { [NORMAL]: S.MIDDLE_TO_TOP, [BOLD]: S.LEFT_TO_RIGHT },
|
|
221
|
+
"┸": { [NORMAL]: S.LEFT_TO_RIGHT, [BOLD]: S.MIDDLE_TO_TOP },
|
|
222
|
+
"┹": { [NORMAL]: S.MIDDLE_TO_RIGHT, [BOLD]: S.TOP_TO_LEFT },
|
|
223
|
+
"┺": { [NORMAL]: S.MIDDLE_TO_LEFT, [BOLD]: S.TOP_TO_RIGHT },
|
|
224
|
+
"┽": { [NORMAL]: `${S.TOP_TO_BOTTOM} ${S.MIDDLE_TO_RIGHT}`, [BOLD]: S.MIDDLE_TO_LEFT },
|
|
225
|
+
"┾": { [NORMAL]: `${S.TOP_TO_BOTTOM} ${S.MIDDLE_TO_LEFT}`, [BOLD]: S.MIDDLE_TO_RIGHT },
|
|
226
|
+
"┿": { [NORMAL]: S.TOP_TO_BOTTOM, [BOLD]: S.LEFT_TO_RIGHT },
|
|
227
|
+
"╀": { [NORMAL]: `${S.LEFT_TO_RIGHT} ${S.MIDDLE_TO_BOTTOM}`, [BOLD]: S.MIDDLE_TO_TOP },
|
|
228
|
+
"╁": { [NORMAL]: `${S.MIDDLE_TO_TOP} ${S.LEFT_TO_RIGHT}`, [BOLD]: S.MIDDLE_TO_BOTTOM },
|
|
229
|
+
"╂": { [NORMAL]: S.LEFT_TO_RIGHT, [BOLD]: S.TOP_TO_BOTTOM },
|
|
230
|
+
"╃": { [NORMAL]: S.RIGHT_TO_BOTTOM, [BOLD]: S.TOP_TO_LEFT },
|
|
231
|
+
"╄": { [NORMAL]: S.LEFT_TO_BOTTOM, [BOLD]: S.TOP_TO_RIGHT },
|
|
232
|
+
"╅": { [NORMAL]: S.TOP_TO_RIGHT, [BOLD]: S.LEFT_TO_BOTTOM },
|
|
233
|
+
"╆": { [NORMAL]: S.TOP_TO_LEFT, [BOLD]: S.RIGHT_TO_BOTTOM },
|
|
234
|
+
"╇": { [NORMAL]: S.MIDDLE_TO_BOTTOM, [BOLD]: `${S.MIDDLE_TO_TOP} ${S.LEFT_TO_RIGHT}` },
|
|
235
|
+
"╈": { [NORMAL]: S.MIDDLE_TO_TOP, [BOLD]: `${S.LEFT_TO_RIGHT} ${S.MIDDLE_TO_BOTTOM}` },
|
|
236
|
+
"╉": { [NORMAL]: S.MIDDLE_TO_RIGHT, [BOLD]: `${S.TOP_TO_BOTTOM} ${S.MIDDLE_TO_LEFT}` },
|
|
237
|
+
"╊": { [NORMAL]: S.MIDDLE_TO_LEFT, [BOLD]: `${S.TOP_TO_BOTTOM} ${S.MIDDLE_TO_RIGHT}` },
|
|
238
|
+
// Dashed
|
|
239
|
+
"╌": { [NORMAL]: S.TWO_DASHES_HORIZONTAL },
|
|
240
|
+
"╍": { [BOLD]: S.TWO_DASHES_HORIZONTAL },
|
|
241
|
+
"┄": { [NORMAL]: S.THREE_DASHES_HORIZONTAL },
|
|
242
|
+
"┅": { [BOLD]: S.THREE_DASHES_HORIZONTAL },
|
|
243
|
+
"┈": { [NORMAL]: S.FOUR_DASHES_HORIZONTAL },
|
|
244
|
+
"┉": { [BOLD]: S.FOUR_DASHES_HORIZONTAL },
|
|
245
|
+
"╎": { [NORMAL]: S.TWO_DASHES_VERTICAL },
|
|
246
|
+
"╏": { [BOLD]: S.TWO_DASHES_VERTICAL },
|
|
247
|
+
"┆": { [NORMAL]: S.THREE_DASHES_VERTICAL },
|
|
248
|
+
"┇": { [BOLD]: S.THREE_DASHES_VERTICAL },
|
|
249
|
+
"┊": { [NORMAL]: S.FOUR_DASHES_VERTICAL },
|
|
250
|
+
"┋": { [BOLD]: S.FOUR_DASHES_VERTICAL },
|
|
251
|
+
// Curved
|
|
252
|
+
"╭": { [NORMAL]: (xp, yp) => `M.5,1 L.5,${.5 + (yp / .15 * .5)} C.5,${.5 + (yp / .15 * .5)},.5,.5,1,.5` },
|
|
253
|
+
"╮": { [NORMAL]: (xp, yp) => `M.5,1 L.5,${.5 + (yp / .15 * .5)} C.5,${.5 + (yp / .15 * .5)},.5,.5,0,.5` },
|
|
254
|
+
"╯": { [NORMAL]: (xp, yp) => `M.5,0 L.5,${.5 - (yp / .15 * .5)} C.5,${.5 - (yp / .15 * .5)},.5,.5,0,.5` },
|
|
255
|
+
"╰": { [NORMAL]: (xp, yp) => `M.5,0 L.5,${.5 - (yp / .15 * .5)} C.5,${.5 - (yp / .15 * .5)},.5,.5,1,.5` },
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const FILL = 0;
|
|
259
|
+
const STROKE = 1;
|
|
260
|
+
|
|
261
|
+
// Powerline and private-use separators (https://github.com/powerline/fontpatcher).
|
|
262
|
+
// Line variants extend past the cell and are clipped so the line ends stay hidden.
|
|
263
|
+
const powerlineDefinitions = {
|
|
264
|
+
"\u{E0A0}": { d: "M.3,1 L.03,1 L.03,.88 C.03,.82,.06,.78,.11,.73 C.15,.7,.2,.68,.28,.65 L.43,.6 C.49,.58,.53,.56,.56,.53 C.59,.5,.6,.47,.6,.43 L.6,.27 L.4,.27 L.69,.1 L.98,.27 L.78,.27 L.78,.46 C.78,.52,.76,.56,.72,.61 C.68,.66,.63,.67,.56,.7 L.48,.72 C.42,.74,.38,.76,.35,.78 C.32,.8,.31,.84,.31,.88 L.31,1 M.3,.5 L.03,.59 L.03,.09 L.3,.09 L.3,.655", type: FILL },
|
|
265
|
+
"\u{E0A1}": { d: "M.7,.4 L.7,.47 L.2,.47 L.2,.03 L.355,.03 L.355,.4 L.705,.4 M.7,.5 L.86,.5 L.86,.95 L.69,.95 L.44,.66 L.46,.86 L.46,.95 L.3,.95 L.3,.49 L.46,.49 L.71,.78 L.69,.565 L.69,.5", type: FILL },
|
|
266
|
+
"\u{E0A2}": { d: "M.25,.94 C.16,.94,.11,.92,.11,.87 L.11,.53 C.11,.48,.15,.455,.23,.45 L.23,.3 C.23,.25,.26,.22,.31,.19 C.36,.16,.43,.15,.51,.15 C.59,.15,.66,.16,.71,.19 C.77,.22,.79,.26,.79,.3 L.79,.45 C.87,.45,.91,.48,.91,.53 L.91,.87 C.91,.92,.86,.94,.77,.94 L.24,.94 M.53,.2 C.49,.2,.45,.21,.42,.23 C.39,.25,.38,.27,.38,.3 L.38,.45 L.68,.45 L.68,.3 C.68,.27,.67,.25,.64,.23 C.61,.21,.58,.2,.53,.2 M.58,.82 L.58,.66 C.63,.65,.65,.63,.65,.6 C.65,.58,.64,.57,.61,.56 C.58,.55,.56,.54,.52,.54 C.48,.54,.46,.55,.43,.56 C.4,.57,.39,.59,.39,.6 C.39,.63,.41,.64,.46,.66 L.46,.82 L.57,.82", type: FILL },
|
|
267
|
+
"\u{E0B0}": { d: "M0,0 L1,.5 L0,1", type: FILL, rightPadding: 2 },
|
|
268
|
+
"\u{E0B1}": { d: "M-1,-.5 L1,.5 L-1,1.5", type: STROKE, leftPadding: 1, rightPadding: 1 },
|
|
269
|
+
"\u{E0B2}": { d: "M1,0 L0,.5 L1,1", type: FILL, leftPadding: 2 },
|
|
270
|
+
"\u{E0B3}": { d: "M2,-.5 L0,.5 L2,1.5", type: STROKE, leftPadding: 1, rightPadding: 1 },
|
|
271
|
+
"\u{E0B4}": { d: "M0,0 L0,1 C0.552,1,1,0.776,1,.5 C1,0.224,0.552,0,0,0", type: FILL, rightPadding: 1 },
|
|
272
|
+
"\u{E0B5}": { d: "M.2,1 C.422,1,.8,.826,.78,.5 C.8,.174,0.422,0,.2,0", type: STROKE, rightPadding: 1 },
|
|
273
|
+
"\u{E0B6}": { d: "M1,0 L1,1 C0.448,1,0,0.776,0,.5 C0,0.224,0.448,0,1,0", type: FILL, leftPadding: 1 },
|
|
274
|
+
"\u{E0B7}": { d: "M.8,1 C0.578,1,0.2,.826,.22,.5 C0.2,0.174,0.578,0,0.8,0", type: STROKE, leftPadding: 1 },
|
|
275
|
+
"\u{E0B8}": { d: "M-.5,-.5 L1.5,1.5 L-.5,1.5", type: FILL },
|
|
276
|
+
"\u{E0B9}": { d: "M-.5,-.5 L1.5,1.5", type: STROKE, leftPadding: 1, rightPadding: 1 },
|
|
277
|
+
"\u{E0BA}": { d: "M1.5,-.5 L-.5,1.5 L1.5,1.5", type: FILL },
|
|
278
|
+
"\u{E0BC}": { d: "M1.5,-.5 L-.5,1.5 L-.5,-.5", type: FILL },
|
|
279
|
+
"\u{E0BD}": { d: "M1.5,-.5 L-.5,1.5", type: STROKE, leftPadding: 1, rightPadding: 1 },
|
|
280
|
+
"\u{E0BE}": { d: "M-.5,-.5 L1.5,1.5 L1.5,-.5", type: FILL },
|
|
281
|
+
};
|
|
282
|
+
powerlineDefinitions["\u{E0BB}"] = powerlineDefinitions["\u{E0BD}"];
|
|
283
|
+
powerlineDefinitions["\u{E0BF}"] = powerlineDefinitions["\u{E0B9}"];
|
|
284
|
+
|
|
285
|
+
export const hasCustomGlyph = (character) =>
|
|
286
|
+
character in blockElementDefinitions
|
|
287
|
+
|| character in patternDefinitions
|
|
288
|
+
|| character in boxDrawingDefinitions
|
|
289
|
+
|| character in powerlineDefinitions;
|
|
290
|
+
|
|
291
|
+
// "M.5,0 L.5,1 C..." → [["M", .5, 0], ["L", .5, 1], ["C", ...]]
|
|
292
|
+
const parsePath = (instructions) => instructions.split(" ").map((instruction) => {
|
|
293
|
+
const numbers = instruction.slice(1).split(",").map(Number);
|
|
294
|
+
return [instruction[0], ...numbers];
|
|
295
|
+
}).filter((op) => op.length >= 3 && "MLC".includes(op[0]));
|
|
296
|
+
|
|
297
|
+
const parsedPaths = new Map();
|
|
298
|
+
|
|
299
|
+
const pathFor = (instructions) => {
|
|
300
|
+
let ops = parsedPaths.get(instructions);
|
|
301
|
+
if (!ops) {
|
|
302
|
+
ops = parsePath(instructions);
|
|
303
|
+
parsedPaths.set(instructions, ops);
|
|
304
|
+
}
|
|
305
|
+
return ops;
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
const clamp = (value, maximum) => Math.max(Math.min(value, maximum), 0);
|
|
309
|
+
|
|
310
|
+
// Scales 0–1 path coordinates to the cell. Box drawing coordinates snap to
|
|
311
|
+
// pixel centres (odd line widths) or pixel edges (even) so lines are crisp
|
|
312
|
+
// and meet the neighbouring cell without a seam.
|
|
313
|
+
const buildPath = (CanvasKit, ops, x, y, width, height, {
|
|
314
|
+
snap = false, lineWidth = 1, leftPadding = 0, rightPadding = 0,
|
|
315
|
+
} = {}) => {
|
|
316
|
+
const builder = new CanvasKit.PathBuilder();
|
|
317
|
+
const drawWidth = width - leftPadding - rightPadding;
|
|
318
|
+
const half = lineWidth % 2 ? 0.5 : 0;
|
|
319
|
+
const translateX = (value) => {
|
|
320
|
+
let result = value * drawWidth;
|
|
321
|
+
if (snap && result !== 0) result = clamp(Math.round(result + half) - half, width);
|
|
322
|
+
return result + x + leftPadding;
|
|
323
|
+
};
|
|
324
|
+
const translateY = (value) => {
|
|
325
|
+
let result = value * height;
|
|
326
|
+
if (snap && result !== 0) result = clamp(Math.round(result + half) - half, height);
|
|
327
|
+
return result + y;
|
|
328
|
+
};
|
|
329
|
+
for (const op of ops) {
|
|
330
|
+
if (op[0] === "M") builder.moveTo(translateX(op[1]), translateY(op[2]));
|
|
331
|
+
else if (op[0] === "L") builder.lineTo(translateX(op[1]), translateY(op[2]));
|
|
332
|
+
else if (op[0] === "C") {
|
|
333
|
+
builder.cubicTo(translateX(op[1]), translateY(op[2]), translateX(op[3]), translateY(op[4]),
|
|
334
|
+
translateX(op[5]), translateY(op[6]));
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
const path = builder.detach();
|
|
338
|
+
builder.delete();
|
|
339
|
+
return path;
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
// Shade characters are a repeating image shader, one per (pattern, color).
|
|
343
|
+
const shaderCache = new Map();
|
|
344
|
+
|
|
345
|
+
const patternShader = (CanvasKit, pattern, color) => {
|
|
346
|
+
const key = pattern.length + ":" + color.join(",");
|
|
347
|
+
let entry = shaderCache.get(key);
|
|
348
|
+
if (!entry) {
|
|
349
|
+
const height = pattern.length;
|
|
350
|
+
const width = pattern[0].length;
|
|
351
|
+
const pixels = new Uint8Array(width * height * 4);
|
|
352
|
+
for (let row = 0; row < height; row++) {
|
|
353
|
+
for (let column = 0; column < width; column++) {
|
|
354
|
+
const offset = (row * width + column) * 4;
|
|
355
|
+
pixels[offset] = color[0];
|
|
356
|
+
pixels[offset + 1] = color[1];
|
|
357
|
+
pixels[offset + 2] = color[2];
|
|
358
|
+
pixels[offset + 3] = pattern[row][column] ? 255 : 0;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
const image = CanvasKit.MakeImage({
|
|
362
|
+
width, height,
|
|
363
|
+
colorType: CanvasKit.ColorType.RGBA_8888,
|
|
364
|
+
alphaType: CanvasKit.AlphaType.Unpremul,
|
|
365
|
+
colorSpace: CanvasKit.ColorSpace.SRGB,
|
|
366
|
+
}, pixels, width * 4);
|
|
367
|
+
const shader = image.makeShaderOptions(CanvasKit.TileMode.Repeat, CanvasKit.TileMode.Repeat,
|
|
368
|
+
CanvasKit.FilterMode.Nearest, CanvasKit.MipmapMode.None);
|
|
369
|
+
entry = { image, shader };
|
|
370
|
+
shaderCache.set(key, entry);
|
|
371
|
+
}
|
|
372
|
+
return entry.shader;
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
// Draws `character` into the cell at (x, y) if it has a vector definition.
|
|
376
|
+
// `paint` is a fill paint carrying the foreground colour; `color` is the
|
|
377
|
+
// same colour as [r, g, b] for the shade shader cache. `fontSize` scales the
|
|
378
|
+
// line widths: 1 px up to 23 px, then one more pixel per 12 px, the way
|
|
379
|
+
// xterm.js's Powerline glyphs scale. Returns false when the character is not
|
|
380
|
+
// a custom glyph and should come from a font.
|
|
381
|
+
export const drawCustomGlyph = (CanvasKit, canvas, character, x, y, width, height, fontSize, paint, color) => {
|
|
382
|
+
const block = blockElementDefinitions[character];
|
|
383
|
+
if (block) {
|
|
384
|
+
const eighthX = width / 8;
|
|
385
|
+
const eighthY = height / 8;
|
|
386
|
+
for (const box of block) {
|
|
387
|
+
canvas.drawRect(CanvasKit.XYWHRect(x + box.x * eighthX, y + box.y * eighthY,
|
|
388
|
+
box.w * eighthX, box.h * eighthY), paint);
|
|
389
|
+
}
|
|
390
|
+
return true;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const pattern = patternDefinitions[character];
|
|
394
|
+
if (pattern) {
|
|
395
|
+
const shaded = new CanvasKit.Paint();
|
|
396
|
+
shaded.setShader(patternShader(CanvasKit, pattern, color));
|
|
397
|
+
canvas.drawRect(CanvasKit.XYWHRect(x, y, width, height), shaded);
|
|
398
|
+
shaded.delete();
|
|
399
|
+
return true;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const unit = Math.max(1, Math.floor(fontSize / 12));
|
|
403
|
+
const box = boxDrawingDefinitions[character];
|
|
404
|
+
if (box) {
|
|
405
|
+
const stroke = paint.copy();
|
|
406
|
+
stroke.setStyle(CanvasKit.PaintStyle.Stroke);
|
|
407
|
+
stroke.setAntiAlias(false);
|
|
408
|
+
for (const [weight, instructions] of Object.entries(box)) {
|
|
409
|
+
const lineWidth = unit * Number(weight);
|
|
410
|
+
stroke.setStrokeWidth(lineWidth);
|
|
411
|
+
const resolved = typeof instructions === "function"
|
|
412
|
+
? instructions(0.15, 0.15 / height * width)
|
|
413
|
+
: instructions;
|
|
414
|
+
const path = buildPath(CanvasKit, pathFor(resolved), x, y, width, height, { snap: true, lineWidth });
|
|
415
|
+
canvas.drawPath(path, stroke);
|
|
416
|
+
path.delete();
|
|
417
|
+
}
|
|
418
|
+
stroke.delete();
|
|
419
|
+
return true;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const powerline = powerlineDefinitions[character];
|
|
423
|
+
if (powerline) {
|
|
424
|
+
const lineWidth = fontSize / 12;
|
|
425
|
+
const path = buildPath(CanvasKit, pathFor(powerline.d), x, y, width, height, {
|
|
426
|
+
leftPadding: (powerline.leftPadding ?? 0) * lineWidth / 2,
|
|
427
|
+
rightPadding: (powerline.rightPadding ?? 0) * lineWidth / 2,
|
|
428
|
+
});
|
|
429
|
+
canvas.save();
|
|
430
|
+
canvas.clipRect(CanvasKit.XYWHRect(x, y, width, height), CanvasKit.ClipOp.Intersect, false);
|
|
431
|
+
if (powerline.type === STROKE) {
|
|
432
|
+
const stroke = paint.copy();
|
|
433
|
+
stroke.setStyle(CanvasKit.PaintStyle.Stroke);
|
|
434
|
+
stroke.setStrokeWidth(lineWidth);
|
|
435
|
+
canvas.drawPath(path, stroke);
|
|
436
|
+
stroke.delete();
|
|
437
|
+
} else {
|
|
438
|
+
canvas.drawPath(path, paint);
|
|
439
|
+
}
|
|
440
|
+
canvas.restore();
|
|
441
|
+
path.delete();
|
|
442
|
+
return true;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return false;
|
|
446
|
+
};
|