bmweb-cli 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/dist/bmweb.js +100 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -315,7 +315,10 @@ cancels. The home starts with or without a cable.
|
|
|
315
315
|
|
|
316
316
|
The TUI runs on the terminal's alternate screen (the buffer vim and htop
|
|
317
317
|
use), so the shell's scrollback is never touched and quitting restores it;
|
|
318
|
-
a screen redraws in place, only the lines that changed.
|
|
318
|
+
a screen redraws in place, only the lines that changed. A viewer longer
|
|
319
|
+
than the terminal (a fault protocol, a report) scrolls: Up/Down a line,
|
|
320
|
+
PgUp/PgDn a page, Home/End to either end, with a line under it saying
|
|
321
|
+
which rows are shown.
|
|
319
322
|
|
|
320
323
|
Every dialog INPA opens is a prompt: a message waits for Enter, an input
|
|
321
324
|
asks for the number (or hex, or text) within the declared range, the
|
|
@@ -350,6 +353,11 @@ tests drive the app's runtime against a fake car and a scripted terminal,
|
|
|
350
353
|
with a module script written for the tests in INPA's language. The
|
|
351
354
|
repository's `tools/check.sh` runs all of it.
|
|
352
355
|
|
|
356
|
+
Set `BMWEB_VERBOSE=1` to see what the app's runtime logs: the wire trace
|
|
357
|
+
the bus dumps after an error, each variant probe's verdict, the cable
|
|
358
|
+
events. It goes to stderr; without it the runtime is silent and a command's
|
|
359
|
+
output is only its own.
|
|
360
|
+
|
|
353
361
|
## License
|
|
354
362
|
|
|
355
363
|
GPL-3.0, as the repository is. See `LICENSE`.
|
package/dist/bmweb.js
CHANGED
|
@@ -111,6 +111,7 @@ function formatCount(n) {
|
|
|
111
111
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
112
112
|
import { join as join3 } from "node:path";
|
|
113
113
|
import { fileURLToPath } from "node:url";
|
|
114
|
+
import { format, inspect } from "node:util";
|
|
114
115
|
import { createContext, runInContext } from "node:vm";
|
|
115
116
|
|
|
116
117
|
// src/runtime-files.json
|
|
@@ -284,14 +285,49 @@ function runtimeGlobals() {
|
|
|
284
285
|
loadRuntime();
|
|
285
286
|
return sandboxRef;
|
|
286
287
|
}
|
|
288
|
+
function runtimeConsole() {
|
|
289
|
+
const on = !!process.env.BMWEB_VERBOSE;
|
|
290
|
+
const say = (...a) => {
|
|
291
|
+
if (on) process.stderr.write(`${format(...a)}
|
|
292
|
+
`);
|
|
293
|
+
};
|
|
294
|
+
const table = (rows) => {
|
|
295
|
+
if (on)
|
|
296
|
+
process.stderr.write(
|
|
297
|
+
`${inspect(rows, { depth: 3, maxArrayLength: 200, breakLength: 160 })}
|
|
298
|
+
`
|
|
299
|
+
);
|
|
300
|
+
};
|
|
301
|
+
const noop = () => {
|
|
302
|
+
};
|
|
303
|
+
return {
|
|
304
|
+
log: say,
|
|
305
|
+
info: say,
|
|
306
|
+
warn: say,
|
|
307
|
+
error: say,
|
|
308
|
+
debug: say,
|
|
309
|
+
trace: say,
|
|
310
|
+
table,
|
|
311
|
+
group: say,
|
|
312
|
+
groupCollapsed: say,
|
|
313
|
+
groupEnd: noop,
|
|
314
|
+
time: noop,
|
|
315
|
+
timeEnd: noop,
|
|
316
|
+
assert: noop,
|
|
317
|
+
dir: table
|
|
318
|
+
};
|
|
319
|
+
}
|
|
287
320
|
function hostGlobals() {
|
|
288
321
|
const noop = () => {
|
|
289
322
|
};
|
|
290
323
|
const sandbox = {
|
|
291
|
-
// the scripts
|
|
292
|
-
//
|
|
293
|
-
//
|
|
294
|
-
|
|
324
|
+
// the app's scripts talk to the browser console: the bus dumps its wire
|
|
325
|
+
// trace after an IFH error (console.table in a collapsed group), the
|
|
326
|
+
// variant resolver notes every probe's verdict, the bus reports the
|
|
327
|
+
// cable. In a terminal those are noise between a command's own lines
|
|
328
|
+
// (a scan's table had the trace printed through it), so they go to
|
|
329
|
+
// stderr only when BMWEB_VERBOSE is set, and never to stdout
|
|
330
|
+
console: runtimeConsole(),
|
|
295
331
|
// timers.js's bmwSleep falls back to setTimeout where there is no
|
|
296
332
|
// Worker; program.js schedules screen cycles and drains key presses
|
|
297
333
|
// through setTimeout; activations.js defers a session end a microtask
|
|
@@ -2008,6 +2044,12 @@ var TuiUi = class {
|
|
|
2008
2044
|
frame = [];
|
|
2009
2045
|
/** a picker owns the keyboard: the program's key handler must stand back */
|
|
2010
2046
|
modal = false;
|
|
2047
|
+
/** the first line of the viewer shown (INPA's viewer scrolls; so does this) */
|
|
2048
|
+
viewTop = 0;
|
|
2049
|
+
/** the view the scroll position belongs to; a new view starts at the top */
|
|
2050
|
+
viewShown = null;
|
|
2051
|
+
/** how many viewer lines the last frame had room for */
|
|
2052
|
+
viewRoom = 0;
|
|
2011
2053
|
/** the terminal size the frame was drawn for; a change draws fresh */
|
|
2012
2054
|
frameSize = "";
|
|
2013
2055
|
leftResolve = null;
|
|
@@ -2422,6 +2464,32 @@ Save as [fault-memory.txt]: `);
|
|
|
2422
2464
|
paint(p) {
|
|
2423
2465
|
this.flush(this.frameLines(p));
|
|
2424
2466
|
}
|
|
2467
|
+
/**
|
|
2468
|
+
* Scroll the viewer by a key: a line, a page, or to an end. Nothing
|
|
2469
|
+
* happens without a viewer on screen.
|
|
2470
|
+
* @param how - 'up' | 'down' | 'pageup' | 'pagedown' | 'home' | 'end'
|
|
2471
|
+
* @returns whether the key was for the viewer
|
|
2472
|
+
*/
|
|
2473
|
+
scrollView(how) {
|
|
2474
|
+
const p = this.program;
|
|
2475
|
+
if (!p || !p.view) return false;
|
|
2476
|
+
const page = Math.max(1, this.viewRoom - 1);
|
|
2477
|
+
const n = (p.view.lines || []).length;
|
|
2478
|
+
const max = Math.max(0, n - this.viewRoom);
|
|
2479
|
+
const jump = {
|
|
2480
|
+
up: -1,
|
|
2481
|
+
down: 1,
|
|
2482
|
+
pageup: -page,
|
|
2483
|
+
pagedown: page,
|
|
2484
|
+
home: -n,
|
|
2485
|
+
end: n
|
|
2486
|
+
};
|
|
2487
|
+
const by = jump[how];
|
|
2488
|
+
if (by === void 0) return false;
|
|
2489
|
+
this.viewTop = Math.max(0, Math.min(max, this.viewTop + by));
|
|
2490
|
+
this.paint(p);
|
|
2491
|
+
return true;
|
|
2492
|
+
}
|
|
2425
2493
|
/**
|
|
2426
2494
|
* The frame as lines: title, rule, the view or the grid, a blank, the
|
|
2427
2495
|
* key bar, then the status and progress lines. Cut to the terminal's
|
|
@@ -2434,16 +2502,34 @@ Save as [fault-memory.txt]: `);
|
|
|
2434
2502
|
const w = this.term.columns;
|
|
2435
2503
|
const title = `${p.ecu.label || p.ecu.sgbd} ${p.ecu.sgbd}.prg ${p.title || ""}`.trim();
|
|
2436
2504
|
const head = [title, "-".repeat(Math.min(w, 78))];
|
|
2437
|
-
let body = p.view ? [...p.view.lines || []] : this.gridLines(p);
|
|
2438
2505
|
const tail = ["", ...this.keyLines(p), this.statusText, this.progressText];
|
|
2439
2506
|
const room = Math.max(1, this.term.rows - 1 - head.length - tail.length);
|
|
2440
|
-
|
|
2441
|
-
if (
|
|
2442
|
-
const
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2507
|
+
let body;
|
|
2508
|
+
if (p.view) {
|
|
2509
|
+
const lines = [...p.view.lines || []];
|
|
2510
|
+
if (p.view !== this.viewShown) {
|
|
2511
|
+
this.viewShown = p.view;
|
|
2512
|
+
this.viewTop = 0;
|
|
2513
|
+
}
|
|
2514
|
+
const fits = lines.length <= room;
|
|
2515
|
+
const window = fits ? room : room - 1;
|
|
2516
|
+
this.viewRoom = window;
|
|
2517
|
+
this.viewTop = Math.max(0, Math.min(this.viewTop, lines.length - window));
|
|
2518
|
+
body = lines.slice(this.viewTop, this.viewTop + window);
|
|
2519
|
+
if (!fits)
|
|
2520
|
+
body.push(
|
|
2521
|
+
`\x1B[2mrows ${this.viewTop + 1}-${this.viewTop + body.length} of ${lines.length} \u2191\u2193 PgUp PgDn Home End scroll\x1B[0m`
|
|
2522
|
+
);
|
|
2523
|
+
} else {
|
|
2524
|
+
body = this.gridLines(p);
|
|
2525
|
+
if (body.length > room) body = body.filter((l, i) => l || body[i - 1]);
|
|
2526
|
+
if (body.length > room) {
|
|
2527
|
+
const hidden = body.length - (room - 1);
|
|
2528
|
+
body = [
|
|
2529
|
+
...body.slice(0, room - 1),
|
|
2530
|
+
`(${hidden} more rows: enlarge the terminal)`
|
|
2531
|
+
];
|
|
2532
|
+
}
|
|
2447
2533
|
}
|
|
2448
2534
|
return [...head, ...body, ...tail].map(
|
|
2449
2535
|
(l) => String(l).replace(/[\r\n]/g, " ").slice(0, w)
|
|
@@ -2623,6 +2709,7 @@ async function tuiCommand(chassis, sgbd, opts = {}) {
|
|
|
2623
2709
|
let leaving = false;
|
|
2624
2710
|
const unsubscribe = term.onKey((k) => {
|
|
2625
2711
|
if (ui.modal) return;
|
|
2712
|
+
if (ui.scrollView(k.name)) return;
|
|
2626
2713
|
const what = keyToPress(k);
|
|
2627
2714
|
if (what === null) return;
|
|
2628
2715
|
if (what === "quit") {
|
|
@@ -2662,7 +2749,7 @@ async function tuiCommand(chassis, sgbd, opts = {}) {
|
|
|
2662
2749
|
}
|
|
2663
2750
|
|
|
2664
2751
|
// src/bmweb.ts
|
|
2665
|
-
var VERSION = true ? "0.1.
|
|
2752
|
+
var VERSION = true ? "0.1.6" : "0.0.0-dev";
|
|
2666
2753
|
var INCLUDE = {
|
|
2667
2754
|
include: {
|
|
2668
2755
|
kind: "list",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bmweb-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "BMWeb's tools as a command line: read INPA .IPO scripts, compile .IPS sources, search the corpus job index, decode and diff shared Garage reports, and, over a K+DCAN cable, run jobs, whole-car scans and INPA screens in the terminal.",
|
|
5
5
|
"license": "GPL-3.0-only",
|
|
6
6
|
"type": "module",
|