Initial commit
						commit
						fdad031f12
					
				@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					/@types/
 | 
				
			||||||
 | 
					/lib/
 | 
				
			||||||
 | 
					/node_modules/
 | 
				
			||||||
@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  useTabs: true,
 | 
				
			||||||
 | 
					  tabWidth: 4,
 | 
				
			||||||
 | 
					  trailingComma: "es5",
 | 
				
			||||||
 | 
					  "overrides": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "files": "*.yml",
 | 
				
			||||||
 | 
					      "options": {
 | 
				
			||||||
 | 
					        "tabWidth": 2,
 | 
				
			||||||
 | 
					        "useTabs": false
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name": "node-zenity",
 | 
				
			||||||
 | 
					  "version": "1.0.0",
 | 
				
			||||||
 | 
					  "lockfileVersion": 1,
 | 
				
			||||||
 | 
					  "requires": true,
 | 
				
			||||||
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "@types/node": {
 | 
				
			||||||
 | 
					      "version": "14.14.17",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.17.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-G0lD1/7qD60TJ/mZmhog76k7NcpLWkPVGgzkRy3CTlnFu4LUQh5v2Wa661z6vnXmD8EQrnALUyf0VRtrACYztw=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "typescript": {
 | 
				
			||||||
 | 
					      "version": "4.1.3",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==",
 | 
				
			||||||
 | 
					      "dev": true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
						"name": "node-zenity",
 | 
				
			||||||
 | 
						"description": "Node zenity bindings with typescript support",
 | 
				
			||||||
 | 
						"version": "1.0.0",
 | 
				
			||||||
 | 
						"author": "Kuba Orlik <kontakt@kuba-orlik.name>",
 | 
				
			||||||
 | 
						"license": "MIT",
 | 
				
			||||||
 | 
						"main": "./lib/index.js",
 | 
				
			||||||
 | 
						"types": "./@types/index.d.ts",
 | 
				
			||||||
 | 
						"scripts": {
 | 
				
			||||||
 | 
							"build": "tsc",
 | 
				
			||||||
 | 
							"watch": "npm run build -- --watch"
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						"dependencies": {
 | 
				
			||||||
 | 
							"@types/node": "^14.14.17"
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						"devDependencies": {
 | 
				
			||||||
 | 
							"typescript": "^4.1.3"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,183 @@
 | 
				
			|||||||
 | 
					import { ChildProcessWithoutNullStreams, spawn } from "child_process";
 | 
				
			||||||
 | 
					import { EventEmitter } from "events";
 | 
				
			||||||
 | 
					import { promisify } from "util";
 | 
				
			||||||
 | 
					import simpleSpawn from "./simple-spawn";
 | 
				
			||||||
 | 
					import sleep from "./sleep";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type DialogOptions = Record<
 | 
				
			||||||
 | 
						string,
 | 
				
			||||||
 | 
						true | string | undefined | string[]
 | 
				
			||||||
 | 
					>; // array value means use this flag this many times
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let last_position: { x: number; y: number } | null = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function get_geometry() {
 | 
				
			||||||
 | 
						const result = (await simpleSpawn("bash", [
 | 
				
			||||||
 | 
							"-c",
 | 
				
			||||||
 | 
							'wmctrl -l -x node-zenity -G | grep node-zenity | awk \'{print $3 " " $4 " " $5 " " $6}\'',
 | 
				
			||||||
 | 
						])) as string;
 | 
				
			||||||
 | 
						const [x, y, width, height] = result
 | 
				
			||||||
 | 
							.split("\n")[0]
 | 
				
			||||||
 | 
							.split(" ")
 | 
				
			||||||
 | 
							.map((s) => parseInt(s));
 | 
				
			||||||
 | 
						return { x, y, width, height };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function set_geometry({
 | 
				
			||||||
 | 
						x,
 | 
				
			||||||
 | 
						y,
 | 
				
			||||||
 | 
						width,
 | 
				
			||||||
 | 
						height,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
						x: number;
 | 
				
			||||||
 | 
						y: number;
 | 
				
			||||||
 | 
						width?: number;
 | 
				
			||||||
 | 
						height?: number;
 | 
				
			||||||
 | 
					}) {
 | 
				
			||||||
 | 
						if (width === undefined) {
 | 
				
			||||||
 | 
							width = -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (height === undefined) {
 | 
				
			||||||
 | 
							height = -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						await simpleSpawn("wmctrl", [
 | 
				
			||||||
 | 
							"-x",
 | 
				
			||||||
 | 
							"-a",
 | 
				
			||||||
 | 
							"node-zenity",
 | 
				
			||||||
 | 
							"-e",
 | 
				
			||||||
 | 
							`0,${Math.round(x)},${Math.round(y)},${Math.round(width)},${Math.round(
 | 
				
			||||||
 | 
								height
 | 
				
			||||||
 | 
							)}`,
 | 
				
			||||||
 | 
						]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type DialogResponse = {
 | 
				
			||||||
 | 
						code: number;
 | 
				
			||||||
 | 
						output: string;
 | 
				
			||||||
 | 
						error: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class Dialog extends EventEmitter {
 | 
				
			||||||
 | 
						shown = false;
 | 
				
			||||||
 | 
						process: ChildProcessWithoutNullStreams;
 | 
				
			||||||
 | 
						output: string = "";
 | 
				
			||||||
 | 
						error: string = "";
 | 
				
			||||||
 | 
						constructor(
 | 
				
			||||||
 | 
							public type_option: string,
 | 
				
			||||||
 | 
							public args: DialogOptions,
 | 
				
			||||||
 | 
							public positional_args: string[] = []
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							super();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private prepareArguments(): string[] {
 | 
				
			||||||
 | 
							const ret = [`--${this.type_option}`];
 | 
				
			||||||
 | 
							for (const arg in this.args) {
 | 
				
			||||||
 | 
								const value = this.args[arg];
 | 
				
			||||||
 | 
								if (typeof value === "boolean") {
 | 
				
			||||||
 | 
									ret.push(`--${arg}`);
 | 
				
			||||||
 | 
								} else if (typeof value === "string") {
 | 
				
			||||||
 | 
									ret.push(`--${arg}=${value}`);
 | 
				
			||||||
 | 
								} else if (Array.isArray(value)) {
 | 
				
			||||||
 | 
									value.forEach((element) => ret.push(`--${arg}=${element}`));
 | 
				
			||||||
 | 
								} else if (value === undefined) {
 | 
				
			||||||
 | 
									//void
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									console.log("unknown value:", value);
 | 
				
			||||||
 | 
									throw new Error("uknown arg value type");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						async show(): Promise<void> {
 | 
				
			||||||
 | 
							const args: string[] = [
 | 
				
			||||||
 | 
								"--class=node-zenity",
 | 
				
			||||||
 | 
								...this.prepareArguments(),
 | 
				
			||||||
 | 
								...this.positional_args,
 | 
				
			||||||
 | 
							];
 | 
				
			||||||
 | 
							console.log("spawning process!", args.join(" "));
 | 
				
			||||||
 | 
							this.process = spawn("zenity", args);
 | 
				
			||||||
 | 
							let position_listener_interval = setInterval(async () => {
 | 
				
			||||||
 | 
								const { x, y, width, height } = await get_geometry();
 | 
				
			||||||
 | 
								console.log(
 | 
				
			||||||
 | 
									{ x, y, width, height },
 | 
				
			||||||
 | 
									{ x: Math.round(x + width / 2), y: Math.round(y + height / 2) }
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
								last_position = {
 | 
				
			||||||
 | 
									x: Math.round(x + width / 2),
 | 
				
			||||||
 | 
									y: Math.round(y + height / 2),
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
							}, 2000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let spawned = false;
 | 
				
			||||||
 | 
							return new Promise((resolve, reject) => {
 | 
				
			||||||
 | 
								this.process.on("spawn", async () => {
 | 
				
			||||||
 | 
									spawned = true;
 | 
				
			||||||
 | 
									resolve();
 | 
				
			||||||
 | 
									let tries = 0;
 | 
				
			||||||
 | 
									let succeded = false;
 | 
				
			||||||
 | 
									while (!succeded && tries < 15) {
 | 
				
			||||||
 | 
										try {
 | 
				
			||||||
 | 
											tries++;
 | 
				
			||||||
 | 
											await sleep(50);
 | 
				
			||||||
 | 
											await simpleSpawn("wmctrl", [
 | 
				
			||||||
 | 
												"-x",
 | 
				
			||||||
 | 
												"-r",
 | 
				
			||||||
 | 
												"node-zenity",
 | 
				
			||||||
 | 
												"-b",
 | 
				
			||||||
 | 
												"add,above",
 | 
				
			||||||
 | 
											]); // to  pin to top
 | 
				
			||||||
 | 
											await simpleSpawn("wmctrl", [
 | 
				
			||||||
 | 
												"-x",
 | 
				
			||||||
 | 
												"-a",
 | 
				
			||||||
 | 
												"node-zenity",
 | 
				
			||||||
 | 
											]); // to activate it
 | 
				
			||||||
 | 
											if (last_position) {
 | 
				
			||||||
 | 
												const { width, height } = await get_geometry();
 | 
				
			||||||
 | 
												await set_geometry({
 | 
				
			||||||
 | 
													x: last_position.x - width / 2 - 11,
 | 
				
			||||||
 | 
													y: last_position.y - height / 2 - 82,
 | 
				
			||||||
 | 
												}); // to put it where it last was
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											succeded = true;
 | 
				
			||||||
 | 
											console.log("WMCTRL SUCCEEDED!");
 | 
				
			||||||
 | 
										} catch (e) {
 | 
				
			||||||
 | 
											console.error(e);
 | 
				
			||||||
 | 
											continue;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
								this.process.stdout.on("data", (chunk) => {
 | 
				
			||||||
 | 
									this.output += chunk;
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
								this.process.stderr.on("data", (chunk) => {
 | 
				
			||||||
 | 
									this.error += chunk;
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
								this.process.on("close", (code) => {
 | 
				
			||||||
 | 
									clearInterval(position_listener_interval);
 | 
				
			||||||
 | 
									console.log("process closed. output:", this.output);
 | 
				
			||||||
 | 
									if (code !== 0) {
 | 
				
			||||||
 | 
										if (!spawned) {
 | 
				
			||||||
 | 
											reject({ code, message: this.error });
 | 
				
			||||||
 | 
										} else {
 | 
				
			||||||
 | 
											this.emit("error", code);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										this.emit("done");
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						getAnswer(): Promise<DialogResponse> {
 | 
				
			||||||
 | 
							return new Promise((resolve, reject) => {
 | 
				
			||||||
 | 
								this.on("done", () =>
 | 
				
			||||||
 | 
									resolve({ code: 0, output: this.output, error: this.error })
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
								this.on("error", (code) => {
 | 
				
			||||||
 | 
									resolve({ code, output: this.output, error: this.error });
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					import Dialog from "./dialog";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class Entry {
 | 
				
			||||||
 | 
						static async show(
 | 
				
			||||||
 | 
							options?: Partial<{
 | 
				
			||||||
 | 
								text: string;
 | 
				
			||||||
 | 
								"entry-text": string;
 | 
				
			||||||
 | 
								"hide-text": true;
 | 
				
			||||||
 | 
								title: string;
 | 
				
			||||||
 | 
								width: number;
 | 
				
			||||||
 | 
								height: number;
 | 
				
			||||||
 | 
							}>
 | 
				
			||||||
 | 
						): Promise<string> {
 | 
				
			||||||
 | 
							const dialog = new Dialog("entry", {
 | 
				
			||||||
 | 
								...options,
 | 
				
			||||||
 | 
								width: ((options?.width as unknown) as string)?.toString(),
 | 
				
			||||||
 | 
								height: ((options?.height as unknown) as string)?.toString(),
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
							await dialog.show();
 | 
				
			||||||
 | 
							return dialog.output.split("\n")[0];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					import Dialog from "./dialog";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class FileSelection {
 | 
				
			||||||
 | 
						static async getFile(
 | 
				
			||||||
 | 
							options: Partial<{
 | 
				
			||||||
 | 
								multiple?: true;
 | 
				
			||||||
 | 
								directory?: true;
 | 
				
			||||||
 | 
								save?: true;
 | 
				
			||||||
 | 
								separator: string;
 | 
				
			||||||
 | 
								"confirm-overwrite"?: true;
 | 
				
			||||||
 | 
								"file-filter": string;
 | 
				
			||||||
 | 
								title: string;
 | 
				
			||||||
 | 
							}>
 | 
				
			||||||
 | 
						): Promise<string[]> {
 | 
				
			||||||
 | 
							const dialog = new Dialog("file-selection", options);
 | 
				
			||||||
 | 
							await dialog.show();
 | 
				
			||||||
 | 
							await dialog.getAnswer();
 | 
				
			||||||
 | 
							return dialog.output.split("\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					export { default as FileSelection } from "./file-selection";
 | 
				
			||||||
 | 
					export { default as Info } from "./info";
 | 
				
			||||||
 | 
					export {
 | 
				
			||||||
 | 
						default as List,
 | 
				
			||||||
 | 
						responseIsCustomButton,
 | 
				
			||||||
 | 
						ItemsSelectedResponse,
 | 
				
			||||||
 | 
					} from "./list";
 | 
				
			||||||
 | 
					export { default as Entry } from "./entry";
 | 
				
			||||||
@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					import Dialog from "./dialog";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class Info {
 | 
				
			||||||
 | 
						static async show(
 | 
				
			||||||
 | 
							text: string,
 | 
				
			||||||
 | 
							options?: Partial<{
 | 
				
			||||||
 | 
								"icon-name": string;
 | 
				
			||||||
 | 
								"no-wrap": true;
 | 
				
			||||||
 | 
								"no-markup": true;
 | 
				
			||||||
 | 
								ellipsize: true;
 | 
				
			||||||
 | 
								title: string;
 | 
				
			||||||
 | 
							}>
 | 
				
			||||||
 | 
						): Promise<void> {
 | 
				
			||||||
 | 
							const dialog = new Dialog("info", { ...options, text });
 | 
				
			||||||
 | 
							await dialog.show();
 | 
				
			||||||
 | 
							await dialog.getAnswer();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,103 @@
 | 
				
			|||||||
 | 
					import Dialog, { DialogOptions } from "./dialog";
 | 
				
			||||||
 | 
					import sleep from "./sleep";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type ListOptions = {
 | 
				
			||||||
 | 
						mode: "checklist" | "radiolist" | "imagelist" | "list";
 | 
				
			||||||
 | 
						columns: string[];
 | 
				
			||||||
 | 
					} & Partial<{
 | 
				
			||||||
 | 
						title: string;
 | 
				
			||||||
 | 
						text: string;
 | 
				
			||||||
 | 
						rows: string[][];
 | 
				
			||||||
 | 
						multiple: true;
 | 
				
			||||||
 | 
						separator: string;
 | 
				
			||||||
 | 
						editable: true;
 | 
				
			||||||
 | 
						"print-column": number;
 | 
				
			||||||
 | 
						extraButtons: string[];
 | 
				
			||||||
 | 
						height: number;
 | 
				
			||||||
 | 
						width: number;
 | 
				
			||||||
 | 
					}>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type CustomButtonPressed = { _type: "custom_button"; button_pressed: string };
 | 
				
			||||||
 | 
					export type ItemsSelectedResponse = {
 | 
				
			||||||
 | 
						_type: "items_selected";
 | 
				
			||||||
 | 
						items_selected: string[];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type ListResponse = CustomButtonPressed | ItemsSelectedResponse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function responseIsCustomButton(
 | 
				
			||||||
 | 
						response: ListResponse
 | 
				
			||||||
 | 
					): response is CustomButtonPressed {
 | 
				
			||||||
 | 
						return response._type === "custom_button";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class List {
 | 
				
			||||||
 | 
						private dialog: Dialog;
 | 
				
			||||||
 | 
						constructor(private options: ListOptions) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						async show(): Promise<void> {
 | 
				
			||||||
 | 
							const dialog = new Dialog(
 | 
				
			||||||
 | 
								"list",
 | 
				
			||||||
 | 
								List.prepareOptions(this.options),
 | 
				
			||||||
 | 
								List.preparePositionalArguments(this.options)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							this.dialog = dialog;
 | 
				
			||||||
 | 
							await dialog.show();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						async getAnswer(): Promise<ListResponse> {
 | 
				
			||||||
 | 
							const response = await this.dialog.getAnswer();
 | 
				
			||||||
 | 
							if (response.code === 1) {
 | 
				
			||||||
 | 
								return {
 | 
				
			||||||
 | 
									_type: "custom_button",
 | 
				
			||||||
 | 
									button_pressed: response.output.split("\n")[0],
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return {
 | 
				
			||||||
 | 
								_type: "items_selected",
 | 
				
			||||||
 | 
								items_selected: response.output
 | 
				
			||||||
 | 
									.split("\n")[0]
 | 
				
			||||||
 | 
									.split(this.options.separator || "|"),
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static async showAndGetAnswer(options: ListOptions) {
 | 
				
			||||||
 | 
							const list = new List(options);
 | 
				
			||||||
 | 
							await list.show();
 | 
				
			||||||
 | 
							return list.getAnswer();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static prepareOptions(options: ListOptions): DialogOptions {
 | 
				
			||||||
 | 
							const ret: DialogOptions = {};
 | 
				
			||||||
 | 
							if (options.mode !== "list") {
 | 
				
			||||||
 | 
								ret[options.mode] = true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ret.title = options.title;
 | 
				
			||||||
 | 
							ret.text = options.text;
 | 
				
			||||||
 | 
							if (options.columns) {
 | 
				
			||||||
 | 
								ret.column = options.columns;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ret.multiple = options.multiple;
 | 
				
			||||||
 | 
							ret.separator = options.separator;
 | 
				
			||||||
 | 
							ret.editable = options.editable;
 | 
				
			||||||
 | 
							ret["print-column"] = options["print-column"]?.toString();
 | 
				
			||||||
 | 
							ret["extra-button"] = options.extraButtons;
 | 
				
			||||||
 | 
							ret.height = options.height?.toString();
 | 
				
			||||||
 | 
							ret.width = options.width?.toString();
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static preparePositionalArguments(options: ListOptions): string[] {
 | 
				
			||||||
 | 
							const ret: string[] = [];
 | 
				
			||||||
 | 
							for (const row of options.rows || []) {
 | 
				
			||||||
 | 
								for (const element of row) {
 | 
				
			||||||
 | 
									ret.push(element);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hide() {
 | 
				
			||||||
 | 
							this.dialog.process.kill();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					import { spawn } from "child_process";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function simpleSpawn(cmd: string, arg: string[]) {
 | 
				
			||||||
 | 
						const process = spawn(cmd, arg);
 | 
				
			||||||
 | 
						let output = "";
 | 
				
			||||||
 | 
						let err = "";
 | 
				
			||||||
 | 
						return new Promise((resolve, reject) => {
 | 
				
			||||||
 | 
							process.on("close", (code) => {
 | 
				
			||||||
 | 
								code === 0 ? resolve(output) : reject(err);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
							process.stdout.on("data", (data) => (output += data.toString("utf-8")));
 | 
				
			||||||
 | 
							process.stderr.on("data", (data) => (err += data.toString("utf-8")));
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					import { promisify } from "util";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const sleep = (timeout: number) =>
 | 
				
			||||||
 | 
						promisify((time: number, cb: (...args: any[]) => void) =>
 | 
				
			||||||
 | 
							setTimeout(cb, time)
 | 
				
			||||||
 | 
						)(timeout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default sleep;
 | 
				
			||||||
@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "compilerOptions": {
 | 
				
			||||||
 | 
					    "module": "commonjs",
 | 
				
			||||||
 | 
					    "moduleResolution": "node",
 | 
				
			||||||
 | 
					    "noImplicitAny": true,
 | 
				
			||||||
 | 
					    "noImplicitThis": true,
 | 
				
			||||||
 | 
					    "strictNullChecks": true,
 | 
				
			||||||
 | 
					    "target": "ES2020",
 | 
				
			||||||
 | 
					    "declaration": true,
 | 
				
			||||||
 | 
					    "esModuleInterop": true,
 | 
				
			||||||
 | 
					    "lib": ["es6", "esnext"],
 | 
				
			||||||
 | 
					    "outDir": "lib",
 | 
				
			||||||
 | 
					    "checkJs": true,
 | 
				
			||||||
 | 
					    "allowJs": true,
 | 
				
			||||||
 | 
					    "declarationDir": "@types",
 | 
				
			||||||
 | 
					    "resolveJsonModule": true,
 | 
				
			||||||
 | 
					    "sourceMap": true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "include": ["src/**/*"]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
					Loading…
					
					
				
		Reference in New Issue