@bramburn/qi-tui 0.0.0-stage → 0.85.1
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 +853 -2
- package/dist/alt-screen-search.d.ts +26 -0
- package/dist/alt-screen-search.d.ts.map +1 -0
- package/dist/alt-screen-search.js +122 -0
- package/dist/alt-screen-search.js.map +1 -0
- package/dist/autocomplete.d.ts +57 -0
- package/dist/autocomplete.d.ts.map +1 -0
- package/dist/autocomplete.js +665 -0
- package/dist/autocomplete.js.map +1 -0
- package/dist/components/alt-screen-flash.d.ts +13 -0
- package/dist/components/alt-screen-flash.d.ts.map +1 -0
- package/dist/components/alt-screen-flash.js +37 -0
- package/dist/components/alt-screen-flash.js.map +1 -0
- package/dist/components/box.d.ts +22 -0
- package/dist/components/box.d.ts.map +1 -0
- package/dist/components/box.js +104 -0
- package/dist/components/box.js.map +1 -0
- package/dist/components/cancellable-loader.d.ts +22 -0
- package/dist/components/cancellable-loader.d.ts.map +1 -0
- package/dist/components/cancellable-loader.js +35 -0
- package/dist/components/cancellable-loader.js.map +1 -0
- package/dist/components/editor.d.ts +385 -0
- package/dist/components/editor.d.ts.map +1 -0
- package/dist/components/editor.js +2246 -0
- package/dist/components/editor.js.map +1 -0
- package/dist/components/h-stack.d.ts +7 -0
- package/dist/components/h-stack.d.ts.map +1 -0
- package/dist/components/h-stack.js +43 -0
- package/dist/components/h-stack.js.map +1 -0
- package/dist/components/image.d.ts +28 -0
- package/dist/components/image.d.ts.map +1 -0
- package/dist/components/image.js +90 -0
- package/dist/components/image.js.map +1 -0
- package/dist/components/input.d.ts +37 -0
- package/dist/components/input.d.ts.map +1 -0
- package/dist/components/input.js +378 -0
- package/dist/components/input.js.map +1 -0
- package/dist/components/loader.d.ts +31 -0
- package/dist/components/loader.d.ts.map +1 -0
- package/dist/components/loader.js +69 -0
- package/dist/components/loader.js.map +1 -0
- package/dist/components/markdown.d.ts +103 -0
- package/dist/components/markdown.d.ts.map +1 -0
- package/dist/components/markdown.js +811 -0
- package/dist/components/markdown.js.map +1 -0
- package/dist/components/scroll-view.d.ts +56 -0
- package/dist/components/scroll-view.d.ts.map +1 -0
- package/dist/components/scroll-view.js +189 -0
- package/dist/components/scroll-view.js.map +1 -0
- package/dist/components/select-list.d.ts +50 -0
- package/dist/components/select-list.d.ts.map +1 -0
- package/dist/components/select-list.js +159 -0
- package/dist/components/select-list.js.map +1 -0
- package/dist/components/settings-list.d.ts +56 -0
- package/dist/components/settings-list.d.ts.map +1 -0
- package/dist/components/settings-list.js +202 -0
- package/dist/components/settings-list.js.map +1 -0
- package/dist/components/spacer.d.ts +12 -0
- package/dist/components/spacer.d.ts.map +1 -0
- package/dist/components/spacer.js +23 -0
- package/dist/components/spacer.js.map +1 -0
- package/dist/components/stack.d.ts +32 -0
- package/dist/components/stack.d.ts.map +1 -0
- package/dist/components/stack.js +111 -0
- package/dist/components/stack.js.map +1 -0
- package/dist/components/text.d.ts +19 -0
- package/dist/components/text.d.ts.map +1 -0
- package/dist/components/text.js +90 -0
- package/dist/components/text.js.map +1 -0
- package/dist/components/truncated-text.d.ts +13 -0
- package/dist/components/truncated-text.d.ts.map +1 -0
- package/dist/components/truncated-text.js +51 -0
- package/dist/components/truncated-text.js.map +1 -0
- package/dist/components/v-stack.d.ts +8 -0
- package/dist/components/v-stack.d.ts.map +1 -0
- package/dist/components/v-stack.js +26 -0
- package/dist/components/v-stack.js.map +1 -0
- package/dist/editor-component.d.ts +68 -0
- package/dist/editor-component.d.ts.map +1 -0
- package/dist/editor-component.js +2 -0
- package/dist/editor-component.js.map +1 -0
- package/dist/fuzzy.d.ts +16 -0
- package/dist/fuzzy.d.ts.map +1 -0
- package/dist/fuzzy.js +110 -0
- package/dist/fuzzy.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/keybindings.d.ts +273 -0
- package/dist/keybindings.d.ts.map +1 -0
- package/dist/keybindings.js +232 -0
- package/dist/keybindings.js.map +1 -0
- package/dist/keys.d.ts +184 -0
- package/dist/keys.d.ts.map +1 -0
- package/dist/keys.js +1186 -0
- package/dist/keys.js.map +1 -0
- package/dist/kill-ring.d.ts +28 -0
- package/dist/kill-ring.d.ts.map +1 -0
- package/dist/kill-ring.js +44 -0
- package/dist/kill-ring.js.map +1 -0
- package/dist/latex.d.ts +10 -0
- package/dist/latex.d.ts.map +1 -0
- package/dist/latex.js +1271 -0
- package/dist/latex.js.map +1 -0
- package/dist/layout-node.d.ts +40 -0
- package/dist/layout-node.d.ts.map +1 -0
- package/dist/layout-node.js +6 -0
- package/dist/layout-node.js.map +1 -0
- package/dist/layout.d.ts +40 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +321 -0
- package/dist/layout.js.map +1 -0
- package/dist/native-modifiers.d.ts +3 -0
- package/dist/native-modifiers.d.ts.map +1 -0
- package/dist/native-modifiers.js +54 -0
- package/dist/native-modifiers.js.map +1 -0
- package/dist/native-module-path.d.ts +7 -0
- package/dist/native-module-path.d.ts.map +1 -0
- package/dist/native-module-path.js +19 -0
- package/dist/native-module-path.js.map +1 -0
- package/dist/stdin-buffer.d.ts +56 -0
- package/dist/stdin-buffer.d.ts.map +1 -0
- package/dist/stdin-buffer.js +366 -0
- package/dist/stdin-buffer.js.map +1 -0
- package/dist/terminal-colors.d.ts +10 -0
- package/dist/terminal-colors.d.ts.map +1 -0
- package/dist/terminal-colors.js +59 -0
- package/dist/terminal-colors.js.map +1 -0
- package/dist/terminal-image.d.ts +118 -0
- package/dist/terminal-image.d.ts.map +1 -0
- package/dist/terminal-image.js +557 -0
- package/dist/terminal-image.js.map +1 -0
- package/dist/terminal.d.ts +117 -0
- package/dist/terminal.d.ts.map +1 -0
- package/dist/terminal.js +447 -0
- package/dist/terminal.js.map +1 -0
- package/dist/tui-alt-screen.d.ts +129 -0
- package/dist/tui-alt-screen.d.ts.map +1 -0
- package/dist/tui-alt-screen.js +1191 -0
- package/dist/tui-alt-screen.js.map +1 -0
- package/dist/tui-main-screen.d.ts +39 -0
- package/dist/tui-main-screen.d.ts.map +1 -0
- package/dist/tui-main-screen.js +621 -0
- package/dist/tui-main-screen.js.map +1 -0
- package/dist/tui.d.ts +308 -0
- package/dist/tui.d.ts.map +1 -0
- package/dist/tui.js +941 -0
- package/dist/tui.js.map +1 -0
- package/dist/undo-stack.d.ts +26 -0
- package/dist/undo-stack.d.ts.map +1 -0
- package/dist/undo-stack.js +36 -0
- package/dist/undo-stack.js.map +1 -0
- package/dist/utils.d.ts +96 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +1191 -0
- package/dist/utils.js.map +1 -0
- package/dist/word-navigation.d.ts +25 -0
- package/dist/word-navigation.d.ts.map +1 -0
- package/dist/word-navigation.js +96 -0
- package/dist/word-navigation.js.map +1 -0
- package/native/darwin/README.md +20 -0
- package/native/darwin/build.sh +62 -0
- package/native/darwin/prebuilds/darwin-arm64/darwin-modifiers.node +0 -0
- package/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
- package/native/darwin/src/darwin-modifiers.c +70 -0
- package/native/win32/README.md +22 -0
- package/native/win32/build.mjs +229 -0
- package/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
- package/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
- package/native/win32/src/win32-console-mode.c +119 -0
- package/package.json +55 -5
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { chmodSync, copyFileSync, existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
7
|
+
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const sourceFile = path.join(scriptDir, "src", "win32-console-mode.c");
|
|
9
|
+
const temporaryDir = mkdtempSync(path.join(tmpdir(), "pi-tui-win32-"));
|
|
10
|
+
|
|
11
|
+
const targets = [
|
|
12
|
+
{
|
|
13
|
+
arch: "x64",
|
|
14
|
+
msvcArch: "x64",
|
|
15
|
+
mingwTarget: "x86_64-w64-windows-gnu",
|
|
16
|
+
prefixedCompilers: ["x86_64-w64-mingw32-gcc", "x86_64-w64-mingw32-clang"],
|
|
17
|
+
envCompiler: "CC_X64",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
arch: "arm64",
|
|
21
|
+
msvcArch: "arm64",
|
|
22
|
+
mingwTarget: "aarch64-w64-windows-gnu",
|
|
23
|
+
prefixedCompilers: ["aarch64-w64-mingw32-gcc", "aarch64-w64-mingw32-clang"],
|
|
24
|
+
envCompiler: "CC_ARM64",
|
|
25
|
+
},
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
function removeTemporaryDir() {
|
|
29
|
+
rmSync(temporaryDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
process.on("exit", removeTemporaryDir);
|
|
33
|
+
process.on("SIGINT", () => {
|
|
34
|
+
removeTemporaryDir();
|
|
35
|
+
process.exit(130);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
function commandExists(command) {
|
|
39
|
+
const result = spawnSync(command, ["--version"], { stdio: "ignore" });
|
|
40
|
+
return !result.error || result.error.code !== "ENOENT";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function run(command, args, options = {}) {
|
|
44
|
+
const result = spawnSync(command, args, { stdio: "inherit", ...options });
|
|
45
|
+
if (result.error) throw result.error;
|
|
46
|
+
if (result.status !== 0) throw new Error(`${command} failed with exit code ${result.status ?? 1}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function quoteBatch(value) {
|
|
50
|
+
return `"${value.replaceAll('"', '""')}"`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function msvcHostArch() {
|
|
54
|
+
return process.arch === "arm64" ? "arm64" : "x64";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function findVisualStudioDevCmd() {
|
|
58
|
+
const candidates = [];
|
|
59
|
+
const programFilesX86 = process.env["ProgramFiles(x86)"];
|
|
60
|
+
if (programFilesX86) {
|
|
61
|
+
const vswhere = path.join(programFilesX86, "Microsoft Visual Studio", "Installer", "vswhere.exe");
|
|
62
|
+
if (existsSync(vswhere)) {
|
|
63
|
+
const result = spawnSync(
|
|
64
|
+
vswhere,
|
|
65
|
+
[
|
|
66
|
+
"-latest",
|
|
67
|
+
"-products",
|
|
68
|
+
"*",
|
|
69
|
+
"-requires",
|
|
70
|
+
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
|
|
71
|
+
"-property",
|
|
72
|
+
"installationPath",
|
|
73
|
+
],
|
|
74
|
+
{ encoding: "utf8" },
|
|
75
|
+
);
|
|
76
|
+
for (const line of result.stdout.split(/\r?\n/)) {
|
|
77
|
+
const installationPath = line.trim();
|
|
78
|
+
if (installationPath) candidates.push(path.join(installationPath, "Common7", "Tools", "VsDevCmd.bat"));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
for (const base of [process.env.ProgramFiles, programFilesX86]) {
|
|
84
|
+
if (!base) continue;
|
|
85
|
+
for (const edition of ["BuildTools", "Community", "Professional", "Enterprise"]) {
|
|
86
|
+
candidates.push(path.join(base, "Microsoft Visual Studio", "2022", edition, "Common7", "Tools", "VsDevCmd.bat"));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return candidates.find((candidate) => existsSync(candidate));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function canUseMsvc(vsDevCmd) {
|
|
94
|
+
const probeDir = path.join(temporaryDir, "msvc-probe");
|
|
95
|
+
mkdirSync(probeDir, { recursive: true });
|
|
96
|
+
const batchFile = path.join(probeDir, "probe.cmd");
|
|
97
|
+
writeFileSync(
|
|
98
|
+
batchFile,
|
|
99
|
+
[
|
|
100
|
+
"@echo off",
|
|
101
|
+
`call ${quoteBatch(vsDevCmd)} -no_logo -arch=x64 -host_arch=${msvcHostArch()} >nul`,
|
|
102
|
+
"if errorlevel 1 exit /b %errorlevel%",
|
|
103
|
+
"where cl.exe >nul 2>nul",
|
|
104
|
+
].join("\r\n"),
|
|
105
|
+
);
|
|
106
|
+
const result = spawnSync("cmd.exe", ["/d", "/s", "/c", batchFile], { cwd: probeDir, stdio: "ignore" });
|
|
107
|
+
return !result.error && result.status === 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function resolveMingwCompiler(target) {
|
|
111
|
+
const envCompiler = process.env[target.envCompiler];
|
|
112
|
+
if (envCompiler) return { command: envCompiler, useTargetFlag: false };
|
|
113
|
+
if (process.env.CC) return { command: process.env.CC, useTargetFlag: true };
|
|
114
|
+
for (const command of target.prefixedCompilers) {
|
|
115
|
+
if (commandExists(command)) return { command, useTargetFlag: false };
|
|
116
|
+
}
|
|
117
|
+
if (commandExists("clang")) return { command: "clang", useTargetFlag: true };
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function installOutput(temporaryOutput, target) {
|
|
122
|
+
const outputDir = path.join(scriptDir, "prebuilds", `win32-${target.arch}`);
|
|
123
|
+
mkdirSync(outputDir, { recursive: true });
|
|
124
|
+
const output = path.join(outputDir, "win32-console-mode.node");
|
|
125
|
+
copyFileSync(temporaryOutput, output);
|
|
126
|
+
chmodSync(output, 0o755);
|
|
127
|
+
console.log(`Built ${path.relative(process.cwd(), output)}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function buildWithMsvc(target, vsDevCmd) {
|
|
131
|
+
const buildDir = path.join(temporaryDir, `msvc-${target.arch}`);
|
|
132
|
+
const temporaryOutput = path.join(buildDir, "win32-console-mode.node");
|
|
133
|
+
mkdirSync(buildDir, { recursive: true });
|
|
134
|
+
|
|
135
|
+
const batchFile = path.join(buildDir, "build.cmd");
|
|
136
|
+
writeFileSync(
|
|
137
|
+
batchFile,
|
|
138
|
+
[
|
|
139
|
+
"@echo off",
|
|
140
|
+
`call ${quoteBatch(vsDevCmd)} -no_logo -arch=${target.msvcArch} -host_arch=${msvcHostArch()}`,
|
|
141
|
+
"if errorlevel 1 exit /b %errorlevel%",
|
|
142
|
+
[
|
|
143
|
+
"cl",
|
|
144
|
+
"/nologo",
|
|
145
|
+
"/TC",
|
|
146
|
+
"/std:c11",
|
|
147
|
+
"/W4",
|
|
148
|
+
"/O1",
|
|
149
|
+
"/GS-",
|
|
150
|
+
"/LD",
|
|
151
|
+
`/Fe:${quoteBatch(temporaryOutput)}`,
|
|
152
|
+
quoteBatch(sourceFile),
|
|
153
|
+
"/link",
|
|
154
|
+
"/NOENTRY",
|
|
155
|
+
"/NODEFAULTLIB",
|
|
156
|
+
"kernel32.lib",
|
|
157
|
+
"/OPT:REF",
|
|
158
|
+
"/OPT:ICF",
|
|
159
|
+
].join(" "),
|
|
160
|
+
"if errorlevel 1 exit /b %errorlevel%",
|
|
161
|
+
].join("\r\n"),
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
run("cmd.exe", ["/d", "/s", "/c", batchFile], { cwd: buildDir });
|
|
165
|
+
installOutput(temporaryOutput, target);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function buildWithMingw(target) {
|
|
169
|
+
const compiler = resolveMingwCompiler(target);
|
|
170
|
+
if (!compiler) {
|
|
171
|
+
throw new Error(
|
|
172
|
+
`No Windows cross-compiler found for ${target.arch}. Install Microsoft C++ Build Tools on Windows, or set ${target.envCompiler} to a MinGW-compatible compiler.`,
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const buildDir = path.join(temporaryDir, `mingw-${target.arch}`);
|
|
177
|
+
const temporaryOutput = path.join(buildDir, "win32-console-mode.node");
|
|
178
|
+
mkdirSync(buildDir, { recursive: true });
|
|
179
|
+
|
|
180
|
+
const args = [
|
|
181
|
+
...(compiler.useTargetFlag ? [`--target=${target.mingwTarget}`] : []),
|
|
182
|
+
"-std=c11",
|
|
183
|
+
"-Wall",
|
|
184
|
+
"-Wextra",
|
|
185
|
+
"-Oz",
|
|
186
|
+
"-shared",
|
|
187
|
+
"-nostdlib",
|
|
188
|
+
"-Wl,--no-entry",
|
|
189
|
+
"-Wl,--strip-all",
|
|
190
|
+
sourceFile,
|
|
191
|
+
"-lkernel32",
|
|
192
|
+
"-o",
|
|
193
|
+
temporaryOutput,
|
|
194
|
+
];
|
|
195
|
+
|
|
196
|
+
run(compiler.command, args, { cwd: buildDir });
|
|
197
|
+
installOutput(temporaryOutput, target);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (process.argv.includes("--help") || process.argv.includes("-h")) {
|
|
201
|
+
console.log(`Usage: npm --prefix packages/tui run build:native:win32
|
|
202
|
+
|
|
203
|
+
Builds win32-x64 and win32-arm64 native prebuilds.
|
|
204
|
+
|
|
205
|
+
Environment:
|
|
206
|
+
QI_TUI_WIN32_TOOLCHAIN=msvc|mingw
|
|
207
|
+
CC_X64=/path/to/x86_64-w64-mingw32-gcc
|
|
208
|
+
CC_ARM64=/path/to/aarch64-w64-mingw32-gcc
|
|
209
|
+
CC=/path/to/clang`);
|
|
210
|
+
process.exit(0);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const requestedToolchain = process.env.QI_TUI_WIN32_TOOLCHAIN;
|
|
214
|
+
if (requestedToolchain && requestedToolchain !== "msvc" && requestedToolchain !== "mingw") {
|
|
215
|
+
throw new Error("QI_TUI_WIN32_TOOLCHAIN must be either 'msvc' or 'mingw'");
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const vsDevCmd = findVisualStudioDevCmd();
|
|
219
|
+
const hasMsvc = vsDevCmd ? canUseMsvc(vsDevCmd) : false;
|
|
220
|
+
const toolchain = requestedToolchain ?? (process.platform === "win32" && vsDevCmd ? "msvc" : "mingw");
|
|
221
|
+
|
|
222
|
+
if (toolchain === "msvc") {
|
|
223
|
+
if (!vsDevCmd || !hasMsvc) {
|
|
224
|
+
throw new Error("Microsoft C++ Build Tools not found. Install the Visual Studio C++ workload or set QI_TUI_WIN32_TOOLCHAIN=mingw.");
|
|
225
|
+
}
|
|
226
|
+
for (const target of targets) buildWithMsvc(target, vsDevCmd);
|
|
227
|
+
} else {
|
|
228
|
+
for (const target of targets) buildWithMingw(target);
|
|
229
|
+
}
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
#include <windows.h>
|
|
2
|
+
|
|
3
|
+
#ifndef ENABLE_VIRTUAL_TERMINAL_INPUT
|
|
4
|
+
#define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200
|
|
5
|
+
#endif
|
|
6
|
+
|
|
7
|
+
#define NAPI_AUTO_LENGTH ((unsigned long long)-1)
|
|
8
|
+
#define KEY_PRESSED_MASK 0x8000
|
|
9
|
+
|
|
10
|
+
typedef void* napi_env;
|
|
11
|
+
typedef void* napi_value;
|
|
12
|
+
typedef void* napi_callback_info;
|
|
13
|
+
typedef napi_value (__cdecl *napi_callback)(napi_env, napi_callback_info);
|
|
14
|
+
typedef int (__cdecl *napi_create_function_fn)(napi_env, const char*, unsigned long long, napi_callback, void*, napi_value*);
|
|
15
|
+
typedef int (__cdecl *napi_set_named_property_fn)(napi_env, napi_value, const char*, napi_value);
|
|
16
|
+
typedef int (__cdecl *napi_get_boolean_fn)(napi_env, int, napi_value*);
|
|
17
|
+
typedef int (__cdecl *napi_get_cb_info_fn)(napi_env, napi_callback_info, unsigned long long*, napi_value*, napi_value*, void**);
|
|
18
|
+
typedef int (__cdecl *napi_get_value_string_utf8_fn)(napi_env, napi_value, char*, unsigned long long, unsigned long long*);
|
|
19
|
+
typedef SHORT (WINAPI *get_async_key_state_fn)(int);
|
|
20
|
+
|
|
21
|
+
static void* node_symbol(const char* name) {
|
|
22
|
+
HMODULE module = GetModuleHandleA(0);
|
|
23
|
+
void* proc = module ? (void*)GetProcAddress(module, name) : 0;
|
|
24
|
+
if (proc) return proc;
|
|
25
|
+
|
|
26
|
+
module = GetModuleHandleA("node.dll");
|
|
27
|
+
return module ? (void*)GetProcAddress(module, name) : 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static int string_equals(const char* left, const char* right) {
|
|
31
|
+
while (*left && *right && *left == *right) {
|
|
32
|
+
left++;
|
|
33
|
+
right++;
|
|
34
|
+
}
|
|
35
|
+
return *left == 0 && *right == 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static get_async_key_state_fn get_async_key_state_symbol(void) {
|
|
39
|
+
static int loaded = 0;
|
|
40
|
+
static get_async_key_state_fn get_async_key_state = 0;
|
|
41
|
+
|
|
42
|
+
if (!loaded) {
|
|
43
|
+
HMODULE module = GetModuleHandleA("user32.dll");
|
|
44
|
+
if (!module) module = LoadLibraryA("user32.dll");
|
|
45
|
+
get_async_key_state = module ? (get_async_key_state_fn)GetProcAddress(module, "GetAsyncKeyState") : 0;
|
|
46
|
+
loaded = 1;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return get_async_key_state;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static int is_key_pressed(int virtual_key) {
|
|
53
|
+
get_async_key_state_fn get_async_key_state = get_async_key_state_symbol();
|
|
54
|
+
return get_async_key_state && (((unsigned short)get_async_key_state(virtual_key)) & KEY_PRESSED_MASK) != 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static int is_modifier_name_pressed(const char* name) {
|
|
58
|
+
if (string_equals(name, "shift")) return is_key_pressed(VK_SHIFT) || is_key_pressed(VK_LSHIFT) || is_key_pressed(VK_RSHIFT);
|
|
59
|
+
if (string_equals(name, "control")) return is_key_pressed(VK_CONTROL) || is_key_pressed(VK_LCONTROL) || is_key_pressed(VK_RCONTROL);
|
|
60
|
+
if (string_equals(name, "option") || string_equals(name, "alt")) return is_key_pressed(VK_MENU) || is_key_pressed(VK_LMENU) || is_key_pressed(VK_RMENU);
|
|
61
|
+
if (string_equals(name, "command") || string_equals(name, "super") || string_equals(name, "win")) return is_key_pressed(VK_LWIN) || is_key_pressed(VK_RWIN);
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static napi_value __cdecl enable_virtual_terminal_input(napi_env env, napi_callback_info info) {
|
|
66
|
+
(void)info;
|
|
67
|
+
|
|
68
|
+
HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
|
|
69
|
+
DWORD mode = 0;
|
|
70
|
+
int enabled = handle != INVALID_HANDLE_VALUE &&
|
|
71
|
+
GetConsoleMode(handle, &mode) &&
|
|
72
|
+
SetConsoleMode(handle, mode | ENABLE_VIRTUAL_TERMINAL_INPUT);
|
|
73
|
+
|
|
74
|
+
napi_get_boolean_fn napi_get_boolean = (napi_get_boolean_fn)node_symbol("napi_get_boolean");
|
|
75
|
+
napi_value result = 0;
|
|
76
|
+
if (napi_get_boolean) napi_get_boolean(env, enabled, &result);
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static napi_value __cdecl is_modifier_pressed(napi_env env, napi_callback_info info) {
|
|
81
|
+
napi_get_cb_info_fn napi_get_cb_info = (napi_get_cb_info_fn)node_symbol("napi_get_cb_info");
|
|
82
|
+
napi_get_value_string_utf8_fn napi_get_value_string_utf8 = (napi_get_value_string_utf8_fn)node_symbol("napi_get_value_string_utf8");
|
|
83
|
+
napi_get_boolean_fn napi_get_boolean = (napi_get_boolean_fn)node_symbol("napi_get_boolean");
|
|
84
|
+
|
|
85
|
+
int pressed = 0;
|
|
86
|
+
if (napi_get_cb_info && napi_get_value_string_utf8) {
|
|
87
|
+
unsigned long long argc = 1;
|
|
88
|
+
napi_value args[1] = {0};
|
|
89
|
+
if (napi_get_cb_info(env, info, &argc, args, 0, 0) == 0 && argc >= 1 && args[0]) {
|
|
90
|
+
char name[16] = {0};
|
|
91
|
+
unsigned long long copied = 0;
|
|
92
|
+
if (napi_get_value_string_utf8(env, args[0], name, sizeof(name), &copied) == 0) {
|
|
93
|
+
pressed = is_modifier_name_pressed(name);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
napi_value result = 0;
|
|
99
|
+
if (napi_get_boolean) napi_get_boolean(env, pressed, &result);
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
static void set_function_export(napi_env env, napi_value exports, const char* name, napi_callback callback) {
|
|
104
|
+
napi_create_function_fn napi_create_function = (napi_create_function_fn)node_symbol("napi_create_function");
|
|
105
|
+
napi_set_named_property_fn napi_set_named_property = (napi_set_named_property_fn)node_symbol("napi_set_named_property");
|
|
106
|
+
|
|
107
|
+
napi_value fn = 0;
|
|
108
|
+
if (napi_create_function &&
|
|
109
|
+
napi_set_named_property &&
|
|
110
|
+
napi_create_function(env, name, NAPI_AUTO_LENGTH, callback, 0, &fn) == 0) {
|
|
111
|
+
napi_set_named_property(env, exports, name, fn);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
__declspec(dllexport) napi_value __cdecl napi_register_module_v1(napi_env env, napi_value exports) {
|
|
116
|
+
set_function_export(env, exports, "enableVirtualTerminalInput", enable_virtual_terminal_input);
|
|
117
|
+
set_function_export(env, exports, "isModifierPressed", is_modifier_pressed);
|
|
118
|
+
return exports;
|
|
119
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,56 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "@bramburn/qi-tui",
|
|
3
|
+
"version": "0.85.1",
|
|
4
|
+
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"clean": "shx rm -rf dist",
|
|
9
|
+
"build": "tsgo -p tsconfig.build.json",
|
|
10
|
+
"build:native:darwin": "native/darwin/build.sh",
|
|
11
|
+
"build:native:win32": "node native/win32/build.mjs",
|
|
12
|
+
"test": "node --test --experimental-strip-types --test-reporter=dot --test-reporter-destination=stdout test/*.test.ts",
|
|
13
|
+
"prepublishOnly": "bun --bun run clean && bun --bun run build"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist/**/*",
|
|
17
|
+
"native/win32/prebuilds/**/*.node",
|
|
18
|
+
"native/win32/src/**/*.c",
|
|
19
|
+
"native/win32/build.mjs",
|
|
20
|
+
"native/win32/README.md",
|
|
21
|
+
"native/darwin/prebuilds/**/*.node",
|
|
22
|
+
"native/darwin/src/**/*.c",
|
|
23
|
+
"native/darwin/build.sh",
|
|
24
|
+
"native/darwin/README.md",
|
|
25
|
+
"README.md"
|
|
26
|
+
],
|
|
27
|
+
"keywords": [
|
|
28
|
+
"tui",
|
|
29
|
+
"terminal",
|
|
30
|
+
"ui",
|
|
31
|
+
"text-editor",
|
|
32
|
+
"differential-rendering",
|
|
33
|
+
"typescript",
|
|
34
|
+
"cli"
|
|
35
|
+
],
|
|
36
|
+
"author": "Mario Zechner",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/bramburn/qi.git",
|
|
41
|
+
"directory": "packages/tui"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=22.19.0",
|
|
45
|
+
"bun": ">=1.3.14"
|
|
46
|
+
},
|
|
47
|
+
"types": "./dist/index.d.ts",
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"get-east-asian-width": "1.6.0",
|
|
50
|
+
"marked": "18.0.5"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@xterm/headless": "5.5.0",
|
|
54
|
+
"chalk": "5.6.2"
|
|
55
|
+
}
|
|
56
|
+
}
|