1
0
mirror of https://github.com/spacebarchat/server.git synced 2024-11-22 02:12:40 +01:00

WIP logo/terminal stuff

This commit is contained in:
Emma [it/its]@Rory& 2024-10-27 23:30:14 +01:00
parent a4a70cf89b
commit 70cbd7d2de
15 changed files with 1552 additions and 26 deletions

BIN
assets/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -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 {

View File

@ -58,7 +58,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);

View File

@ -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();

View File

@ -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(

141
src/util/util/KittyLogo.ts Normal file
View File

@ -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");
// }

55
src/util/util/Logo.ts Normal file
View File

@ -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();

View File

@ -22,3 +22,9 @@ export function trimSpecial(str?: string): string {
if (!str) return "";
return str.replace(SPECIAL_CHAR, "").trim();
}
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);
}

View File

@ -43,3 +43,4 @@ export * from "./TraverseDirectory";
export * from "./WebAuthn";
export * from "./Gifs";
export * from "./Application";
export * from "./Logo";

View File

@ -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;
}

View File

@ -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",
],
};

View File

@ -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
};

View File

@ -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),
};
}

View File

@ -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;
}