@h-rig/cli 0.0.6-alpha.85 → 0.0.6-alpha.87
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/dist/bin/rig.js +79 -1027
- package/dist/src/app-opentui/bootstrap.js +79 -1027
- package/dist/src/app-opentui/command-palette.js +1 -0
- package/dist/src/app-opentui/drone.js +1 -0
- package/dist/src/app-opentui/index.js +61 -1024
- package/dist/src/app-opentui/list-search.d.ts +5 -1
- package/dist/src/app-opentui/list-search.js +2 -2
- package/dist/src/app-opentui/react/App.js +62 -970
- package/dist/src/app-opentui/react/Backdrop.js +3 -9
- package/dist/src/app-opentui/react/ChromeHost.js +6 -1038
- package/dist/src/app-opentui/react/SceneFrameView.js +55 -5
- package/dist/src/app-opentui/react/launch.js +62 -970
- package/dist/src/app-opentui/react/syntax.js +1 -0
- package/dist/src/app-opentui/registry.js +3 -5
- package/dist/src/app-opentui/render/constants.d.ts +0 -1
- package/dist/src/app-opentui/render/constants.js +0 -2
- package/dist/src/app-opentui/render/graphics.js +3 -9
- package/dist/src/app-opentui/render/hover.d.ts +11 -0
- package/dist/src/app-opentui/render/hover.js +34 -0
- package/dist/src/app-opentui/render/native-host.js +1 -0
- package/dist/src/app-opentui/render/panels.js +50 -3
- package/dist/src/app-opentui/render/preloader.js +1 -0
- package/dist/src/app-opentui/render/scene.js +1 -0
- package/dist/src/app-opentui/render/text.d.ts +13 -0
- package/dist/src/app-opentui/render/text.js +54 -5
- package/dist/src/app-opentui/render/type-bar.js +1 -0
- package/dist/src/app-opentui/runtime.js +62 -1025
- package/dist/src/app-opentui/scenes/command.js +1 -0
- package/dist/src/app-opentui/scenes/doctor.js +1 -0
- package/dist/src/app-opentui/scenes/error.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/agent.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/browser.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/dist.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/git.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/github.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/harness.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/index.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/kit.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/profile.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/queue.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/remote.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/review.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/setup.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/stats.js +1 -0
- package/dist/src/app-opentui/scenes/family.js +1 -0
- package/dist/src/app-opentui/scenes/fleet.js +3 -5
- package/dist/src/app-opentui/scenes/handoff.js +1 -0
- package/dist/src/app-opentui/scenes/help.js +1 -0
- package/dist/src/app-opentui/scenes/inbox.js +1 -0
- package/dist/src/app-opentui/scenes/init.js +1 -0
- package/dist/src/app-opentui/scenes/inspect.js +1 -0
- package/dist/src/app-opentui/scenes/main.js +1 -0
- package/dist/src/app-opentui/scenes/pi.js +1 -0
- package/dist/src/app-opentui/scenes/plugin.js +1 -0
- package/dist/src/app-opentui/scenes/repo.js +1 -0
- package/dist/src/app-opentui/scenes/run-detail.js +1 -0
- package/dist/src/app-opentui/scenes/server.js +1 -0
- package/dist/src/app-opentui/scenes/tasks.js +3 -5
- package/dist/src/app-opentui/scenes/workspace.js +1 -0
- package/dist/src/app-opentui/selectable.js +1 -0
- package/dist/src/app-opentui/theme.d.ts +1 -0
- package/dist/src/app-opentui/theme.js +1 -0
- package/package.json +8 -8
- package/dist/src/app-opentui/render/image-visual-layer-worker.d.ts +0 -1
- package/dist/src/app-opentui/render/image-visual-layer-worker.js +0 -1084
- package/dist/src/app-opentui/render/image-visual-layer.d.ts +0 -109
- package/dist/src/app-opentui/render/image-visual-layer.js +0 -1068
- package/dist/src/app-opentui/terminal-capabilities.d.ts +0 -7
- package/dist/src/app-opentui/terminal-capabilities.js +0 -15
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/cli/src/app-opentui/react/App.tsx
|
|
3
|
-
import { useMemo, useRef as useRef4 } from "react";
|
|
3
|
+
import { useMemo, useRef as useRef4, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
4
4
|
import { useKeyboard, useRenderer as useRenderer4, useTerminalDimensions as useTerminalDimensions2 } from "@opentui/react";
|
|
5
5
|
|
|
6
6
|
// packages/cli/src/app-opentui/layout.ts
|
|
@@ -59,6 +59,7 @@ var RIG_UI = {
|
|
|
59
59
|
bg2: "#0b0c0e",
|
|
60
60
|
panel: "#101115",
|
|
61
61
|
panel2: "#14161b",
|
|
62
|
+
hover: "#181b24",
|
|
62
63
|
glass: "#1e2230",
|
|
63
64
|
border: "#2a2e3a",
|
|
64
65
|
ink: "#f4f5f8",
|
|
@@ -2540,19 +2541,6 @@ function panelContentRect(layout, panel) {
|
|
|
2540
2541
|
const contentWidth = Math.max(1, width - paddingX * 2 - 1);
|
|
2541
2542
|
return { left, top, width, height, paddingX, paddingY, contentWidth };
|
|
2542
2543
|
}
|
|
2543
|
-
function panelPixelPlacement(layout, panel, size, minPixels = 8) {
|
|
2544
|
-
const cellW = size.width / layout.width;
|
|
2545
|
-
const cellH = size.height / layout.height;
|
|
2546
|
-
const leftCells = layout.centerLeft + (panel.left ?? 0);
|
|
2547
|
-
const topCells = layout.centerTop + panel.top;
|
|
2548
|
-
const widthCells = panel.width ?? layout.centerWidth;
|
|
2549
|
-
const heightCells = panel.height;
|
|
2550
|
-
const left = Math.round(leftCells * cellW);
|
|
2551
|
-
const top = Math.round(topCells * cellH);
|
|
2552
|
-
const width = Math.round(widthCells * cellW);
|
|
2553
|
-
const height = Math.round(heightCells * cellH);
|
|
2554
|
-
return width > minPixels && height > minPixels ? { left, top, width, height, leftCells, topCells, widthCells, heightCells } : null;
|
|
2555
|
-
}
|
|
2556
2544
|
|
|
2557
2545
|
// packages/cli/src/app-opentui/render/constants.ts
|
|
2558
2546
|
var LCG_MULTIPLIER = 1664525;
|
|
@@ -2585,7 +2573,6 @@ var RAIL_YS_LOOP = [0.18, 0.5, 0.82];
|
|
|
2585
2573
|
var RAIL_YS_CARRIER = [0.24, 0.54, 0.82];
|
|
2586
2574
|
var RAIL_YS_DISPATCH = [0.18, 0.58, 0.82];
|
|
2587
2575
|
var GLOW_FALLOFF_EXP_ASCII = 2.2;
|
|
2588
|
-
var GLOW_FALLOFF_EXP_IMAGE = 2.4;
|
|
2589
2576
|
|
|
2590
2577
|
// packages/cli/src/app-opentui/render/graphics.ts
|
|
2591
2578
|
var BRAILLE_SAMPLES_X = 2;
|
|
@@ -3017,27 +3004,20 @@ function writeCell(layer, x, y, char, fg, bg) {
|
|
|
3017
3004
|
function drawFullCell(layer, x, y, bg) {
|
|
3018
3005
|
writeCell(layer, x, y, " ", TRANSPARENT, bg);
|
|
3019
3006
|
}
|
|
3020
|
-
function
|
|
3021
|
-
writeCell(layer, x, y, char, fg, BACKDROP);
|
|
3022
|
-
}
|
|
3023
|
-
function drawRoundedFill(layer, left, top, right, bottom, dividerY) {
|
|
3007
|
+
function drawPanelFill(layer, left, top, right, bottom, dividerY) {
|
|
3024
3008
|
const bgForY = (y) => y < dividerY ? PANEL_HEADER_BG : PANEL_BG;
|
|
3025
3009
|
for (let y = top;y <= bottom; y += 1) {
|
|
3026
3010
|
const bg = bgForY(y);
|
|
3027
3011
|
for (let x = left;x <= right; x += 1)
|
|
3028
3012
|
drawFullCell(layer, x, y, bg);
|
|
3029
3013
|
}
|
|
3030
|
-
drawCornerCut(layer, left, top, "\u2597", PANEL_HEADER_BG);
|
|
3031
|
-
drawCornerCut(layer, right, top, "\u2596", PANEL_HEADER_BG);
|
|
3032
|
-
drawCornerCut(layer, left, bottom, "\u259D", PANEL_BG);
|
|
3033
|
-
drawCornerCut(layer, right, bottom, "\u2598", PANEL_BG);
|
|
3034
3014
|
}
|
|
3035
3015
|
function drawAdTerminalPanel(layer, layout, panel) {
|
|
3036
3016
|
const rect = panelCellRect(layout, panel);
|
|
3037
3017
|
if (!rect)
|
|
3038
3018
|
return;
|
|
3039
3019
|
const { left, top, width, right, bottom, headerHeight, dividerY } = rect;
|
|
3040
|
-
|
|
3020
|
+
drawPanelFill(layer, left, top, right, bottom, dividerY);
|
|
3041
3021
|
if (dividerY > top && dividerY < bottom) {
|
|
3042
3022
|
for (let x = left + 2;x < right - 1; x += 1) {
|
|
3043
3023
|
writeCell(layer, x, dividerY, "\u2500", PANEL_LINE_DIM, PANEL_BG);
|
|
@@ -3123,963 +3103,71 @@ function drawAmbientField(layer, layout, _tick, scene = "fleet", load = 0, activ
|
|
|
3123
3103
|
layer.__rigAmbientKey = key;
|
|
3124
3104
|
}
|
|
3125
3105
|
|
|
3126
|
-
// packages/cli/src/app-opentui/render/
|
|
3127
|
-
import {
|
|
3128
|
-
import { deflateSync } from "zlib";
|
|
3129
|
-
import { allocateImageId, deleteKittyImage } from "@earendil-works/pi-tui";
|
|
3130
|
-
|
|
3131
|
-
// packages/cli/src/app-opentui/terminal-capabilities.ts
|
|
3132
|
-
import { getCapabilities } from "@earendil-works/pi-tui";
|
|
3133
|
-
function getRigTerminalCapabilities() {
|
|
3134
|
-
const imageProtocol = getCapabilities().images;
|
|
3135
|
-
const supportsKittyImages = imageProtocol === "kitty";
|
|
3136
|
-
return {
|
|
3137
|
-
imageProtocol,
|
|
3138
|
-
supportsKittyImages,
|
|
3139
|
-
visualMode: supportsKittyImages ? "kitty-images" : "framebuffer-fallback"
|
|
3140
|
-
};
|
|
3141
|
-
}
|
|
3106
|
+
// packages/cli/src/app-opentui/render/text.ts
|
|
3107
|
+
import { RGBA as RGBA4, TextAttributes as TextAttributes4, TextRenderable } from "@opentui/core";
|
|
3142
3108
|
|
|
3143
|
-
// packages/cli/src/app-opentui/render/
|
|
3144
|
-
var
|
|
3145
|
-
var
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
var PANEL_BLUR_RADIUS_MAX = 28;
|
|
3149
|
-
var PANEL_BLUR_RADIUS_FACTOR = 0.018;
|
|
3150
|
-
var BG = [7, 8, 9, 255];
|
|
3151
|
-
var PANEL = [16, 17, 21, 184];
|
|
3152
|
-
var PANEL_HEADER = [16, 17, 21, 190];
|
|
3153
|
-
var PANEL_LINE2 = [255, 255, 255, 24];
|
|
3154
|
-
var LIME = [204, 255, 77, 255];
|
|
3155
|
-
var LIME_DIM = [169, 214, 63, 255];
|
|
3156
|
-
var CYAN = [86, 216, 255, 255];
|
|
3157
|
-
var MAGENTA = [255, 121, 176, 255];
|
|
3158
|
-
var INK_DIM = [108, 110, 121, 255];
|
|
3159
|
-
var PNG_SIGNATURE = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
3160
|
-
var CRC_TABLE = makeCrcTable();
|
|
3161
|
-
var MAX_IMAGE_BYTES = 48 * 1024 * 1024;
|
|
3162
|
-
var KITTY_CHUNK_SIZE = 4096;
|
|
3163
|
-
var PANEL_BLUR_SCALE = 1;
|
|
3164
|
-
var PANEL_MASK_CACHE_LIMIT = 16;
|
|
3165
|
-
var ZLIB_LEVEL = 1;
|
|
3166
|
-
var LOAD_BUCKETS = 5;
|
|
3167
|
-
function loadBucket(load) {
|
|
3168
|
-
if (!Number.isFinite(load ?? NaN))
|
|
3169
|
-
return 0;
|
|
3170
|
-
return Math.max(0, Math.min(LOAD_BUCKETS, Math.round((load ?? 0) * LOAD_BUCKETS)));
|
|
3171
|
-
}
|
|
3172
|
-
var panelMaskCache = new Map;
|
|
3173
|
-
var BG_WORD = rgbaWord(BG);
|
|
3174
|
-
function imageTransport() {
|
|
3175
|
-
const forced = process.env.RIG_OPENTUI_IMAGE_TRANSPORT;
|
|
3176
|
-
if (forced === "rgba-zlib")
|
|
3177
|
-
return "rgba-zlib";
|
|
3178
|
-
return "png";
|
|
3179
|
-
}
|
|
3180
|
-
function rgbaWord(color) {
|
|
3181
|
-
return (color[3] << 24 | color[2] << 16 | color[1] << 8 | color[0]) >>> 0;
|
|
3182
|
-
}
|
|
3183
|
-
function fillRgba(data, color, word = rgbaWord(color)) {
|
|
3184
|
-
if (data.byteOffset % 4 === 0 && data.byteLength % 4 === 0) {
|
|
3185
|
-
new Uint32Array(data.buffer, data.byteOffset, data.byteLength / 4).fill(word);
|
|
3186
|
-
return;
|
|
3187
|
-
}
|
|
3188
|
-
for (let i = 0;i < data.length; i += 4) {
|
|
3189
|
-
data[i] = color[0];
|
|
3190
|
-
data[i + 1] = color[1];
|
|
3191
|
-
data[i + 2] = color[2];
|
|
3192
|
-
data[i + 3] = color[3];
|
|
3193
|
-
}
|
|
3194
|
-
}
|
|
3195
|
-
var ASCII_GLYPHS = {
|
|
3196
|
-
".": ["00000", "00000", "00000", "00000", "00000", "00100", "00100"],
|
|
3197
|
-
"'": ["00100", "00100", "00000", "00000", "00000", "00000", "00000"],
|
|
3198
|
-
"-": ["00000", "00000", "00000", "11111", "00000", "00000", "00000"],
|
|
3199
|
-
_: ["00000", "00000", "00000", "00000", "00000", "00000", "11111"],
|
|
3200
|
-
"=": ["00000", "11111", "00000", "00000", "11111", "00000", "00000"],
|
|
3201
|
-
"|": ["00100", "00100", "00100", "00100", "00100", "00100", "00100"],
|
|
3202
|
-
"/": ["00001", "00010", "00010", "00100", "01000", "01000", "10000"],
|
|
3203
|
-
"\\": ["10000", "01000", "01000", "00100", "00010", "00010", "00001"],
|
|
3204
|
-
"(": ["00010", "00100", "01000", "01000", "01000", "00100", "00010"],
|
|
3205
|
-
")": ["01000", "00100", "00010", "00010", "00010", "00100", "01000"],
|
|
3206
|
-
"!": ["00100", "00100", "00100", "00100", "00100", "00000", "00100"],
|
|
3207
|
-
"%": ["11001", "11010", "00100", "01000", "10110", "00110", "00000"],
|
|
3208
|
-
$: ["00100", "11110", "10100", "11110", "00101", "11110", "00100"],
|
|
3209
|
-
"@": ["01110", "10001", "10111", "10101", "10111", "10000", "01111"],
|
|
3210
|
-
o: ["00000", "01110", "10001", "10001", "10001", "01110", "00000"],
|
|
3211
|
-
"*": ["00100", "10101", "01110", "11111", "01110", "10101", "00100"]
|
|
3212
|
-
};
|
|
3213
|
-
function sceneStaticTick(scene) {
|
|
3214
|
-
let hash = 0;
|
|
3215
|
-
for (let index = 0;index < scene.length; index += 1)
|
|
3216
|
-
hash = hash * 33 + scene.charCodeAt(index) >>> 0;
|
|
3217
|
-
return 11 + hash % 97;
|
|
3218
|
-
}
|
|
3219
|
-
function charColor(char, row, totalRows) {
|
|
3220
|
-
if (char === "@" || char === "$" || char === "o")
|
|
3221
|
-
return LIME;
|
|
3222
|
-
if (char === "%" || char === "!" || char === "/" || char === "\\" || char === "|")
|
|
3223
|
-
return CYAN;
|
|
3224
|
-
if (char === "." || char === "'" || char === "_" || row < 3 || row > totalRows - 4)
|
|
3225
|
-
return INK_DIM;
|
|
3226
|
-
if (char === "-" || char === "=" || char === "(" || char === ")")
|
|
3227
|
-
return LIME_DIM;
|
|
3228
|
-
return MAGENTA;
|
|
3229
|
-
}
|
|
3230
|
-
function fillRectAlpha(data, width, height, left, top, rectWidth, rectHeight, color, alpha) {
|
|
3231
|
-
const x0 = Math.max(0, Math.floor(left));
|
|
3232
|
-
const y0 = Math.max(0, Math.floor(top));
|
|
3233
|
-
const x1 = Math.min(width, Math.ceil(left + rectWidth));
|
|
3234
|
-
const y1 = Math.min(height, Math.ceil(top + rectHeight));
|
|
3235
|
-
for (let y = y0;y < y1; y += 1) {
|
|
3236
|
-
for (let x = x0;x < x1; x += 1)
|
|
3237
|
-
blendOver(data, (y * width + x) * 4, color, alpha);
|
|
3238
|
-
}
|
|
3239
|
-
}
|
|
3240
|
-
function drawAsciiGlyph(data, width, height, x, y, cellWidth, cellHeight, char, color, alpha) {
|
|
3241
|
-
const pattern = ASCII_GLYPHS[char] ?? ASCII_GLYPHS["*"];
|
|
3242
|
-
const glyphWidth = Math.max(1, cellWidth * 0.56);
|
|
3243
|
-
const glyphHeight = Math.max(1, cellHeight * 0.7);
|
|
3244
|
-
const originX = x + (cellWidth - glyphWidth) * 0.5;
|
|
3245
|
-
const originY = y + (cellHeight - glyphHeight) * 0.5;
|
|
3246
|
-
const pixelWidth = Math.max(1, glyphWidth / pattern[0].length);
|
|
3247
|
-
const pixelHeight = Math.max(1, glyphHeight / pattern.length);
|
|
3248
|
-
for (let row = 0;row < pattern.length; row += 1) {
|
|
3249
|
-
const bits = pattern[row];
|
|
3250
|
-
for (let col = 0;col < bits.length; col += 1) {
|
|
3251
|
-
if (bits[col] !== "1")
|
|
3252
|
-
continue;
|
|
3253
|
-
fillRectAlpha(data, width, height, originX + col * pixelWidth, originY + row * pixelHeight, pixelWidth * 0.72, pixelHeight * 0.72, color, alpha);
|
|
3254
|
-
}
|
|
3255
|
-
}
|
|
3256
|
-
}
|
|
3257
|
-
function drawStaticAsciiFleetBackground(data, width, height, scene, layout, load, activeRuns) {
|
|
3258
|
-
const rows = fleetRows(sceneStaticTick(scene), { animate: true });
|
|
3259
|
-
const cellWidth = width / Math.max(1, layout.width);
|
|
3260
|
-
const cellHeight = height / Math.max(1, layout.height);
|
|
3261
|
-
const sideBySide = layout.width >= FLEET_GRID_WIDTH * 1.9;
|
|
3262
|
-
const leftCells = sideBySide ? Math.max(1, Math.floor(layout.width * 0.3 - FLEET_GRID_WIDTH / 2)) : Math.floor((layout.width - FLEET_GRID_WIDTH) / 2);
|
|
3263
|
-
const topCells = Math.floor((layout.height - FLEET_GRID_HEIGHT) / 2);
|
|
3264
|
-
const fleetLeft = leftCells * cellWidth;
|
|
3265
|
-
const fleetTop = topCells * cellHeight;
|
|
3266
|
-
drawGlow2(data, width, height, width * 0.5, height * 0.5, Math.min(width, height) * 0.4, LIME, 0.022 + load * 0.03);
|
|
3267
|
-
drawGlow2(data, width, height, width * 0.18, height * 0.22, Math.min(width, height) * 0.28, CYAN, 0.018 + load * 0.012);
|
|
3268
|
-
drawGlow2(data, width, height, width * 0.82, height * 0.78, Math.min(width, height) * 0.22, MAGENTA, 0.012 + load * 0.008);
|
|
3269
|
-
let droneTotal = 0;
|
|
3270
|
-
for (const line2 of rows)
|
|
3271
|
-
for (const char of line2)
|
|
3272
|
-
if (char === "@" || char === "$" || char === "%")
|
|
3273
|
-
droneTotal += 1;
|
|
3274
|
-
const litTarget = Math.max(0, Math.min(droneTotal, activeRuns));
|
|
3275
|
-
let droneIndex = 0;
|
|
3276
|
-
for (let row = 0;row < rows.length; row += 1) {
|
|
3277
|
-
const line2 = rows[row];
|
|
3278
|
-
for (let col = 0;col < line2.length; col += 1) {
|
|
3279
|
-
const char = line2[col];
|
|
3280
|
-
if (char === " ")
|
|
3281
|
-
continue;
|
|
3282
|
-
const x = fleetLeft + col * cellWidth;
|
|
3283
|
-
const y = fleetTop + row * cellHeight;
|
|
3284
|
-
const color = charColor(char, row, rows.length);
|
|
3285
|
-
const isDrone = char === "@" || char === "$" || char === "%";
|
|
3286
|
-
const lit = isDrone && droneIndex < litTarget;
|
|
3287
|
-
drawAsciiGlyph(data, width, height, x + cellWidth * 0.07, y + cellHeight * 0.05, cellWidth, cellHeight, char, color, lit ? 0.72 : 0.46);
|
|
3288
|
-
if (isDrone) {
|
|
3289
|
-
droneIndex += 1;
|
|
3290
|
-
drawGlow2(data, width, height, x + cellWidth * 0.5, y + cellHeight * 0.5, Math.max(cellWidth, cellHeight) * 0.95, color, lit ? 0.044 : 0.014);
|
|
3291
|
-
}
|
|
3292
|
-
}
|
|
3293
|
-
}
|
|
3294
|
-
}
|
|
3295
|
-
function applyStaticAtmosphere(data, width, height, load) {
|
|
3296
|
-
const cx = width * 0.5;
|
|
3297
|
-
const cy = height * 0.42;
|
|
3298
|
-
const radius = Math.max(width, height) * 0.78;
|
|
3299
|
-
const minVignette = 0.1 - load * 0.02;
|
|
3300
|
-
for (let y = 0;y < height; y += 1) {
|
|
3301
|
-
for (let x = 0;x < width; x += 1) {
|
|
3302
|
-
const distance = Math.hypot(x - cx, y - cy) / radius;
|
|
3303
|
-
const alpha = Math.max(minVignette, Math.min(0.82, 0.12 + Math.pow(distance, 1.65) * 0.62));
|
|
3304
|
-
blendOver(data, (y * width + x) * 4, BG, alpha);
|
|
3305
|
-
}
|
|
3306
|
-
}
|
|
3307
|
-
drawGlow2(data, width, height, width * 0.82, height * 0.04, Math.min(width, height) * 0.2, LIME, 0.024 + load * 0.012);
|
|
3308
|
-
drawGlow2(data, width, height, width * 0.12, height * 0.18, Math.min(width, height) * 0.16, CYAN, 0.018 + load * 0.008);
|
|
3309
|
-
}
|
|
3310
|
-
function makeCrcTable() {
|
|
3311
|
-
const table = new Uint32Array(256);
|
|
3312
|
-
for (let n = 0;n < 256; n += 1) {
|
|
3313
|
-
let c = n;
|
|
3314
|
-
for (let k = 0;k < 8; k += 1)
|
|
3315
|
-
c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
|
|
3316
|
-
table[n] = c >>> 0;
|
|
3317
|
-
}
|
|
3318
|
-
return table;
|
|
3319
|
-
}
|
|
3320
|
-
function crc32(bytes) {
|
|
3321
|
-
let c = 4294967295;
|
|
3322
|
-
for (let i = 0;i < bytes.length; i += 1)
|
|
3323
|
-
c = CRC_TABLE[(c ^ bytes[i]) & 255] ^ c >>> 8;
|
|
3324
|
-
return (c ^ 4294967295) >>> 0;
|
|
3325
|
-
}
|
|
3326
|
-
function chunk2(type, data) {
|
|
3327
|
-
const out = new Uint8Array(12 + data.length);
|
|
3328
|
-
const view = new DataView(out.buffer);
|
|
3329
|
-
view.setUint32(0, data.length);
|
|
3330
|
-
out[4] = type.charCodeAt(0);
|
|
3331
|
-
out[5] = type.charCodeAt(1);
|
|
3332
|
-
out[6] = type.charCodeAt(2);
|
|
3333
|
-
out[7] = type.charCodeAt(3);
|
|
3334
|
-
out.set(data, 8);
|
|
3335
|
-
view.setUint32(8 + data.length, crc32(out.subarray(4, 8 + data.length)));
|
|
3336
|
-
return out;
|
|
3109
|
+
// packages/cli/src/app-opentui/render/hover.ts
|
|
3110
|
+
var hoveredId;
|
|
3111
|
+
var listeners = new Set;
|
|
3112
|
+
function getHoveredSelectableId() {
|
|
3113
|
+
return hoveredId;
|
|
3337
3114
|
}
|
|
3338
|
-
function
|
|
3339
|
-
|
|
3340
|
-
const ihdrView = new DataView(ihdr.buffer);
|
|
3341
|
-
ihdrView.setUint32(0, width);
|
|
3342
|
-
ihdrView.setUint32(4, height);
|
|
3343
|
-
ihdr[8] = 8;
|
|
3344
|
-
ihdr[9] = 6;
|
|
3345
|
-
ihdr[10] = 0;
|
|
3346
|
-
ihdr[11] = 0;
|
|
3347
|
-
ihdr[12] = 0;
|
|
3348
|
-
const stride = width * 4;
|
|
3349
|
-
const raw = new Uint8Array((stride + 1) * height);
|
|
3350
|
-
for (let y = 0;y < height; y += 1) {
|
|
3351
|
-
const rawOffset = y * (stride + 1);
|
|
3352
|
-
raw[rawOffset] = 0;
|
|
3353
|
-
raw.set(rgba.subarray(y * stride, y * stride + stride), rawOffset + 1);
|
|
3354
|
-
}
|
|
3355
|
-
const compressed = deflateSync(raw, { level: ZLIB_LEVEL });
|
|
3356
|
-
return Buffer.concat([
|
|
3357
|
-
Buffer.from(PNG_SIGNATURE),
|
|
3358
|
-
Buffer.from(chunk2("IHDR", ihdr)),
|
|
3359
|
-
Buffer.from(chunk2("IDAT", compressed)),
|
|
3360
|
-
Buffer.from(chunk2("IEND", new Uint8Array(0)))
|
|
3361
|
-
]);
|
|
3362
|
-
}
|
|
3363
|
-
function kittyImageSequence(base64, options) {
|
|
3364
|
-
const params = [`a=T`, `f=${options.format}`, `q=2`, `C=1`, `c=${options.columns}`, `r=${options.rows}`, `i=${options.imageId}`, `z=${options.zIndex}`];
|
|
3365
|
-
if (options.format === 32) {
|
|
3366
|
-
params.push(`s=${options.pixelWidth ?? 1}`, `v=${options.pixelHeight ?? 1}`);
|
|
3367
|
-
if (options.compressed)
|
|
3368
|
-
params.push("o=z");
|
|
3369
|
-
}
|
|
3370
|
-
if (base64.length <= KITTY_CHUNK_SIZE)
|
|
3371
|
-
return `\x1B_G${params.join(",")};${base64}\x1B\\`;
|
|
3372
|
-
const chunks = [];
|
|
3373
|
-
for (let offset = 0;offset < base64.length; offset += KITTY_CHUNK_SIZE) {
|
|
3374
|
-
const part = base64.slice(offset, offset + KITTY_CHUNK_SIZE);
|
|
3375
|
-
const last = offset + KITTY_CHUNK_SIZE >= base64.length;
|
|
3376
|
-
chunks.push(`\x1B_G${offset === 0 ? `${params.join(",")},` : ""}m=${last ? 0 : 1};${part}\x1B\\`);
|
|
3377
|
-
}
|
|
3378
|
-
return chunks.join("");
|
|
3379
|
-
}
|
|
3380
|
-
function clampByte(value) {
|
|
3381
|
-
return Math.max(0, Math.min(255, Math.round(value)));
|
|
3382
|
-
}
|
|
3383
|
-
function blendOver(data, index, color, alphaScale = 1) {
|
|
3384
|
-
const alpha = color[3] / 255 * alphaScale;
|
|
3385
|
-
const inv = 1 - alpha;
|
|
3386
|
-
data[index] = clampByte(color[0] * alpha + data[index] * inv);
|
|
3387
|
-
data[index + 1] = clampByte(color[1] * alpha + data[index + 1] * inv);
|
|
3388
|
-
data[index + 2] = clampByte(color[2] * alpha + data[index + 2] * inv);
|
|
3389
|
-
data[index + 3] = 255;
|
|
3390
|
-
}
|
|
3391
|
-
function drawDisc(data, width, height, cx, cy, radius, color, alpha = 1) {
|
|
3392
|
-
const minX = Math.max(0, Math.floor(cx - radius));
|
|
3393
|
-
const maxX = Math.min(width - 1, Math.ceil(cx + radius));
|
|
3394
|
-
const minY = Math.max(0, Math.floor(cy - radius));
|
|
3395
|
-
const maxY = Math.min(height - 1, Math.ceil(cy + radius));
|
|
3396
|
-
for (let y = minY;y <= maxY; y += 1) {
|
|
3397
|
-
for (let x = minX;x <= maxX; x += 1) {
|
|
3398
|
-
const dx = x + 0.5 - cx;
|
|
3399
|
-
const dy = y + 0.5 - cy;
|
|
3400
|
-
const d = Math.sqrt(dx * dx + dy * dy);
|
|
3401
|
-
if (d > radius)
|
|
3402
|
-
continue;
|
|
3403
|
-
const edge = Math.max(0, Math.min(1, radius - d));
|
|
3404
|
-
blendOver(data, (y * width + x) * 4, color, alpha * Math.min(1, 0.35 + edge));
|
|
3405
|
-
}
|
|
3406
|
-
}
|
|
3407
|
-
}
|
|
3408
|
-
function drawGlow2(data, width, height, cx, cy, radius, color, alpha = 0.18) {
|
|
3409
|
-
const minX = Math.max(0, Math.floor(cx - radius));
|
|
3410
|
-
const maxX = Math.min(width - 1, Math.ceil(cx + radius));
|
|
3411
|
-
const minY = Math.max(0, Math.floor(cy - radius));
|
|
3412
|
-
const maxY = Math.min(height - 1, Math.ceil(cy + radius));
|
|
3413
|
-
for (let y = minY;y <= maxY; y += 1) {
|
|
3414
|
-
for (let x = minX;x <= maxX; x += 1) {
|
|
3415
|
-
const dx = x + 0.5 - cx;
|
|
3416
|
-
const dy = y + 0.5 - cy;
|
|
3417
|
-
const d = Math.sqrt(dx * dx + dy * dy);
|
|
3418
|
-
if (d > radius)
|
|
3419
|
-
continue;
|
|
3420
|
-
const falloff = Math.pow(1 - d / Math.max(1, radius), GLOW_FALLOFF_EXP_IMAGE);
|
|
3421
|
-
blendOver(data, (y * width + x) * 4, color, alpha * falloff);
|
|
3422
|
-
}
|
|
3423
|
-
}
|
|
3115
|
+
function isHovered(id) {
|
|
3116
|
+
return id !== undefined && id === hoveredId;
|
|
3424
3117
|
}
|
|
3425
|
-
function
|
|
3426
|
-
|
|
3427
|
-
const dy = y1 - y0;
|
|
3428
|
-
const steps = Math.max(1, Math.ceil(Math.hypot(dx, dy) * 1.2));
|
|
3429
|
-
for (let i = 0;i <= steps; i += 1) {
|
|
3430
|
-
const t2 = i / steps;
|
|
3431
|
-
drawDisc(data, width, height, x0 + dx * t2, y0 + dy * t2, thickness, color, alpha);
|
|
3432
|
-
}
|
|
3433
|
-
}
|
|
3434
|
-
function roundRectAlpha(px, py, x, y, w, h, r) {
|
|
3435
|
-
const rx = Math.max(x + r, Math.min(px, x + w - r));
|
|
3436
|
-
const ry = Math.max(y + r, Math.min(py, y + h - r));
|
|
3437
|
-
const dx = px - rx;
|
|
3438
|
-
const dy = py - ry;
|
|
3439
|
-
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
3440
|
-
return Math.max(0, Math.min(1, r + 0.75 - dist));
|
|
3441
|
-
}
|
|
3442
|
-
function panelRect(layout, panel, size) {
|
|
3443
|
-
return panelPixelPlacement(layout, panel, size);
|
|
3444
|
-
}
|
|
3445
|
-
function downsampleRegion(data, canvasW, canvasH, rect, scale) {
|
|
3446
|
-
const w = Math.max(1, Math.ceil(rect.width / scale));
|
|
3447
|
-
const h = Math.max(1, Math.ceil(rect.height / scale));
|
|
3448
|
-
const out = new Uint8ClampedArray(w * h * 3);
|
|
3449
|
-
for (let y = 0;y < h; y += 1) {
|
|
3450
|
-
for (let x = 0;x < w; x += 1) {
|
|
3451
|
-
let r = 0, g = 0, b = 0, count = 0;
|
|
3452
|
-
const sx0 = rect.left + x * scale;
|
|
3453
|
-
const sy0 = rect.top + y * scale;
|
|
3454
|
-
for (let yy = 0;yy < scale; yy += 1) {
|
|
3455
|
-
const sy = sy0 + yy;
|
|
3456
|
-
if (sy < 0 || sy >= canvasH)
|
|
3457
|
-
continue;
|
|
3458
|
-
for (let xx = 0;xx < scale; xx += 1) {
|
|
3459
|
-
const sx = sx0 + xx;
|
|
3460
|
-
if (sx < 0 || sx >= canvasW)
|
|
3461
|
-
continue;
|
|
3462
|
-
const i = (sy * canvasW + sx) * 4;
|
|
3463
|
-
r += data[i];
|
|
3464
|
-
g += data[i + 1];
|
|
3465
|
-
b += data[i + 2];
|
|
3466
|
-
count += 1;
|
|
3467
|
-
}
|
|
3468
|
-
}
|
|
3469
|
-
const oi = (y * w + x) * 3;
|
|
3470
|
-
out[oi] = count ? r / count : BG[0];
|
|
3471
|
-
out[oi + 1] = count ? g / count : BG[1];
|
|
3472
|
-
out[oi + 2] = count ? b / count : BG[2];
|
|
3473
|
-
}
|
|
3474
|
-
}
|
|
3475
|
-
return { pixels: out, width: w, height: h };
|
|
3476
|
-
}
|
|
3477
|
-
function blurRgb(buffer, width, height, radius) {
|
|
3478
|
-
const tmp = new Uint8ClampedArray(buffer.length);
|
|
3479
|
-
const out = new Uint8ClampedArray(buffer.length);
|
|
3480
|
-
const window = radius * 2 + 1;
|
|
3481
|
-
for (let y = 0;y < height; y += 1) {
|
|
3482
|
-
let r = 0, g = 0, b = 0;
|
|
3483
|
-
for (let x = -radius;x <= radius; x += 1) {
|
|
3484
|
-
const sx = Math.max(0, Math.min(width - 1, x));
|
|
3485
|
-
const i = (y * width + sx) * 3;
|
|
3486
|
-
r += buffer[i];
|
|
3487
|
-
g += buffer[i + 1];
|
|
3488
|
-
b += buffer[i + 2];
|
|
3489
|
-
}
|
|
3490
|
-
for (let x = 0;x < width; x += 1) {
|
|
3491
|
-
const oi = (y * width + x) * 3;
|
|
3492
|
-
tmp[oi] = r / window;
|
|
3493
|
-
tmp[oi + 1] = g / window;
|
|
3494
|
-
tmp[oi + 2] = b / window;
|
|
3495
|
-
const removeX = Math.max(0, x - radius);
|
|
3496
|
-
const addX = Math.min(width - 1, x + radius + 1);
|
|
3497
|
-
const ri = (y * width + removeX) * 3;
|
|
3498
|
-
const ai = (y * width + addX) * 3;
|
|
3499
|
-
r += tmp.length ? buffer[ai] - buffer[ri] : 0;
|
|
3500
|
-
g += tmp.length ? buffer[ai + 1] - buffer[ri + 1] : 0;
|
|
3501
|
-
b += tmp.length ? buffer[ai + 2] - buffer[ri + 2] : 0;
|
|
3502
|
-
}
|
|
3503
|
-
}
|
|
3504
|
-
for (let x = 0;x < width; x += 1) {
|
|
3505
|
-
let r = 0, g = 0, b = 0;
|
|
3506
|
-
for (let y = -radius;y <= radius; y += 1) {
|
|
3507
|
-
const sy = Math.max(0, Math.min(height - 1, y));
|
|
3508
|
-
const i = (sy * width + x) * 3;
|
|
3509
|
-
r += tmp[i];
|
|
3510
|
-
g += tmp[i + 1];
|
|
3511
|
-
b += tmp[i + 2];
|
|
3512
|
-
}
|
|
3513
|
-
for (let y = 0;y < height; y += 1) {
|
|
3514
|
-
const oi = (y * width + x) * 3;
|
|
3515
|
-
out[oi] = r / window;
|
|
3516
|
-
out[oi + 1] = g / window;
|
|
3517
|
-
out[oi + 2] = b / window;
|
|
3518
|
-
const removeY = Math.max(0, y - radius);
|
|
3519
|
-
const addY = Math.min(height - 1, y + radius + 1);
|
|
3520
|
-
const ri = (removeY * width + x) * 3;
|
|
3521
|
-
const ai = (addY * width + x) * 3;
|
|
3522
|
-
r += tmp[ai] - tmp[ri];
|
|
3523
|
-
g += tmp[ai + 1] - tmp[ri + 1];
|
|
3524
|
-
b += tmp[ai + 2] - tmp[ri + 2];
|
|
3525
|
-
}
|
|
3526
|
-
}
|
|
3527
|
-
return out;
|
|
3528
|
-
}
|
|
3529
|
-
function panelMaskKey(width, height, rect, headerPx, blurScale) {
|
|
3530
|
-
return `${width}x${height}:${rect.left},${rect.top},${rect.width},${rect.height}:${Math.round(headerPx * 100) / 100}:${blurScale}`;
|
|
3531
|
-
}
|
|
3532
|
-
function getPanelMask(width, height, rect, headerPx, blurScale) {
|
|
3533
|
-
const key = panelMaskKey(width, height, rect, headerPx, blurScale);
|
|
3534
|
-
const cached = panelMaskCache.get(key);
|
|
3535
|
-
if (cached)
|
|
3536
|
-
return cached;
|
|
3537
|
-
const radius = Math.max(PANEL_MASK_RADIUS_MIN, Math.min(PANEL_MASK_RADIUS_MAX, Math.round(Math.min(rect.width, rect.height) * PANEL_MASK_RADIUS_FACTOR)));
|
|
3538
|
-
const sampledWidth = Math.max(1, Math.ceil(rect.width / blurScale));
|
|
3539
|
-
const sampledHeight = Math.max(1, Math.ceil(rect.height / blurScale));
|
|
3540
|
-
const x0 = Math.max(0, rect.left);
|
|
3541
|
-
const y0 = Math.max(0, rect.top);
|
|
3542
|
-
const x1 = Math.min(width - 1, rect.left + rect.width - 1);
|
|
3543
|
-
const y1 = Math.min(height - 1, rect.top + rect.height - 1);
|
|
3544
|
-
const indices = [];
|
|
3545
|
-
const sampleIndices = [];
|
|
3546
|
-
const panelAlpha = [];
|
|
3547
|
-
const edgeAlpha = [];
|
|
3548
|
-
const headerFlags = [];
|
|
3549
|
-
const dividerIndices = [];
|
|
3550
|
-
for (let y = y0;y <= y1; y += 1) {
|
|
3551
|
-
for (let x = x0;x <= x1; x += 1) {
|
|
3552
|
-
const a = roundRectAlpha(x + 0.5, y + 0.5, rect.left, rect.top, rect.width, rect.height, radius);
|
|
3553
|
-
if (a <= 0)
|
|
3554
|
-
continue;
|
|
3555
|
-
const edge = roundRectAlpha(x + 0.5, y + 0.5, rect.left + 1.2, rect.top + 1.2, rect.width - 2.4, rect.height - 2.4, Math.max(1, radius - 1.2));
|
|
3556
|
-
const sx = Math.max(0, Math.min(sampledWidth - 1, Math.floor((x - rect.left) / blurScale)));
|
|
3557
|
-
const sy = Math.max(0, Math.min(sampledHeight - 1, Math.floor((y - rect.top) / blurScale)));
|
|
3558
|
-
indices.push((y * width + x) * 4);
|
|
3559
|
-
sampleIndices.push((sy * sampledWidth + sx) * 3);
|
|
3560
|
-
panelAlpha.push(a);
|
|
3561
|
-
edgeAlpha.push(edge < 0.96 ? Math.min(1, (1 - edge) * 0.7) : 0);
|
|
3562
|
-
headerFlags.push(y < rect.top + headerPx ? 1 : 0);
|
|
3563
|
-
}
|
|
3564
|
-
}
|
|
3565
|
-
const dividerY = Math.round(rect.top + headerPx);
|
|
3566
|
-
if (dividerY > y0 && dividerY < y1) {
|
|
3567
|
-
for (let x = x0 + radius;x <= x1 - radius; x += 1) {
|
|
3568
|
-
dividerIndices.push((dividerY * width + x) * 4);
|
|
3569
|
-
}
|
|
3570
|
-
}
|
|
3571
|
-
const mask = {
|
|
3572
|
-
key,
|
|
3573
|
-
indices: Uint32Array.from(indices),
|
|
3574
|
-
sampleIndices: Uint32Array.from(sampleIndices),
|
|
3575
|
-
panelAlpha: Float32Array.from(panelAlpha),
|
|
3576
|
-
edgeAlpha: Float32Array.from(edgeAlpha),
|
|
3577
|
-
headerFlags: Uint8Array.from(headerFlags),
|
|
3578
|
-
dividerIndices: Uint32Array.from(dividerIndices)
|
|
3579
|
-
};
|
|
3580
|
-
panelMaskCache.set(key, mask);
|
|
3581
|
-
while (panelMaskCache.size > PANEL_MASK_CACHE_LIMIT) {
|
|
3582
|
-
const oldest = panelMaskCache.keys().next().value;
|
|
3583
|
-
if (!oldest)
|
|
3584
|
-
break;
|
|
3585
|
-
panelMaskCache.delete(oldest);
|
|
3586
|
-
}
|
|
3587
|
-
return mask;
|
|
3588
|
-
}
|
|
3589
|
-
function compositePanel(data, width, height, rect, headerPx) {
|
|
3590
|
-
const blurScale = PANEL_BLUR_SCALE;
|
|
3591
|
-
const sampled = downsampleRegion(data, width, height, rect, blurScale);
|
|
3592
|
-
const blurRadius = Math.max(PANEL_BLUR_RADIUS_MIN, Math.min(PANEL_BLUR_RADIUS_MAX, Math.round(Math.min(rect.width, rect.height) * PANEL_BLUR_RADIUS_FACTOR)));
|
|
3593
|
-
const blurred = blurRgb(sampled.pixels, sampled.width, sampled.height, blurRadius);
|
|
3594
|
-
const mask = getPanelMask(width, height, rect, headerPx, blurScale);
|
|
3595
|
-
for (let i = 0;i < mask.indices.length; i += 1) {
|
|
3596
|
-
const idx = mask.indices[i];
|
|
3597
|
-
const sampleIdx = mask.sampleIndices[i];
|
|
3598
|
-
data[idx] = blurred[sampleIdx];
|
|
3599
|
-
data[idx + 1] = blurred[sampleIdx + 1];
|
|
3600
|
-
data[idx + 2] = blurred[sampleIdx + 2];
|
|
3601
|
-
data[idx + 3] = 255;
|
|
3602
|
-
blendOver(data, idx, mask.headerFlags[i] ? PANEL_HEADER : PANEL, mask.panelAlpha[i]);
|
|
3603
|
-
const edge = mask.edgeAlpha[i];
|
|
3604
|
-
if (edge > 0)
|
|
3605
|
-
blendOver(data, idx, PANEL_LINE2, edge);
|
|
3606
|
-
}
|
|
3607
|
-
for (let i = 0;i < mask.dividerIndices.length; i += 1) {
|
|
3608
|
-
blendOver(data, mask.dividerIndices[i], PANEL_LINE2, 0.28);
|
|
3609
|
-
}
|
|
3610
|
-
}
|
|
3611
|
-
var RIG_GLYPH_STROKES = {
|
|
3612
|
-
R: [[0, 0, 0, 1], [0, 0, 0.82, 0], [0.82, 0, 0.82, 0.5], [0, 0.5, 0.82, 0.5], [0.36, 0.5, 0.92, 1]],
|
|
3613
|
-
I: [[0.5, 0, 0.5, 1], [0.18, 0, 0.82, 0], [0.18, 1, 0.82, 1]],
|
|
3614
|
-
G: [[0.92, 0.08, 0.12, 0], [0.12, 0, 0.12, 1], [0.12, 1, 0.92, 1], [0.92, 0.5, 0.92, 1], [0.5, 0.5, 0.92, 0.5]]
|
|
3615
|
-
};
|
|
3616
|
-
function drawBigRigWordmark(data, width, height, layout, load) {
|
|
3617
|
-
const sideBySide = layout.width >= FLEET_GRID_WIDTH * 1.9;
|
|
3618
|
-
if (!sideBySide)
|
|
3118
|
+
function setHoveredSelectableId(id) {
|
|
3119
|
+
if (hoveredId === id)
|
|
3619
3120
|
return;
|
|
3620
|
-
|
|
3621
|
-
const
|
|
3622
|
-
|
|
3623
|
-
const glyphW = width * 0.13;
|
|
3624
|
-
const gap = glyphW * 0.3;
|
|
3625
|
-
const totalW = letters.length * glyphW + (letters.length - 1) * gap;
|
|
3626
|
-
const centerX = width * 0.71;
|
|
3627
|
-
const startX = centerX - totalW / 2;
|
|
3628
|
-
const top = (height - glyphH) / 2;
|
|
3629
|
-
const stroke = Math.max(2, min * 0.013);
|
|
3630
|
-
drawGlow2(data, width, height, centerX, top + glyphH / 2, Math.max(glyphW, glyphH) * 0.9, LIME, 0.022 + load * 0.02);
|
|
3631
|
-
const strokeAlpha = 0.1 + load * 0.06;
|
|
3632
|
-
letters.split("").forEach((letter, index) => {
|
|
3633
|
-
const segments = RIG_GLYPH_STROKES[letter];
|
|
3634
|
-
if (!segments)
|
|
3635
|
-
return;
|
|
3636
|
-
const ox = startX + index * (glyphW + gap);
|
|
3637
|
-
for (const [x0, y0, x1, y1] of segments) {
|
|
3638
|
-
drawLine2(data, width, height, ox + x0 * glyphW, top + y0 * glyphH, ox + x1 * glyphW, top + y1 * glyphH, LIME_DIM, strokeAlpha, stroke);
|
|
3639
|
-
}
|
|
3640
|
-
});
|
|
3121
|
+
hoveredId = id;
|
|
3122
|
+
for (const listener of listeners)
|
|
3123
|
+
listener();
|
|
3641
3124
|
}
|
|
3642
|
-
function
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
drawBigRigWordmark(data, width, height, layout, load);
|
|
3646
|
-
applyStaticAtmosphere(data, width, height, load);
|
|
3647
|
-
}
|
|
3648
|
-
function imageVisualFrameKey(input) {
|
|
3649
|
-
const width = Math.max(1, Math.floor(input.pixelSize.width));
|
|
3650
|
-
const height = Math.max(1, Math.floor(input.pixelSize.height));
|
|
3651
|
-
const layer = "layer" in input ? input.layer ?? "full" : "full";
|
|
3652
|
-
const load = loadBucket(input.load);
|
|
3653
|
-
return `${layer}:${width}x${height}:${input.layout.width}x${input.layout.height}:${input.scene}:${input.tick}:l${load}:${input.panels.map((panel) => `${panel.id}:${panel.top}:${panel.height}:${panel.width ?? ""}:${panel.left ?? ""}:${panel.headerHeight ?? ""}`).join("|")}`;
|
|
3654
|
-
}
|
|
3655
|
-
function encodeKittyFrame(width, height, data, input) {
|
|
3656
|
-
if (input.transport === "png") {
|
|
3657
|
-
const png = encodePng(width, height, data);
|
|
3658
|
-
return kittyImageSequence(png.toString("base64"), { columns: input.layout.width, rows: input.layout.height, imageId: input.imageId, zIndex: input.zIndex, format: 100 });
|
|
3659
|
-
}
|
|
3660
|
-
const compressed = deflateSync(data, { level: ZLIB_LEVEL });
|
|
3661
|
-
return kittyImageSequence(compressed.toString("base64"), {
|
|
3662
|
-
columns: input.layout.width,
|
|
3663
|
-
rows: input.layout.height,
|
|
3664
|
-
imageId: input.imageId,
|
|
3665
|
-
zIndex: input.zIndex,
|
|
3666
|
-
format: 32,
|
|
3667
|
-
pixelWidth: width,
|
|
3668
|
-
pixelHeight: height,
|
|
3669
|
-
compressed: true
|
|
3670
|
-
});
|
|
3125
|
+
function clearHoveredSelectableId(id) {
|
|
3126
|
+
if (id !== undefined && hoveredId === id)
|
|
3127
|
+
setHoveredSelectableId(undefined);
|
|
3671
3128
|
}
|
|
3672
|
-
function
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
}
|
|
3678
|
-
return out;
|
|
3679
|
-
}
|
|
3680
|
-
function encodePanelPatch(data, sourceWidth, placement, imageId, zIndex) {
|
|
3681
|
-
const patch = cropRgba(data, sourceWidth, placement);
|
|
3682
|
-
const png = encodePng(placement.width, placement.height, patch);
|
|
3683
|
-
const sequence = kittyImageSequence(png.toString("base64"), {
|
|
3684
|
-
columns: Math.max(1, Math.round(placement.widthCells)),
|
|
3685
|
-
rows: Math.max(1, Math.round(placement.heightCells)),
|
|
3686
|
-
imageId,
|
|
3687
|
-
zIndex,
|
|
3688
|
-
format: 100
|
|
3689
|
-
});
|
|
3690
|
-
return `\x1B[${Math.max(1, Math.round(placement.topCells) + 1)};${Math.max(1, Math.round(placement.leftCells) + 1)}H${sequence}`;
|
|
3691
|
-
}
|
|
3692
|
-
function renderImageVisualFrame(input) {
|
|
3693
|
-
const width = Math.max(1, Math.floor(input.pixelSize.width));
|
|
3694
|
-
const height = Math.max(1, Math.floor(input.pixelSize.height));
|
|
3695
|
-
const byteCount = width * height * 4;
|
|
3696
|
-
if (byteCount > MAX_IMAGE_BYTES)
|
|
3697
|
-
return null;
|
|
3698
|
-
const layer = input.layer ?? "full";
|
|
3699
|
-
const data = new Uint8ClampedArray(byteCount);
|
|
3700
|
-
const load = loadBucket(input.load) / LOAD_BUCKETS;
|
|
3701
|
-
const activeRuns = Math.max(0, Math.floor(input.activeRuns ?? 0));
|
|
3702
|
-
drawBackground(data, width, height, 0, input.scene, input.layout, load, activeRuns);
|
|
3703
|
-
if (layer === "split") {
|
|
3704
|
-
const sequences = [encodeKittyFrame(width, height, data, input)];
|
|
3705
|
-
let panelIndex = 0;
|
|
3706
|
-
for (const panel of input.panels) {
|
|
3707
|
-
if (panel.chrome !== "ad-terminal")
|
|
3708
|
-
continue;
|
|
3709
|
-
const placement = panelPixelPlacement(input.layout, panel, { width, height });
|
|
3710
|
-
if (!placement)
|
|
3711
|
-
continue;
|
|
3712
|
-
const cellH = height / input.layout.height;
|
|
3713
|
-
const headerPx = Math.max(cellH * 3, (panel.headerHeight ?? 3) * cellH);
|
|
3714
|
-
compositePanel(data, width, height, placement, headerPx);
|
|
3715
|
-
const imageId = input.imageIds?.[panelIndex] ?? (input.imageId + 1000 + panelIndex >>> 0 || panelIndex + 1);
|
|
3716
|
-
sequences.push(encodePanelPatch(data, width, placement, imageId, -12));
|
|
3717
|
-
panelIndex += 1;
|
|
3718
|
-
}
|
|
3719
|
-
return { key: imageVisualFrameKey(input), sequence: sequences.join("") };
|
|
3720
|
-
}
|
|
3721
|
-
if (layer === "panel-chrome")
|
|
3722
|
-
return { key: imageVisualFrameKey(input), sequence: "" };
|
|
3723
|
-
if (layer === "background") {
|
|
3724
|
-
return { key: imageVisualFrameKey(input), sequence: encodeKittyFrame(width, height, data, input) };
|
|
3725
|
-
}
|
|
3726
|
-
if (layer === "panel-patches") {
|
|
3727
|
-
const sequences = [];
|
|
3728
|
-
let panelIndex = 0;
|
|
3729
|
-
for (const panel of input.panels) {
|
|
3730
|
-
if (panel.chrome !== "ad-terminal")
|
|
3731
|
-
continue;
|
|
3732
|
-
const placement = panelPixelPlacement(input.layout, panel, { width, height });
|
|
3733
|
-
if (!placement)
|
|
3734
|
-
continue;
|
|
3735
|
-
const cellH = height / input.layout.height;
|
|
3736
|
-
const headerPx = Math.max(cellH * 3, (panel.headerHeight ?? 3) * cellH);
|
|
3737
|
-
compositePanel(data, width, height, placement, headerPx);
|
|
3738
|
-
const imageId = input.imageIds?.[panelIndex] ?? (input.imageId + 1000 + panelIndex >>> 0 || panelIndex + 1);
|
|
3739
|
-
sequences.push(encodePanelPatch(data, width, placement, imageId, input.zIndex));
|
|
3740
|
-
panelIndex += 1;
|
|
3741
|
-
}
|
|
3742
|
-
return { key: imageVisualFrameKey(input), sequence: sequences.join("") };
|
|
3743
|
-
}
|
|
3744
|
-
for (const panel of input.panels) {
|
|
3745
|
-
if (panel.chrome !== "ad-terminal")
|
|
3746
|
-
continue;
|
|
3747
|
-
const rect = panelRect(input.layout, panel, { width, height });
|
|
3748
|
-
if (!rect)
|
|
3749
|
-
continue;
|
|
3750
|
-
const cellH = height / input.layout.height;
|
|
3751
|
-
const headerPx = Math.max(cellH * 3, (panel.headerHeight ?? 3) * cellH);
|
|
3752
|
-
compositePanel(data, width, height, rect, headerPx);
|
|
3753
|
-
}
|
|
3754
|
-
return { key: imageVisualFrameKey(input), sequence: encodeKittyFrame(width, height, data, input) };
|
|
3755
|
-
}
|
|
3756
|
-
function shouldRenderImagesInline() {
|
|
3757
|
-
return process.env.RIG_OPENTUI_IMAGE_WORKER === "0" || import.meta.url.includes("$bunfs");
|
|
3758
|
-
}
|
|
3759
|
-
function createImageWorker() {
|
|
3760
|
-
if (shouldRenderImagesInline())
|
|
3761
|
-
return null;
|
|
3762
|
-
const isTypeScriptRuntime = import.meta.url.endsWith(".ts");
|
|
3763
|
-
const workerUrl = new URL(isTypeScriptRuntime ? "./image-visual-layer-worker.ts" : "./image-visual-layer-worker.js", import.meta.url);
|
|
3764
|
-
try {
|
|
3765
|
-
return new Worker(workerUrl);
|
|
3766
|
-
} catch {
|
|
3767
|
-
if (typeof process.versions.bun === "string") {
|
|
3768
|
-
try {
|
|
3769
|
-
return new Worker("./src/app-opentui/render/image-visual-layer-worker.ts");
|
|
3770
|
-
} catch {}
|
|
3771
|
-
}
|
|
3772
|
-
return null;
|
|
3773
|
-
}
|
|
3774
|
-
}
|
|
3775
|
-
var RECENT_WRITTEN_LIMIT = 24;
|
|
3776
|
-
var DEFAULT_IMAGE_OUTPUT_BACKLOG_BYTES = 256 * 1024;
|
|
3777
|
-
var DEFAULT_IMAGE_OUTPUT_BYTES_PER_SECOND = 850 * 1024;
|
|
3778
|
-
function imageOutputBacklogBytes() {
|
|
3779
|
-
const raw = Number.parseInt(process.env.RIG_OPENTUI_IMAGE_BACKLOG_BYTES ?? "", 10);
|
|
3780
|
-
if (Number.isFinite(raw) && raw > 0)
|
|
3781
|
-
return Math.max(64 * 1024, Math.min(2 * 1024 * 1024, raw));
|
|
3782
|
-
return DEFAULT_IMAGE_OUTPUT_BACKLOG_BYTES;
|
|
3783
|
-
}
|
|
3784
|
-
function imageOutputBytesPerSecond() {
|
|
3785
|
-
const raw = Number.parseInt(process.env.RIG_OPENTUI_IMAGE_BYTES_PER_SECOND ?? "", 10);
|
|
3786
|
-
if (Number.isFinite(raw) && raw > 0)
|
|
3787
|
-
return Math.max(128 * 1024, Math.min(2 * 1024 * 1024, raw));
|
|
3788
|
-
return DEFAULT_IMAGE_OUTPUT_BYTES_PER_SECOND;
|
|
3789
|
-
}
|
|
3790
|
-
function pendingLayerKey(key) {
|
|
3791
|
-
return key.split(":", 1)[0] || "full";
|
|
3792
|
-
}
|
|
3793
|
-
|
|
3794
|
-
class ImageVisualLayer {
|
|
3795
|
-
imageId = allocateImageId();
|
|
3796
|
-
panelImageIds = Array.from({ length: 8 }, () => allocateImageId());
|
|
3797
|
-
panelChromeImageIds = Array.from({ length: 8 }, () => allocateImageId());
|
|
3798
|
-
stdout;
|
|
3799
|
-
onFrameReady;
|
|
3800
|
-
protocol;
|
|
3801
|
-
transport = imageTransport();
|
|
3802
|
-
maxOutputBacklogBytes = imageOutputBacklogBytes();
|
|
3803
|
-
outputBytesPerSecond = imageOutputBytesPerSecond();
|
|
3804
|
-
outputBudgetBytes = imageOutputBytesPerSecond();
|
|
3805
|
-
lastBudgetAtMs = Date.now();
|
|
3806
|
-
motionSlot = this.createSlot();
|
|
3807
|
-
workersStarted = false;
|
|
3808
|
-
pendingFrames = new Map;
|
|
3809
|
-
recentWrittenKeys = [];
|
|
3810
|
-
imagesVisible = false;
|
|
3811
|
-
flushPaused = false;
|
|
3812
|
-
requestId = 0;
|
|
3813
|
-
lastBackgroundKey = "";
|
|
3814
|
-
fatalWorkerError = null;
|
|
3815
|
-
destroyed = false;
|
|
3816
|
-
constructor(stdout = process.stdout, onFrameReady) {
|
|
3817
|
-
this.stdout = stdout;
|
|
3818
|
-
this.onFrameReady = onFrameReady;
|
|
3819
|
-
this.protocol = getRigTerminalCapabilities().imageProtocol;
|
|
3820
|
-
}
|
|
3821
|
-
get enabled() {
|
|
3822
|
-
return this.protocol === "kitty";
|
|
3823
|
-
}
|
|
3824
|
-
clear() {
|
|
3825
|
-
if (this.enabled) {
|
|
3826
|
-
if (this.imagesVisible)
|
|
3827
|
-
this.stdout.write([this.imageId, ...this.panelImageIds, ...this.panelChromeImageIds].map((id) => deleteKittyImage(id)).join("") + "\x1B[?25h");
|
|
3828
|
-
this.imagesVisible = false;
|
|
3829
|
-
this.pendingFrames.clear();
|
|
3830
|
-
this.recentWrittenKeys.length = 0;
|
|
3831
|
-
this.resetSlot(this.motionSlot);
|
|
3832
|
-
this.lastBackgroundKey = "";
|
|
3833
|
-
this.outputBudgetBytes = this.outputBytesPerSecond;
|
|
3834
|
-
this.lastBudgetAtMs = Date.now();
|
|
3835
|
-
this.motionSlot.clearedThroughRequestId = this.requestId;
|
|
3836
|
-
}
|
|
3837
|
-
}
|
|
3838
|
-
destroy() {
|
|
3839
|
-
if (this.destroyed)
|
|
3840
|
-
return;
|
|
3841
|
-
this.clear();
|
|
3842
|
-
this.destroyed = true;
|
|
3843
|
-
const workers = [this.motionSlot.worker];
|
|
3844
|
-
this.motionSlot.worker = null;
|
|
3845
|
-
for (const worker of workers)
|
|
3846
|
-
if (worker)
|
|
3847
|
-
worker.terminate().catch(() => {
|
|
3848
|
-
return;
|
|
3849
|
-
});
|
|
3850
|
-
}
|
|
3851
|
-
setFlushPaused(paused) {
|
|
3852
|
-
this.flushPaused = paused;
|
|
3853
|
-
}
|
|
3854
|
-
isReady(input) {
|
|
3855
|
-
if (!this.enabled || this.destroyed)
|
|
3856
|
-
return true;
|
|
3857
|
-
this.throwIfFatal();
|
|
3858
|
-
const splitKey = imageVisualFrameKey({ ...input, tick: 0, layer: "split" });
|
|
3859
|
-
return this.recentWrittenKeys.includes(splitKey) || Array.from(this.pendingFrames.values()).some((frame) => frame.key === splitKey);
|
|
3860
|
-
}
|
|
3861
|
-
render(input) {
|
|
3862
|
-
if (!this.enabled || this.destroyed)
|
|
3863
|
-
return;
|
|
3864
|
-
this.throwIfFatal();
|
|
3865
|
-
if (this.transport !== "png")
|
|
3866
|
-
this.failWorker("renderer", new Error("OpenTUI image visuals require PNG transport for static-background rendering."));
|
|
3867
|
-
this.ensureWorkersStarted();
|
|
3868
|
-
const width = Math.max(1, Math.floor(input.pixelSize.width));
|
|
3869
|
-
const height = Math.max(1, Math.floor(input.pixelSize.height));
|
|
3870
|
-
if (width * height * 4 > MAX_IMAGE_BYTES)
|
|
3871
|
-
return;
|
|
3872
|
-
if (this.isOutputBackedUp())
|
|
3873
|
-
return;
|
|
3874
|
-
this.refillOutputBudget();
|
|
3875
|
-
const splitInput = { ...input, tick: 0, layer: "split" };
|
|
3876
|
-
const splitKey = imageVisualFrameKey(splitInput);
|
|
3877
|
-
if (input.force || splitKey !== this.lastBackgroundKey) {
|
|
3878
|
-
this.scheduleRender(this.motionSlot, splitInput, this.imageId, -30, input.force, this.panelImageIds);
|
|
3879
|
-
this.lastBackgroundKey = splitKey;
|
|
3880
|
-
}
|
|
3881
|
-
}
|
|
3882
|
-
flush() {
|
|
3883
|
-
this.throwIfFatal();
|
|
3884
|
-
if (this.flushPaused)
|
|
3885
|
-
return false;
|
|
3886
|
-
if (this.pendingFrames.size === 0)
|
|
3887
|
-
return false;
|
|
3888
|
-
this.refillOutputBudget();
|
|
3889
|
-
if (this.isOutputBackedUp()) {
|
|
3890
|
-
const retainedSplit = this.pendingFrames.get("split");
|
|
3891
|
-
this.pendingFrames.clear();
|
|
3892
|
-
if (retainedSplit)
|
|
3893
|
-
this.pendingFrames.set("split", retainedSplit);
|
|
3894
|
-
return false;
|
|
3895
|
-
}
|
|
3896
|
-
const framePriority = (frame) => {
|
|
3897
|
-
const layer = pendingLayerKey(frame.key);
|
|
3898
|
-
if (layer === "split")
|
|
3899
|
-
return 1;
|
|
3900
|
-
return 4;
|
|
3901
|
-
};
|
|
3902
|
-
const frames = Array.from(this.pendingFrames.values()).sort((a, b) => framePriority(a) - framePriority(b));
|
|
3903
|
-
const prefix = "\x1B[?25l\x1B7\x1B[s\x1B[H";
|
|
3904
|
-
const suffix = "\x1B[u\x1B8";
|
|
3905
|
-
const selected = [];
|
|
3906
|
-
const retained = new Map;
|
|
3907
|
-
let sequence = "";
|
|
3908
|
-
let byteLength = Buffer.byteLength(prefix + suffix);
|
|
3909
|
-
for (const frame of frames) {
|
|
3910
|
-
const candidate = sequence + frame.sequence;
|
|
3911
|
-
const candidateBytes = Buffer.byteLength(prefix + candidate + suffix);
|
|
3912
|
-
const layer = pendingLayerKey(frame.key);
|
|
3913
|
-
const allowOneStaticFrame = selected.length === 0 && layer === "split";
|
|
3914
|
-
if (candidateBytes <= this.outputBudgetBytes || allowOneStaticFrame) {
|
|
3915
|
-
selected.push(frame);
|
|
3916
|
-
sequence = candidate;
|
|
3917
|
-
byteLength = candidateBytes;
|
|
3918
|
-
} else if (layer === "split") {
|
|
3919
|
-
retained.set(layer, frame);
|
|
3920
|
-
}
|
|
3921
|
-
}
|
|
3922
|
-
this.pendingFrames.clear();
|
|
3923
|
-
for (const [layer, frame] of retained)
|
|
3924
|
-
this.pendingFrames.set(layer, frame);
|
|
3925
|
-
if (!sequence || selected.length === 0)
|
|
3926
|
-
return false;
|
|
3927
|
-
const payload = `${prefix}${sequence}${suffix}`;
|
|
3928
|
-
for (const frame of selected)
|
|
3929
|
-
this.markWritten(frame.key);
|
|
3930
|
-
this.outputBudgetBytes -= byteLength;
|
|
3931
|
-
this.stdout.cork?.();
|
|
3932
|
-
const accepted = this.stdout.write(payload);
|
|
3933
|
-
this.stdout.uncork?.();
|
|
3934
|
-
this.imagesVisible = true;
|
|
3935
|
-
return accepted;
|
|
3936
|
-
}
|
|
3937
|
-
createSlot() {
|
|
3938
|
-
return { worker: null, busy: false, queuedRequest: null, inFlightKey: "", queuedKey: "", clearedThroughRequestId: 0, latestRequestId: 0 };
|
|
3939
|
-
}
|
|
3940
|
-
resetSlot(slot) {
|
|
3941
|
-
slot.busy = false;
|
|
3942
|
-
slot.queuedRequest = null;
|
|
3943
|
-
slot.inFlightKey = "";
|
|
3944
|
-
slot.queuedKey = "";
|
|
3945
|
-
}
|
|
3946
|
-
markWritten(key) {
|
|
3947
|
-
this.recentWrittenKeys.push(key);
|
|
3948
|
-
while (this.recentWrittenKeys.length > RECENT_WRITTEN_LIMIT)
|
|
3949
|
-
this.recentWrittenKeys.shift();
|
|
3950
|
-
}
|
|
3951
|
-
refillOutputBudget() {
|
|
3952
|
-
const now = Date.now();
|
|
3953
|
-
const elapsedMs = Math.max(0, now - this.lastBudgetAtMs);
|
|
3954
|
-
this.lastBudgetAtMs = now;
|
|
3955
|
-
this.outputBudgetBytes = Math.min(this.outputBytesPerSecond, this.outputBudgetBytes + elapsedMs / 1000 * this.outputBytesPerSecond);
|
|
3956
|
-
}
|
|
3957
|
-
isOutputBackedUp() {
|
|
3958
|
-
return Boolean(this.stdout.writableNeedDrain) || this.stdout.writableLength > this.maxOutputBacklogBytes;
|
|
3959
|
-
}
|
|
3960
|
-
stageFrame(frame) {
|
|
3961
|
-
this.pendingFrames.set(pendingLayerKey(frame.key), frame);
|
|
3962
|
-
}
|
|
3963
|
-
isKnownKey(slot, key) {
|
|
3964
|
-
return this.recentWrittenKeys.includes(key) || Array.from(this.pendingFrames.values()).some((frame) => frame.key === key) || key === slot.inFlightKey || key === slot.queuedKey;
|
|
3965
|
-
}
|
|
3966
|
-
ensureWorkersStarted() {
|
|
3967
|
-
if (this.workersStarted)
|
|
3968
|
-
return;
|
|
3969
|
-
this.workersStarted = true;
|
|
3970
|
-
this.startWorker(this.motionSlot, "static-visuals");
|
|
3971
|
-
}
|
|
3972
|
-
failWorker(name, error) {
|
|
3973
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
3974
|
-
this.fatalWorkerError ??= new Error(`OpenTUI image worker ${name} failed: ${detail}`);
|
|
3975
|
-
throw this.fatalWorkerError;
|
|
3976
|
-
}
|
|
3977
|
-
throwIfFatal() {
|
|
3978
|
-
if (this.fatalWorkerError)
|
|
3979
|
-
throw this.fatalWorkerError;
|
|
3980
|
-
}
|
|
3981
|
-
scheduleRender(slot, input, imageId, zIndex, force, imageIds) {
|
|
3982
|
-
this.throwIfFatal();
|
|
3983
|
-
const key = imageVisualFrameKey(input);
|
|
3984
|
-
if (!force && this.isKnownKey(slot, key))
|
|
3985
|
-
return;
|
|
3986
|
-
const request = {
|
|
3987
|
-
...input,
|
|
3988
|
-
imageId,
|
|
3989
|
-
...imageIds ? { imageIds } : {},
|
|
3990
|
-
zIndex,
|
|
3991
|
-
transport: this.transport,
|
|
3992
|
-
requestId: ++this.requestId,
|
|
3993
|
-
key
|
|
3994
|
-
};
|
|
3995
|
-
slot.latestRequestId = request.requestId;
|
|
3996
|
-
if (!slot.worker) {
|
|
3997
|
-
this.renderInline(slot, request);
|
|
3998
|
-
return;
|
|
3999
|
-
}
|
|
4000
|
-
this.enqueueWorkerRender(slot, request);
|
|
4001
|
-
}
|
|
4002
|
-
startWorker(slot, name) {
|
|
4003
|
-
const worker = createImageWorker();
|
|
4004
|
-
if (!worker)
|
|
4005
|
-
return;
|
|
4006
|
-
slot.worker = worker;
|
|
4007
|
-
worker.on("message", (message) => this.handleWorkerMessage(slot, message));
|
|
4008
|
-
worker.once("error", (error) => {
|
|
4009
|
-
if (!this.destroyed)
|
|
4010
|
-
this.fatalWorkerError ??= new Error(`OpenTUI image worker ${name} failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
4011
|
-
});
|
|
4012
|
-
worker.once("exit", (code) => {
|
|
4013
|
-
if (!this.destroyed)
|
|
4014
|
-
this.fatalWorkerError ??= new Error(`OpenTUI image worker ${name} exited unexpectedly with code ${code}.`);
|
|
4015
|
-
});
|
|
4016
|
-
}
|
|
4017
|
-
renderInline(slot, request) {
|
|
4018
|
-
try {
|
|
4019
|
-
const result = renderImageVisualFrame(request);
|
|
4020
|
-
if (result?.sequence && !this.isKnownKey(slot, result.key) && (!this.isOutputBackedUp() || pendingLayerKey(result.key) === "split")) {
|
|
4021
|
-
this.stageFrame({ key: result.key, sequence: result.sequence });
|
|
4022
|
-
this.onFrameReady?.();
|
|
4023
|
-
}
|
|
4024
|
-
} catch (error) {
|
|
4025
|
-
this.failWorker(String(request.layer ?? "visual"), error);
|
|
4026
|
-
}
|
|
4027
|
-
}
|
|
4028
|
-
enqueueWorkerRender(slot, request) {
|
|
4029
|
-
this.throwIfFatal();
|
|
4030
|
-
if (slot.busy) {
|
|
4031
|
-
slot.queuedRequest = request;
|
|
4032
|
-
slot.queuedKey = request.key;
|
|
4033
|
-
return;
|
|
4034
|
-
}
|
|
4035
|
-
this.dispatchWorkerRender(slot, request);
|
|
4036
|
-
}
|
|
4037
|
-
dispatchWorkerRender(slot, request) {
|
|
4038
|
-
this.throwIfFatal();
|
|
4039
|
-
if (!slot.worker)
|
|
4040
|
-
this.failWorker(String(request.layer ?? "visual"), new Error("worker is unavailable"));
|
|
4041
|
-
slot.busy = true;
|
|
4042
|
-
slot.inFlightKey = request.key;
|
|
4043
|
-
try {
|
|
4044
|
-
slot.worker.postMessage(request);
|
|
4045
|
-
} catch (error) {
|
|
4046
|
-
this.failWorker(String(request.layer ?? "visual"), error);
|
|
4047
|
-
}
|
|
4048
|
-
}
|
|
4049
|
-
handleWorkerMessage(slot, message) {
|
|
4050
|
-
if (this.destroyed || !message || typeof message !== "object")
|
|
4051
|
-
return;
|
|
4052
|
-
const response = message;
|
|
4053
|
-
slot.busy = false;
|
|
4054
|
-
slot.inFlightKey = "";
|
|
4055
|
-
const isStale = response.requestId <= slot.clearedThroughRequestId || response.requestId < slot.latestRequestId;
|
|
4056
|
-
if (!isStale) {
|
|
4057
|
-
if (response.error)
|
|
4058
|
-
this.failWorker(pendingLayerKey(response.key), new Error(response.error));
|
|
4059
|
-
if (response.sequence && !this.isKnownKey(slot, response.key) && (!this.isOutputBackedUp() || pendingLayerKey(response.key) === "split")) {
|
|
4060
|
-
this.stageFrame({ key: response.key, sequence: response.sequence });
|
|
4061
|
-
this.onFrameReady?.();
|
|
4062
|
-
}
|
|
4063
|
-
}
|
|
4064
|
-
const next = slot.queuedRequest;
|
|
4065
|
-
slot.queuedRequest = null;
|
|
4066
|
-
slot.queuedKey = "";
|
|
4067
|
-
if (next && !this.isKnownKey(slot, next.key))
|
|
4068
|
-
this.dispatchWorkerRender(slot, next);
|
|
4069
|
-
}
|
|
3129
|
+
function subscribeHover(listener) {
|
|
3130
|
+
listeners.add(listener);
|
|
3131
|
+
return () => {
|
|
3132
|
+
listeners.delete(listener);
|
|
3133
|
+
};
|
|
4070
3134
|
}
|
|
4071
3135
|
|
|
4072
3136
|
// packages/cli/src/app-opentui/render/text.ts
|
|
4073
|
-
import { RGBA as RGBA4, TextAttributes as TextAttributes4, TextRenderable } from "@opentui/core";
|
|
4074
3137
|
var TRANSPARENT2 = RGBA4.fromInts(0, 0, 0, 0);
|
|
3138
|
+
var HOVER_BG = RGBA4.fromHex(RIG_UI.hover);
|
|
3139
|
+
function lineIsClickable(line2) {
|
|
3140
|
+
return line2?.selectable !== undefined || line2?.selectableIndex !== undefined;
|
|
3141
|
+
}
|
|
3142
|
+
function lineSelectableId(line2) {
|
|
3143
|
+
return line2?.selectable?.id ?? line2?.selectableId;
|
|
3144
|
+
}
|
|
3145
|
+
function lineBackground(line2) {
|
|
3146
|
+
if (line2?.bg)
|
|
3147
|
+
return RGBA4.fromHex(line2.bg);
|
|
3148
|
+
const id = lineSelectableId(line2);
|
|
3149
|
+
if (id !== undefined && isHovered(id))
|
|
3150
|
+
return HOVER_BG;
|
|
3151
|
+
return TRANSPARENT2;
|
|
3152
|
+
}
|
|
4075
3153
|
function selectableMouseHandler(currentLineRef, onLineMouseDown) {
|
|
4076
3154
|
return (event) => {
|
|
4077
3155
|
const currentLine = currentLineRef();
|
|
4078
|
-
if (currentLine
|
|
3156
|
+
if (!lineIsClickable(currentLine))
|
|
4079
3157
|
return;
|
|
4080
3158
|
onLineMouseDown?.(currentLine, event);
|
|
4081
3159
|
};
|
|
4082
3160
|
}
|
|
3161
|
+
function hoverHandlers(currentLineRef) {
|
|
3162
|
+
return {
|
|
3163
|
+
onMouseOver: () => {
|
|
3164
|
+
const id = lineSelectableId(currentLineRef());
|
|
3165
|
+
if (id !== undefined)
|
|
3166
|
+
setHoveredSelectableId(id);
|
|
3167
|
+
},
|
|
3168
|
+
onMouseOut: () => clearHoveredSelectableId(lineSelectableId(currentLineRef()))
|
|
3169
|
+
};
|
|
3170
|
+
}
|
|
4083
3171
|
function createFlowTextLine(renderer, id, onLineMouseDown) {
|
|
4084
3172
|
let currentLine;
|
|
4085
3173
|
const renderable = new TextRenderable(renderer, {
|
|
@@ -4090,7 +3178,8 @@ function createFlowTextLine(renderer, id, onLineMouseDown) {
|
|
|
4090
3178
|
flexShrink: 0,
|
|
4091
3179
|
fg: RIG_UI.ink2,
|
|
4092
3180
|
selectable: true,
|
|
4093
|
-
onMouseDown: selectableMouseHandler(() => currentLine, onLineMouseDown)
|
|
3181
|
+
onMouseDown: selectableMouseHandler(() => currentLine, onLineMouseDown),
|
|
3182
|
+
...hoverHandlers(() => currentLine)
|
|
4094
3183
|
});
|
|
4095
3184
|
renderable.setRigSceneLine = (line2) => {
|
|
4096
3185
|
currentLine = line2;
|
|
@@ -4104,7 +3193,7 @@ function applyFlowTextLine(renderable, line2, width) {
|
|
|
4104
3193
|
renderable.width = Math.max(1, width);
|
|
4105
3194
|
renderable.content = line2?.styledText ?? line2?.text ?? "";
|
|
4106
3195
|
renderable.fg = line2?.fg ?? RIG_UI.ink2;
|
|
4107
|
-
renderable.bg = line2
|
|
3196
|
+
renderable.bg = lineBackground(line2);
|
|
4108
3197
|
renderable.attributes = line2?.bold ? TextAttributes4.BOLD : line2?.dim ? TextAttributes4.DIM : 0;
|
|
4109
3198
|
}
|
|
4110
3199
|
|
|
@@ -4777,13 +3866,16 @@ function lineContent(line2) {
|
|
|
4777
3866
|
}
|
|
4778
3867
|
function LineView(props) {
|
|
4779
3868
|
const { line: line2, onLineClick } = props;
|
|
3869
|
+
const id = lineSelectableId(line2);
|
|
4780
3870
|
return /* @__PURE__ */ jsxDEV("text", {
|
|
4781
3871
|
style: { position: "absolute", left: props.left, top: props.top, width: props.width, zIndex: 5 },
|
|
4782
3872
|
fg: line2.fg ?? RIG_UI.ink2,
|
|
4783
|
-
bg: line2
|
|
3873
|
+
bg: lineBackground(line2),
|
|
4784
3874
|
attributes: lineAttributes(line2),
|
|
4785
3875
|
content: lineContent(line2),
|
|
4786
|
-
onMouseDown: onLineClick ? () => onLineClick(line2) : undefined
|
|
3876
|
+
onMouseDown: onLineClick ? () => onLineClick(line2) : undefined,
|
|
3877
|
+
onMouseOver: id !== undefined ? () => setHoveredSelectableId(id) : undefined,
|
|
3878
|
+
onMouseOut: id !== undefined ? () => clearHoveredSelectableId(id) : undefined
|
|
4787
3879
|
}, undefined, false, undefined, this);
|
|
4788
3880
|
}
|
|
4789
3881
|
function PanelHost(props) {
|
|
@@ -5019,6 +4111,7 @@ function App(props) {
|
|
|
5019
4111
|
const runAppAction = useRunAppAction();
|
|
5020
4112
|
const store = useStore();
|
|
5021
4113
|
const renderer = useRenderer4();
|
|
4114
|
+
useSyncExternalStore2(subscribeHover, getHoveredSelectableId, getHoveredSelectableId);
|
|
5022
4115
|
const dims = useTerminalDimensions2();
|
|
5023
4116
|
const layout = computeStageLayout(dims.width, dims.height);
|
|
5024
4117
|
const registry = useMemo(() => ({ ...BUILTIN, ...props.sceneRenderers ?? {} }), [props.sceneRenderers]);
|
|
@@ -5053,8 +4146,7 @@ function App(props) {
|
|
|
5053
4146
|
} else {
|
|
5054
4147
|
return;
|
|
5055
4148
|
}
|
|
5056
|
-
|
|
5057
|
-
runAppAction("Activate selection", () => activateSelection(runtime, items));
|
|
4149
|
+
runAppAction("Activate selection", () => activateSelection(runtime, items));
|
|
5058
4150
|
};
|
|
5059
4151
|
return /* @__PURE__ */ jsxDEV3("box", {
|
|
5060
4152
|
style: { position: "absolute", left: 0, top: 0, width: "100%", height: "100%" },
|