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.
Files changed (75) hide show
  1. package/LICENSES/Apache-2.0.txt +202 -0
  2. package/LICENSES/BSD-3-Clause-Skia.txt +29 -0
  3. package/LICENSES/Bitstream-Vera.txt +44 -0
  4. package/LICENSES/MIT-xterm.js.txt +21 -0
  5. package/LICENSES/OFL-1.1.txt +91 -0
  6. package/NOTICE.md +18 -1
  7. package/README.md +226 -22
  8. package/fetch-alpine.sh +9 -4
  9. package/graphics.md +213 -0
  10. package/initramfs/bin/bunterm +66 -0
  11. package/initramfs/bin/ip +2 -1
  12. package/initramfs/bin/mount +2 -1
  13. package/initramfs/bin/poweroff +6 -27
  14. package/initramfs/bin/ps +256 -0
  15. package/initramfs/bin/reboot +10 -0
  16. package/initramfs/bin/tar +169 -0
  17. package/initramfs/bin/top +129 -0
  18. package/initramfs/bin/umount +2 -1
  19. package/initramfs/buninu/CHANGELOG.md +40 -0
  20. package/initramfs/buninu/apps/bunmsh/CHANGELOG.md +36 -0
  21. package/initramfs/buninu/apps/bunmsh/README.md +7 -0
  22. package/initramfs/buninu/apps/bunmsh/package.json +1 -1
  23. package/initramfs/buninu/apps/bunmsh/src/fancy-ls.js +29 -14
  24. package/initramfs/buninu/apps/bunmsh/src/line-edit.js +43 -0
  25. package/initramfs/buninu/apps/bunmsh/src/main.js +15 -1
  26. package/initramfs/buninu/apps/bunmsh/src/mouse.js +29 -4
  27. package/initramfs/buninu/apps/bunmsh/src/shell.js +9 -1
  28. package/initramfs/buninu/apps/bunmsh/test/shell1.test.js +70 -0
  29. package/initramfs/buninu/apps/jsgotty/gotty.js +4 -3
  30. package/initramfs/buninu/apps/jsgotty/package.json +1 -1
  31. package/initramfs/buninu/apps/jsmdcui/CHANGELOG.md +10 -0
  32. package/initramfs/buninu/apps/jsmdcui/README.md +2 -0
  33. package/initramfs/buninu/apps/jsmdcui/package.json +1 -1
  34. package/initramfs/buninu/apps/jsmdcui/runtime/help/commands.md +4 -1
  35. package/initramfs/buninu/apps/jsmdcui/runtime/help/help.md +2 -0
  36. package/initramfs/buninu/apps/jsmdcui/src/index.js +40 -13
  37. package/initramfs/buninu/package.json +1 -1
  38. package/initramfs/init.js +6 -0
  39. package/initramfs/lib/bunterm/glyphs.js +446 -0
  40. package/initramfs/lib/bunterm/images.js +225 -0
  41. package/initramfs/lib/bunterm/input.js +140 -0
  42. package/initramfs/lib/bunterm/renderer.js +424 -0
  43. package/initramfs/lib/bunterm/terminal.js +203 -0
  44. package/initramfs/lib/canvas.js +181 -0
  45. package/initramfs/lib/canvaskit/LICENSE +29 -0
  46. package/initramfs/lib/canvaskit/canvaskit.js +264 -0
  47. package/initramfs/lib/canvaskit/canvaskit.wasm +0 -0
  48. package/initramfs/lib/dlopen.js +14 -11
  49. package/initramfs/lib/document.js +6 -0
  50. package/initramfs/lib/fbdev.js +581 -0
  51. package/initramfs/lib/power.js +35 -0
  52. package/initramfs/lib/xterm/LICENSE +21 -0
  53. package/initramfs/lib/xterm/addon-unicode-graphemes.mjs +44 -0
  54. package/initramfs/lib/xterm/xterm-headless.mjs +46 -0
  55. package/initramfs/usr/share/doc/buninu-linux/bunterm.md +83 -0
  56. package/initramfs/usr/share/doc/buninu-linux/canvas.md +91 -0
  57. package/initramfs/usr/share/doc/buninu-linux/fbdev.md +113 -0
  58. package/initramfs/usr/share/doc/buninu-linux/ps.md +94 -0
  59. package/initramfs/usr/share/doc/buninu-linux/reboot.md +15 -0
  60. package/initramfs/usr/share/doc/buninu-linux/tar.md +73 -0
  61. package/initramfs/usr/share/doc/buninu-linux/top.md +23 -0
  62. package/initramfs/usr/share/fonts/DejaVuSansMono-Bold.ttf +0 -0
  63. package/initramfs/usr/share/fonts/DejaVuSansMono.ttf +0 -0
  64. package/initramfs/usr/share/fonts/LICENSE-Apache-2.0.txt +202 -0
  65. package/initramfs/usr/share/fonts/LICENSE-DejaVu.txt +44 -0
  66. package/initramfs/usr/share/fonts/LICENSE-OFL-1.1.txt +91 -0
  67. package/initramfs/usr/share/fonts/NotoColorEmoji.ttf +0 -0
  68. package/initramfs/usr/share/fonts/NotoColorEmojiFlags.ttf +0 -0
  69. package/initramfs/usr/share/fonts/NotoSansCJK-Regular.ttc +0 -0
  70. package/initramfs/usr/share/fonts/NotoSansSymbols-Regular-Subsetted.ttf +0 -0
  71. package/initramfs/usr/share/fonts/NotoSansSymbols-Regular-Subsetted2.ttf +0 -0
  72. package/initramfs/usr/share/fonts/Roboto-Regular.ttf +0 -0
  73. package/initramfs/usr/share/fonts/fonts.json +28 -0
  74. package/package.json +2 -2
  75. package/run-qemu.sh +1 -1
