@wolfstar/cli 2.6.0-next-20261007152629 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -1
- package/dist/cli.js +1 -1
- package/dist/{commands-3Tgwy6cj.js → commands-BiY_99sF.js} +4 -4
- package/dist/{commands-3Tgwy6cj.js.map → commands-BiY_99sF.js.map} +1 -1
- package/dist/commands-DuiQDJUH.js +3 -0
- package/dist/{completions-Cs6YbuXO.js → completions-5E5jiT_A.js} +2 -2
- package/dist/{completions-Cs6YbuXO.js.map → completions-5E5jiT_A.js.map} +1 -1
- package/dist/{dev-9YvzhtkU.js → dev-Vv2-8hUB.js} +10 -3
- package/dist/{dev-9YvzhtkU.js.map → dev-Vv2-8hUB.js.map} +1 -1
- package/dist/index.js +1 -1
- package/dist/{info-eXsx1AfE.js → info-C_YDcVul.js} +2 -1
- package/dist/info-C_YDcVul.js.map +1 -0
- package/dist/{run-DlNY1QM1.js → run-BkfjbY7l.js} +2 -2
- package/dist/{run-DlNY1QM1.js.map → run-BkfjbY7l.js.map} +1 -1
- package/dist/{tui-CB_qk2Z1.js → tui-BOkOx13K.js} +313 -48
- package/dist/tui-BOkOx13K.js.map +1 -0
- package/package.json +5 -5
- package/dist/commands-3qXbxhXx.js +0 -3
- package/dist/info-eXsx1AfE.js.map +0 -1
- package/dist/tui-CB_qk2Z1.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"info-C_YDcVul.js","names":[],"sources":["../src/commands/info.ts"],"sourcesContent":["import { displayPath, type ResolvedStarsConfig, type StarsEnvSetupOptions } from '@wolfstar/schema';\nimport { defineCommand } from 'citty';\nimport { createColors } from 'colorette';\nimport { arch, platform } from 'node:os';\nimport { relative } from 'node:path';\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\nimport { applyEnvOptions, loadProject } from '../utils/hooks.js';\nimport { modulesPreloadWarning } from '../utils/modules.js';\nimport { resolveOutputMode, shouldUseColor } from '../utils/output-mode.js';\nimport { findInstalledVersion } from '../utils/project.js';\nimport { readOwnPackageJson } from '../utils/version.js';\n\nexport interface InfoOptions extends ProjectArgs {\n\tjson?: boolean;\n\tstdout?: NodeJS.WritableStream;\n}\n\nexport interface ProjectInfo {\n\tcli: { version: string; node: string; platform: string; outputMode: 'tui' | 'plain' };\n\tproject: {\n\t\tcwd: string;\n\t\troot: string;\n\t\tconfigFile: string | null;\n\t\tname: string | null;\n\t\tversion: string | null;\n\t\tentry: string;\n\t\tframeworkVersion: string | null;\n\t};\n\tbuild: ResolvedStarsConfig['build'];\n\tdev: ResolvedStarsConfig['dev'];\n\tcodegen: ResolvedStarsConfig['codegen'];\n\timports: ResolvedStarsConfig['imports'];\n\texperimental: ResolvedStarsConfig['experimental'];\n\tfuture: ResolvedStarsConfig['future'];\n\tenv: ResolvedStarsConfig['env'];\n\t/** The names of the hooks registered in `stars.config`, flattened (`build:done`). */\n\thooks: string[];\n\t/** The installed modules, and the runtime plugins they registered (`module → export from package`). */\n\tmodules: { installed: string[]; plugins: string[] };\n\t/** Non-fatal configuration diagnostics, as `CODE: message`. */\n\twarnings: string[];\n\t/**\n\t * The option names set in the `tsdown`/`vite` blocks. Only the names: the values hold plugins and callbacks,\n\t * which neither serialize to JSON nor read usefully on a terminal.\n\t */\n\toptions: { tsdown: string[]; vite: string[] };\n}\n\nexport function collectInfo(config: ResolvedStarsConfig): ProjectInfo {\n\treturn {\n\t\tcli: {\n\t\t\tversion: readOwnPackageJson().version,\n\t\t\tnode: process.version,\n\t\t\tplatform: `${platform()} ${arch()}`,\n\t\t\toutputMode: resolveOutputMode()\n\t\t},\n\t\tproject: {\n\t\t\tcwd: config.cwd,\n\t\t\troot: config.root,\n\t\t\tconfigFile: config.configFile,\n\t\t\tname: config.packageJson?.name ?? null,\n\t\t\tversion: config.packageJson?.version ?? null,\n\t\t\tentry: config.entry,\n\t\t\tframeworkVersion: findInstalledVersion(config.root, '@wolfstar/http-framework')\n\t\t},\n\t\tbuild: config.build,\n\t\tdev: config.dev,\n\t\tcodegen: config.codegen,\n\t\timports: config.imports,\n\t\texperimental: config.experimental,\n\t\tfuture: config.future,\n\t\tenv: config.env,\n\t\thooks: Object.keys(config.hooks),\n\t\tmodules: {\n\t\t\tinstalled: (config.runtime?.modules ?? []).map((module) => module.name),\n\t\t\tplugins: (config.runtime?.plugins ?? []).map((plugin) => `${plugin.module} → ${plugin.export} from ${plugin.from}`)\n\t\t},\n\t\twarnings: [...config.warnings, modulesPreloadWarning(config)]\n\t\t\t.filter((warning) => warning !== null)\n\t\t\t.map((warning) => `${warning.code}: ${warning.message}`),\n\t\toptions: { tsdown: Object.keys(config.tsdown), vite: Object.keys(config.vite) }\n\t};\n}\n\nexport function formatInfo(info: ProjectInfo, useColor: boolean): string {\n\tconst colors = createColors({ useColor });\n\tconst { root } = info.project;\n\tconst show = (path: string | null) => (path === null ? colors.dim('none') : displayPath(root, path));\n\tconst row = (label: string, value: string) => ` ${colors.dim(label.padEnd(12))}${value}`;\n\tconst section = (title: string, rows: string[]) => [colors.bold(title), ...rows].join('\\n');\n\n\treturn [\n\t\tsection(`stars ${colors.green(`v${info.cli.version}`)}`, [\n\t\t\trow('node', info.cli.node),\n\t\t\trow('platform', info.cli.platform),\n\t\t\trow('output', info.cli.outputMode),\n\t\t\trow(\n\t\t\t\t'framework',\n\t\t\t\tinfo.project.frameworkVersion\n\t\t\t\t\t? `@wolfstar/http-framework v${info.project.frameworkVersion}`\n\t\t\t\t\t: colors.yellow('@wolfstar/http-framework not installed')\n\t\t\t)\n\t\t]),\n\t\tsection('Project', [\n\t\t\trow(\n\t\t\t\t'name',\n\t\t\t\tinfo.project.name\n\t\t\t\t\t? `${info.project.name}${info.project.version ? colors.dim(` v${info.project.version}`) : ''}`\n\t\t\t\t\t: colors.dim('unnamed')\n\t\t\t),\n\t\t\trow('root', root),\n\t\t\trow(\n\t\t\t\t'config',\n\t\t\t\tinfo.project.configFile ? relative(root, info.project.configFile) || info.project.configFile : colors.dim('none (defaults)')\n\t\t\t),\n\t\t\trow('entry', show(info.project.entry))\n\t\t]),\n\t\tsection('Build', [\n\t\t\trow('tool', info.build.tool),\n\t\t\t// Which file the build tool is configured from: its own, or this project's `stars.config`.\n\t\t\trow('config', info.build.configFile ? show(info.build.configFile) : colors.dim('stars.config')),\n\t\t\trow('options', describeOptions(info, colors)),\n\t\t\trow('outDir', show(info.build.outDir)),\n\t\t\trow('tsconfig', show(info.build.tsconfig)),\n\t\t\t// Everything `stars typecheck` checks: the generated app and node projects from compatibility version 6 (a `tsc`\n\t\t\t// or `none` project keeps its own tsconfig for the bot and gets the node one on top).\n\t\t\trow('typechecks', info.dev.typecheck.projects.length > 0 ? info.dev.typecheck.projects.map(show).join(', ') : colors.dim('none')),\n\t\t\trow('runs', show(info.build.output))\n\t\t]),\n\t\tsection('Dev', [\n\t\t\trow('watch', info.dev.watch.map(show).join(', ')),\n\t\t\trow('debounce', `${info.dev.debounce}ms`),\n\t\t\trow('node args', info.dev.nodeArgs.join(' ') || colors.dim('none')),\n\t\t\trow('args', info.dev.args.join(' ') || colors.dim('none')),\n\t\t\trow('url', info.dev.url ?? colors.dim('unknown, set dev.url or HTTP_PORT')),\n\t\t\trow('health', info.dev.health ?? colors.dim('none')),\n\t\t\trow(\n\t\t\t\t'typecheck',\n\t\t\t\tinfo.dev.typecheck.enabled ? `${info.dev.typecheck.checker} → ${show(info.dev.typecheck.tsconfig)}` : colors.dim('disabled')\n\t\t\t),\n\t\t\trow('tunnel', describeTunnel(info.dev.tunnel, colors)),\n\t\t\trow('log file', info.dev.logFile ? show(info.dev.logFile) : colors.dim('disabled')),\n\t\t\trow('log dir', info.dev.logs.dir ? `${show(info.dev.logs.dir)} (keeps ${info.dev.logs.keep})` : colors.dim('disabled')),\n\t\t\trow('layout', info.dev.layout),\n\t\t\trow('mouse', info.dev.mouse ? 'clickable dashboard' : colors.dim('left to the terminal')),\n\t\t\trow('channels', info.dev.logs.channels?.join(', ') ?? colors.dim('all')),\n\t\t\trow('levels', info.dev.logs.levels.join(', ')),\n\t\t\trow('commands', `refresh: ${info.dev.commands.refresh}`),\n\t\t\trow('hmr', info.dev.hmr ? 'left to the bot when it hot reloads' : colors.dim('always restart'))\n\t\t]),\n\t\tsection('Codegen', [\n\t\t\trow('i18n', info.codegen.i18n ? `${show(info.codegen.i18n.locales)} → ${show(info.codegen.i18n.output)}` : colors.dim('disabled')),\n\t\t\trow('commands', info.codegen.commands ? show(info.codegen.commands.output) : colors.dim('disabled'))\n\t\t]),\n\t\tsection('Future', [\n\t\t\trow('compat', `v${info.future.compatibilityVersion} defaults`),\n\t\t\t...info.warnings.map((warning) => row('warning', colors.yellow(warning)))\n\t\t]),\n\t\tsection('Env', [row('register', info.env.enabled ? colors.green(describeEnvOptions(info.env.options)) : colors.dim('disabled'))]),\n\t\tsection('Hooks', [row('registered', info.hooks.join(', ') || colors.dim('none'))]),\n\t\tsection('Modules', [\n\t\t\trow('installed', info.modules.installed.join(', ') || colors.dim('none')),\n\t\t\t...info.modules.plugins.map((plugin) => row('plugin', plugin))\n\t\t]),\n\t\tsection('Experimental', [\n\t\t\trow('vite', flag(info.experimental.enableVite, colors)),\n\t\t\trow('nitro', flag(info.experimental.enableNitro, colors)),\n\t\t\t...(info.experimental.enableNitro ? [row('nitro preset', info.experimental.nitro.preset)] : []),\n\t\t\trow('external', flag(info.experimental.enableExternalVite, colors))\n\t\t]),\n\t\tsection('Imports', [\n\t\t\trow('auto', info.imports.enabled ? colors.green('enabled') : colors.dim('disabled')),\n\t\t\trow('dirs', info.imports.dirs.map(show).join(', ')),\n\t\t\trow('presets', info.imports.presets.join(', ') || colors.dim('none')),\n\t\t\trow('dts', show(info.imports.dts))\n\t\t])\n\t].join('\\n\\n');\n}\n\nfunction describeOptions(info: ProjectInfo, colors: ReturnType<typeof createColors>): string {\n\tconst names = info.build.tool === 'vite' ? info.options.vite : info.options.tsdown;\n\treturn names.length > 0 ? names.join(', ') : colors.dim('none');\n}\n\nfunction describeEnvOptions(options: Readonly<StarsEnvSetupOptions>): string {\n\tconst entries = Object.entries(options).map(([key, value]) => `${key} ${String(value)}`);\n\treturn entries.length > 0 ? `enabled (${entries.join(', ')})` : 'enabled';\n}\n\nfunction flag(enabled: boolean, colors: ReturnType<typeof createColors>): string {\n\treturn enabled ? colors.green('enabled') : colors.dim('disabled');\n}\n\nfunction describeTunnel(tunnel: ResolvedStarsConfig['dev']['tunnel'], colors: ReturnType<typeof createColors>): string {\n\tswitch (tunnel.mode) {\n\t\tcase 'quick':\n\t\t\treturn 'cloudflared quick tunnel';\n\t\tcase 'url':\n\t\t\treturn tunnel.url;\n\t\tdefault:\n\t\t\treturn colors.dim('disabled');\n\t}\n}\n\nexport async function runInfo(options: InfoOptions): Promise<void> {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst project = await loadProject({ cwd: resolveCwd(options), configFile: options.config });\n\t// What the build would use: `env:options` may change the env files.\n\tconst config = await applyEnvOptions(project.config, project.hooks);\n\tconst info = collectInfo(config);\n\tstdout.write(`${options.json ? JSON.stringify(info, null, 2) : formatInfo(info, shouldUseColor())}\\n`);\n}\n\nexport default defineCommand({\n\tmeta: {\n\t\tname: 'info',\n\t\tdescription: 'Print the resolved project configuration and environment'\n\t},\n\targs: {\n\t\t...projectArgs,\n\t\tjson: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Print machine-readable JSON',\n\t\t\tdefault: false\n\t\t}\n\t},\n\tasync run({ args }) {\n\t\tawait runInfo({ config: args.config, cwd: args.cwd, json: args.json });\n\t}\n});\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as commands } from "./commands-
|
|
1
|
+
import { t as commands } from "./commands-BiY_99sF.js";
|
|
2
2
|
import { t as readOwnPackageJson } from "./version-BzclCE19.js";
|
|
3
3
|
import { n as exitCodeOf, r as formatError } from "./errors-COFWKKKw.js";
|
|
4
4
|
import { defineCommand, renderUsage, runCommand } from "citty";
|
|
@@ -52,4 +52,4 @@ async function runMain(argv = process.argv.slice(2)) {
|
|
|
52
52
|
|
|
53
53
|
//#endregion
|
|
54
54
|
export { runMain as t };
|
|
55
|
-
//# sourceMappingURL=run-
|
|
55
|
+
//# sourceMappingURL=run-BkfjbY7l.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-
|
|
1
|
+
{"version":3,"file":"run-BkfjbY7l.js","names":["_runCommand"],"sources":["../src/main.ts","../src/run.ts"],"sourcesContent":["import { defineCommand, type CommandDef } from 'citty';\nimport { commands } from './commands/index.js';\nimport { readOwnPackageJson } from './utils/version.js';\n\n// citty types each command by its own arguments; the registry needs the erased form.\n// oxlint-disable-next-line typescript/no-explicit-any\ntype AnyCommand = CommandDef<any>;\n\nconst packageJson = readOwnPackageJson();\n\nexport const main = defineCommand({\n\tmeta: {\n\t\tname: 'stars',\n\t\tversion: packageJson.version,\n\t\tdescription: packageJson.description\n\t},\n\tsubCommands: commands\n}) as AnyCommand;\n","import { renderUsage, runCommand as _runCommand, type CommandDef } from 'citty';\nimport process from 'node:process';\nimport { commands } from './commands/index.js';\nimport { main } from './main.js';\nimport { exitCodeOf, formatError } from './utils/errors.js';\nimport { readOwnPackageJson } from './utils/version.js';\n\n// citty types each command by its own arguments; the registry needs the erased form.\n// oxlint-disable-next-line typescript/no-explicit-any\ntype AnyCommand = CommandDef<any>;\n\n/**\n * Walks the command names of `stars <command> [<subcommand>] --help` so nested commands (`stars commands clean`)\n * render their own usage instead of their parent's.\n */\nasync function resolveHelpTarget(names: string[]): Promise<AnyCommand | null> {\n\tconst [first, ...rest] = names;\n\tif (!first || !Object.hasOwn(commands, first)) return null;\n\n\tlet command = await commands[first]!();\n\tfor (const name of rest) {\n\t\tconst resolved = typeof command.subCommands === 'function' ? await command.subCommands() : await command.subCommands;\n\t\tconst child: unknown = (resolved as Record<string, unknown> | undefined)?.[name];\n\t\tif (!child) break;\n\t\tcommand = (typeof child === 'function' ? await child() : child) as AnyCommand;\n\t}\n\n\treturn command;\n}\n\nexport async function runMain(argv: string[] = process.argv.slice(2)): Promise<void> {\n\tif (argv.includes('--version') || argv.includes('-V')) {\n\t\tconsole.log(readOwnPackageJson().version);\n\t\tprocess.exit(0);\n\t}\n\n\tif (argv.length === 0 || argv.includes('--help') || argv.includes('-h')) {\n\t\t// citty's showUsage logs through consola, which is muted in some environments; render and print directly.\n\t\tconst command = await resolveHelpTarget(argv.filter((argument) => !argument.startsWith('-')));\n\t\tconsole.log(await (command ? renderUsage(command, main) : renderUsage(main)));\n\t\tprocess.exit(0);\n\t}\n\n\ttry {\n\t\tawait _runCommand(main, { rawArgs: argv });\n\t} catch (error) {\n\t\tconsole.error(await formatError(error));\n\t\tprocess.exit(exitCodeOf(error));\n\t}\n}\n"],"mappings":";;;;;;;AAQA,MAAM,cAAc,mBAAmB;AAEvC,MAAa,OAAO,cAAc;CACjC,MAAM;EACL,MAAM;EACN,SAAS,YAAY;EACrB,aAAa,YAAY;CAC1B;CACA,aAAa;AACd,CAAC;;;;;;;;ACFD,eAAe,kBAAkB,OAA6C;CAC7E,MAAM,CAAC,OAAO,GAAG,QAAQ;CACzB,IAAI,CAAC,SAAS,CAAC,OAAO,OAAO,UAAU,KAAK,GAAG,OAAO;CAEtD,IAAI,UAAU,MAAM,SAAS,MAAM,CAAE;CACrC,KAAK,MAAM,QAAQ,MAAM;EAExB,MAAM,SADW,OAAO,QAAQ,gBAAgB,aAAa,MAAM,QAAQ,YAAY,IAAI,MAAM,QAAQ,YACzE,GAA2C;EAC3E,IAAI,CAAC,OAAO;EACZ,UAAW,OAAO,UAAU,aAAa,MAAM,MAAM,IAAI;CAC1D;CAEA,OAAO;AACR;AAEA,eAAsB,QAAQ,OAAiB,QAAQ,KAAK,MAAM,CAAC,GAAkB;CACpF,IAAI,KAAK,SAAS,WAAW,KAAK,KAAK,SAAS,IAAI,GAAG;EACtD,QAAQ,IAAI,mBAAmB,CAAC,CAAC,OAAO;EACxC,QAAQ,KAAK,CAAC;CACf;CAEA,IAAI,KAAK,WAAW,KAAK,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,IAAI,GAAG;EAExE,MAAM,UAAU,MAAM,kBAAkB,KAAK,QAAQ,aAAa,CAAC,SAAS,WAAW,GAAG,CAAC,CAAC;EAC5F,QAAQ,IAAI,OAAO,UAAU,YAAY,SAAS,IAAI,IAAI,YAAY,IAAI,EAAE;EAC5E,QAAQ,KAAK,CAAC;CACf;CAEA,IAAI;EACH,MAAMA,WAAY,MAAM,EAAE,SAAS,KAAK,CAAC;CAC1C,SAAS,OAAO;EACf,QAAQ,MAAM,MAAM,YAAY,KAAK,CAAC;EACtC,QAAQ,KAAK,WAAW,KAAK,CAAC;CAC/B;AACD"}
|
|
@@ -9,6 +9,7 @@ import { stripVTControlCharacters } from "node:util";
|
|
|
9
9
|
import { Box, Text, render, useInput, useWindowSize } from "ink";
|
|
10
10
|
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
11
11
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
+
import { PassThrough } from "node:stream";
|
|
12
13
|
import { StringDecoder } from "node:string_decoder";
|
|
13
14
|
|
|
14
15
|
//#region src/dev/tui/ink/hooks/useLogVersion.ts
|
|
@@ -364,6 +365,13 @@ function useUptime(startedAt) {
|
|
|
364
365
|
|
|
365
366
|
//#endregion
|
|
366
367
|
//#region src/dev/tui/ink/components/Sidebar.tsx
|
|
368
|
+
/** The region of the sidebar at a cell, if a click there does something. */
|
|
369
|
+
function findSidebarRegion(regions, row, column) {
|
|
370
|
+
return regions.find((region) => region.row === row && (region.kind !== "item" || column >= region.start && column < region.end)) ?? null;
|
|
371
|
+
}
|
|
372
|
+
/** The padding of the sidebar, then the indentation of the lines of a group. */
|
|
373
|
+
const PADDING = 1;
|
|
374
|
+
const INDENT = 2;
|
|
367
375
|
const LEVEL_TOKENS = {
|
|
368
376
|
error: "error",
|
|
369
377
|
warn: "warning",
|
|
@@ -411,7 +419,7 @@ function readFrameworkVersion(root) {
|
|
|
411
419
|
* short terminal the key help goes first, then the filters' own hints: the status and the filters are what it is for.
|
|
412
420
|
*/
|
|
413
421
|
function Sidebar(props) {
|
|
414
|
-
const { status, config, counters, filter, channels, focus, collapsed, live, grouped, frame, elapsedMs, width, height, confirmQuit } = props;
|
|
422
|
+
const { status, config, counters, filter, channels, focus, collapsed, live, grouped, frame, elapsedMs, width, height, confirmQuit, onRegions } = props;
|
|
415
423
|
const paint = usePaint();
|
|
416
424
|
const uptime = useUptime(status.startedAt);
|
|
417
425
|
const state = describeBadge(status);
|
|
@@ -556,10 +564,28 @@ function Sidebar(props) {
|
|
|
556
564
|
};
|
|
557
565
|
const budget = Math.max(1, height - 1);
|
|
558
566
|
const labelWidth = Math.max(1, inner - 2);
|
|
559
|
-
const lines = (group, labels, nodes, range = [0, Infinity]) => wrapLabels(labels, labelWidth).slice(...range).map((line, index) =>
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
567
|
+
const lines = (group, labels, nodes, range = [0, Infinity]) => wrapLabels(labels, labelWidth).slice(...range).map((line, index) => {
|
|
568
|
+
let column = 3;
|
|
569
|
+
return {
|
|
570
|
+
hit: {
|
|
571
|
+
kind: "items",
|
|
572
|
+
group,
|
|
573
|
+
items: line.map((label) => {
|
|
574
|
+
const start = column;
|
|
575
|
+
column += labels[label].length + 1;
|
|
576
|
+
return {
|
|
577
|
+
index: label,
|
|
578
|
+
start,
|
|
579
|
+
end: column - 1
|
|
580
|
+
};
|
|
581
|
+
})
|
|
582
|
+
},
|
|
583
|
+
node: /* @__PURE__ */ jsxs(Text, {
|
|
584
|
+
wrap: "truncate-end",
|
|
585
|
+
children: [" ".repeat(INDENT), line.flatMap((label, position) => position > 0 ? [" ", nodes[label]] : [nodes[label]])]
|
|
586
|
+
}, `${group}-${index}`)
|
|
587
|
+
};
|
|
588
|
+
});
|
|
563
589
|
const levelNodes = VIEW_LEVELS.map((level, index) => item("levels", index, level, filter.levels.has(level), LEVEL_TOKENS[level]));
|
|
564
590
|
const levelLines = collapsed.levels ? [] : lines("levels", VIEW_LEVELS, levelNodes);
|
|
565
591
|
const channelNodes = channels.map((channel, index) => item("channels", index, channel, isChannelVisible(filter, channel), channelToken(channel)));
|
|
@@ -568,46 +594,80 @@ function Sidebar(props) {
|
|
|
568
594
|
const range = windowAround(channelLayout.length, focusedLine, Math.max(1, budget - head.length - 3 - levelLines.length));
|
|
569
595
|
const hiddenChannels = channelLayout.length - (range[1] - range[0]);
|
|
570
596
|
const filters = [
|
|
571
|
-
/* @__PURE__ */ jsx(Text, { children: " " }, "gap-filters"),
|
|
572
|
-
|
|
597
|
+
{ node: /* @__PURE__ */ jsx(Text, { children: " " }, "gap-filters") },
|
|
598
|
+
{
|
|
599
|
+
hit: {
|
|
600
|
+
kind: "header",
|
|
601
|
+
group: "channels"
|
|
602
|
+
},
|
|
603
|
+
node: groupHeader("channels", !collapsed.channels && hiddenChannels > 0 ? ` · ${range[0] + 1}-${range[1]}/${channelLayout.length}` : "")
|
|
604
|
+
},
|
|
573
605
|
...collapsed.channels ? [] : lines("channels", channels, channelNodes, range),
|
|
574
|
-
|
|
606
|
+
{
|
|
607
|
+
hit: {
|
|
608
|
+
kind: "header",
|
|
609
|
+
group: "levels"
|
|
610
|
+
},
|
|
611
|
+
node: groupHeader("levels")
|
|
612
|
+
},
|
|
575
613
|
...levelLines
|
|
576
614
|
];
|
|
577
|
-
const keys = KEYS$1.map((section, sectionIndex) => [/* @__PURE__ */ jsx(Text, { children: " " }, `gap-keys-${sectionIndex}`), ...section.map(([key, label]) =>
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
615
|
+
const keys = KEYS$1.map((section, sectionIndex) => [{ node: /* @__PURE__ */ jsx(Text, { children: " " }, `gap-keys-${sectionIndex}`) }, ...section.map(([key, label]) => ({
|
|
616
|
+
hit: {
|
|
617
|
+
kind: "key",
|
|
618
|
+
key
|
|
619
|
+
},
|
|
620
|
+
node: /* @__PURE__ */ jsxs(Text, {
|
|
621
|
+
wrap: "truncate-end",
|
|
622
|
+
children: [
|
|
623
|
+
/* @__PURE__ */ jsx(Text, {
|
|
624
|
+
bold: true,
|
|
625
|
+
color: paint("url"),
|
|
626
|
+
children: key
|
|
627
|
+
}),
|
|
628
|
+
" ",
|
|
629
|
+
/* @__PURE__ */ jsx(Text, {
|
|
630
|
+
dimColor: true,
|
|
631
|
+
children: label
|
|
632
|
+
})
|
|
633
|
+
]
|
|
634
|
+
}, key)
|
|
635
|
+
}))]);
|
|
636
|
+
const statusRows = head.map((node) => ({ node }));
|
|
592
637
|
let body = [
|
|
593
|
-
...
|
|
638
|
+
...statusRows,
|
|
594
639
|
...filters,
|
|
595
640
|
...keys.flat()
|
|
596
641
|
];
|
|
597
642
|
if (body.length > budget) body = [
|
|
598
|
-
...
|
|
643
|
+
...statusRows,
|
|
599
644
|
...filters,
|
|
600
645
|
...keys[1]
|
|
601
646
|
];
|
|
602
|
-
if (body.length > budget) body = [...
|
|
647
|
+
if (body.length > budget) body = [...statusRows, ...filters];
|
|
603
648
|
body = body.slice(0, budget);
|
|
649
|
+
const regions = body.flatMap(({ hit }, row) => {
|
|
650
|
+
if (hit === void 0) return [];
|
|
651
|
+
if (hit.kind === "items") return hit.items.map((item) => ({
|
|
652
|
+
kind: "item",
|
|
653
|
+
group: hit.group,
|
|
654
|
+
row,
|
|
655
|
+
...item
|
|
656
|
+
}));
|
|
657
|
+
return [{
|
|
658
|
+
...hit,
|
|
659
|
+
row
|
|
660
|
+
}];
|
|
661
|
+
});
|
|
662
|
+
const regionsKey = JSON.stringify(regions);
|
|
663
|
+
useEffect(() => onRegions?.(regions), [regionsKey, onRegions]);
|
|
604
664
|
return /* @__PURE__ */ jsxs(Box, {
|
|
605
665
|
flexDirection: "column",
|
|
606
666
|
width,
|
|
607
667
|
height,
|
|
608
|
-
paddingX:
|
|
668
|
+
paddingX: PADDING,
|
|
609
669
|
children: [
|
|
610
|
-
body.map((node, index) => /* @__PURE__ */ jsx(Box, {
|
|
670
|
+
body.map(({ node }, index) => /* @__PURE__ */ jsx(Box, {
|
|
611
671
|
height: 1,
|
|
612
672
|
width: inner,
|
|
613
673
|
children: node
|
|
@@ -638,6 +698,17 @@ function Sidebar(props) {
|
|
|
638
698
|
|
|
639
699
|
//#endregion
|
|
640
700
|
//#region src/dev/tui/ink/components/Dashboard.tsx
|
|
701
|
+
/** How many rows a notch of the wheel scrolls. */
|
|
702
|
+
const WHEEL_ROWS = 3;
|
|
703
|
+
/** Two clicks on the same entry within this many milliseconds are a double click. */
|
|
704
|
+
const DOUBLE_CLICK_MS = 400;
|
|
705
|
+
const NO_KEY = {};
|
|
706
|
+
/** The keys of the sidebar a click can press, by how the sidebar writes them: the others stand for several keys. */
|
|
707
|
+
const HINT_KEYS = {
|
|
708
|
+
tab: ["", { tab: true }],
|
|
709
|
+
space: [" ", {}],
|
|
710
|
+
s: ["s", {}]
|
|
711
|
+
};
|
|
641
712
|
/** The sidebar takes about a quarter of the terminal, within what its longest lines need and can spare. */
|
|
642
713
|
function sidebarWidth(columns) {
|
|
643
714
|
return Math.max(24, Math.min(34, Math.floor(columns * .26)));
|
|
@@ -648,7 +719,7 @@ function sidebarWidth(columns) {
|
|
|
648
719
|
* here only change what is looked at.
|
|
649
720
|
*/
|
|
650
721
|
function Dashboard(props) {
|
|
651
|
-
const { service, status, counters, frame, elapsedMs, width, height, confirmQuit, initialFilter, active, onCapture } = props;
|
|
722
|
+
const { service, status, counters, frame, elapsedMs, width, height, confirmQuit, initialFilter, active, onCapture, mouse, onKey } = props;
|
|
652
723
|
const paint = usePaint();
|
|
653
724
|
const [filter, setFilter] = useState(initialFilter);
|
|
654
725
|
const [focus, setFocus] = useState({
|
|
@@ -664,6 +735,11 @@ function Dashboard(props) {
|
|
|
664
735
|
const [pinned, setPinned] = useState(null);
|
|
665
736
|
const [marked, setMarked] = useState(null);
|
|
666
737
|
const version = useLogVersion(service.logs);
|
|
738
|
+
const regions = useRef([]);
|
|
739
|
+
const lastClick = useRef(null);
|
|
740
|
+
const onRegions = useCallback((next) => {
|
|
741
|
+
regions.current = next;
|
|
742
|
+
}, []);
|
|
667
743
|
const channels = useMemo(() => [.../* @__PURE__ */ new Set([...initialFilter.allow ?? [], ...service.logs.channels()])].sort(), [
|
|
668
744
|
service,
|
|
669
745
|
initialFilter,
|
|
@@ -694,7 +770,7 @@ function Dashboard(props) {
|
|
|
694
770
|
const scroll = (delta) => {
|
|
695
771
|
setPinned(pinAt(rows, Math.max(Math.min(paneHeight, rows.length), end + delta)));
|
|
696
772
|
};
|
|
697
|
-
|
|
773
|
+
const handleKey = (input, key) => {
|
|
698
774
|
if (key.ctrl || confirmQuit) return;
|
|
699
775
|
if (searching) {
|
|
700
776
|
if (key.escape) {
|
|
@@ -770,7 +846,64 @@ function Dashboard(props) {
|
|
|
770
846
|
setMarked(row.kind === "entry" ? row.entry.id : null);
|
|
771
847
|
setPinned(pinAt(rows, Math.max(paneHeight, index + Math.ceil(paneHeight / 2))));
|
|
772
848
|
}
|
|
773
|
-
}
|
|
849
|
+
};
|
|
850
|
+
useInput(handleKey, { isActive: active });
|
|
851
|
+
const select = (from, group, index, solo) => {
|
|
852
|
+
const target = (group === "channels" ? channels : VIEW_LEVELS)[index];
|
|
853
|
+
if (target === void 0) return;
|
|
854
|
+
setFocus({
|
|
855
|
+
group,
|
|
856
|
+
index
|
|
857
|
+
});
|
|
858
|
+
if (group === "channels") return change(solo ? soloChannel(from, target) : toggleChannel(from, target));
|
|
859
|
+
const level = target;
|
|
860
|
+
return change(solo ? soloLevel(from, level) : toggleLevel(from, level));
|
|
861
|
+
};
|
|
862
|
+
const handleMouse = (event) => {
|
|
863
|
+
if (confirmQuit) return;
|
|
864
|
+
if (event.kind === "wheel") {
|
|
865
|
+
if (event.column >= side) scroll(event.wheel * WHEEL_ROWS);
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
if (event.kind !== "press" || event.button !== "left" || event.column >= side) return;
|
|
869
|
+
const region = findSidebarRegion(regions.current, event.row, event.column);
|
|
870
|
+
if (region === null) return;
|
|
871
|
+
if (region.kind === "header") {
|
|
872
|
+
setFocus((current) => current.group === region.group ? current : {
|
|
873
|
+
group: region.group,
|
|
874
|
+
index: 0
|
|
875
|
+
});
|
|
876
|
+
return setCollapsed((current) => ({
|
|
877
|
+
...current,
|
|
878
|
+
[region.group]: !current[region.group]
|
|
879
|
+
}));
|
|
880
|
+
}
|
|
881
|
+
if (region.kind === "key") {
|
|
882
|
+
if (searching) return;
|
|
883
|
+
const own = HINT_KEYS[region.key];
|
|
884
|
+
return own ? handleKey(own[0], {
|
|
885
|
+
...NO_KEY,
|
|
886
|
+
...own[1]
|
|
887
|
+
}) : onKey(region.key);
|
|
888
|
+
}
|
|
889
|
+
const now = Date.now();
|
|
890
|
+
const previous = lastClick.current;
|
|
891
|
+
const double = previous !== null && previous.group === region.group && previous.index === region.index && now - previous.at <= DOUBLE_CLICK_MS;
|
|
892
|
+
lastClick.current = double ? null : {
|
|
893
|
+
group: region.group,
|
|
894
|
+
index: region.index,
|
|
895
|
+
at: now,
|
|
896
|
+
filter
|
|
897
|
+
};
|
|
898
|
+
if (double) return select(previous.filter, region.group, region.index, true);
|
|
899
|
+
return select(filter, region.group, region.index, event.alt || event.ctrl);
|
|
900
|
+
};
|
|
901
|
+
const mouseHandler = useRef(handleMouse);
|
|
902
|
+
mouseHandler.current = handleMouse;
|
|
903
|
+
useEffect(() => {
|
|
904
|
+
if (!mouse || !active) return void 0;
|
|
905
|
+
return mouse.subscribe((event) => mouseHandler.current(event));
|
|
906
|
+
}, [mouse, active]);
|
|
774
907
|
return /* @__PURE__ */ jsxs(Box, {
|
|
775
908
|
width,
|
|
776
909
|
height,
|
|
@@ -788,7 +921,8 @@ function Dashboard(props) {
|
|
|
788
921
|
elapsedMs,
|
|
789
922
|
width: side,
|
|
790
923
|
height,
|
|
791
|
-
confirmQuit
|
|
924
|
+
confirmQuit,
|
|
925
|
+
onRegions
|
|
792
926
|
}), /* @__PURE__ */ jsxs(Box, {
|
|
793
927
|
flexDirection: "column",
|
|
794
928
|
width: mainWidth + 1,
|
|
@@ -1587,7 +1721,8 @@ function resolveLayout(layout, columns, rows) {
|
|
|
1587
1721
|
* the bottom of the normal buffer with the logs folded away, and is what a small terminal gets. The browsable
|
|
1588
1722
|
* overlays use the alternate buffer from either, preserving the terminal's history and the panel when they close.
|
|
1589
1723
|
*/
|
|
1590
|
-
function DevApp(
|
|
1724
|
+
function DevApp(props) {
|
|
1725
|
+
const { service, color, theme, reducedMotion, layout = "auto", filter, onQuit, onViewChange, onCopy, onThemeSave, mouse, onMouseChange } = props;
|
|
1591
1726
|
const { columns, rows } = useWindowSize();
|
|
1592
1727
|
const [overlay, setOverlay] = useState(null);
|
|
1593
1728
|
const [chosen, setChosen] = useState(layout);
|
|
@@ -1620,18 +1755,13 @@ function DevApp({ service, color, theme, reducedMotion, layout = "auto", filter,
|
|
|
1620
1755
|
onViewChange(fullScreen);
|
|
1621
1756
|
repaint((count) => count + 1);
|
|
1622
1757
|
}, [fullScreen, onViewChange]);
|
|
1758
|
+
const takesMouse = base === "dashboard" && overlay === null;
|
|
1759
|
+
useEffect(() => {
|
|
1760
|
+
onMouseChange?.(takesMouse);
|
|
1761
|
+
}, [takesMouse, onMouseChange]);
|
|
1623
1762
|
const onCapture = useCallback((capturing) => setCaptured(capturing), []);
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
if (key.ctrl && input === "l") return service.clearLogs();
|
|
1627
|
-
if (overlay !== null || captured) return;
|
|
1628
|
-
if (confirmQuit) {
|
|
1629
|
-
if (input === "y") return onQuit();
|
|
1630
|
-
return setConfirmQuit(false);
|
|
1631
|
-
}
|
|
1632
|
-
if (key.ctrl && input === "r") return void service.restart("manual");
|
|
1633
|
-
if (key.ctrl && input === "d") return busy ? setConfirmQuit(true) : onQuit();
|
|
1634
|
-
if (status.prompt && (input === "y" || input === "n")) return service.answerPrompt(input === "y");
|
|
1763
|
+
/** The keys that act on the session or change the view; also what a click on their hint in the sidebar runs. */
|
|
1764
|
+
const runKey = (input) => {
|
|
1635
1765
|
switch (input) {
|
|
1636
1766
|
case "q": return busy ? setConfirmQuit(true) : onQuit();
|
|
1637
1767
|
case "r":
|
|
@@ -1655,6 +1785,19 @@ function DevApp({ service, color, theme, reducedMotion, layout = "auto", filter,
|
|
|
1655
1785
|
case "h":
|
|
1656
1786
|
case "?": return show("help");
|
|
1657
1787
|
}
|
|
1788
|
+
};
|
|
1789
|
+
useInput((input, key) => {
|
|
1790
|
+
if (key.ctrl && input === "c") return onQuit();
|
|
1791
|
+
if (key.ctrl && input === "l") return service.clearLogs();
|
|
1792
|
+
if (overlay !== null || captured) return;
|
|
1793
|
+
if (confirmQuit) {
|
|
1794
|
+
if (input === "y") return onQuit();
|
|
1795
|
+
return setConfirmQuit(false);
|
|
1796
|
+
}
|
|
1797
|
+
if (key.ctrl && input === "r") return void service.restart("manual");
|
|
1798
|
+
if (key.ctrl && input === "d") return busy ? setConfirmQuit(true) : onQuit();
|
|
1799
|
+
if (status.prompt && (input === "y" || input === "n")) return service.answerPrompt(input === "y");
|
|
1800
|
+
runKey(input);
|
|
1658
1801
|
});
|
|
1659
1802
|
return /* @__PURE__ */ jsx(ThemeProvider, {
|
|
1660
1803
|
color,
|
|
@@ -1712,7 +1855,9 @@ function DevApp({ service, color, theme, reducedMotion, layout = "auto", filter,
|
|
|
1712
1855
|
confirmQuit,
|
|
1713
1856
|
initialFilter,
|
|
1714
1857
|
active: overlay === null,
|
|
1715
|
-
onCapture
|
|
1858
|
+
onCapture,
|
|
1859
|
+
mouse,
|
|
1860
|
+
onKey: runKey
|
|
1716
1861
|
})
|
|
1717
1862
|
}),
|
|
1718
1863
|
base === "panel" && overlay === null && /* @__PURE__ */ jsx(Panel, {
|
|
@@ -1729,6 +1874,113 @@ function DevApp({ service, color, theme, reducedMotion, layout = "auto", filter,
|
|
|
1729
1874
|
});
|
|
1730
1875
|
}
|
|
1731
1876
|
|
|
1877
|
+
//#endregion
|
|
1878
|
+
//#region src/dev/tui/mouse.ts
|
|
1879
|
+
/**
|
|
1880
|
+
* Asks the terminal to report button presses and the wheel (`1000`), with coordinates in the SGR form (`1006`),
|
|
1881
|
+
* which is not limited to 223 columns. Motion is left off: nothing here reacts to a hover, and it is one sequence
|
|
1882
|
+
* per cell the pointer crosses. A terminal that knows neither ignores both.
|
|
1883
|
+
*/
|
|
1884
|
+
const ENABLE_MOUSE = "\x1B[?1000h\x1B[?1006h";
|
|
1885
|
+
const DISABLE_MOUSE = "\x1B[?1006l\x1B[?1000l";
|
|
1886
|
+
const SGR_MOUSE = /\u001B\[<(\d+);(\d+);(\d+)([Mm])/g;
|
|
1887
|
+
/** The start of a report whose end has not arrived yet, at the end of a chunk. */
|
|
1888
|
+
const PARTIAL_SGR_MOUSE = /\u001B(?:\[(?:<[\d;]*)?)?$/;
|
|
1889
|
+
const BUTTONS = [
|
|
1890
|
+
"left",
|
|
1891
|
+
"middle",
|
|
1892
|
+
"right",
|
|
1893
|
+
"none"
|
|
1894
|
+
];
|
|
1895
|
+
/**
|
|
1896
|
+
* Splits what the terminal sent into the mouse reports and everything else.
|
|
1897
|
+
*
|
|
1898
|
+
* @param chunk - A chunk read from the terminal.
|
|
1899
|
+
* @returns The mouse events of the chunk, and the chunk without their sequences: the keys the user typed.
|
|
1900
|
+
*/
|
|
1901
|
+
function parseMouse(chunk) {
|
|
1902
|
+
const events = [];
|
|
1903
|
+
return {
|
|
1904
|
+
events,
|
|
1905
|
+
rest: chunk.replace(SGR_MOUSE, (_match, code, column, row, final) => {
|
|
1906
|
+
const bits = Number(code);
|
|
1907
|
+
if ((bits & 32) !== 0 || (bits & 128) !== 0) return "";
|
|
1908
|
+
const wheel = (bits & 64) !== 0;
|
|
1909
|
+
if (wheel && (bits & 2) !== 0) return "";
|
|
1910
|
+
const event = {
|
|
1911
|
+
column: Number(column) - 1,
|
|
1912
|
+
row: Number(row) - 1,
|
|
1913
|
+
shift: (bits & 4) !== 0,
|
|
1914
|
+
alt: (bits & 8) !== 0,
|
|
1915
|
+
ctrl: (bits & 16) !== 0
|
|
1916
|
+
};
|
|
1917
|
+
if (wheel) events.push({
|
|
1918
|
+
...event,
|
|
1919
|
+
kind: "wheel",
|
|
1920
|
+
button: "none",
|
|
1921
|
+
wheel: (bits & 1) === 0 ? -1 : 1
|
|
1922
|
+
});
|
|
1923
|
+
else events.push({
|
|
1924
|
+
...event,
|
|
1925
|
+
kind: final === "M" ? "press" : "release",
|
|
1926
|
+
button: BUTTONS[bits & 3],
|
|
1927
|
+
wheel: 0
|
|
1928
|
+
});
|
|
1929
|
+
return "";
|
|
1930
|
+
})
|
|
1931
|
+
};
|
|
1932
|
+
}
|
|
1933
|
+
/**
|
|
1934
|
+
* Reads the terminal's input ahead of the UI, so that a mouse report is never taken for typed text: Ink would
|
|
1935
|
+
* otherwise hand `ESC[<0;12;5M` to its key handlers, and a click while searching would type it into the query.
|
|
1936
|
+
*
|
|
1937
|
+
* @param source - The terminal's input.
|
|
1938
|
+
*/
|
|
1939
|
+
function createMouseInput(source) {
|
|
1940
|
+
const filtered = new PassThrough();
|
|
1941
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1942
|
+
const decoder = new StringDecoder("utf8");
|
|
1943
|
+
let pending = "";
|
|
1944
|
+
const onData = (data) => {
|
|
1945
|
+
const { events, rest } = parseMouse(pending + (typeof data === "string" ? data : decoder.write(data)));
|
|
1946
|
+
const partial = rest.length > 1 ? PARTIAL_SGR_MOUSE.exec(rest) : null;
|
|
1947
|
+
const held = partial && partial[0].length > 1 ? partial[0] : "";
|
|
1948
|
+
pending = held;
|
|
1949
|
+
const keys = held ? rest.slice(0, -held.length) : rest;
|
|
1950
|
+
if (keys) filtered.write(keys);
|
|
1951
|
+
for (const event of events) for (const listener of listeners) listener(event);
|
|
1952
|
+
};
|
|
1953
|
+
source.on("data", onData);
|
|
1954
|
+
const stdin = Object.assign(filtered, {
|
|
1955
|
+
isTTY: source.isTTY,
|
|
1956
|
+
setRawMode(mode) {
|
|
1957
|
+
source.setRawMode?.(mode);
|
|
1958
|
+
return stdin;
|
|
1959
|
+
},
|
|
1960
|
+
ref() {
|
|
1961
|
+
source.ref?.();
|
|
1962
|
+
return stdin;
|
|
1963
|
+
},
|
|
1964
|
+
unref() {
|
|
1965
|
+
source.unref?.();
|
|
1966
|
+
return stdin;
|
|
1967
|
+
}
|
|
1968
|
+
});
|
|
1969
|
+
return {
|
|
1970
|
+
stdin,
|
|
1971
|
+
subscribe(listener) {
|
|
1972
|
+
listeners.add(listener);
|
|
1973
|
+
return () => listeners.delete(listener);
|
|
1974
|
+
},
|
|
1975
|
+
dispose() {
|
|
1976
|
+
source.off("data", onData);
|
|
1977
|
+
source.pause?.();
|
|
1978
|
+
listeners.clear();
|
|
1979
|
+
filtered.end();
|
|
1980
|
+
}
|
|
1981
|
+
};
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1732
1984
|
//#endregion
|
|
1733
1985
|
//#region src/dev/tui/capture-output.ts
|
|
1734
1986
|
/** Capture third-party writes before build plugins run. Ink writes through a separate, unpatched sink. */
|
|
@@ -1781,6 +2033,13 @@ function createTuiRenderer(service, options = {}) {
|
|
|
1781
2033
|
const restoreOutput = stdout === process.stdout ? [captureOutput(service, process.stdout, "info"), captureOutput(service, process.stderr, "warn")] : [];
|
|
1782
2034
|
const layout = options.layout ?? service.config.dev.layout ?? "auto";
|
|
1783
2035
|
let alternate = resolveLayout(layout, stdout.columns ?? 80, stdout.rows ?? 24) === "dashboard";
|
|
2036
|
+
const mouse = options.mouse ?? service.config.dev.mouse ? createMouseInput(stdin) : null;
|
|
2037
|
+
let reporting = false;
|
|
2038
|
+
const reportMouse = (wanted) => {
|
|
2039
|
+
if (!mouse || wanted === reporting) return;
|
|
2040
|
+
reporting = wanted;
|
|
2041
|
+
write(wanted ? ENABLE_MOUSE : DISABLE_MOUSE);
|
|
2042
|
+
};
|
|
1784
2043
|
if (alternate) write("\x1B[?1049h\x1B[H");
|
|
1785
2044
|
let stopped = false;
|
|
1786
2045
|
const switchView = (fullScreen) => {
|
|
@@ -1804,10 +2063,14 @@ function createTuiRenderer(service, options = {}) {
|
|
|
1804
2063
|
filter: options.filter,
|
|
1805
2064
|
onQuit: quit,
|
|
1806
2065
|
onViewChange: switchView,
|
|
1807
|
-
onCopy: (text) => write(`\u001B]52;c;${Buffer.from(text.slice(0, 65536)).toString("base64")}\u0007`)
|
|
2066
|
+
onCopy: (text) => write(`\u001B]52;c;${Buffer.from(text.slice(0, 65536)).toString("base64")}\u0007`),
|
|
2067
|
+
mouse: mouse ?? void 0,
|
|
2068
|
+
onMouseChange: (wanted) => {
|
|
2069
|
+
if (!stopped) reportMouse(wanted);
|
|
2070
|
+
}
|
|
1808
2071
|
}), {
|
|
1809
2072
|
stdout: sink,
|
|
1810
|
-
stdin,
|
|
2073
|
+
stdin: mouse?.stdin ?? stdin,
|
|
1811
2074
|
exitOnCtrlC: false,
|
|
1812
2075
|
patchConsole: false,
|
|
1813
2076
|
interactive: true,
|
|
@@ -1823,7 +2086,9 @@ function createTuiRenderer(service, options = {}) {
|
|
|
1823
2086
|
service.promptable = false;
|
|
1824
2087
|
if (alternate) instance.clear();
|
|
1825
2088
|
instance.unmount();
|
|
2089
|
+
reportMouse(false);
|
|
1826
2090
|
if (alternate) write("\x1B[?1049l");
|
|
2091
|
+
mouse?.dispose();
|
|
1827
2092
|
write("\x1B[?25h");
|
|
1828
2093
|
for (const restore of restoreOutput) restore();
|
|
1829
2094
|
if (service.status.progress.readyMs === null) {
|
|
@@ -1837,4 +2102,4 @@ function createTuiRenderer(service, options = {}) {
|
|
|
1837
2102
|
|
|
1838
2103
|
//#endregion
|
|
1839
2104
|
export { createTuiRenderer };
|
|
1840
|
-
//# sourceMappingURL=tui-
|
|
2105
|
+
//# sourceMappingURL=tui-BOkOx13K.js.map
|