bunmicro 1.0.0 → 1.0.3
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/CHANGELOG.md +26 -0
- package/package.json +1 -1
- package/single-exe/README.md +49 -0
- package/single-exe/assets.tar +0 -0
- package/single-exe/assetsLoader.mjs +85 -0
- package/single-exe/entry.mjs +9 -0
- package/single-exe/packAssets.sh +7 -0
- package/src/config/config.js +2 -1
- package/src/highlight/parser.js +20 -11
- package/src/index.js +403 -52
- package/src/lua/engine.js +42 -8
- package/src/platform/clipboard.js +3 -0
- package/src/plugins/js-bridge.js +65 -2
- package/src/plugins/manager.js +56 -1
- package/src/runtime/assets.js +90 -0
- package/src/runtime/compiled.js +25 -0
- package/src/runtime/encodings.js +5 -0
- package/src/runtime/registry.js +39 -3
- package/tests/cmphex3b64.js +95 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.0.3] - 2026-06-27
|
|
4
|
+
- Added hex3 series encodings
|
|
5
|
+
* hex3gz / hex3zst add compressed binary-view encodings
|
|
6
|
+
- Added experimental single-file exe support
|
|
7
|
+
* bundled assets loader
|
|
8
|
+
* internal assets fallback to external file tree when needed
|
|
9
|
+
- Added build helpers for single-exe packaging
|
|
10
|
+
* `--build-exe` runs the asset pack + compile flow
|
|
11
|
+
* `--build-for <target>` runs the same flow with an explicit Bun build target
|
|
12
|
+
|
|
13
|
+
## [1.0.2] - 2026-06-24
|
|
14
|
+
- Added startup profiling flags
|
|
15
|
+
* -profile / --profile
|
|
16
|
+
- Added docs flags
|
|
17
|
+
* --changelog alongside --docs / --readme
|
|
18
|
+
- Disabled OSC 52 probing
|
|
19
|
+
* clipboard now treats OSC 52 as available without detection
|
|
20
|
+
- Added hex3 aliases
|
|
21
|
+
* --xxd / --hexdump => --cat -encoding hex3
|
|
22
|
+
* --hex3 => -encoding hex3
|
|
23
|
+
- Fixed stdin encoding handling
|
|
24
|
+
* hex3 now applies when reading from stdin
|
|
25
|
+
- Parallelized startup loading
|
|
26
|
+
* Lua, JS, and buffer init now run in parallel with safe degradation
|
|
27
|
+
* startup performance improves a lot
|
|
28
|
+
|
|
3
29
|
## [1.0.0] - 2026-06-22
|
|
4
30
|
- Changed command -v to Bun.which
|
|
5
31
|
* for performance improvement
|
package/package.json
CHANGED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# This is completely optional
|
|
2
|
+
- I still recommend using the methods in the root README.md
|
|
3
|
+
- Bun's Android build is currently not supported
|
|
4
|
+
|
|
5
|
+
# Usage
|
|
6
|
+
- First run `bun ./packAssets.sh` to bundle the assets into `assets.tar`
|
|
7
|
+
- Then run the build script like this
|
|
8
|
+
|
|
9
|
+
```shell
|
|
10
|
+
bun build --compile --bytecode --minify ./entry.mjs --outfile=bmi
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
- You'll get a bmi executable
|
|
14
|
+
|
|
15
|
+
# Single Executable Intro
|
|
16
|
+
|
|
17
|
+
This folder contains the Bun single-exe bootstrap used by the project.
|
|
18
|
+
|
|
19
|
+
## Entry Flow
|
|
20
|
+
|
|
21
|
+
- `entry.mjs` imports `assetsLoader.mjs` first
|
|
22
|
+
- `assetsLoader.mjs` loads `assets.tar` with `Bun.Archive` and mounts it as `globalThis.internalAssets`
|
|
23
|
+
- `assetsLoaderPromise` is exposed on `globalThis`
|
|
24
|
+
- `../src/index.js` waits for `assetsLoaderPromise` if it exists
|
|
25
|
+
|
|
26
|
+
That keeps the main program bootable even if asset loading reports errors.
|
|
27
|
+
|
|
28
|
+
## Assets Loading
|
|
29
|
+
|
|
30
|
+
- Bundled assets are loaded sequentially with `await file.bytes()`
|
|
31
|
+
- Load failures are collected and printed to `stderr`
|
|
32
|
+
- Asset loading never rejects the bootstrap promise
|
|
33
|
+
- When loading succeeds, the archive is available through `globalThis.internalAssets`
|
|
34
|
+
|
|
35
|
+
## CLI Flags
|
|
36
|
+
|
|
37
|
+
- `--assets-list`
|
|
38
|
+
- Lists all entries inside bundled `assets.tar`
|
|
39
|
+
- Exits early before the main program starts
|
|
40
|
+
|
|
41
|
+
- `--assets-extract`
|
|
42
|
+
- Extracts bundled assets to the same directory as the executable
|
|
43
|
+
- Exits early before the main program starts
|
|
44
|
+
|
|
45
|
+
- `--assets-external`
|
|
46
|
+
- Skips loading bundled assets into `globalThis.internalAssets`
|
|
47
|
+
- Forces `../src/index.js` and runtime helpers to use the external file tree
|
|
48
|
+
- Keeps the bootstrap alive while leaving `internalAssets` falsy
|
|
49
|
+
|
|
Binary file
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import assets from "./assets.tar" with { type: "file" };
|
|
2
|
+
import { resolveCompiledBaseDir, isCompiledBinary } from "../src/runtime/compiled.js";
|
|
3
|
+
|
|
4
|
+
const forceExternalAssets = process.argv.includes("--assets-external");
|
|
5
|
+
const debugAssetsLoader = Boolean(process.env.BUNMICRO_DEBUG);
|
|
6
|
+
if (forceExternalAssets) {
|
|
7
|
+
const flagIndex = process.argv.indexOf("--assets-external");
|
|
8
|
+
if (flagIndex >= 0) process.argv.splice(flagIndex, 1);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
globalThis.internalAssets = forceExternalAssets ? null : Object.create(null);
|
|
12
|
+
globalThis.assetsLoaderPromise = main(process.argv).catch((error) => {
|
|
13
|
+
console.error("# assets loader failed");
|
|
14
|
+
console.error(error);
|
|
15
|
+
return globalThis.internalAssets;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
async function main(argv) {
|
|
19
|
+
|
|
20
|
+
if (forceExternalAssets &&
|
|
21
|
+
!argv.includes("--assets-list") &&
|
|
22
|
+
!argv.includes("--assets-extract")) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const startedAt = debugAssetsLoader ? Bun.nanoseconds() : 0;
|
|
27
|
+
|
|
28
|
+
const tarball = await Bun.file(assets).bytes();
|
|
29
|
+
const archive = new Bun.Archive(tarball);
|
|
30
|
+
|
|
31
|
+
await cliEarlyExit(archive, argv);
|
|
32
|
+
|
|
33
|
+
const files = await archive.files();
|
|
34
|
+
const entries = [...files.entries()];
|
|
35
|
+
const assetsByPath = Object.create(null);
|
|
36
|
+
const errors = [];
|
|
37
|
+
|
|
38
|
+
for (const [path, file] of entries) {
|
|
39
|
+
try {
|
|
40
|
+
assetsByPath[path] = await file.bytes();
|
|
41
|
+
} catch (reason) {
|
|
42
|
+
errors.push({ path, reason });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (errors.length > 0) {
|
|
47
|
+
console.error(`# Failed to load ${errors.length} bundled asset(s):`);
|
|
48
|
+
for (const { path, reason } of errors) {
|
|
49
|
+
console.error(`- ${path}`);
|
|
50
|
+
if (reason) {
|
|
51
|
+
console.error(reason);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (debugAssetsLoader) {
|
|
56
|
+
const elapsedMs = (Bun.nanoseconds() - startedAt) / 1e6;
|
|
57
|
+
console.error(`Loaded assets: ${elapsedMs.toFixed(3)} ms`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
globalThis.internalAssets = assetsByPath;
|
|
61
|
+
return assetsByPath;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function cliEarlyExit(archive, argv) {
|
|
65
|
+
if (argv.includes("--assets-list")) {
|
|
66
|
+
const files = await archive.files();
|
|
67
|
+
for (const path of [...files.keys()].sort()) {
|
|
68
|
+
console.log(path);
|
|
69
|
+
}
|
|
70
|
+
process.exit(0);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (argv.includes("--assets-extract")) {
|
|
74
|
+
if (isCompiledBinary(argv))
|
|
75
|
+
{
|
|
76
|
+
const targetDir = resolveCompiledBaseDir({ argv });
|
|
77
|
+
const extracted = await archive.extract(targetDir);
|
|
78
|
+
console.log(`Extracted ${extracted} asset(s) to ${targetDir}`);
|
|
79
|
+
} // if isCompiled
|
|
80
|
+
else
|
|
81
|
+
console.log("Assets extraction should only be used in a Bun compiled single-file executable");
|
|
82
|
+
|
|
83
|
+
process.exit(0);
|
|
84
|
+
}
|
|
85
|
+
}
|
package/src/config/config.js
CHANGED
|
@@ -4,6 +4,7 @@ import { homedir } from "node:os";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
//import { Glob } from "bun";
|
|
6
6
|
import { defaultAllSettings, OPTION_CHOICES, LOCAL_SETTINGS } from "./defaults.js";
|
|
7
|
+
import { isHex3Encoding } from "../runtime/encodings.js";
|
|
7
8
|
|
|
8
9
|
export class Config {
|
|
9
10
|
constructor({ configDir = "" } = {}) {
|
|
@@ -105,7 +106,7 @@ function normalizeSetting(key, value) {
|
|
|
105
106
|
function validateOption(option, value) {
|
|
106
107
|
if (option === "encoding") {
|
|
107
108
|
const encoding = String(value || "utf-8");
|
|
108
|
-
if (encoding
|
|
109
|
+
if (isHex3Encoding(encoding)) return;
|
|
109
110
|
try { new TextDecoder(encoding); }
|
|
110
111
|
catch { throw new Error(`Invalid encoding: ${value}`); }
|
|
111
112
|
}
|
package/src/highlight/parser.js
CHANGED
|
@@ -40,15 +40,19 @@ export class SyntaxDefinition {
|
|
|
40
40
|
|
|
41
41
|
export async function loadSyntaxDefinitions(runtime) {
|
|
42
42
|
const headers = new Map();
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
const headerPromises = runtime.list(4).map(async (file) => {
|
|
44
|
+
try {
|
|
45
|
+
const text = await file.text();
|
|
46
|
+
headers.set(file.name, parseHeaderFile(text));
|
|
47
|
+
} catch {}
|
|
48
|
+
});
|
|
49
|
+
await Promise.allSettled(headerPromises);
|
|
46
50
|
|
|
47
|
-
const
|
|
48
|
-
for (const file of runtime.list(1)) {
|
|
51
|
+
const defPromises = runtime.list(1).map(async (file) => {
|
|
49
52
|
let text = "";
|
|
50
53
|
let activeFile = file;
|
|
51
54
|
let source = null;
|
|
55
|
+
let usedFallback = false;
|
|
52
56
|
try {
|
|
53
57
|
text = await file.text();
|
|
54
58
|
source = Bun.YAML.parse(text);
|
|
@@ -59,21 +63,26 @@ export async function loadSyntaxDefinitions(runtime) {
|
|
|
59
63
|
text = await fallback.text();
|
|
60
64
|
source = Bun.YAML.parse(text);
|
|
61
65
|
activeFile = fallback;
|
|
66
|
+
usedFallback = true;
|
|
62
67
|
console.error("Failed to load user syntax yaml, using built-in fallback:", file.name);
|
|
63
68
|
} catch {}
|
|
64
69
|
}
|
|
65
70
|
}
|
|
66
|
-
|
|
71
|
+
const header = headers.get(activeFile.name) ?? (source ? parseHeaderYaml(source) : parseHeaderTextFallback(text, activeFile.name));
|
|
67
72
|
if (!source) {
|
|
68
73
|
console.error("Failed to load syntax yaml:", file.name);
|
|
69
74
|
console.error(" Will not highlight this kind of file");
|
|
70
75
|
console.error(" @ loadSyntaxDefinitions ");
|
|
76
|
+
} else if (usedFallback) {
|
|
77
|
+
// keep the fallback path visible in logs, but do not fail the load
|
|
71
78
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
return definitions
|
|
79
|
+
return new SyntaxDefinition(header, source ?? { rules: [] }, text);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const definitions = await Promise.allSettled(defPromises);
|
|
83
|
+
return definitions
|
|
84
|
+
.filter((result) => result.status === "fulfilled")
|
|
85
|
+
.map((result) => result.value);
|
|
77
86
|
}
|
|
78
87
|
|
|
79
88
|
export function detectSyntax(definitions, { path = "", firstLine = "", lines = [] } = {}) {
|