@@ -0,0 +1,181 @@
1
+ // /lib/canvas.js — CanvasKit (Skia in WebAssembly) on the Linux framebuffer.
2
+ //
3
+ // Skia draws into a buffer inside the wasm heap that already has the
4
+ // framebuffer's own pixel layout, so a frame reaches /dev/fb0 with a single
5
+ // copy: exactly what /lib/fbdev.js does with its JavaScript back buffer. The
6
+ // Framebuffer's `pixels` view is pointed at that heap buffer while a canvas is
7
+ // open, so the fbdev.js drawing calls and flush() keep working on the same
8
+ // frame and Skia and JavaScript drawing can be mixed freely.
9
+
10
+ import { readFileSync } from "node:fs";
11
+ import CanvasKitInit from "./canvaskit/canvaskit.js";
12
+ import { flush as flushFramebuffer } from "./fbdev.js";
13
+
14
+ export const canvasKitDirectory = `${import.meta.dir}/canvaskit`;
15
+ export const fontDirectory = `${import.meta.dir}/../usr/share/fonts`;
16
+
17
+ let canvasKitPromise = null;
18
+
19
+ // One CanvasKit instance per process; the wasm heap starts at 128 MiB.
20
+ export const loadCanvasKit = () => {
21
+ canvasKitPromise ??= CanvasKitInit({
22
+ wasmBinary: readFileSync(`${canvasKitDirectory}/canvaskit.wasm`),
23
+ });
24
+ return canvasKitPromise;
25
+ };
26
+
27
+ const fieldIs = (field, offset, length) =>
28
+ field.offset === offset && field.length === length;
29
+
30
+ // Maps the kernel's bitfield description to a Skia ColorType with the same
31
+ // byte order in memory. The fields are little-endian bit offsets, so 32-bit
32
+ // red@16 green@8 blue@0 is B,G,R,X in memory: Skia's BGRA_8888. Only formats
33
+ // Skia can rasterize into directly are accepted; others must go through
34
+ // blitImageData() in fbdev.js.
35
+ export const pickColorType = (CanvasKit, display) => {
36
+ const { red, green, blue } = display.fields;
37
+ if (display.bitsPerPixel === 32) {
38
+ if (fieldIs(red, 16, 8) && fieldIs(green, 8, 8) && fieldIs(blue, 0, 8)) {
39
+ return CanvasKit.ColorType.BGRA_8888;
40
+ }
41
+ if (fieldIs(red, 0, 8) && fieldIs(green, 8, 8) && fieldIs(blue, 16, 8)) {
42
+ return CanvasKit.ColorType.RGBA_8888;
43
+ }
44
+ }
45
+ if (display.bitsPerPixel === 16
46
+ && fieldIs(red, 11, 5) && fieldIs(green, 5, 6) && fieldIs(blue, 0, 5)) {
47
+ return CanvasKit.ColorType.RGB_565;
48
+ }
49
+ return null;
50
+ };
51
+
52
+ const describeFields = ({ red, green, blue }) =>
53
+ `red@${red.offset}/${red.length} green@${green.offset}/${green.length} blue@${blue.offset}/${blue.length}`;
54
+
55
+ // Binds a Skia raster surface to an open Framebuffer. `display` only needs
56
+ // the fields fbdev.js's Framebuffer exposes (width, height, stride,
57
+ // bitsPerPixel, fields, pixels), so a plain object backed by memory works for
58
+ // tests and off-screen rendering.
59
+ export const openCanvas = (CanvasKit, display) => {
60
+ const colorType = pickColorType(CanvasKit, display);
61
+ if (colorType === null) {
62
+ throw new Error(`no Skia color type for a ${display.bitsPerPixel} bpp framebuffer `
63
+ + `(${describeFields(display.fields)}); use blitImageData() instead`);
64
+ }
65
+ const length = display.stride * display.height;
66
+ const memory = CanvasKit.Malloc(Uint8Array, length);
67
+ const surface = CanvasKit.MakeRasterDirectSurface({
68
+ width: display.width,
69
+ height: display.height,
70
+ colorType,
71
+ alphaType: CanvasKit.AlphaType.Opaque,
72
+ colorSpace: CanvasKit.ColorSpace.SRGB,
73
+ }, memory, display.stride);
74
+ if (!surface) {
75
+ CanvasKit.Free(memory);
76
+ throw new Error("MakeRasterDirectSurface failed");
77
+ }
78
+ const previousPixels = display.pixels;
79
+ // Start from whatever the JavaScript back buffer held (usually zeros).
80
+ memory.toTypedArray().set(previousPixels.subarray(0, length));
81
+ display.pixels = memory.toTypedArray();
82
+ let open = true;
83
+ return {
84
+ CanvasKit,
85
+ display,
86
+ surface,
87
+ canvas: surface.getCanvas(),
88
+ colorType,
89
+ width: display.width,
90
+ height: display.height,
91
+ // Finishes pending Skia work and copies the frame to the framebuffer.
92
+ // toTypedArray() is re-read because wasm heap growth detaches old views.
93
+ flush() {
94
+ if (!open) throw new Error("canvas is closed");
95
+ surface.flush();
96
+ display.pixels = memory.toTypedArray();
97
+ flushFramebuffer(display);
98
+ },
99
+ // Releases the Skia surface and heap buffer; the Framebuffer stays open
100
+ // and gets its own back buffer back, holding the last frame.
101
+ close() {
102
+ if (!open) return;
103
+ open = false;
104
+ previousPixels.set(memory.toTypedArray().subarray(0, previousPixels.length));
105
+ display.pixels = previousPixels;
106
+ surface.delete();
107
+ CanvasKit.Free(memory);
108
+ },
109
+ };
110
+ };
111
+
112
+ // Font catalogue: /usr/share/fonts/fonts.json names every bundled file and
113
+ // the family sets built from them. Files load lazily, since the CJK
114
+ // collection alone is 32 MiB and is copied into the wasm heap.
115
+ let catalogue = null;
116
+
117
+ export const fontCatalogue = () => {
118
+ catalogue ??= JSON.parse(readFileSync(`${fontDirectory}/fonts.json`, "utf8"));
119
+ return catalogue;
120
+ };
121
+
122
+ export const fontPath = (name) => {
123
+ const entry = fontCatalogue().fonts[name];
124
+ if (!entry) throw new Error(`unknown font ${JSON.stringify(name)}`);
125
+ return `${fontDirectory}/${entry.file}`;
126
+ };
127
+
128
+ const fontData = new Map();
129
+
130
+ export const loadFontData = (name) => {
131
+ let data = fontData.get(name);
132
+ if (!data) {
133
+ const bytes = readFileSync(fontPath(name));
134
+ data = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
135
+ fontData.set(name, data);
136
+ }
137
+ return data;
138
+ };
139
+
140
+ // A named font set from fonts.json as CanvasKit objects:
141
+ // typefaces the "regular", "bold" and each fallback font as a Typeface
142
+ // (a collection such as Noto Sans CJK yields its preferred face)
143
+ // fontMgr every file of the set registered by family name, for the
144
+ // Paragraph API; a collection registers all of its families
145
+ // families family names for ParagraphStyle.textStyle.fontFamilies, in
146
+ // lookup order
147
+ export const loadFontSet = (CanvasKit, setName = "terminal") => {
148
+ const { sets, fonts } = fontCatalogue();
149
+ const set = sets[setName];
150
+ if (!set) throw new Error(`unknown font set ${JSON.stringify(setName)}`);
151
+ const names = [set.regular, set.bold, ...(set.fallback ?? [])].filter(Boolean);
152
+ const buffers = names.map(loadFontData);
153
+ const fontMgr = CanvasKit.FontMgr.FromData(...buffers);
154
+ if (!fontMgr) throw new Error("FontMgr.FromData failed");
155
+ const typefaces = {};
156
+ names.forEach((name, index) => {
157
+ // A collection's "preferred" family picks the face (Noto Sans CJK TC for
158
+ // Taiwanese glyph forms); a single-face file loads directly.
159
+ const preferred = fonts[name].preferred;
160
+ const typeface = preferred
161
+ ? fontMgr.matchFamilyStyle(preferred, {})
162
+ : CanvasKit.Typeface.MakeFreeTypeFaceFromData(buffers[index]);
163
+ if (!typeface) throw new Error(`cannot load font ${name} (${fonts[name].file})`);
164
+ typefaces[name] = typeface;
165
+ });
166
+ const families = names.flatMap((name) => fonts[name].families ?? [name]);
167
+ return {
168
+ set,
169
+ names,
170
+ typefaces,
171
+ regular: typefaces[set.regular],
172
+ bold: set.bold ? typefaces[set.bold] : null,
173
+ fallback: (set.fallback ?? []).map((name) => typefaces[name]),
174
+ fontMgr,
175
+ families,
176
+ delete() {
177
+ for (const typeface of Object.values(typefaces)) typeface.delete();
178
+ fontMgr.delete();
179
+ },
180
+ };
181
+ };
@@ -0,0 +1,29 @@
1
+ // Copyright (c) 2011 Google Inc. All rights reserved.
2
+ //
3
+ // Redistribution and use in source and binary forms, with or without
4
+ // modification, are permitted provided that the following conditions are
5
+ // met:
6
+ //
7
+ // * Redistributions of source code must retain the above copyright
8
+ // notice, this list of conditions and the following disclaimer.
9
+ // * Redistributions in binary form must reproduce the above
10
+ // copyright notice, this list of conditions and the following disclaimer
11
+ // in the documentation and/or other materials provided with the
12
+ // distribution.
13
+ // * Neither the name of Google Inc. nor the names of its
14
+ // contributors may be used to endorse or promote products derived from
15
+ // this software without specific prior written permission.
16
+ //
17
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
+ // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
+ // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
+ // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21
+ // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
+ // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23
+ // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
+ // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
+ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ --------------------------------------------------------------------------------