Squashed 'third_party/pi/' content from commit d981de122

git-subtree-dir: third_party/pi
git-subtree-split: d981de1229ef899957bbe968bc8dcda02a21f477
This commit is contained in:
2026-09-14 10:40:08 -04:00
commit 67b361f0e9
1669 changed files with 397627 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
# Darwin native prebuilds
Build both macOS architectures from the repository root:
```sh
npm --prefix packages/tui run build:native:darwin
```
The build uses macOS 11.0 as the arm64 deployment target and macOS 10.15 as the x86_64 deployment target. On macOS, `build.sh` finds Apple clang and the active macOS SDK through `xcrun`. Either an Intel or Apple Silicon host can build both outputs.
A non-macOS host needs a complete Darwin cross-toolchain, including a macOS SDK and a Mach-O linker. For example, an osxcross installation can be selected with `CC` and `SDKROOT`:
```sh
CC=/path/to/osxcross/clang SDKROOT=/path/to/MacOSX.sdk \
npm --prefix packages/tui run build:native:darwin
```
The SDK must be obtained and used in accordance with Apple's license. Plain Linux or Windows clang is not enough because the addon includes and links CoreGraphics.
Zig is not used here because it does not provide the Apple SDK or CoreGraphics framework stubs. It therefore does not make this build SDK-independent, and its clang driver does not currently handle this Mach-O bundle recipe as a drop-in replacement for Apple clang.

View File

@@ -0,0 +1,62 @@
#!/usr/bin/env bash
set -euo pipefail
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source_file="$script_dir/src/darwin-modifiers.c"
if [[ -n "${CC:-}" ]]; then
compiler="$CC"
elif [[ "$(uname -s)" == "Darwin" ]] && command -v xcrun >/dev/null 2>&1; then
compiler="$(xcrun --find clang)"
else
compiler="clang"
fi
if ! command -v "$compiler" >/dev/null 2>&1; then
echo "Darwin C compiler not found: $compiler" >&2
exit 1
fi
sdk_flags=()
if [[ -n "${SDKROOT:-}" ]]; then
if [[ ! -d "$SDKROOT" ]]; then
echo "SDKROOT does not exist: $SDKROOT" >&2
exit 1
fi
sdk_flags=(-isysroot "$SDKROOT" "-F$SDKROOT/System/Library/Frameworks")
elif [[ "$(uname -s)" == "Darwin" ]]; then
sdkroot="$(xcrun --sdk macosx --show-sdk-path)"
sdk_flags=(-isysroot "$sdkroot" "-F$sdkroot/System/Library/Frameworks")
fi
temporary_dir="$(mktemp -d "${TMPDIR:-/tmp}/pi-tui-darwin.XXXXXX")"
trap 'rm -rf "$temporary_dir"' EXIT
build() {
local arch="$1"
local target="$2"
local output_dir="$script_dir/prebuilds/darwin-$arch"
local temporary_output="$temporary_dir/darwin-$arch/darwin-modifiers.node"
mkdir -p "$(dirname "$temporary_output")"
"$compiler" \
-std=c11 \
-Wall \
-Wextra \
-O2 \
"--target=$target" \
"${sdk_flags[@]}" \
-bundle \
-undefined dynamic_lookup \
-framework CoreGraphics \
"$source_file" \
-o "$temporary_output"
mkdir -p "$output_dir"
install -m 755 "$temporary_output" "$output_dir/darwin-modifiers.node"
echo "Built $output_dir/darwin-modifiers.node"
}
build arm64 arm64-apple-macos11.0
build x64 x86_64-apple-macos10.15

View File

