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/src/index.js
CHANGED
|
@@ -1,5 +1,97 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
+
let mainPromise = globalThis.assetsLoaderPromise ||
|
|
4
|
+
Promise.resolve();
|
|
5
|
+
|
|
6
|
+
const jsStart = globalThis.Bun ? Bun.nanoseconds() : Date.now() * 1e6;
|
|
7
|
+
const checkpoints = [
|
|
8
|
+
{ name: "Bun Engine Boot", time: 0 },
|
|
9
|
+
{ name: "JS Load & Module Imports", time: jsStart }
|
|
10
|
+
];
|
|
11
|
+
function addCheckpoint(name) {
|
|
12
|
+
checkpoints.push({ name, time: globalThis.Bun ? Bun.nanoseconds() : Date.now() * 1e6 });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let parallelTimings = null;
|
|
16
|
+
|
|
17
|
+
function printProfileReport() {
|
|
18
|
+
console.log("\x1b[1m\x1b[36m=== Bunmicro Startup Performance Profile ===\x1b[0m\n");
|
|
19
|
+
|
|
20
|
+
let totalMs = 0;
|
|
21
|
+
const rows = [];
|
|
22
|
+
|
|
23
|
+
for (let i = 0; i < checkpoints.length - 1; i++) {
|
|
24
|
+
const current = checkpoints[i];
|
|
25
|
+
const next = checkpoints[i + 1];
|
|
26
|
+
const durationNs = next.time - current.time;
|
|
27
|
+
const durationMs = durationNs / 1e6;
|
|
28
|
+
totalMs += durationMs;
|
|
29
|
+
|
|
30
|
+
rows.push({
|
|
31
|
+
phase: current.name,
|
|
32
|
+
durationMs: durationMs,
|
|
33
|
+
cumulativeMs: totalMs
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const colWidths = { phase: 32, duration: 15, cumulative: 15 };
|
|
38
|
+
|
|
39
|
+
const header =
|
|
40
|
+
"Phase".padEnd(colWidths.phase) + " | " +
|
|
41
|
+
"Duration (ms)".padStart(colWidths.duration) + " | " +
|
|
42
|
+
"Cumulative (ms)".padStart(colWidths.cumulative);
|
|
43
|
+
|
|
44
|
+
const separator =
|
|
45
|
+
"-".repeat(colWidths.phase) + "-+-" +
|
|
46
|
+
"-".repeat(colWidths.duration) + "-+-" +
|
|
47
|
+
"-".repeat(colWidths.cumulative);
|
|
48
|
+
|
|
49
|
+
console.log(header);
|
|
50
|
+
console.log(separator);
|
|
51
|
+
|
|
52
|
+
for (const row of rows) {
|
|
53
|
+
const phaseStr = row.phase.padEnd(colWidths.phase);
|
|
54
|
+
const durStr = row.durationMs.toFixed(3).padStart(colWidths.duration);
|
|
55
|
+
const cumStr = row.cumulativeMs.toFixed(3).padStart(colWidths.cumulative);
|
|
56
|
+
|
|
57
|
+
let color = "";
|
|
58
|
+
if (row.durationMs > 50) {
|
|
59
|
+
color = "\x1b[31m"; // Red
|
|
60
|
+
} else if (row.durationMs > 10) {
|
|
61
|
+
color = "\x1b[33m"; // Yellow
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const reset = color ? "\x1b[0m" : "";
|
|
65
|
+
console.log(`${color}${phaseStr}${reset} | ${color}${durStr}${reset} | ${cumStr}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
console.log(separator);
|
|
69
|
+
|
|
70
|
+
if (parallelTimings) {
|
|
71
|
+
console.log("\x1b[1mParallel Tasks Breakdown:\x1b[0m");
|
|
72
|
+
console.log(` ├── Lua Plugins & Hooks : ${parallelTimings.lua.toFixed(3).padStart(8)} ms`);
|
|
73
|
+
console.log(` ├── JS Plugins Load : ${parallelTimings.js.toFixed(3).padStart(8)} ms`);
|
|
74
|
+
console.log(` └── Buffer & History : ${parallelTimings.buffers.toFixed(3).padStart(8)} ms`);
|
|
75
|
+
console.log(separator);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
console.log(`\x1b[1mTotal Startup Time: ${totalMs.toFixed(3)} ms\x1b[0m\n`);
|
|
79
|
+
|
|
80
|
+
const slowest = [...rows].sort((a, b) => b.durationMs - a.durationMs)[0];
|
|
81
|
+
if (slowest) {
|
|
82
|
+
console.log(`\x1b[1mSlowest Phase:\x1b[0m ${slowest.phase} (${slowest.durationMs.toFixed(3)} ms)`);
|
|
83
|
+
if (slowest.phase.includes("Clipboard")) {
|
|
84
|
+
console.log("\x1b[32mTip: Clipboard probing can be slow. Setting 'clipboard' option to 'terminal' or a specific tool can bypass auto-detection.\x1b[0m");
|
|
85
|
+
} else if (slowest.phase.includes("Plugin")) {
|
|
86
|
+
console.log("\x1b[32mTip: Disable unnecessary plugins to speed up startup.\x1b[0m");
|
|
87
|
+
} else if (slowest.phase.includes("Syntax")) {
|
|
88
|
+
console.log("\x1b[32mTip: Syntax loading parses many YAML/JSON files. You can pre-compile or bundle syntax definitions to speed this up.\x1b[0m");
|
|
89
|
+
} else if (slowest.phase.includes("JS Load")) {
|
|
90
|
+
console.log("\x1b[32mTip: JS load time includes loading packages like wasmoon, which might take time due to file system lookups.\x1b[0m");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
3
95
|
import child_process from "node:child_process"
|
|
4
96
|
import { accessSync, constants, existsSync, readdirSync, statSync, unlinkSync } from "node:fs";
|
|
5
97
|
import { mkdir } from "node:fs/promises";
|
|
@@ -10,6 +102,7 @@ import { Config } from "./config/config.js";
|
|
|
10
102
|
import { defaultAllSettings, OPTION_CHOICES, LOCAL_SETTINGS } from "./config/defaults.js";
|
|
11
103
|
import { cleanConfig } from "./config/clean.js";
|
|
12
104
|
import { RuntimeRegistry, RTColorscheme, RTHelp } from "./runtime/registry.js";
|
|
105
|
+
import { assetPath, hasInternalAssets, listInternalAssetDirs, readInternalAssetText } from "./runtime/assets.js";
|
|
13
106
|
import { PluginManager } from "./plugins/manager.js";
|
|
14
107
|
import { JsPluginManager, buildMicroGlobal, runAction, listActions } from "./plugins/js-bridge.js";
|
|
15
108
|
import { Colorscheme } from "./config/colorscheme.js";
|
|
@@ -24,9 +117,11 @@ import { shellSplit } from "./shell/shell.js";
|
|
|
24
117
|
import { styleToAnsi } from "./display/ansi-style.js";
|
|
25
118
|
import { encodeBinaryToBuffer, decodeBinaryBytes } from "./buffer/fixed3-codec.js";
|
|
26
119
|
import { writeBackup, removeBackup, applyBackup } from "./buffer/backup.js";
|
|
120
|
+
import { isHex3Encoding } from "./runtime/encodings.js";
|
|
27
121
|
import { createInterface } from "node:readline/promises";
|
|
28
122
|
|
|
29
123
|
import pkg from "../package.json" with { type: "json" };
|
|
124
|
+
import { isCompiledBinary, resolveCompiledBaseDir } from "./runtime/compiled.js";
|
|
30
125
|
|
|
31
126
|
|
|
32
127
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -70,7 +165,13 @@ Windows
|
|
|
70
165
|
}
|
|
71
166
|
|
|
72
167
|
const VERSION = pkg.version;
|
|
73
|
-
const
|
|
168
|
+
const IS_COMPILED = isCompiledBinary(process.argv);
|
|
169
|
+
const REPO_ROOT = IS_COMPILED
|
|
170
|
+
? resolveCompiledBaseDir({ argv: process.argv })
|
|
171
|
+
: resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
172
|
+
const SINGLE_EXE_DIR = resolve(REPO_ROOT, "single-exe");
|
|
173
|
+
const SINGLE_EXE_ENTRY = resolve(SINGLE_EXE_DIR, "entry.mjs");
|
|
174
|
+
const DEFAULT_BUILD_OUTFILE = "bmi";
|
|
74
175
|
const decoder = new TextDecoder();
|
|
75
176
|
let _activeTtyStream = null; // set in App.start() for use by the global error handler
|
|
76
177
|
|
|
@@ -164,13 +265,44 @@ function isHttpUrl(value) {
|
|
|
164
265
|
}
|
|
165
266
|
|
|
166
267
|
function decodeTextBytesWithEncoding(bytes, encoding = "utf-8") {
|
|
167
|
-
|
|
168
|
-
|
|
268
|
+
const normalized = normalizeEncodingLabel(encoding);
|
|
269
|
+
if (normalized === "hex3gz") {
|
|
270
|
+
const decoded = decodeHex3Bytes(Bun.gunzipSync(bytes));
|
|
271
|
+
return { ...decoded, encoding: "hex3gz" };
|
|
272
|
+
}
|
|
273
|
+
if (normalized === "hex3zst") {
|
|
274
|
+
const decoded = decodeHex3Bytes(Bun.zstdDecompressSync(bytes));
|
|
275
|
+
return { ...decoded, encoding: "hex3zst" };
|
|
276
|
+
}
|
|
277
|
+
if (normalized === "hex3") {
|
|
278
|
+
return decodeHex3Bytes(bytes);
|
|
169
279
|
}
|
|
170
|
-
const decoder = new TextDecoder(
|
|
280
|
+
const decoder = new TextDecoder(normalized);
|
|
171
281
|
return { text: decoder.decode(bytes), encoding: decoder.encoding };
|
|
172
282
|
}
|
|
173
283
|
|
|
284
|
+
function encodeTextBytesWithEncoding(text, encoding = "utf-8") {
|
|
285
|
+
const normalized = normalizeEncodingLabel(encoding);
|
|
286
|
+
if (normalized === "hex3gz") {
|
|
287
|
+
return Bun.gzipSync(encodeHex3Text(text));
|
|
288
|
+
}
|
|
289
|
+
if (normalized === "hex3zst") {
|
|
290
|
+
return Bun.zstdCompressSync(encodeHex3Text(text));
|
|
291
|
+
}
|
|
292
|
+
if (normalized === "hex3") {
|
|
293
|
+
return encodeHex3Text(text);
|
|
294
|
+
}
|
|
295
|
+
return new TextEncoder().encode(String(text));
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function decodeHex3Bytes(bytes) {
|
|
299
|
+
return { text: encodeBinaryToBuffer(bytes).toString("latin1"), encoding: "hex3" };
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function encodeHex3Text(text) {
|
|
303
|
+
return decodeBinaryBytes(Buffer.from(text, "latin1"));
|
|
304
|
+
}
|
|
305
|
+
|
|
174
306
|
async function readTextFileWithEncoding(path, encoding = "utf-8") {
|
|
175
307
|
const bytes = new Uint8Array(await Bun.file(path).arrayBuffer());
|
|
176
308
|
return decodeTextBytesWithEncoding(bytes, encoding);
|
|
@@ -183,7 +315,7 @@ async function fetchTextWithEncoding(url, encoding = "utf-8") {
|
|
|
183
315
|
|
|
184
316
|
function normalizeEncodingLabel(encoding = "utf-8") {
|
|
185
317
|
const s = String(encoding || "utf-8");
|
|
186
|
-
if (s
|
|
318
|
+
if (isHex3Encoding(s)) return s.toLowerCase();
|
|
187
319
|
return new TextDecoder(s).encoding;
|
|
188
320
|
}
|
|
189
321
|
|
|
@@ -512,6 +644,9 @@ function parseArgs(argv) {
|
|
|
512
644
|
clean: false,
|
|
513
645
|
cat: false,
|
|
514
646
|
docs: false,
|
|
647
|
+
changelog: false,
|
|
648
|
+
buildExe: false,
|
|
649
|
+
buildFor: "",
|
|
515
650
|
configDir: "",
|
|
516
651
|
debug: false,
|
|
517
652
|
profile: false,
|
|
@@ -529,9 +664,25 @@ function parseArgs(argv) {
|
|
|
529
664
|
else if (arg === "-help" || arg === "--help" || arg === "-h") flags.help = true;
|
|
530
665
|
else if (arg === "-clean") flags.clean = true;
|
|
531
666
|
else if (arg === "--cat" || arg === "-cat" || arg === "--ccat" || arg === "-ccat" || arg === "--bat" || arg === "-bat" || arg === "--glow" || arg === "-glow") flags.cat = true;
|
|
667
|
+
else if (arg === "--xxd" || arg === "--hexdump") {
|
|
668
|
+
flags.cat = true;
|
|
669
|
+
flags.settings.set("encoding", "hex3");
|
|
670
|
+
}
|
|
671
|
+
else if (arg === "--hex3") {
|
|
672
|
+
flags.settings.set("encoding", "hex3");
|
|
673
|
+
}
|
|
674
|
+
else if (arg === "--hex3gz") {
|
|
675
|
+
flags.settings.set("encoding", "hex3gz");
|
|
676
|
+
}
|
|
677
|
+
else if (arg === "--hex3zst") {
|
|
678
|
+
flags.settings.set("encoding", "hex3zst");
|
|
679
|
+
}
|
|
532
680
|
else if (arg === "--docs" || arg === "--readme") flags.docs = true;
|
|
681
|
+
else if (arg === "--changelog") flags.changelog = true;
|
|
682
|
+
else if (arg === "--build-exe") flags.buildExe = true;
|
|
683
|
+
else if (arg === "--build-for") flags.buildFor = argv[++i] ?? "";
|
|
533
684
|
else if (arg === "-debug") flags.debug = true;
|
|
534
|
-
else if (arg === "-profile") flags.profile = true;
|
|
685
|
+
else if (arg === "-profile" || arg === "--profile") flags.profile = true;
|
|
535
686
|
else if (arg === "-config-dir") flags.configDir = argv[++i] ?? "";
|
|
536
687
|
else if (arg === "-plugin") flags.plugin = argv[++i] ?? "";
|
|
537
688
|
else if (arg.startsWith("--remote-debugging-port=")) {
|
|
@@ -578,14 +729,23 @@ function usage() {
|
|
|
578
729
|
" Set an option for this session",
|
|
579
730
|
"-options",
|
|
580
731
|
" Show option help and exit\n",
|
|
732
|
+
"-profile, --profile",
|
|
733
|
+
" Print startup performance profile and exit\n",
|
|
581
734
|
"--cat, --ccat, --bat, --glow",
|
|
582
735
|
" Syntax-highlight file(s) and write to stdout, then exit (.md uses Bun.markdown.ansi)\n",
|
|
736
|
+
"--xxd, --hexdump",
|
|
737
|
+
" Hex3 dump file(s) and write to stdout (same as --cat -encoding hex3)\n",
|
|
738
|
+
"--hex3, --hex3gz, --hex3zst",
|
|
739
|
+
" Set -encoding hex3, hex3gz, or hex3zst for this session",
|
|
740
|
+
" hex3 shows raw bytes; gz/zst variants compress the same hex3 view\n",
|
|
583
741
|
"-help, -h, --help",
|
|
584
742
|
" Show this help & exit",
|
|
585
743
|
"-version, -V, --version",
|
|
586
744
|
" Show version+backend info & exit",
|
|
587
745
|
"--docs, --readme",
|
|
588
746
|
` Show ${pkg.name}'s README.md & exit`,
|
|
747
|
+
"--changelog",
|
|
748
|
+
" Show CHANGELOG.md & exit",
|
|
589
749
|
"",
|
|
590
750
|
"--remote-debugging-port=PORT",
|
|
591
751
|
" Start CDP (Chrome DevTools Protocol) server on PORT at launch",
|
|
@@ -595,6 +755,50 @@ function usage() {
|
|
|
595
755
|
].join("\n");
|
|
596
756
|
}
|
|
597
757
|
|
|
758
|
+
async function buildExecutable(target = "") {
|
|
759
|
+
const outfile = resolve(process.cwd(), DEFAULT_BUILD_OUTFILE);
|
|
760
|
+
const normalizedTarget = String(target || "").trim();
|
|
761
|
+
|
|
762
|
+
const steps = [
|
|
763
|
+
{
|
|
764
|
+
label: "Pack assets",
|
|
765
|
+
cwd: SINGLE_EXE_DIR,
|
|
766
|
+
cmd: "bun",
|
|
767
|
+
args: ["./packAssets.sh"],
|
|
768
|
+
},
|
|
769
|
+
{
|
|
770
|
+
label: "Compile executable",
|
|
771
|
+
cwd: process.cwd(),
|
|
772
|
+
cmd: "bun",
|
|
773
|
+
args: [
|
|
774
|
+
"build",
|
|
775
|
+
"--compile",
|
|
776
|
+
"--bytecode",
|
|
777
|
+
"--minify",
|
|
778
|
+
SINGLE_EXE_ENTRY,
|
|
779
|
+
`--outfile=${DEFAULT_BUILD_OUTFILE}`,
|
|
780
|
+
...(normalizedTarget ? [`--target=${normalizedTarget}`] : []),
|
|
781
|
+
],
|
|
782
|
+
},
|
|
783
|
+
];
|
|
784
|
+
|
|
785
|
+
for (const step of steps) {
|
|
786
|
+
console.log('');
|
|
787
|
+
console.log(Bun.markdown.ansi('## '+step.label));
|
|
788
|
+
|
|
789
|
+
const result = child_process.spawnSync(step.cmd, step.args, {
|
|
790
|
+
cwd: step.cwd,
|
|
791
|
+
stdio: "inherit",
|
|
792
|
+
env: process.env,
|
|
793
|
+
});
|
|
794
|
+
if (result.status !== 0) {
|
|
795
|
+
process.exit(result.status ?? 1);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
console.log(`Built executable: ${outfile}`);
|
|
800
|
+
}
|
|
801
|
+
|
|
598
802
|
function parseInput(args) {
|
|
599
803
|
const files = [];
|
|
600
804
|
const command = {
|
|
@@ -1177,9 +1381,9 @@ class BufferModel {
|
|
|
1177
1381
|
if (this._backupRevision === backupRevision) this._backupRequested = false;
|
|
1178
1382
|
this._forceKeepBackup = true;
|
|
1179
1383
|
}
|
|
1180
|
-
if (this.encoding
|
|
1384
|
+
if (isHex3Encoding(this.encoding)) {
|
|
1181
1385
|
try {
|
|
1182
|
-
await Bun.write(targetPath,
|
|
1386
|
+
await Bun.write(targetPath, encodeTextBytesWithEncoding(text, this.encoding));
|
|
1183
1387
|
} finally {
|
|
1184
1388
|
this._forceKeepBackup = false;
|
|
1185
1389
|
}
|
|
@@ -4037,7 +4241,7 @@ class App {
|
|
|
4037
4241
|
if (!force && this.buffer?.readonly) { this.message = "Can't save under readonly mode"; return; }
|
|
4038
4242
|
try {
|
|
4039
4243
|
const enc = normalizeEncodingLabel(this.buffer?.encoding);
|
|
4040
|
-
if (enc !== "utf-8" && enc
|
|
4244
|
+
if (enc !== "utf-8" && !isHex3Encoding(enc)) {
|
|
4041
4245
|
this.openYNPrompt("Save in UTF-8?(y,n)", async (answer) => {
|
|
4042
4246
|
if (answer === "y") await this.saveUtf8();
|
|
4043
4247
|
});
|
|
@@ -4454,7 +4658,8 @@ class App {
|
|
|
4454
4658
|
const saveArgs = [...cmdArgs];
|
|
4455
4659
|
const saveForce = saveArgs[0] === "-f" && (saveArgs.shift(), true);
|
|
4456
4660
|
if (!saveForce && buf?.readonly) { this.message = "Can't save under readonly mode"; break; }
|
|
4457
|
-
|
|
4661
|
+
const bufferEncoding = normalizeEncodingLabel(buf?.encoding);
|
|
4662
|
+
if (saveArgs.length > 0 && bufferEncoding !== "utf-8" && !isHex3Encoding(bufferEncoding)) {
|
|
4458
4663
|
const target = resolve(expandHome(saveArgs[0]));
|
|
4459
4664
|
this.openYNPrompt("Save in UTF-8?(y,n)", async (answer) => {
|
|
4460
4665
|
if (answer === "y") {
|
|
@@ -5329,14 +5534,14 @@ const COMMAND_NAMES = [
|
|
|
5329
5534
|
];
|
|
5330
5535
|
|
|
5331
5536
|
const SUPPORTED_ENCODING_LABELS = [
|
|
5332
|
-
"hex3",
|
|
5537
|
+
"hex3", "hex3gz", "hex3zst",
|
|
5333
5538
|
"utf-8", "utf-16le", "utf-16be",
|
|
5334
5539
|
"windows-1252", "iso-8859-1", "latin1",
|
|
5335
5540
|
"big5", "gbk", "gb18030",
|
|
5336
5541
|
"shift_jis", "sjis", "euc-jp", "iso-2022-jp",
|
|
5337
5542
|
"euc-kr", "ks_c_5601-1987",
|
|
5338
5543
|
].filter((encoding) => {
|
|
5339
|
-
if (encoding
|
|
5544
|
+
if (isHex3Encoding(encoding)) return true;
|
|
5340
5545
|
try { new TextDecoder(encoding); return true; }
|
|
5341
5546
|
catch { return false; }
|
|
5342
5547
|
});
|
|
@@ -6573,8 +6778,16 @@ async function loadBuffers(files, command) {
|
|
|
6573
6778
|
} else if (!process.stdin.isTTY) {
|
|
6574
6779
|
const chunks = [];
|
|
6575
6780
|
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
6576
|
-
const
|
|
6577
|
-
const
|
|
6781
|
+
const context = loadBuffers.context ?? {};
|
|
6782
|
+
const encoding = context.config?.globalSettings?.encoding ?? DEFAULT_SETTINGS.encoding;
|
|
6783
|
+
const decoded = decodeTextBytesWithEncoding(Buffer.concat(chunks), encoding);
|
|
6784
|
+
const stdinText = decoded.text;
|
|
6785
|
+
const stdinBuf = new BufferModel({
|
|
6786
|
+
text: stdinText,
|
|
6787
|
+
type: process.stdout.isTTY ? "default" : "stdout",
|
|
6788
|
+
command,
|
|
6789
|
+
encoding: decoded.encoding,
|
|
6790
|
+
});
|
|
6578
6791
|
if (loadBuffers.context) attachSyntax(stdinBuf, loadBuffers.context, "", stdinText);
|
|
6579
6792
|
buffers.push(stdinBuf);
|
|
6580
6793
|
} else {
|
|
@@ -6589,12 +6802,38 @@ async function loadBuffers(files, command) {
|
|
|
6589
6802
|
}
|
|
6590
6803
|
|
|
6591
6804
|
async function printReadmeDocs() {
|
|
6592
|
-
const readme = await Bun.file(join(REPO_ROOT, "README.md")).text();
|
|
6805
|
+
const readme = readInternalAssetText("README.md") ?? await Bun.file(join(REPO_ROOT, "README.md")).text();
|
|
6593
6806
|
process.stdout.write(Bun.markdown.ansi(readme, { hyperlinks: true }));
|
|
6594
6807
|
}
|
|
6595
6808
|
|
|
6809
|
+
async function printChangelogDocs() {
|
|
6810
|
+
const changelog = readInternalAssetText("CHANGELOG.md") ?? await Bun.file(join(REPO_ROOT, "CHANGELOG.md")).text();
|
|
6811
|
+
process.stdout.write(Bun.markdown.ansi(changelog, { hyperlinks: true }));
|
|
6812
|
+
}
|
|
6813
|
+
|
|
6596
6814
|
async function main() {
|
|
6815
|
+
addCheckpoint("Argument Parsing");
|
|
6597
6816
|
const { flags, files: rawFiles } = parseArgs(process.argv.slice(2));
|
|
6817
|
+
if (flags.buildExe && flags.buildFor) {
|
|
6818
|
+
console.error("--build-exe and --build-for are separate paths; use only one");
|
|
6819
|
+
process.exit(1);
|
|
6820
|
+
}
|
|
6821
|
+
if (flags.buildExe) {
|
|
6822
|
+
if (IS_COMPILED) {
|
|
6823
|
+
console.error("--build-exe is only available in the source tree");
|
|
6824
|
+
process.exit(1);
|
|
6825
|
+
}
|
|
6826
|
+
await buildExecutable();
|
|
6827
|
+
return;
|
|
6828
|
+
}
|
|
6829
|
+
if (flags.buildFor) {
|
|
6830
|
+
if (IS_COMPILED) {
|
|
6831
|
+
console.error("--build-for is only available in the source tree");
|
|
6832
|
+
process.exit(1);
|
|
6833
|
+
}
|
|
6834
|
+
await buildExecutable(flags.buildFor);
|
|
6835
|
+
return;
|
|
6836
|
+
}
|
|
6598
6837
|
if (flags.help) {
|
|
6599
6838
|
console.log(usage());
|
|
6600
6839
|
return;
|
|
@@ -6628,6 +6867,10 @@ async function main() {
|
|
|
6628
6867
|
await printReadmeDocs();
|
|
6629
6868
|
return;
|
|
6630
6869
|
}
|
|
6870
|
+
if (flags.changelog) {
|
|
6871
|
+
await printChangelogDocs();
|
|
6872
|
+
return;
|
|
6873
|
+
}
|
|
6631
6874
|
if (flags.options) {
|
|
6632
6875
|
for (const [key, value] of Object.entries(defaultAllSettings()).sort(([a], [b]) => a.localeCompare(b))) {
|
|
6633
6876
|
console.log(`-${key} value`);
|
|
@@ -6635,13 +6878,16 @@ async function main() {
|
|
|
6635
6878
|
}
|
|
6636
6879
|
return;
|
|
6637
6880
|
}
|
|
6881
|
+
addCheckpoint("Config Initialization");
|
|
6638
6882
|
const config = await new Config({ configDir: flags.configDir }).init();
|
|
6639
6883
|
config.applyCliSettings(flags.settings);
|
|
6640
6884
|
syncEditorSettings(config);
|
|
6641
6885
|
|
|
6886
|
+
addCheckpoint("Runtime Registry Init");
|
|
6642
6887
|
const runtime = new RuntimeRegistry({ repoRoot: REPO_ROOT, configDir: config.configDir });
|
|
6643
6888
|
await runtime.init({ user: true });
|
|
6644
6889
|
|
|
6890
|
+
addCheckpoint("Colorscheme & Syntax Load");
|
|
6645
6891
|
const colorscheme = await new Colorscheme(runtime).load(config.getGlobalOption("colorscheme") || "default");
|
|
6646
6892
|
const syntaxDefinitions = await loadSyntaxDefinitions(runtime);
|
|
6647
6893
|
|
|
@@ -6650,22 +6896,36 @@ async function main() {
|
|
|
6650
6896
|
return;
|
|
6651
6897
|
}
|
|
6652
6898
|
|
|
6899
|
+
addCheckpoint("Lua Plugin Manager Init");
|
|
6653
6900
|
const plugins = new PluginManager({ config, runtime, repoRoot: REPO_ROOT });
|
|
6654
6901
|
await plugins.init();
|
|
6655
6902
|
|
|
6656
6903
|
if (flags.plugin === "list") {
|
|
6657
6904
|
const luaList = plugins.list();
|
|
6658
|
-
const jsDirs = [
|
|
6659
|
-
{ dir: join(REPO_ROOT, "runtime", "jsplugins"), builtin: true },
|
|
6660
|
-
{ dir: join(config.configDir, "jsplug"), builtin: false },
|
|
6661
|
-
];
|
|
6662
6905
|
const jsItems = [];
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6906
|
+
const builtinJsPluginNames = hasInternalAssets()
|
|
6907
|
+
? listInternalAssetDirs(assetPath("runtime", "jsplugins"))
|
|
6908
|
+
: [];
|
|
6909
|
+
if (builtinJsPluginNames.length > 0) {
|
|
6910
|
+
for (const name of builtinJsPluginNames) {
|
|
6911
|
+
jsItems.push({ name, builtin: true });
|
|
6912
|
+
}
|
|
6913
|
+
} else {
|
|
6914
|
+
const builtinJsDir = join(REPO_ROOT, "runtime", "jsplugins");
|
|
6915
|
+
if (existsSync(builtinJsDir)) {
|
|
6916
|
+
for (const entry of readdirSync(builtinJsDir, { withFileTypes: true })) {
|
|
6917
|
+
if (!entry.isDirectory()) continue;
|
|
6918
|
+
if (existsSync(join(builtinJsDir, entry.name, `${entry.name}.js`)))
|
|
6919
|
+
jsItems.push({ name: entry.name, builtin: true });
|
|
6920
|
+
}
|
|
6921
|
+
}
|
|
6922
|
+
}
|
|
6923
|
+
const userJsDir = join(config.configDir, "jsplug");
|
|
6924
|
+
if (existsSync(userJsDir)) {
|
|
6925
|
+
for (const entry of readdirSync(userJsDir, { withFileTypes: true })) {
|
|
6666
6926
|
if (!entry.isDirectory()) continue;
|
|
6667
|
-
if (existsSync(join(
|
|
6668
|
-
jsItems.push({ name: entry.name, builtin });
|
|
6927
|
+
if (existsSync(join(userJsDir, entry.name, `${entry.name}.js`)))
|
|
6928
|
+
jsItems.push({ name: entry.name, builtin: false });
|
|
6669
6929
|
}
|
|
6670
6930
|
}
|
|
6671
6931
|
const fmtTag = (p) => p.builtin ? " *(built-in)*" : "";
|
|
@@ -6688,50 +6948,114 @@ async function main() {
|
|
|
6688
6948
|
return;
|
|
6689
6949
|
}
|
|
6690
6950
|
|
|
6691
|
-
const pluginErr = await plugins.loadAll();
|
|
6692
|
-
if (pluginErr) console.error(`Plugin runtime disabled: ${pluginErr.message}`);
|
|
6693
|
-
if (!pluginErr) {
|
|
6694
|
-
await plugins.run("preinit");
|
|
6695
|
-
await plugins.run("init");
|
|
6696
|
-
await plugins.run("postinit");
|
|
6697
|
-
}
|
|
6698
|
-
|
|
6699
|
-
// ── JS plugin system ──────────────────────────────────────────────────────
|
|
6700
|
-
const jsPlugins = new JsPluginManager();
|
|
6701
6951
|
const { files, command } = parseInput(rawFiles);
|
|
6952
|
+
const jsPlugins = new JsPluginManager();
|
|
6702
6953
|
const context = { colorscheme, syntaxDefinitions, plugins, config, runtime, jsPlugins };
|
|
6703
6954
|
jsPlugins.setContext(context);
|
|
6704
6955
|
buildMicroGlobal(jsPlugins); // sets globalThis.micro
|
|
6705
6956
|
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6957
|
+
addCheckpoint("Parallel Initialization Start");
|
|
6958
|
+
|
|
6959
|
+
const luaPromise = (async () => {
|
|
6960
|
+
// return 0;
|
|
6961
|
+
const start = Bun.nanoseconds();
|
|
6962
|
+
const pluginErr = await plugins.loadAll();
|
|
6963
|
+
if (pluginErr) console.error(`Plugin runtime disabled: ${pluginErr.message}`);
|
|
6964
|
+
if (!pluginErr) {
|
|
6965
|
+
await plugins.run("preinit");
|
|
6966
|
+
await plugins.run("init");
|
|
6967
|
+
await plugins.run("postinit");
|
|
6968
|
+
}
|
|
6969
|
+
const end = Bun.nanoseconds();
|
|
6970
|
+
return { pluginErr, duration: end - start };
|
|
6971
|
+
})();
|
|
6972
|
+
|
|
6973
|
+
const jsPromise = (async () => {
|
|
6974
|
+
const start = Bun.nanoseconds();
|
|
6975
|
+
const jsDirs = [
|
|
6976
|
+
{ dir: join(REPO_ROOT, "runtime", "jsplugins"), builtin: true },
|
|
6977
|
+
{ dir: join(config.configDir, "jsplug"), builtin: false },
|
|
6978
|
+
];
|
|
6979
|
+
await jsPlugins.loadFrom(jsDirs);
|
|
6980
|
+
const end = Bun.nanoseconds();
|
|
6981
|
+
return { duration: end - start };
|
|
6982
|
+
})();
|
|
6983
|
+
|
|
6984
|
+
const buffersPromise = (async () => {
|
|
6985
|
+
const start = Bun.nanoseconds();
|
|
6986
|
+
let cursorStates = {};
|
|
6987
|
+
if (DEFAULT_SETTINGS.savecursor) {
|
|
6988
|
+
cursorStates = await loadCursorStates(config.configDir);
|
|
6989
|
+
}
|
|
6990
|
+
// Mix in context properties needed for buffer loading:
|
|
6991
|
+
context.cursorStates = cursorStates;
|
|
6992
|
+
context._openBuffers = new Map();
|
|
6993
|
+
context._termPrompt = process.stdout.isTTY ? termPromptLine : null;
|
|
6994
|
+
|
|
6995
|
+
loadBuffers.context = context;
|
|
6996
|
+
const buffers = await loadBuffers(files.map((file) =>
|
|
6997
|
+
isHttpUrl(file) ? file : resolve(file)
|
|
6998
|
+
), command);
|
|
6712
6999
|
|
|
6713
|
-
|
|
6714
|
-
|
|
7000
|
+
let historyPromise = Promise.resolve();
|
|
7001
|
+
if (config.getGlobalOption("savehistory") !== false) {
|
|
7002
|
+
historyPromise = loadHistory(config.configDir);
|
|
7003
|
+
}
|
|
7004
|
+
await historyPromise;
|
|
7005
|
+
const end = Bun.nanoseconds();
|
|
7006
|
+
return { buffers, duration: end - start };
|
|
7007
|
+
})();
|
|
7008
|
+
|
|
7009
|
+
const [luaSettled, jsSettled, buffersSettled] = await Promise.allSettled([
|
|
7010
|
+
luaPromise,
|
|
7011
|
+
jsPromise,
|
|
7012
|
+
buffersPromise
|
|
7013
|
+
]);
|
|
7014
|
+
|
|
7015
|
+
const luaResult = luaSettled.status === "fulfilled"
|
|
7016
|
+
? luaSettled.value
|
|
7017
|
+
: { pluginErr: luaSettled.reason, duration: 0 };
|
|
7018
|
+
if (luaSettled.status === "rejected") {
|
|
7019
|
+
console.error(`Lua plugin runtime disabled: ${luaSettled.reason?.message || luaSettled.reason}`);
|
|
7020
|
+
}
|
|
7021
|
+
|
|
7022
|
+
const jsResult = jsSettled.status === "fulfilled"
|
|
7023
|
+
? jsSettled.value
|
|
7024
|
+
: { duration: 0 };
|
|
7025
|
+
if (jsSettled.status === "rejected") {
|
|
7026
|
+
console.error(`JS plugin runtime disabled: ${jsSettled.reason?.message || jsSettled.reason}`);
|
|
7027
|
+
}
|
|
7028
|
+
|
|
7029
|
+
const buffersResult = buffersSettled.status === "fulfilled"
|
|
7030
|
+
? buffersSettled.value
|
|
7031
|
+
: { buffers: [new BufferModel({ command })], duration: 0 };
|
|
7032
|
+
if (buffersSettled.status === "rejected") {
|
|
7033
|
+
console.error(`Buffer load failed: ${buffersSettled.reason?.message || buffersSettled.reason}`);
|
|
6715
7034
|
}
|
|
6716
|
-
// Backup prompt available before App starts (stdin still in cooked mode).
|
|
6717
|
-
context._termPrompt = process.stdout.isTTY ? termPromptLine : null;
|
|
6718
|
-
loadBuffers.context = context;
|
|
6719
|
-
const buffers = await loadBuffers(files.map((file) =>
|
|
6720
|
-
isHttpUrl(file) ? file : resolve(file)
|
|
6721
|
-
), command);
|
|
6722
7035
|
|
|
6723
|
-
|
|
7036
|
+
addCheckpoint("Parallel Initialization End");
|
|
7037
|
+
|
|
7038
|
+
parallelTimings = {
|
|
7039
|
+
lua: luaResult.duration / 1e6,
|
|
7040
|
+
js: jsResult.duration / 1e6,
|
|
7041
|
+
buffers: buffersResult.duration / 1e6
|
|
7042
|
+
};
|
|
7043
|
+
|
|
7044
|
+
const { pluginErr } = luaResult;
|
|
7045
|
+
const { buffers } = buffersResult;
|
|
7046
|
+
|
|
7047
|
+
if (!process.stdout.isTTY && !flags.profile) {
|
|
6724
7048
|
console.log(buffers[0].lines.join("\n"));
|
|
6725
7049
|
return;
|
|
6726
7050
|
}
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
}
|
|
7051
|
+
|
|
7052
|
+
addCheckpoint("App Instantiation");
|
|
6730
7053
|
const app = new App(buffers, context);
|
|
6731
7054
|
jsPlugins.setApp(app);
|
|
6732
7055
|
if (plugins && !pluginErr && app.buffer) plugins.curPaneAdapter = makePaneAdapter(app.buffer, app);
|
|
6733
7056
|
// Dispatch all JS plugin lifecycle hooks after setApp so TermMessage,
|
|
6734
7057
|
// CurPane, cmd/action proxies, and buffer APIs all work correctly.
|
|
7058
|
+
addCheckpoint("JS Lifecycle Hooks");
|
|
6735
7059
|
await jsPlugins.run("preinit");
|
|
6736
7060
|
await jsPlugins.run("init");
|
|
6737
7061
|
await jsPlugins.run("postinit");
|
|
@@ -6744,6 +7068,26 @@ async function main() {
|
|
|
6744
7068
|
if (flags.cdpAddress) cdpArgs.push(`--address=${flags.cdpAddress}`);
|
|
6745
7069
|
await app.handleCommand(`cdp ${cdpArgs.join(" ")}`);
|
|
6746
7070
|
}
|
|
7071
|
+
|
|
7072
|
+
if (flags.profile) {
|
|
7073
|
+
addCheckpoint("Clipboard Probing");
|
|
7074
|
+
const clipSetting = config.getGlobalOption("clipboard") ?? "external";
|
|
7075
|
+
const clipboard = new ClipboardManager();
|
|
7076
|
+
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
7077
|
+
process.stdin.setRawMode?.(true);
|
|
7078
|
+
process.stdin.resume();
|
|
7079
|
+
await clipboard.initFromSetting(clipSetting, process.stdin, process.stdout, 150);
|
|
7080
|
+
process.stdin.setRawMode?.(false);
|
|
7081
|
+
process.stdin.pause();
|
|
7082
|
+
} else {
|
|
7083
|
+
await clipboard.initFromSetting(clipSetting, process.stdin, process.stdout, 150);
|
|
7084
|
+
}
|
|
7085
|
+
|
|
7086
|
+
addCheckpoint("Profile Done");
|
|
7087
|
+
printProfileReport();
|
|
7088
|
+
process.exit(0);
|
|
7089
|
+
}
|
|
7090
|
+
|
|
6747
7091
|
await app.start();
|
|
6748
7092
|
}
|
|
6749
7093
|
|
|
@@ -7168,6 +7512,10 @@ async function catFiles(files, colorscheme, syntaxDefinitions, encoding = DEFAUL
|
|
|
7168
7512
|
}
|
|
7169
7513
|
}
|
|
7170
7514
|
|
|
7515
|
+
|
|
7516
|
+
mainPromise.then(r=>{
|
|
7517
|
+
|
|
7518
|
+
|
|
7171
7519
|
main().catch((error) => {
|
|
7172
7520
|
try {
|
|
7173
7521
|
(_activeTtyStream ?? process.stdin).setRawMode?.(false);
|
|
@@ -7177,3 +7525,6 @@ main().catch((error) => {
|
|
|
7177
7525
|
process.exit(1);
|
|
7178
7526
|
}
|
|
7179
7527
|
});
|
|
7528
|
+
|
|
7529
|
+
|
|
7530
|
+
})
|