diff --git a/src/api/start.ts b/src/api/start.ts
index 4a3f858eb..ff447f483 100644
--- a/src/api/start.ts
+++ b/src/api/start.ts
@@ -35,7 +35,7 @@ try {
}
if (cluster.isPrimary && process.env.NODE_ENV == "production") {
- console.log(`Primary ${process.pid} is running`);
+ console.log(`Primary PID: ${process.pid}`);
// Fork workers.
for (let i = 0; i < cores; i++) {
@@ -43,7 +43,7 @@ if (cluster.isPrimary && process.env.NODE_ENV == "production") {
}
cluster.on("exit", (worker) => {
- console.log(`worker ${worker.process.pid} died, restart worker`);
+ console.log(`Worker ${worker.process.pid} died, restarting worker`);
cluster.fork();
});
} else {
diff --git a/src/bundle/Server.ts b/src/bundle/Server.ts
index d7ba9260d..8ef727509 100644
--- a/src/bundle/Server.ts
+++ b/src/bundle/Server.ts
@@ -91,7 +91,7 @@ async function main() {
Sentry.errorHandler(app);
- console.log(`[Server] ${green(`listening on port ${bold(port)}`)}`);
+ console.log(`[Server] ${green(`Listening on port ${bold(port)}`)}`);
}
main().catch(console.error);
diff --git a/src/bundle/start.ts b/src/bundle/start.ts
index fe177cbc7..33465abc3 100644
--- a/src/bundle/start.ts
+++ b/src/bundle/start.ts
@@ -18,6 +18,7 @@
// process.env.MONGOMS_DEBUG = "true";
import moduleAlias from "module-alias";
+
moduleAlias(__dirname + "../../../package.json");
import "reflect-metadata";
@@ -26,8 +27,10 @@ import os from "os";
import { red, bold, yellow, cyan } from "picocolors";
import { initStats } from "./stats";
import { config } from "dotenv";
+
config();
import { execSync } from "child_process";
+import { centerString, Logo } from "@spacebar/util";
const cores = process.env.THREADS ? parseInt(process.env.THREADS) : 1;
@@ -41,23 +44,19 @@ function getCommitOrFail() {
if (cluster.isPrimary) {
const commit = getCommitOrFail();
-
+ Logo.printLogo();
console.log(
bold(`
-███████╗██████╗ █████╗ ██████╗███████╗██████╗ █████╗ ██████╗
-██╔════╝██╔══██╗██╔══██╗██╔════╝██╔════╝██╔══██╗██╔══██╗██╔══██╗
-███████╗██████╔╝███████║██║ █████╗ ██████╔╝███████║██████╔╝
-╚════██║██╔═══╝ ██╔══██║██║ ██╔══╝ ██╔══██╗██╔══██║██╔══██╗
-███████║██║ ██║ ██║╚██████╗███████╗██████╔╝██║ ██║██║ ██║
-╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝╚══════╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝
-
- spacebar-server | ${yellow(
- `Pre-release (${
- commit !== null
- ? commit.slice(0, 7)
- : "Unknown (Git cannot be found)"
- })`,
- )}
+${centerString(
+ `spacebar-server | ${yellow(
+ `Pre-release (${
+ commit !== null
+ ? commit.slice(0, 7)
+ : "Unknown (Git cannot be found)"
+ })`,
+ )}`,
+ 64,
+)}
Commit Hash: ${
commit !== null
@@ -74,7 +73,7 @@ Cores: ${cyan(os.cpus().length)} (Using ${cores} thread(s).)
initStats();
- console.log(`[Process] starting with ${cores} threads`);
+ console.log(`[Process] Starting with ${cores} threads`);
if (cores === 1) {
require("./Server");
@@ -87,7 +86,7 @@ Cores: ${cyan(os.cpus().length)} (Using ${cores} thread(s).)
const delay = process.env.DATABASE?.includes("://") ? 0 : i * 1000;
setTimeout(() => {
cluster.fork();
- console.log(`[Process] worker ${cyan(i)} started.`);
+ console.log(`[Process] Worker ${cyan(i)} started.`);
}, delay);
}
@@ -102,7 +101,7 @@ Cores: ${cyan(os.cpus().length)} (Using ${cores} thread(s).)
cluster.on("exit", (worker) => {
console.log(
`[Worker] ${red(
- `died with PID: ${worker.process.pid} , restarting ...`,
+ `PID ${worker.process.pid} died, restarting ...`,
)}`,
);
cluster.fork();
diff --git a/src/bundle/stats.ts b/src/bundle/stats.ts
index b690eb752..92e46027b 100644
--- a/src/bundle/stats.ts
+++ b/src/bundle/stats.ts
@@ -18,18 +18,44 @@
import os from "os";
import osu from "node-os-utils";
+import { readFileSync } from "node:fs";
import { red } from "picocolors";
export function initStats() {
- console.log(`[Path] running in ${__dirname}`);
+ console.log(`[Path] Running in ${process.cwd()}`);
+ console.log(`[Path] Running from ${__dirname}`);
try {
- console.log(`[CPU] ${osu.cpu.model()} Cores x${osu.cpu.count()}`);
+ console.log(`[CPU] ${osu.cpu.model()} (x${osu.cpu.count()})`);
} catch {
- console.log("[CPU] Failed to get cpu model!");
+ console.log("[CPU] Failed to get CPU model!");
}
- console.log(`[System] ${os.platform()} ${os.arch()}`);
- console.log(`[Process] running with PID: ${process.pid}`);
+ console.log(`[System] ${os.platform()} ${os.release()} ${os.arch()}`);
+ if (os.platform() == "linux") {
+ try {
+ const osReleaseLines = readFileSync(
+ "/etc/os-release",
+ "utf8",
+ ).split("\n");
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ //@ts-ignore
+ const osRelease: any = {};
+ for (const line of osReleaseLines) {
+ if (!line) continue;
+ const [key, value] = line.match(/(.*?)="?([^"]*)"?/)!.slice(1);
+ osRelease[key] = value;
+ }
+ console.log(
+ `[System]\x1b[${osRelease.ANSI_COLOR}m ${osRelease.NAME ?? "Unknown"} ${osRelease.VERSION ?? "Unknown"} (${osRelease.BUILD_ID ?? "No build ID"})\x1b[0m`,
+ );
+ } catch (e) {
+ console.log(
+ "[System] Unknown Linux distribution (missing /etc/os-release)",
+ );
+ console.log(e);
+ }
+ }
+ console.log(`[Process] Running with PID: ${process.pid}`);
if (process.getuid && process.getuid() === 0) {
console.warn(
red(
diff --git a/src/util/util/KittyLogo.ts b/src/util/util/KittyLogo.ts
new file mode 100644
index 000000000..6e74007f4
--- /dev/null
+++ b/src/util/util/KittyLogo.ts
@@ -0,0 +1,141 @@
+import { readFileSync } from "node:fs";
+import fs from "fs";
+
+var util = require("util");
+
+// noinspection ES6ConvertRequireIntoImport
+// const ioctl = require("ioctl");
+// import ref from "ref";
+// import ArrayType from "ref-array";
+// import StructType from "ref-struct";
+// import os from "os";
+
+// const winsize = StructType({
+// ws_row : ref.types.ushort,
+// ws_col : ref.types.ushort,
+// ws_xpixel : ref.types.ushort,
+// ws_ypixel : ref.types.ushort
+// });
+
+// const originalConsoleLog = console.log;
+// console.error =
+// console.log =
+// console.debug =
+// function (message: object, ...optionalParams: object[]) {
+// KittyLogo.printWithIcon(message + " " + optionalParams.join(" "));
+// };
+
+export class KittyLogo {
+ public static printLogo(): void {
+ const data = readFileSync(__dirname + "/../../../assets/logo.png", {
+ encoding: "base64",
+ });
+ KittyLogo.writeImage({
+ base64Data: data,
+ width: 70,
+ addNewline: true,
+ });
+ }
+
+ public static printWithIcon(text?: string): void {
+ if (text) {
+ const lines = text.split("\n");
+ for (const line of lines) {
+ this.writeIcon();
+ process.stdout.write(" " + line + "\n");
+ }
+ }
+ }
+
+ private static writeIcon(): void {
+ const data = readFileSync(__dirname + "/../../../assets/icon.png", {
+ encoding: "base64",
+ });
+ KittyLogo.writeImage({
+ base64Data: data,
+ width: 2,
+ addNewline: false,
+ });
+ }
+
+ private static checkSupport(cb: void): boolean {
+ process.stdin.setEncoding("utf8");
+ process.stdin.setRawMode(true);
+ let resp = "";
+ process.stdin.once("data", function (key) {
+ console.log(util.inspect(key));
+ process.stdin.setRawMode(false);
+ process.stdin.pause();
+ resp = key.toString();
+ });
+ process.stdout.write(
+ "\x1b_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\x1b\\\x1b[c",
+ );
+
+ while(resp == "") {
+ console.log("waiting");
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 1000);
+ }
+
+ return false;
+ }
+
+ // private static sleep(ms: number): void {
+ // Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
+ // }
+
+ private static writeImage(request: KittyImageMetadata): void {
+ if (this.checkSupport()) return;
+ let pngData = request.base64Data;
+
+ // Ga=T,q=2,o=z,s=1022,v=181,X=5;
+ const chunkSize = 1024;
+
+ //#region Header
+ let header = `\x1b_G`; // enable graphics
+ header += "a=T"; // action = transmit & display
+ header += ",q=2"; // suppress response
+ header += ",f=100"; // image format = png
+ header += ",t=d"; // transmission = direct
+ header += ",x=0"; // current x position
+ header += ",y=0"; // current y position
+ if (request.width) header += `,c=${request.width}`; // width (columns)
+ if (request.height) header += `,r=${request.height}`; // height (rows)
+ if (request.widthPixels) header += `,w=${request.widthPixels}`; // width (pixels)
+ if (request.heightPixels) header += `,h=${request.heightPixels}`; // height (pixels)
+ //#endregion
+
+ while (pngData.length > 0) {
+ const dataSize = Math.min(pngData.length, chunkSize);
+
+ process.stdout.write(
+ header + `,m=${dataSize == chunkSize ? 1 : 0};`,
+ );
+ process.stdout.write(pngData.slice(0, chunkSize));
+ pngData = pngData.slice(chunkSize);
+ process.stdout.write("\x1b\\");
+ }
+
+ if (request.addNewline) process.stdout.write("\n");
+ }
+}
+
+export class KittyImageMetadata {
+ public base64Data: string;
+ public width?: number;
+ public height?: number;
+ public widthPixels?: number;
+ public heightPixels?: number;
+ public addNewline?: boolean;
+}
+
+KittyLogo.printLogo();
+
+//
+// for (let i = 0; i < 10; i++) {
+// KittyLogo.printLogo();
+// }
+// for (let i = 0; i < 10; i++) {
+//
+// console.log(" ".repeat(i)+"meow");
+// }
diff --git a/src/util/util/Logo.ts b/src/util/util/Logo.ts
new file mode 100644
index 000000000..20a3253ad
--- /dev/null
+++ b/src/util/util/Logo.ts
@@ -0,0 +1,55 @@
+import { execSync } from "child_process";
+import findOnPath from "./os-utils/OsUtils";
+// noinspection ES6ConvertRequireIntoImport
+import terminfo from "./os-utils/TermInfo/TermInfo";
+import { KittyLogo } from "./KittyLogo";
+
+
+export class Logo {
+ public static printLogo() {
+ KittyLogo.printLogo();
+ // const chafaPath = findOnPath("chafa");
+ // console.log("Chafa path: " + chafaPath);
+ // const info = terminfo.parse({debug: true});
+ // process.exit(0);
+ return;
+ // console.log(info);
+ // if (chafaPath)
+ // return execSync(
+ // "chafa Spacebar__Logo-Blue.png -s 70",
+ // {
+ // env: process.env,
+ // encoding: "utf-8",
+ // stdio: "inherit"
+ // }
+ // );
+ // else console.log(Logo.logoVersions["1"] as string);
+ }
+
+ private static getConsoleColors(): number {
+ return 1;
+ if (!process.env.TERM) return 1;
+ else {
+ switch (process.env.TERM) {
+ case "":
+ break;
+
+ default:
+ break;
+ }
+ }
+ return 1;
+ }
+ private static logoVersions: any = {
+ "1": `
+ ███████╗██████╗ █████╗ ██████╗███████╗██████╗ █████╗ ██████╗
+ ██╔════╝██╔══██╗██╔══██╗██╔════╝██╔════╝██╔══██╗██╔══██╗██╔══██╗
+ ███████╗██████╔╝███████║██║ █████╗ ██████╔╝███████║██████╔╝
+ ╚════██║██╔═══╝ ██╔══██║██║ ██╔══╝ ██╔══██╗██╔══██║██╔══██╗
+ ███████║██║ ██║ ██║╚██████╗███████╗██████╔╝██║ ██║██║ ██║
+ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝╚══════╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝`,
+ "2": ``
+ };
+}
+
+Logo.printLogo();
\ No newline at end of file
diff --git a/src/util/util/String.ts b/src/util/util/String.ts
index 171bc3b6a..2d2e132a7 100644
--- a/src/util/util/String.ts
+++ b/src/util/util/String.ts
@@ -32,3 +32,9 @@ export function capitalize(str: string): string {
if (!str) return "";
return str.charAt(0).toUpperCase() + str.slice(1);
}
+
+export function centerString(str: string, len: number): string {
+ const pad = len - str.length;
+ const padLeft = Math.floor(pad / 2) + str.length;
+ return str.padStart(padLeft).padEnd(len);
+}
\ No newline at end of file
diff --git a/src/util/util/index.ts b/src/util/util/index.ts
index 4383c1d90..ce30b8005 100644
--- a/src/util/util/index.ts
+++ b/src/util/util/index.ts
@@ -44,4 +44,5 @@ export * from "./WebAuthn";
export * from "./Url";
export * from "./Gifs";
export * from "./Application";
+export * from "./Logo";
export * from "./NameValidation";
diff --git a/src/util/util/os-utils/OsUtils.ts b/src/util/util/os-utils/OsUtils.ts
new file mode 100644
index 000000000..babc99a1a
--- /dev/null
+++ b/src/util/util/os-utils/OsUtils.ts
@@ -0,0 +1,21 @@
+import { existsSync, statSync } from "fs";
+import os from "os";
+
+export default function findOnPath(binary: string): string | null {
+ const paths =
+ (os.platform() == "win32"
+ ? process.env.PATH?.split(";")
+ : process.env.PATH?.split(":")) || [];
+
+ if (os.platform() == "win32") {
+ binary += ".exe";
+ }
+
+ for (const path of paths) {
+ if (existsSync(`${path}/${binary}`)) {
+ const stat = statSync(`${path}/${binary}`);
+ if (stat.isFile() && stat.mode & 0o111) return `${path}/${binary}`;
+ }
+ }
+ return null;
+}
diff --git a/src/util/util/os-utils/TermInfo/Constants.ts b/src/util/util/os-utils/TermInfo/Constants.ts
new file mode 100644
index 000000000..34f6e4a66
--- /dev/null
+++ b/src/util/util/os-utils/TermInfo/Constants.ts
@@ -0,0 +1,964 @@
+"use strict";
+
+/* =========================================================================
+ * Copyright (c) 2016 Eivind Storm Aarnæs
+ * Licensed under the MIT license
+ * (see https://github.com/eistaa/parse-terminfo/blob/master/LICENSE)
+ * ========================================================================= */
+
+/*
+ * the variable names and capnames are from the terminfo(5) man page
+ */
+
+export const ALL_VARS: Record<string, string> = {
+ // ==============
+ // == BOOLEANS ==
+ // ==============
+ AUTO_LEFT_MARGIN: "bw",
+ AUTO_RIGHT_MARGIN: "am",
+ BACK_COLOR_ERASE: "bce",
+ CAN_CHANGE: "ccc",
+ CEOL_STANDOUT_GLITCH: "xhp",
+ COL_ADDR_GLITCH: "xhpa",
+ CPI_CHANGES_RES: "cpix",
+ CR_CANCELS_MICRO_MODE: "crxm",
+ DEST_TABS_MAGIC_SMSO: "xt",
+ EAT_NEWLINE_GLITCH: "xenl",
+ ERASE_OVERSTRIKE: "eo",
+ GENERIC_TYPE: "gn",
+ HARD_COPY: "hc",
+ HARD_CURSOR: "chts",
+ HAS_META_KEY: "km",
+ HAS_PRINT_WHEEL: "daisy",
+ HAS_STATUS_LINE: "hs",
+ HUE_LIGHTNESS_SATURATION: "hls",
+ INSERT_NULL_GLITCH: "in",
+ LPI_CHANGES_RES: "lpix",
+ MEMORY_ABOVE: "da",
+ MEMORY_BELOW: "db",
+ MOVE_INSERT_MODE: "mir",
+ MOVE_STANDOUT_MODE: "msgr",
+ NEEDS_XON_XOFF: "nxon",
+ NO_ESC_CTLC: "xsb",
+ NO_PAD_CHAR: "npc",
+ NON_DEST_SCROLL_REGION: "ndscr",
+ NON_REV_RMCUP: "nrrmc",
+ OVER_STRIKE: "os",
+ PRTR_SILENT: "mc5i",
+ ROW_ADDR_GLITCH: "xvpa",
+ SEMI_AUTO_RIGHT_MARGIN: "sam",
+ STATUS_LINE_ESC_OK: "eslok",
+ TILDE_GLITCH: "hz",
+ TRANSPARENT_UNDERLINE: "ul",
+ XON_XOFF: "xon",
+ // =============
+ // == NUMBERS ==
+ // =============
+ COLUMNS: "cols",
+ INIT_TABS: "it",
+ LABEL_HEIGHT: "lh",
+ LABEL_WIDTH: "lw",
+ LINES: "lines",
+ LINES_OF_MEMORY: "lm",
+ MAGIC_COOKIE_GLITCH: "xmc",
+ MAX_ATTRIBUTES: "ma",
+ MAX_COLORS: "colors",
+ MAX_PAIRS: "pairs",
+ MAXIMUM_WINDOWS: "wnum",
+ NO_COLOR_VIDEO: "ncv",
+ NUM_LABELS: "nlab",
+ PADDING_BAUD_RATE: "pb",
+ VIRTUAL_TERMINAL: "vt",
+ WIDTH_STATUS_LINE: "wsl",
+ BIT_IMAGE_ENTWINING: "bitwin",
+ BIT_IMAGE_TYPE: "bitype",
+ BUFFER_CAPACITY: "bufsz",
+ BUTTONS: "btns",
+ DOT_HORZ_SPACING: "spinh",
+ DOT_VERT_SPACING: "spinv",
+ MAX_MICRO_ADDRESS: "maddr",
+ MAX_MICRO_JUMP: "mjump",
+ MICRO_COL_SIZE: "mcs",
+ MICRO_LINE_SIZE: "mls",
+ NUMBER_OF_PINS: "npins",
+ OUTPUT_RES_CHAR: "orc",
+ OUTPUT_RES_HORZ_INCH: "orhi",
+ OUTPUT_RES_LINE: "orl",
+ OUTPUT_RES_VERT_INCH: "orvi",
+ PRINT_RATE: "cps",
+ WIDE_CHAR_SIZE: "widcs",
+ // =============
+ // == STRINGS ==
+ // =============
+ ACS_CHARS: "acsc",
+ BACK_TAB: "cbt",
+ BELL: "bel",
+ CARRIAGE_RETURN: "cr",
+ CHANGE_CHAR_PITCH: "cpi",
+ CHANGE_LINE_PITCH: "lpi",
+ CHANGE_RES_HORZ: "chr",
+ CHANGE_RES_VERT: "cvr",
+ CHANGE_SCROLL_REGION: "csr",
+ CHAR_PADDING: "rmp",
+ CLEAR_ALL_TABS: "tbc",
+ CLEAR_MARGINS: "mgc",
+ CLEAR_SCREEN: "clear",
+ CLR_BOL: "el1",
+ CLR_EOL: "el",
+ CLR_EOS: "ed",
+ COLUMN_ADDRESS: "hpa",
+ COMMAND_CHARACTER: "cmdch",
+ CREATE_WINDOW: "cwin",
+ CURSOR_ADDRESS: "cup",
+ CURSOR_DOWN: "cud1",
+ CURSOR_HOME: "home",
+ CURSOR_INVISIBLE: "civis",
+ CURSOR_LEFT: "cub1",
+ CURSOR_MEM_ADDRESS: "mrcup",
+ CURSOR_NORMAL: "cnorm",
+ CURSOR_RIGHT: "cuf1",
+ CURSOR_TO_LL: "ll",
+ CURSOR_UP: "cuu1",
+ CURSOR_VISIBLE: "cvvis",
+ DEFINE_CHAR: "defc",
+ DELETE_CHARACTER: "dch1",
+ DELETE_LINE: "dl1",
+ DIAL_PHONE: "dial",
+ DIS_STATUS_LINE: "dsl",
+ DISPLAY_CLOCK: "dclk",
+ DOWN_HALF_LINE: "hd",
+ ENA_ACS: "enacs",
+ ENTER_ALT_CHARSET_MODE: "smacs",
+ ENTER_AM_MODE: "smam",
+ ENTER_BLINK_MODE: "blink",
+ ENTER_BOLD_MODE: "bold",
+ ENTER_CA_MODE: "smcup",
+ ENTER_DELETE_MODE: "smdc",
+ ENTER_DIM_MODE: "dim",
+ ENTER_DOUBLEWIDE_MODE: "swidm",
+ ENTER_DRAFT_QUALITY: "sdrfq",
+ ENTER_INSERT_MODE: "smir",
+ ENTER_ITALICS_MODE: "sitm",
+ ENTER_LEFTWARD_MODE: "slm",
+ ENTER_MICRO_MODE: "smicm",
+ ENTER_NEAR_LETTER_QUALITY: "snlq",
+ ENTER_NORMAL_QUALITY: "snrmq",
+ ENTER_PROTECTED_MODE: "prot",
+ ENTER_REVERSE_MODE: "rev",
+ ENTER_SECURE_MODE: "invis",
+ ENTER_SHADOW_MODE: "sshm",
+ ENTER_STANDOUT_MODE: "smso",
+ ENTER_SUBSCRIPT_MODE: "ssubm",
+ ENTER_SUPERSCRIPT_MODE: "ssupm",
+ ENTER_UNDERLINE_MODE: "smul",
+ ENTER_UPWARD_MODE: "sum",
+ ENTER_XON_MODE: "smxon",
+ ERASE_CHARS: "ech",
+ EXIT_ALT_CHARSET_MODE: "rmacs",
+ EXIT_AM_MODE: "rmam",
+ EXIT_ATTRIBUTE_MODE: "sgr0",
+ EXIT_CA_MODE: "rmcup",
+ EXIT_DELETE_MODE: "rmdc",
+ EXIT_DOUBLEWIDE_MODE: "rwidm",
+ EXIT_INSERT_MODE: "rmir",
+ EXIT_ITALICS_MODE: "ritm",
+ EXIT_LEFTWARD_MODE: "rlm",
+ EXIT_MICRO_MODE: "rmicm",
+ EXIT_SHADOW_MODE: "rshm",
+ EXIT_STANDOUT_MODE: "rmso",
+ EXIT_SUBSCRIPT_MODE: "rsubm",
+ EXIT_SUPERSCRIPT_MODE: "rsupm",
+ EXIT_UNDERLINE_MODE: "rmul",
+ EXIT_UPWARD_MODE: "rum",
+ EXIT_XON_MODE: "rmxon",
+ FIXED_PAUSE: "pause",
+ FLASH_HOOK: "hook",
+ FLASH_SCREEN: "flash",
+ FORM_FEED: "ff",
+ FROM_STATUS_LINE: "fsl",
+ GOTO_WINDOW: "wingo",
+ HANGUP: "hup",
+ INIT_1STRING: "is1",
+ INIT_2STRING: "is2",
+ INIT_3STRING: "is3",
+ INIT_FILE: "if",
+ INIT_PROG: "iprog",
+ INITIALIZE_COLOR: "initc",
+ INITIALIZE_PAIR: "initp",
+ INSERT_CHARACTER: "ich1",
+ INSERT_LINE: "il1",
+ INSERT_PADDING: "ip",
+ KEY_A1: "ka1",
+ KEY_A3: "ka3",
+ KEY_B2: "kb2",
+ KEY_BACKSPACE: "kbs",
+ KEY_BEG: "kbeg",
+ KEY_BTAB: "kcbt",
+ KEY_C1: "kc1",
+ KEY_C3: "kc3",
+ KEY_CANCEL: "kcan",
+ KEY_CATAB: "ktbc",
+ KEY_CLEAR: "kclr",
+ KEY_CLOSE: "kclo",
+ KEY_COMMAND: "kcmd",
+ KEY_COPY: "kcpy",
+ KEY_CREATE: "kcrt",
+ KEY_CTAB: "kctab",
+ KEY_DC: "kdch1",
+ KEY_DL: "kdl1",
+ KEY_DOWN: "kcud1",
+ KEY_EIC: "krmir",
+ KEY_END: "kend",
+ KEY_ENTER: "kent",
+ KEY_EOL: "kel",
+ KEY_EOS: "ked",
+ KEY_EXIT: "kext",
+ KEY_F0: "kf0",
+ KEY_F1: "kf1",
+ KEY_F10: "kf10",
+ KEY_F11: "kf11",
+ KEY_F12: "kf12",
+ KEY_F13: "kf13",
+ KEY_F14: "kf14",
+ KEY_F15: "kf15",
+ KEY_F16: "kf16",
+ KEY_F17: "kf17",
+ KEY_F18: "kf18",
+ KEY_F19: "kf19",
+ KEY_F2: "kf2",
+ KEY_F20: "kf20",
+ KEY_F21: "kf21",
+ KEY_F22: "kf22",
+ KEY_F23: "kf23",
+ KEY_F24: "kf24",
+ KEY_F25: "kf25",
+ KEY_F26: "kf26",
+ KEY_F27: "kf27",
+ KEY_F28: "kf28",
+ KEY_F29: "kf29",
+ KEY_F3: "kf3",
+ KEY_F30: "kf30",
+ KEY_F31: "kf31",
+ KEY_F32: "kf32",
+ KEY_F33: "kf33",
+ KEY_F34: "kf34",
+ KEY_F35: "kf35",
+ KEY_F36: "kf36",
+ KEY_F37: "kf37",
+ KEY_F38: "kf38",
+ KEY_F39: "kf39",
+ KEY_F4: "kf4",
+ KEY_F40: "kf40",
+ KEY_F41: "kf41",
+ KEY_F42: "kf42",
+ KEY_F43: "kf43",
+ KEY_F44: "kf44",
+ KEY_F45: "kf45",
+ KEY_F46: "kf46",
+ KEY_F47: "kf47",
+ KEY_F48: "kf48",
+ KEY_F49: "kf49",
+ KEY_F5: "kf5",
+ KEY_F50: "kf50",
+ KEY_F51: "kf51",
+ KEY_F52: "kf52",
+ KEY_F53: "kf53",
+ KEY_F54: "kf54",
+ KEY_F55: "kf55",
+ KEY_F56: "kf56",
+ KEY_F57: "kf57",
+ KEY_F58: "kf58",
+ KEY_F59: "kf59",
+ KEY_F6: "kf6",
+ KEY_F60: "kf60",
+ KEY_F61: "kf61",
+ KEY_F62: "kf62",
+ KEY_F63: "kf63",
+ KEY_F7: "kf7",
+ KEY_F8: "kf8",
+ KEY_F9: "kf9",
+ KEY_FIND: "kfnd",
+ KEY_HELP: "khlp",
+ KEY_HOME: "khome",
+ KEY_IC: "kich1",
+ KEY_IL: "kil1",
+ KEY_LEFT: "kcub1",
+ KEY_LL: "kll",
+ KEY_MARK: "kmrk",
+ KEY_MESSAGE: "kmsg",
+ KEY_MOVE: "kmov",
+ KEY_NEXT: "knxt",
+ KEY_NPAGE: "knp",
+ KEY_OPEN: "kopn",
+ KEY_OPTIONS: "kopt",
+ KEY_PPAGE: "kpp",
+ KEY_PREVIOUS: "kprv",
+ KEY_PRINT: "kprt",
+ KEY_REDO: "krdo",
+ KEY_REFERENCE: "kref",
+ KEY_REFRESH: "krfr",
+ KEY_REPLACE: "krpl",
+ KEY_RESTART: "krst",
+ KEY_RESUME: "kres",
+ KEY_RIGHT: "kcuf1",
+ KEY_SAVE: "ksav",
+ KEY_SBEG: "kBEG",
+ KEY_SCANCEL: "kCAN",
+ KEY_SCOMMAND: "kCMD",
+ KEY_SCOPY: "kCPY",
+ KEY_SCREATE: "kCRT",
+ KEY_SDC: "kDC",
+ KEY_SDL: "kDL",
+ KEY_SELECT: "kslt",
+ KEY_SEND: "kEND",
+ KEY_SEOL: "kEOL",
+ KEY_SEXIT: "kEXT",
+ KEY_SF: "kind",
+ KEY_SFIND: "kFND",
+ KEY_SHELP: "kHLP",
+ KEY_SHOME: "kHOM",
+ KEY_SIC: "kIC",
+ KEY_SLEFT: "kLFT",
+ KEY_SMESSAGE: "kMSG",
+ KEY_SMOVE: "kMOV",
+ KEY_SNEXT: "kNXT",
+ KEY_SOPTIONS: "kOPT",
+ KEY_SPREVIOUS: "kPRV",
+ KEY_SPRINT: "kPRT",
+ KEY_SR: "kri",
+ KEY_SREDO: "kRDO",
+ KEY_SREPLACE: "kRPL",
+ KEY_SRIGHT: "kRIT",
+ KEY_SRSUME: "kRES",
+ KEY_SSAVE: "kSAV",
+ KEY_SSUSPEND: "kSPD",
+ KEY_STAB: "khts",
+ KEY_SUNDO: "kUND",
+ KEY_SUSPEND: "kspd",
+ KEY_UNDO: "kund",
+ KEY_UP: "kcuu1",
+ KEYPAD_LOCAL: "rmkx",
+ KEYPAD_XMIT: "smkx",
+ LAB_F0: "lf0",
+ LAB_F1: "lf1",
+ LAB_F10: "lf10",
+ LAB_F2: "lf2",
+ LAB_F3: "lf3",
+ LAB_F4: "lf4",
+ LAB_F5: "lf5",
+ LAB_F6: "lf6",
+ LAB_F7: "lf7",
+ LAB_F8: "lf8",
+ LAB_F9: "lf9",
+ LABEL_FORMAT: "fln",
+ LABEL_OFF: "rmln",
+ LABEL_ON: "smln",
+ META_OFF: "rmm",
+ META_ON: "smm",
+ MICRO_COLUMN_ADDRESS: "mhpa",
+ MICRO_DOWN: "mcud1",
+ MICRO_LEFT: "mcub1",
+ MICRO_RIGHT: "mcuf1",
+ MICRO_ROW_ADDRESS: "mvpa",
+ MICRO_UP: "mcuu1",
+ NEWLINE: "nel",
+ ORDER_OF_PINS: "porder",
+ ORIG_COLORS: "oc",
+ ORIG_PAIR: "op",
+ PAD_CHAR: "pad",
+ PARM_DCH: "dch",
+ PARM_DELETE_LINE: "dl",
+ PARM_DOWN_CURSOR: "cud",
+ PARM_DOWN_MICRO: "mcud",
+ PARM_ICH: "ich",
+ PARM_INDEX: "indn",
+ PARM_INSERT_LINE: "il",
+ PARM_LEFT_CURSOR: "cub",
+ PARM_LEFT_MICRO: "mcub",
+ PARM_RIGHT_CURSOR: "cuf",
+ PARM_RIGHT_MICRO: "mcuf",
+ PARM_RINDEX: "rin",
+ PARM_UP_CURSOR: "cuu",
+ PARM_UP_MICRO: "mcuu",
+ PKEY_KEY: "pfkey",
+ PKEY_LOCAL: "pfloc",
+ PKEY_XMIT: "pfx",
+ PLAB_NORM: "pln",
+ PRINT_SCREEN: "mc0",
+ PRTR_NON: "mc5p",
+ PRTR_OFF: "mc4",
+ PRTR_ON: "mc5",
+ PULSE: "pulse",
+ QUICK_DIAL: "qdial",
+ REMOVE_CLOCK: "rmclk",
+ REPEAT_CHAR: "rep",
+ REQ_FOR_INPUT: "rfi",
+ RESET_1STRING: "rs1",
+ RESET_2STRING: "rs2",
+ RESET_3STRING: "rs3",
+ RESET_FILE: "rf",
+ RESTORE_CURSOR: "rc",
+ ROW_ADDRESS: "vpa",
+ SAVE_CURSOR: "sc",
+ SCROLL_FORWARD: "ind",
+ SCROLL_REVERSE: "ri",
+ SELECT_CHAR_SET: "scs",
+ SET_ATTRIBUTES: "sgr",
+ SET_BACKGROUND: "setb",
+ SET_BOTTOM_MARGIN: "smgb",
+ SET_BOTTOM_MARGIN_PARM: "smgbp",
+ SET_CLOCK: "sclk",
+ SET_COLOR_PAIR: "scp",
+ SET_FOREGROUND: "setf",
+ SET_LEFT_MARGIN: "smgl",
+ SET_LEFT_MARGIN_PARM: "smglp",
+ SET_RIGHT_MARGIN: "smgr",
+ SET_RIGHT_MARGIN_PARM: "smgrp",
+ SET_TAB: "hts",
+ SET_TOP_MARGIN: "smgt",
+ SET_TOP_MARGIN_PARM: "smgtp",
+ SET_WINDOW: "wind",
+ START_BIT_IMAGE: "sbim",
+ START_CHAR_SET_DEF: "scsd",
+ STOP_BIT_IMAGE: "rbim",
+ STOP_CHAR_SET_DEF: "rcsd",
+ SUBSCRIPT_CHARACTERS: "subcs",
+ SUPERSCRIPT_CHARACTERS: "supcs",
+ TAB: "ht",
+ THESE_CAUSE_CR: "docr",
+ TO_STATUS_LINE: "tsl",
+ TONE: "tone",
+ UNDERLINE_CHAR: "uc",
+ UP_HALF_LINE: "hu",
+ USER0: "u0",
+ USER1: "u1",
+ USER2: "u2",
+ USER3: "u3",
+ USER4: "u4",
+ USER5: "u5",
+ USER6: "u6",
+ USER7: "u7",
+ USER8: "u8",
+ USER9: "u9",
+ WAIT_TONE: "wait",
+ XOFF_CHARACTER: "xoffc",
+ XON_CHARACTER: "xonc",
+ ZERO_MOTION: "zerom",
+ ALT_SCANCODE_ESC: "scesa",
+ BIT_IMAGE_CARRIAGE_RETURN: "bicr",
+ BIT_IMAGE_NEWLINE: "binel",
+ BIT_IMAGE_REPEAT: "birep",
+ CHAR_SET_NAMES: "csnm",
+ CODE_SET_INIT: "csin",
+ COLOR_NAMES: "colornm",
+ DEFINE_BIT_IMAGE_REGION: "defbi",
+ DEVICE_TYPE: "devt",
+ DISPLAY_PC_CHAR: "dispc",
+ END_BIT_IMAGE_REGION: "endbi",
+ ENTER_PC_CHARSET_MODE: "smpch",
+ ENTER_SCANCODE_MODE: "smsc",
+ EXIT_PC_CHARSET_MODE: "rmpch",
+ EXIT_SCANCODE_MODE: "rmsc",
+ GET_MOUSE: "getm",
+ KEY_MOUSE: "kmous",
+ MOUSE_INFO: "minfo",
+ PC_TERM_OPTIONS: "pctrm",
+ PKEY_PLAB: "pfxl",
+ REQ_MOUSE_POS: "reqmp",
+ SCANCODE_ESCAPE: "scesc",
+ SET0_DES_SEQ: "s0ds",
+ SET1_DES_SEQ: "s1ds",
+ SET2_DES_SEQ: "s2ds",
+ SET3_DES_SEQ: "s3ds",
+ SET_A_BACKGROUND: "setab",
+ SET_A_FOREGROUND: "setaf",
+ SET_COLOR_BAND: "setcolor",
+ SET_LR_MARGIN: "smglr",
+ SET_PAGE_LENGTH: "slines",
+ SET_TB_MARGIN: "smgtb",
+ ENTER_HORIZONTAL_HL_MODE: "ehhlm",
+ ENTER_LEFT_HL_MODE: "elhlm",
+ ENTER_LOW_HL_MODE: "elohlm",
+ ENTER_RIGHT_HL_MODE: "erhlm",
+ ENTER_TOP_HL_MODE: "ethlm",
+ ENTER_VERTICAL_HL_MODE: "evhlm",
+ SET_A_ATTRIBUTES: "sgr1",
+ SET_PGLEN_INCH: "slength",
+};
+
+/*
+ * the order of the variables are from the header file <term.h>
+ */
+
+export const VARORDER: Record<"booleans" | "numbers" | "strings", string[]> = {
+ booleans: [
+ "AUTO_LEFT_MARGIN",
+ "AUTO_RIGHT_MARGIN",
+ "NO_ESC_CTLC",
+ "CEOL_STANDOUT_GLITCH",
+ "EAT_NEWLINE_GLITCH",
+ "ERASE_OVERSTRIKE",
+ "GENERIC_TYPE",
+ "HARD_COPY",
+ "HAS_META_KEY",
+ "HAS_STATUS_LINE",
+ "INSERT_NULL_GLITCH",
+ "MEMORY_ABOVE",
+ "MEMORY_BELOW",
+ "MOVE_INSERT_MODE",
+ "MOVE_STANDOUT_MODE",
+ "OVER_STRIKE",
+ "STATUS_LINE_ESC_OK",
+ "DEST_TABS_MAGIC_SMSO",
+ "TILDE_GLITCH",
+ "TRANSPARENT_UNDERLINE",
+ "XON_XOFF",
+ "NEEDS_XON_XOFF",
+ "PRTR_SILENT",
+ "HARD_CURSOR",
+ "NON_REV_RMCUP",
+ "NO_PAD_CHAR",
+ "NON_DEST_SCROLL_REGION",
+ "CAN_CHANGE",
+ "BACK_COLOR_ERASE",
+ "HUE_LIGHTNESS_SATURATION",
+ "COL_ADDR_GLITCH",
+ "CR_CANCELS_MICRO_MODE",
+ "HAS_PRINT_WHEEL",
+ "ROW_ADDR_GLITCH",
+ "SEMI_AUTO_RIGHT_MARGIN",
+ "CPI_CHANGES_RES",
+ "LPI_CHANGES_RES",
+ ],
+ numbers: [
+ "COLUMNS",
+ "INIT_TABS",
+ "LINES",
+ "LINES_OF_MEMORY",
+ "MAGIC_COOKIE_GLITCH",
+ "PADDING_BAUD_RATE",
+ "VIRTUAL_TERMINAL",
+ "WIDTH_STATUS_LINE",
+ "NUM_LABELS",
+ "LABEL_HEIGHT",
+ "LABEL_WIDTH",
+ "MAX_ATTRIBUTES",
+ "MAXIMUM_WINDOWS",
+ "MAX_COLORS",
+ "MAX_PAIRS",
+ "NO_COLOR_VIDEO",
+ "BUFFER_CAPACITY",
+ "DOT_VERT_SPACING",
+ "DOT_HORZ_SPACING",
+ "MAX_MICRO_ADDRESS",
+ "MAX_MICRO_JUMP",
+ "MICRO_COL_SIZE",
+ "MICRO_LINE_SIZE",
+ "NUMBER_OF_PINS",
+ "OUTPUT_RES_CHAR",
+ "OUTPUT_RES_LINE",
+ "OUTPUT_RES_HORZ_INCH",
+ "OUTPUT_RES_VERT_INCH",
+ "PRINT_RATE",
+ "WIDE_CHAR_SIZE",
+ "BUTTONS",
+ "BIT_IMAGE_ENTWINING",
+ "BIT_IMAGE_TYPE",
+ ],
+ strings: [
+ "BACK_TAB",
+ "BELL",
+ "CARRIAGE_RETURN",
+ "CHANGE_SCROLL_REGION",
+ "CLEAR_ALL_TABS",
+ "CLEAR_SCREEN",
+ "CLR_EOL",
+ "CLR_EOS",
+ "COLUMN_ADDRESS",
+ "COMMAND_CHARACTER",
+ "CURSOR_ADDRESS",
+ "CURSOR_DOWN",
+ "CURSOR_HOME",
+ "CURSOR_INVISIBLE",
+ "CURSOR_LEFT",
+ "CURSOR_MEM_ADDRESS",
+ "CURSOR_NORMAL",
+ "CURSOR_RIGHT",
+ "CURSOR_TO_LL",
+ "CURSOR_UP",
+ "CURSOR_VISIBLE",
+ "DELETE_CHARACTER",
+ "DELETE_LINE",
+ "DIS_STATUS_LINE",
+ "DOWN_HALF_LINE",
+ "ENTER_ALT_CHARSET_MODE",
+ "ENTER_BLINK_MODE",
+ "ENTER_BOLD_MODE",
+ "ENTER_CA_MODE",
+ "ENTER_DELETE_MODE",
+ "ENTER_DIM_MODE",
+ "ENTER_INSERT_MODE",
+ "ENTER_SECURE_MODE",
+ "ENTER_PROTECTED_MODE",
+ "ENTER_REVERSE_MODE",
+ "ENTER_STANDOUT_MODE",
+ "ENTER_UNDERLINE_MODE",
+ "ERASE_CHARS",
+ "EXIT_ALT_CHARSET_MODE",
+ "EXIT_ATTRIBUTE_MODE",
+ "EXIT_CA_MODE",
+ "EXIT_DELETE_MODE",
+ "EXIT_INSERT_MODE",
+ "EXIT_STANDOUT_MODE",
+ "EXIT_UNDERLINE_MODE",
+ "FLASH_SCREEN",
+ "FORM_FEED",
+ "FROM_STATUS_LINE",
+ "INIT_1STRING",
+ "INIT_2STRING",
+ "INIT_3STRING",
+ "INIT_FILE",
+ "INSERT_CHARACTER",
+ "INSERT_LINE",
+ "INSERT_PADDING",
+ "KEY_BACKSPACE",
+ "KEY_CATAB",
+ "KEY_CLEAR",
+ "KEY_CTAB",
+ "KEY_DC",
+ "KEY_DL",
+ "KEY_DOWN",
+ "KEY_EIC",
+ "KEY_EOL",
+ "KEY_EOS",
+ "KEY_F0",
+ "KEY_F1",
+ "KEY_F10",
+ "KEY_F2",
+ "KEY_F3",
+ "KEY_F4",
+ "KEY_F5",
+ "KEY_F6",
+ "KEY_F7",
+ "KEY_F8",
+ "KEY_F9",
+ "KEY_HOME",
+ "KEY_IC",
+ "KEY_IL",
+ "KEY_LEFT",
+ "KEY_LL",
+ "KEY_NPAGE",
+ "KEY_PPAGE",
+ "KEY_RIGHT",
+ "KEY_SF",
+ "KEY_SR",
+ "KEY_STAB",
+ "KEY_UP",
+ "KEYPAD_LOCAL",
+ "KEYPAD_XMIT",
+ "LAB_F0",
+ "LAB_F1",
+ "LAB_F10",
+ "LAB_F2",
+ "LAB_F3",
+ "LAB_F4",
+ "LAB_F5",
+ "LAB_F6",
+ "LAB_F7",
+ "LAB_F8",
+ "LAB_F9",
+ "META_OFF",
+ "META_ON",
+ "NEWLINE",
+ "PAD_CHAR",
+ "PARM_DCH",
+ "PARM_DELETE_LINE",
+ "PARM_DOWN_CURSOR",
+ "PARM_ICH",
+ "PARM_INDEX",
+ "PARM_INSERT_LINE",
+ "PARM_LEFT_CURSOR",
+ "PARM_RIGHT_CURSOR",
+ "PARM_RINDEX",
+ "PARM_UP_CURSOR",
+ "PKEY_KEY",
+ "PKEY_LOCAL",
+ "PKEY_XMIT",
+ "PRINT_SCREEN",
+ "PRTR_OFF",
+ "PRTR_ON",
+ "REPEAT_CHAR",
+ "RESET_1STRING",
+ "RESET_2STRING",
+ "RESET_3STRING",
+ "RESET_FILE",
+ "RESTORE_CURSOR",
+ "ROW_ADDRESS",
+ "SAVE_CURSOR",
+ "SCROLL_FORWARD",
+ "SCROLL_REVERSE",
+ "SET_ATTRIBUTES",
+ "SET_TAB",
+ "SET_WINDOW",
+ "TAB",
+ "TO_STATUS_LINE",
+ "UNDERLINE_CHAR",
+ "UP_HALF_LINE",
+ "INIT_PROG",
+ "KEY_A1",
+ "KEY_A3",
+ "KEY_B2",
+ "KEY_C1",
+ "KEY_C3",
+ "PRTR_NON",
+ "CHAR_PADDING",
+ "ACS_CHARS",
+ "PLAB_NORM",
+ "KEY_BTAB",
+ "ENTER_XON_MODE",
+ "EXIT_XON_MODE",
+ "ENTER_AM_MODE",
+ "EXIT_AM_MODE",
+ "XON_CHARACTER",
+ "XOFF_CHARACTER",
+ "ENA_ACS",
+ "LABEL_ON",
+ "LABEL_OFF",
+ "KEY_BEG",
+ "KEY_CANCEL",
+ "KEY_CLOSE",
+ "KEY_COMMAND",
+ "KEY_COPY",
+ "KEY_CREATE",
+ "KEY_END",
+ "KEY_ENTER",
+ "KEY_EXIT",
+ "KEY_FIND",
+ "KEY_HELP",
+ "KEY_MARK",
+ "KEY_MESSAGE",
+ "KEY_MOVE",
+ "KEY_NEXT",
+ "KEY_OPEN",
+ "KEY_OPTIONS",
+ "KEY_PREVIOUS",
+ "KEY_PRINT",
+ "KEY_REDO",
+ "KEY_REFERENCE",
+ "KEY_REFRESH",
+ "KEY_REPLACE",
+ "KEY_RESTART",
+ "KEY_RESUME",
+ "KEY_SAVE",
+ "KEY_SUSPEND",
+ "KEY_UNDO",
+ "KEY_SBEG",
+ "KEY_SCANCEL",
+ "KEY_SCOMMAND",
+ "KEY_SCOPY",
+ "KEY_SCREATE",
+ "KEY_SDC",
+ "KEY_SDL",
+ "KEY_SELECT",
+ "KEY_SEND",
+ "KEY_SEOL",
+ "KEY_SEXIT",
+ "KEY_SFIND",
+ "KEY_SHELP",
+ "KEY_SHOME",
+ "KEY_SIC",
+ "KEY_SLEFT",
+ "KEY_SMESSAGE",
+ "KEY_SMOVE",
+ "KEY_SNEXT",
+ "KEY_SOPTIONS",
+ "KEY_SPREVIOUS",
+ "KEY_SPRINT",
+ "KEY_SREDO",
+ "KEY_SREPLACE",
+ "KEY_SRIGHT",
+ "KEY_SRSUME",
+ "KEY_SSAVE",
+ "KEY_SSUSPEND",
+ "KEY_SUNDO",
+ "REQ_FOR_INPUT",
+ "KEY_F11",
+ "KEY_F12",
+ "KEY_F13",
+ "KEY_F14",
+ "KEY_F15",
+ "KEY_F16",
+ "KEY_F17",
+ "KEY_F18",
+ "KEY_F19",
+ "KEY_F20",
+ "KEY_F21",
+ "KEY_F22",
+ "KEY_F23",
+ "KEY_F24",
+ "KEY_F25",
+ "KEY_F26",
+ "KEY_F27",
+ "KEY_F28",
+ "KEY_F29",
+ "KEY_F30",
+ "KEY_F31",
+ "KEY_F32",
+ "KEY_F33",
+ "KEY_F34",
+ "KEY_F35",
+ "KEY_F36",
+ "KEY_F37",
+ "KEY_F38",
+ "KEY_F39",
+ "KEY_F40",
+ "KEY_F41",
+ "KEY_F42",
+ "KEY_F43",
+ "KEY_F44",
+ "KEY_F45",
+ "KEY_F46",
+ "KEY_F47",
+ "KEY_F48",
+ "KEY_F49",
+ "KEY_F50",
+ "KEY_F51",
+ "KEY_F52",
+ "KEY_F53",
+ "KEY_F54",
+ "KEY_F55",
+ "KEY_F56",
+ "KEY_F57",
+ "KEY_F58",
+ "KEY_F59",
+ "KEY_F60",
+ "KEY_F61",
+ "KEY_F62",
+ "KEY_F63",
+ "CLR_BOL",
+ "CLEAR_MARGINS",
+ "SET_LEFT_MARGIN",
+ "SET_RIGHT_MARGIN",
+ "LABEL_FORMAT",
+ "SET_CLOCK",
+ "DISPLAY_CLOCK",
+ "REMOVE_CLOCK",
+ "CREATE_WINDOW",
+ "GOTO_WINDOW",
+ "HANGUP",
+ "DIAL_PHONE",
+ "QUICK_DIAL",
+ "TONE",
+ "PULSE",
+ "FLASH_HOOK",
+ "FIXED_PAUSE",
+ "WAIT_TONE",
+ "USER0",
+ "USER1",
+ "USER2",
+ "USER3",
+ "USER4",
+ "USER5",
+ "USER6",
+ "USER7",
+ "USER8",
+ "USER9",
+ "ORIG_PAIR",
+ "ORIG_COLORS",
+ "INITIALIZE_COLOR",
+ "INITIALIZE_PAIR",
+ "SET_COLOR_PAIR",
+ "SET_FOREGROUND",
+ "SET_BACKGROUND",
+ "CHANGE_CHAR_PITCH",
+ "CHANGE_LINE_PITCH",
+ "CHANGE_RES_HORZ",
+ "CHANGE_RES_VERT",
+ "DEFINE_CHAR",
+ "ENTER_DOUBLEWIDE_MODE",
+ "ENTER_DRAFT_QUALITY",
+ "ENTER_ITALICS_MODE",
+ "ENTER_LEFTWARD_MODE",
+ "ENTER_MICRO_MODE",
+ "ENTER_NEAR_LETTER_QUALITY",
+ "ENTER_NORMAL_QUALITY",
+ "ENTER_SHADOW_MODE",
+ "ENTER_SUBSCRIPT_MODE",
+ "ENTER_SUPERSCRIPT_MODE",
+ "ENTER_UPWARD_MODE",
+ "EXIT_DOUBLEWIDE_MODE",
+ "EXIT_ITALICS_MODE",
+ "EXIT_LEFTWARD_MODE",
+ "EXIT_MICRO_MODE",
+ "EXIT_SHADOW_MODE",
+ "EXIT_SUBSCRIPT_MODE",
+ "EXIT_SUPERSCRIPT_MODE",
+ "EXIT_UPWARD_MODE",
+ "MICRO_COLUMN_ADDRESS",
+ "MICRO_DOWN",
+ "MICRO_LEFT",
+ "MICRO_RIGHT",
+ "MICRO_ROW_ADDRESS",
+ "MICRO_UP",
+ "ORDER_OF_PINS",
+ "PARM_DOWN_MICRO",
+ "PARM_LEFT_MICRO",
+ "PARM_RIGHT_MICRO",
+ "PARM_UP_MICRO",
+ "SELECT_CHAR_SET",
+ "SET_BOTTOM_MARGIN",
+ "SET_BOTTOM_MARGIN_PARM",
+ "SET_LEFT_MARGIN_PARM",
+ "SET_RIGHT_MARGIN_PARM",
+ "SET_TOP_MARGIN",
+ "SET_TOP_MARGIN_PARM",
+ "START_BIT_IMAGE",
+ "START_CHAR_SET_DEF",
+ "STOP_BIT_IMAGE",
+ "STOP_CHAR_SET_DEF",
+ "SUBSCRIPT_CHARACTERS",
+ "SUPERSCRIPT_CHARACTERS",
+ "THESE_CAUSE_CR",
+ "ZERO_MOTION",
+ "CHAR_SET_NAMES",
+ "KEY_MOUSE",
+ "MOUSE_INFO",
+ "REQ_MOUSE_POS",
+ "GET_MOUSE",
+ "SET_A_FOREGROUND",
+ "SET_A_BACKGROUND",
+ "PKEY_PLAB",
+ "DEVICE_TYPE",
+ "CODE_SET_INIT",
+ "SET0_DES_SEQ",
+ "SET1_DES_SEQ",
+ "SET2_DES_SEQ",
+ "SET3_DES_SEQ",
+ "SET_LR_MARGIN",
+ "SET_TB_MARGIN",
+ "BIT_IMAGE_REPEAT",
+ "BIT_IMAGE_NEWLINE",
+ "BIT_IMAGE_CARRIAGE_RETURN",
+ "COLOR_NAMES",
+ "DEFINE_BIT_IMAGE_REGION",
+ "END_BIT_IMAGE_REGION",
+ "SET_COLOR_BAND",
+ "SET_PAGE_LENGTH",
+ "DISPLAY_PC_CHAR",
+ "ENTER_PC_CHARSET_MODE",
+ "EXIT_PC_CHARSET_MODE",
+ "ENTER_SCANCODE_MODE",
+ "EXIT_SCANCODE_MODE",
+ "PC_TERM_OPTIONS",
+ "SCANCODE_ESCAPE",
+ "ALT_SCANCODE_ESC",
+ "ENTER_HORIZONTAL_HL_MODE",
+ "ENTER_LEFT_HL_MODE",
+ "ENTER_LOW_HL_MODE",
+ "ENTER_RIGHT_HL_MODE",
+ "ENTER_TOP_HL_MODE",
+ "ENTER_VERTICAL_HL_MODE",
+ "SET_A_ATTRIBUTES",
+ "SET_PGLEN_INCH",
+ ],
+};
diff --git a/src/util/util/os-utils/TermInfo/TermInfo.ts b/src/util/util/os-utils/TermInfo/TermInfo.ts
new file mode 100644
index 000000000..bc669960d
--- /dev/null
+++ b/src/util/util/os-utils/TermInfo/TermInfo.ts
@@ -0,0 +1,50 @@
+// SOURCE: https://github.com/eistaa/parse-terminfo
+/* =========================================================================
+ * Copyright (c) 2016 Eivind Storm Aarnæs
+ * Licensed under the MIT license
+ * (see https://github.com/eistaa/parse-terminfo/blob/master/LICENSE)
+ * ========================================================================= */
+
+import { openTerminfoBuffer } from "./openTerminfoBuffer";
+import { parseTerminfo, TermInfo } from "./parseTerminfo";
+
+export class ParseOptions {
+ term?: string;
+ directories?: string[];
+ debug: boolean = false;
+}
+
+export function parse(opts?: ParseOptions): TermInfo {
+ let term;
+
+ if (process.platform === "win32")
+ throw new Error("no terminfo for windows...");
+
+ // get term
+ if (opts?.term) {
+ term = String(opts.term);
+ } else {
+ if (process.env.TERM && process.env.TERM !== "") {
+ term = process.env.TERM;
+ } else {
+ throw new Error(
+ "No terminal specified (`opts.term`) and TERM is undefined",
+ );
+ }
+ }
+
+ if(opts?.debug) console.log("Parsing terminfo for", term);
+
+ const bufferData = openTerminfoBuffer(term, opts);
+ const capabilities = parseTerminfo(bufferData.buffer, term, opts);
+ capabilities.path = bufferData.path;
+
+ if(opts?.debug) console.log("Parsed terminfo for", term, ":", capabilities);
+
+ return capabilities;
+}
+
+export default {
+ VARIABLES: require("./Constants").ALL_VARS,
+ parse
+};
diff --git a/src/util/util/os-utils/TermInfo/openTerminfoBuffer.ts b/src/util/util/os-utils/TermInfo/openTerminfoBuffer.ts
new file mode 100644
index 000000000..6e71510cb
--- /dev/null
+++ b/src/util/util/os-utils/TermInfo/openTerminfoBuffer.ts
@@ -0,0 +1,104 @@
+/* =========================================================================
+ * Copyright (c) 2016 Eivind Storm Aarnæs
+ * Licensed under the MIT license
+ * (see https://github.com/eistaa/parse-terminfo/blob/master/LICENSE)
+ * ========================================================================= */
+
+import fs from "fs";
+import path from "path";
+import { ParseOptions } from "./TermInfo";
+
+const DEFAULT_DB_DIRECTORIES = [
+ "/etc/terminfo",
+ "/lib/terminfo",
+ "/usr/share/terminfo",
+];
+
+function isDirectory(directory: string) {
+ try {
+ return fs.statSync(path.normalize(directory.trim())).isDirectory();
+ } catch (err) {
+ return false;
+ }
+}
+
+function constructDBDirectories(dirs?: string[] | string) {
+ /*
+ * the ordering comes from manpage 'terminfo(5)'
+ */
+
+ const directories: string[] = [];
+
+ // argument can be array or string
+ if (dirs) {
+ if (Array.isArray(dirs)) {
+ dirs.filter(isDirectory).forEach((dir) => directories.push(dir));
+ } else {
+ if (isDirectory(dirs)) directories.push(dirs);
+ }
+ }
+
+ // TERMINFO may exist
+ if (process.env.TERMINFO && isDirectory(process.env.TERMINFO))
+ directories.push(process.env.TERMINFO);
+
+ // there may be a local terminfo directory
+ if (
+ process.env.HOME &&
+ isDirectory(path.normalize(path.join(process.env.HOME, ".terminfo")))
+ )
+ directories.push(path.join(process.env.HOME, ".terminfo"));
+
+ // TERMINFO_DIRS can contain a :-separated list of directories
+ if (process.env.TERMINFO_DIRS) {
+ const terminfoDirectories = process.env.TERMINFO_DIRS.split(":");
+ terminfoDirectories
+ .filter(isDirectory)
+ .forEach((dir) => directories.push(dir));
+ }
+
+ // default to hardcoded directories
+ DEFAULT_DB_DIRECTORIES.filter(isDirectory).forEach((dir) =>
+ directories.push(dir),
+ );
+
+ return directories;
+}
+
+export function openTerminfoBuffer(
+ term: string,
+ opts: ParseOptions | undefined,
+) {
+ // determine directories
+ const directories = constructDBDirectories(opts?.directories);
+
+ if (opts?.debug) console.log("Directories:", directories);
+
+ let filepath;
+
+ if (directories.length === 0)
+ throw new Error("No terminfo database directories exist");
+
+ // use first valid directory
+ for (let i = 0; i < directories.length; i++) {
+ try {
+ filepath = path.join(directories[i], term.charAt(0), term);
+ if (fs.statSync(filepath).isFile()) {
+ if (opts?.debug)
+ console.log("Found terminfo data at", filepath);
+ break;
+ }
+ } catch (err) {
+ filepath = undefined;
+ }
+ }
+
+ if (filepath === undefined)
+ throw new Error("Found no terminfo database for " + term);
+
+ // read to buffer
+ return {
+ path: filepath,
+ buffer: fs.readFileSync(filepath),
+ };
+}
diff --git a/src/util/util/os-utils/TermInfo/parseTerminfo.ts b/src/util/util/os-utils/TermInfo/parseTerminfo.ts
new file mode 100644
index 000000000..71a4b933b
--- /dev/null
+++ b/src/util/util/os-utils/TermInfo/parseTerminfo.ts
@@ -0,0 +1,159 @@
+"use strict";
+
+/* =========================================================================
+ * Copyright (c) 2016 Eivind Storm Aarnæs
+ * Licensed under the MIT license
+ * (see https://github.com/eistaa/parse-terminfo/blob/master/LICENSE)
+ * ========================================================================= */
+
+import { ALL_VARS, VARORDER } from "./Constants";
+
+/*
+ * based of on the format description in the term(5) manual page.
+ */
+
+export class TermInfo {
+ description?: string;
+ term?: string[];
+ capabilities: {
+ booleans: Record<string, boolean>;
+ numbers: Record<string, number>;
+ strings: Record<string, string>;
+ };
+ path: string;
+ integerSize: number;
+}
+
+export function parseTerminfo(
+ buffer: Buffer,
+ term: string,
+ opts?: { debug: boolean },
+): TermInfo {
+ let offset = 0;
+
+ function readInt() {
+ const result = buffer.readInt16LE(offset);
+ console.log("Read int @", offset, ":", result);
+ offset += 2;
+ return result;
+ }
+
+ /// @type {{ description: string | undefined; term: string[] | undefined; capabilities: { booleans: {}; numbers: {}; strings: {}; }; }}
+ const result: TermInfo = {
+ capabilities: {
+ booleans: {},
+ numbers: {},
+ strings: {},
+ },
+ path: "",
+ description: undefined,
+ term: undefined,
+ integerSize: 0,
+ };
+
+ // check the magic number
+ const magic = readInt();
+
+ // if (magic !== 0x011a)
+ // throw new Error("invalid magic number in buffer for " + term + ": " + magic.toString(16));
+ switch (magic) {
+ case 0x011a:
+ result.integerSize = 16;
+ break;
+ case 0x21e:
+ result.integerSize = 32;
+ break;
+ default:
+ throw new Error(
+ "invalid magic number in buffer for " +
+ term +
+ ": " +
+ magic.toString(16),
+ );
+ }
+
+ if (opts?.debug) console.log("Magic number:", magic, "Integer size:", result.integerSize);
+
+ //offset += 2;
+
+ // parse section sizes
+ const sizes = {
+ names: readInt(),
+ booleans: readInt(),
+ numbers: readInt(),
+ strings: readInt(),
+ table: readInt(),
+ };
+
+ if (opts?.debug) console.log("Section sizes:", sizes);
+
+ //offset += 10;
+
+ // parse names section
+ const names = buffer
+ .toString("ascii", offset, offset + sizes.names - 1)
+ .split("|");
+ result.term = names[0].split("|");
+ result.description = names[1];
+ if (opts?.debug)
+ console.log("Got info:", {
+ term: result.term,
+ description: result.description,
+ });
+ offset += sizes.names;
+
+ // parse booleans
+ let boolean;
+ const numBools = Math.min(VARORDER.booleans.length, sizes.booleans);
+ for (let i = 0; i < numBools; i++) {
+ if (i >= VARORDER.booleans.length) {
+ if (opts?.debug) console.log("Read boolean overran length");
+ continue;
+ } // doesn't (yet) support extended terminfo
+
+ const data = buffer.readInt8(offset + i);
+ if (opts?.debug && data != 0 && data != 1)
+ console.log("Invalid boolean data:", data.toString(16));
+
+ boolean = !!data;
+ if (boolean)
+ result.capabilities.booleans[ALL_VARS[VARORDER.booleans[i]]] = true;
+ }
+ offset += sizes.booleans + ((offset + sizes.booleans) % 2); // padded to short boundary
+
+ // parse numbers
+ let number;
+ const numNumbers = Math.min(VARORDER.numbers.length, sizes.numbers);
+ for (let i = 0; i < numNumbers; i++) {
+ if (i >= VARORDER.numbers.length) continue; // doesn't (yet) support extended terminfo
+
+ number = buffer.readInt16LE(offset + 2 * i);
+ if (number !== -1)
+ result.capabilities.numbers[ALL_VARS[VARORDER.numbers[i]]] = number;
+ }
+ offset += 2 * sizes.numbers;
+ if (opts?.debug)
+ console.log("Read numbers up to", offset, ":", result.capabilities.numbers);
+
+ // parse strings
+ let tableOffset, valueEnd;
+ const tableStart = offset + 2 * sizes.strings;
+ const numStrings = Math.min(VARORDER.strings.length, sizes.strings);
+ for (let i = 0; i < numStrings; i++) {
+ if (i >= VARORDER.strings.length) continue; // doesn't (yet) support extended terminfo
+
+ tableOffset = buffer.readInt16LE(offset + 2 * i);
+ if (tableOffset !== -1) {
+ valueEnd = tableStart + tableOffset;
+ while (buffer[valueEnd++] !== 0); // string values are null terminated
+ result.capabilities.strings[ALL_VARS[VARORDER.strings[i]]] =
+ buffer.toString(
+ "ascii",
+ tableStart + tableOffset,
+ valueEnd - 1,
+ );
+ }
+ }
+
+ return result;
+}
|