@@ -0,0 +1,70 @@
#include <CoreGraphics/CoreGraphics.h>
#include <dlfcn.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#define NAPI_AUTO_LENGTH ((size_t)-1)
typedef void* napi_env;
typedef void* napi_value;
typedef void* napi_callback_info;
typedef napi_value (*napi_callback)(napi_env, napi_callback_info);
typedef int (*napi_create_function_fn)(napi_env, const char*, size_t, napi_callback, void*, napi_value*);
typedef int (*napi_set_named_property_fn)(napi_env, napi_value, const char*, napi_value);
typedef int (*napi_get_boolean_fn)(napi_env, bool, napi_value*);
typedef int (*napi_get_cb_info_fn)(napi_env, napi_callback_info, size_t*, napi_value*, napi_value*, void**);
typedef int (*napi_get_value_string_utf8_fn)(napi_env, napi_value, char*, size_t, size_t*);
static void* node_symbol(const char* name) {
return dlsym(RTLD_DEFAULT, name);
}
static CGEventFlags modifier_mask_for_name(const char* name) {
if (strcmp(name, "shift") == 0) return kCGEventFlagMaskShift;
if (strcmp(name, "command") == 0) return kCGEventFlagMaskCommand;
if (strcmp(name, "control") == 0) return kCGEventFlagMaskControl;
if (strcmp(name, "option") == 0) return kCGEventFlagMaskAlternate;
return 0;
}
static napi_value is_modifier_pressed(napi_env env, napi_callback_info info) {
napi_get_cb_info_fn napi_get_cb_info = (napi_get_cb_info_fn)node_symbol("napi_get_cb_info");
napi_get_value_string_utf8_fn napi_get_value_string_utf8 = (napi_get_value_string_utf8_fn)node_symbol("napi_get_value_string_utf8");
napi_get_boolean_fn napi_get_boolean = (napi_get_boolean_fn)node_symbol("napi_get_boolean");
bool pressed = false;
if (napi_get_cb_info && napi_get_value_string_utf8) {
size_t argc = 1;
napi_value args[1] = {0};
if (napi_get_cb_info(env, info, &argc, args, 0, 0) == 0 && argc >= 1 && args[0]) {
char name[16] = {0};
size_t copied = 0;
if (napi_get_value_string_utf8(env, args[0], name, sizeof(name), &copied) == 0) {
CGEventFlags mask = modifier_mask_for_name(name);
if (mask != 0) {
CGEventFlags flags = CGEventSourceFlagsState(kCGEventSourceStateCombinedSessionState);
pressed = (flags & mask) != 0;
}
}
}
}
napi_value result = 0;
if (napi_get_boolean) napi_get_boolean(env, pressed, &result);
return result;
}
__attribute__((visibility("default"))) napi_value napi_register_module_v1(napi_env env, napi_value exports) {
napi_create_function_fn napi_create_function = (napi_create_function_fn)node_symbol("napi_create_function");
napi_set_named_property_fn napi_set_named_property = (napi_set_named_property_fn)node_symbol("napi_set_named_property");
napi_value fn = 0;
if (napi_create_function &&
napi_set_named_property &&
napi_create_function(env, "isModifierPressed", NAPI_AUTO_LENGTH, is_modifier_pressed, 0, &fn) == 0) {
napi_set_named_property(env, exports, "isModifierPressed", fn);
}
return exports;
}

View File

@@ -0,0 +1,22 @@
# Windows native prebuilds
Build both Windows architectures from the repository root:
```sh
npm --prefix packages/tui run build:native:win32
```
On Windows, the build uses the Microsoft C++ Build Tools from Visual Studio. `build.mjs` locates `VsDevCmd.bat`, initializes a developer environment for `amd64` and `arm64`, and builds the addon with `cl.exe`/`link.exe`.
Install the "Desktop development with C++" workload, or at minimum the MSVC toolset and Windows SDK components. No Node headers are required; the addon resolves N-API symbols from the host process.
For non-Windows cross-builds, or for custom Windows toolchains, set `PI_TUI_WIN32_TOOLCHAIN=mingw` and provide MinGW-compatible compilers:
```sh
PI_TUI_WIN32_TOOLCHAIN=mingw \
CC_X64=/path/to/x86_64-w64-mingw32-gcc \
CC_ARM64=/path/to/aarch64-w64-mingw32-gcc \
npm --prefix packages/tui run build:native:win32
```
The addon intentionally avoids the C runtime and links only against `kernel32`.

View File

@@ -0,0 +1,229 @@
import { spawnSync } from "node:child_process";
import { chmodSync, copyFileSync, existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import * as path from "node:path";
import { fileURLToPath } from "node:url";
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
const sourceFile = path.join(scriptDir, "src", "win32-console-mode.c");
const temporaryDir = mkdtempSync(path.join(tmpdir(), "pi-tui-win32-"));
const targets = [
{
arch: "x64",
msvcArch: "x64",
mingwTarget: "x86_64-w64-windows-gnu",
prefixedCompilers: ["x86_64-w64-mingw32-gcc", "x86_64-w64-mingw32-clang"],
envCompiler: "CC_X64",
},
{
arch: "arm64",
msvcArch: "arm64",
mingwTarget: "aarch64-w64-windows-gnu",
prefixedCompilers: ["aarch64-w64-mingw32-gcc", "aarch64-w64-mingw32-clang"],
envCompiler: "CC_ARM64",
},
];
function removeTemporaryDir() {
rmSync(temporaryDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
}
process.on("exit", removeTemporaryDir);
process.on("SIGINT", () => {
removeTemporaryDir();
process.exit(130);
});
function commandExists(command) {
const result = spawnSync(command, ["--version"], { stdio: "ignore" });
return !result.error || result.error.code !== "ENOENT";
}
function run(command, args, options = {}) {
const result = spawnSync(command, args, { stdio: "inherit", ...options });
if (result.error) throw result.error;
if (result.status !== 0) throw new Error(`${command} failed with exit code ${result.status ?? 1}`);
}
function quoteBatch(value) {
return `"${value.replaceAll('"', '""')}"`;
}
function msvcHostArch() {
return process.arch === "arm64" ? "arm64" : "x64";
}
function findVisualStudioDevCmd() {
const candidates = [];
const programFilesX86 = process.env["ProgramFiles(x86)"];
if (programFilesX86) {
const vswhere = path.join(programFilesX86, "Microsoft Visual Studio", "Installer", "vswhere.exe");
if (existsSync(vswhere)) {
const result = spawnSync(
vswhere,
[
"-latest",
"-products",
"*",
"-requires",
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
"-property",
"installationPath",
],
{ encoding: "utf8" },
);
for (const line of result.stdout.split(/\r?\n/)) {
const installationPath = line.trim();
if (installationPath) candidates.push(path.join(installationPath, "Common7", "Tools", "VsDevCmd.bat"));
}
}
}
for (const base of [process.env.ProgramFiles, programFilesX86]) {
if (!base) continue;
for (const edition of ["BuildTools", "Community", "Professional", "Enterprise"]) {
candidates.push(path.join(base, "Microsoft Visual Studio", "2022", edition, "Common7", "Tools", "VsDevCmd.bat"));
}
}
return candidates.find((candidate) => existsSync(candidate));
}
function canUseMsvc(vsDevCmd) {
const probeDir = path.join(temporaryDir, "msvc-probe");
mkdirSync(probeDir, { recursive: true });
const batchFile = path.join(probeDir, "probe.cmd");
writeFileSync(
batchFile,
[
"@echo off",
`call ${quoteBatch(vsDevCmd)} -no_logo -arch=x64 -host_arch=${msvcHostArch()} >nul`,
"if errorlevel 1 exit /b %errorlevel%",
"where cl.exe >nul 2>nul",
].join("\r\n"),
);
const result = spawnSync("cmd.exe", ["/d", "/s", "/c", batchFile], { cwd: probeDir, stdio: "ignore" });
return !result.error && result.status === 0;
}
function resolveMingwCompiler(target) {
const envCompiler = process.env[target.envCompiler];
if (envCompiler) return { command: envCompiler, useTargetFlag: false };
if (process.env.CC) return { command: process.env.CC, useTargetFlag: true };
for (const command of target.prefixedCompilers) {
if (commandExists(command)) return { command, useTargetFlag: false };
}
if (commandExists("clang")) return { command: "clang", useTargetFlag: true };
return undefined;
}
function installOutput(temporaryOutput, target) {
const outputDir = path.join(scriptDir, "prebuilds", `win32-${target.arch}`);
mkdirSync(outputDir, { recursive: true });
const output = path.join(outputDir, "win32-console-mode.node");
copyFileSync(temporaryOutput, output);
chmodSync(output, 0o755);
console.log(`Built ${path.relative(process.cwd(), output)}`);
}
function buildWithMsvc(target, vsDevCmd) {
const buildDir = path.join(temporaryDir, `msvc-${target.arch}`);
const temporaryOutput = path.join(buildDir, "win32-console-mode.node");
mkdirSync(buildDir, { recursive: true });
const batchFile = path.join(buildDir, "build.cmd");
writeFileSync(
batchFile,
[
"@echo off",
`call ${quoteBatch(vsDevCmd)} -no_logo -arch=${target.msvcArch} -host_arch=${msvcHostArch()}`,
"if errorlevel 1 exit /b %errorlevel%",
[
"cl",
"/nologo",
"/TC",
"/std:c11",
"/W4",
"/O1",
"/GS-",
"/LD",
`/Fe:${quoteBatch(temporaryOutput)}`,
quoteBatch(sourceFile),
"/link",
"/NOENTRY",
"/NODEFAULTLIB",
"kernel32.lib",
"/OPT:REF",
"/OPT:ICF",
].join(" "),
"if errorlevel 1 exit /b %errorlevel%",
].join("\r\n"),
);
run("cmd.exe", ["/d", "/s", "/c", batchFile], { cwd: buildDir });
installOutput(temporaryOutput, target);
}
function buildWithMingw(target) {
const compiler = resolveMingwCompiler(target);
if (!compiler) {
throw new Error(
`No Windows cross-compiler found for ${target.arch}. Install Microsoft C++ Build Tools on Windows, or set ${target.envCompiler} to a MinGW-compatible compiler.`,
);
}
const buildDir = path.join(temporaryDir, `mingw-${target.arch}`);
const temporaryOutput = path.join(buildDir, "win32-console-mode.node");
mkdirSync(buildDir, { recursive: true });
const args = [
...(compiler.useTargetFlag ? [`--target=${target.mingwTarget}`] : []),
"-std=c11",
"-Wall",
"-Wextra",
"-Oz",
"-shared",
"-nostdlib",
"-Wl,--no-entry",
"-Wl,--strip-all",
sourceFile,
"-lkernel32",
"-o",
temporaryOutput,
];
run(compiler.command, args, { cwd: buildDir });
installOutput(temporaryOutput, target);
}
if (process.argv.includes("--help") || process.argv.includes("-h")) {
console.log(`Usage: npm --prefix packages/tui run build:native:win32
Builds win32-x64 and win32-arm64 native prebuilds.
Environment:
PI_TUI_WIN32_TOOLCHAIN=msvc|mingw
CC_X64=/path/to/x86_64-w64-mingw32-gcc
CC_ARM64=/path/to/aarch64-w64-mingw32-gcc
CC=/path/to/clang`);
process.exit(0);
}
const requestedToolchain = process.env.PI_TUI_WIN32_TOOLCHAIN;
if (requestedToolchain && requestedToolchain !== "msvc" && requestedToolchain !== "mingw") {
throw new Error("PI_TUI_WIN32_TOOLCHAIN must be either 'msvc' or 'mingw'");
}
const vsDevCmd = findVisualStudioDevCmd();
const hasMsvc = vsDevCmd ? canUseMsvc(vsDevCmd) : false;
const toolchain = requestedToolchain ?? (process.platform === "win32" && vsDevCmd ? "msvc" : "mingw");
if (toolchain === "msvc") {
if (!vsDevCmd || !hasMsvc) {
throw new Error("Microsoft C++ Build Tools not found. Install the Visual Studio C++ workload or set PI_TUI_WIN32_TOOLCHAIN=mingw.");
}
for (const target of targets) buildWithMsvc(target, vsDevCmd);
} else {
for (const target of targets) buildWithMingw(target);
}

View File

@@ -0,0 +1,119 @@
#include <windows.h>
#ifndef ENABLE_VIRTUAL_TERMINAL_INPUT
#define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200
#endif
#define NAPI_AUTO_LENGTH ((unsigned long long)-1)
#define KEY_PRESSED_MASK 0x8000
typedef void* napi_env;
typedef void* napi_value;
typedef void* napi_callback_info;
typedef napi_value (__cdecl *napi_callback)(napi_env, napi_callback_info);
typedef int (__cdecl *napi_create_function_fn)(napi_env, const char*, unsigned long long, napi_callback, void*, napi_value*);
typedef int (__cdecl *napi_set_named_property_fn)(napi_env, napi_value, const char*, napi_value);
typedef int (__cdecl *napi_get_boolean_fn)(napi_env, int, napi_value*);
typedef int (__cdecl *napi_get_cb_info_fn)(napi_env, napi_callback_info, unsigned long long*, napi_value*, napi_value*, void**);
typedef int (__cdecl *napi_get_value_string_utf8_fn)(napi_env, napi_value, char*, unsigned long long, unsigned long long*);
typedef SHORT (WINAPI *get_async_key_state_fn)(int);
static void* node_symbol(const char* name) {
HMODULE module = GetModuleHandleA(0);
void* proc = module ? (void*)GetProcAddress(module, name) : 0;
if (proc) return proc;
module = GetModuleHandleA("node.dll");
return module ? (void*)GetProcAddress(module, name) : 0;
}
static int string_equals(const char* left, const char* right) {
while (*left && *right && *left == *right) {
left++;
right++;
}
return *left == 0 && *right == 0;
}
static get_async_key_state_fn get_async_key_state_symbol(void) {
static int loaded = 0;
static get_async_key_state_fn get_async_key_state = 0;
if (!loaded) {
HMODULE module = GetModuleHandleA("user32.dll");
if (!module) module = LoadLibraryA("user32.dll");
get_async_key_state = module ? (get_async_key_state_fn)GetProcAddress(module, "GetAsyncKeyState") : 0;
loaded = 1;
}
return get_async_key_state;
}
static int is_key_pressed(int virtual_key) {
get_async_key_state_fn get_async_key_state = get_async_key_state_symbol();
return get_async_key_state && (((unsigned short)get_async_key_state(virtual_key)) & KEY_PRESSED_MASK) != 0;
}
static int is_modifier_name_pressed(const char* name) {
if (string_equals(name, "shift")) return is_key_pressed(VK_SHIFT) || is_key_pressed(VK_LSHIFT) || is_key_pressed(VK_RSHIFT);
if (string_equals(name, "control")) return is_key_pressed(VK_CONTROL) || is_key_pressed(VK_LCONTROL) || is_key_pressed(VK_RCONTROL);
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);
if (string_equals(name, "command") || string_equals(name, "super") || string_equals(name, "win")) return is_key_pressed(VK_LWIN) || is_key_pressed(VK_RWIN);
return 0;
}
static napi_value __cdecl enable_virtual_terminal_input(napi_env env, napi_callback_info info) {
(void)info;
HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
DWORD mode = 0;
int enabled = handle != INVALID_HANDLE_VALUE &&
GetConsoleMode(handle, &mode) &&
SetConsoleMode(handle, mode | ENABLE_VIRTUAL_TERMINAL_INPUT);
napi_get_boolean_fn napi_get_boolean = (napi_get_boolean_fn)node_symbol("napi_get_boolean");
napi_value result = 0;
if (napi_get_boolean) napi_get_boolean(env, enabled, &result);
return result;
}
static napi_value __cdecl is_modifier_pressed(napi_env env, napi_callback_info info) {
napi_get_cb_info_fn napi_get_cb_info = (napi_get_cb_info_fn)node_symbol("napi_get_cb_info");
napi_get_value_string_utf8_fn napi_get_value_string_utf8 = (napi_get_value_string_utf8_fn)node_symbol("napi_get_value_string_utf8");
napi_get_boolean_fn napi_get_boolean = (napi_get_boolean_fn)node_symbol("napi_get_boolean");
int pressed = 0;
if (napi_get_cb_info && napi_get_value_string_utf8) {
unsigned long long argc = 1;
napi_value args[1] = {0};
if (napi_get_cb_info(env, info, &argc, args, 0, 0) == 0 && argc >= 1 && args[0]) {
char name[16] = {0};
unsigned long long copied = 0;
if (napi_get_value_string_utf8(env, args[0], name, sizeof(name), &copied) == 0) {
pressed = is_modifier_name_pressed(name);
}
}
}
napi_value result = 0;
if (napi_get_boolean) napi_get_boolean(env, pressed, &result);
return result;
}
static void set_function_export(napi_env env, napi_value exports, const char* name, napi_callback callback) {
napi_create_function_fn napi_create_function = (napi_create_function_fn)node_symbol("napi_create_function");
napi_set_named_property_fn napi_set_named_property = (napi_set_named_property_fn)node_symbol("napi_set_named_property");
napi_value fn = 0;
if (napi_create_function &&
napi_set_named_property &&
napi_create_function(env, name, NAPI_AUTO_LENGTH, callback, 0, &fn) == 0) {
napi_set_named_property(env, exports, name, fn);
}
}
__declspec(dllexport) napi_value __cdecl napi_register_module_v1(napi_env env, napi_value exports) {
set_function_export(env, exports, "enableVirtualTerminalInput", enable_virtual_terminal_input);
set_function_export(env, exports, "isModifierPressed", is_modifier_pressed);
return exports;
}