From 33312438728a34a5480cfb5fa69fe267d8ea57d1 Mon Sep 17 00:00:00 2001 From: Rudis Muiznieks Date: Wed, 20 Apr 2022 08:05:21 -0500 Subject: [PATCH] async menu handling --- bin/main.js | 123 +++++++++++++++++++++++++++------- bin/menu/console.js | 151 ++++++++++++++++++++++++++++++------------ bin/menu/menu.js | 42 +++++++++++- bin/menu/oled.js | 42 +++++++++++- package.json | 2 + src/main.ts | 74 +++++++++++++-------- src/menu/console.ts | 83 ++++++++++++++--------- src/menu/interface.ts | 2 +- src/menu/menu.ts | 2 +- src/menu/oled.ts | 2 +- 10 files changed, 393 insertions(+), 130 deletions(-) diff --git a/bin/main.js b/bin/main.js index ff5a472..7b8d012 100644 --- a/bin/main.js +++ b/bin/main.js @@ -1,31 +1,108 @@ "use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; exports.__esModule = true; var menu_1 = require("./menu/menu"); var interface_1 = require("./menu/interface"); -var menu = new menu_1.Menu([ - { - display: "df -h", - type: interface_1.MenuType.ExecCommand, - command: ["df", "-h"] - }, - { - display: "Games", - type: interface_1.MenuType.SubMenu, - subMenu: [ +var Main = /** @class */ (function () { + function Main() { + this._menu = [ { - display: "Chess", + display: "df -h", type: interface_1.MenuType.ExecCommand, command: ["df", "-h"] }, - ] - }, - { - display: "Reboot", - type: interface_1.MenuType.Reboot - }, - { - display: "Shutdown", - type: interface_1.MenuType.Shutdown - }, -], true); -menu.getSelection(); + { + display: "Games", + type: interface_1.MenuType.SubMenu, + subMenu: [ + { + display: "Chess", + type: interface_1.MenuType.ExecCommand, + command: ["df", "-h"] + }, + ] + }, + { + display: "Reboot", + type: interface_1.MenuType.Reboot + }, + { + display: "Shutdown", + type: interface_1.MenuType.Shutdown + }, + ]; + } + Main.prototype.runAsync = function () { + return __awaiter(this, void 0, void 0, function () { + var selected; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!true) return [3 /*break*/, 2]; + return [4 /*yield*/, new menu_1.Menu(this._menu, process.env['CONSOLE'] === '1').getSelection()]; + case 1: + selected = _a.sent(); + switch (selected.type) { + case interface_1.MenuType.Shutdown: + process.exit(); + case interface_1.MenuType.Reboot: + process.exit(); + case interface_1.MenuType.ExecCommand: + break; + } + return [3 /*break*/, 0]; + case 2: return [2 /*return*/]; + } + }); + }); + }; + return Main; +}()); +function run() { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, new Main().runAsync()]; + case 1: + _a.sent(); + return [2 /*return*/]; + } + }); + }); +} +run(); diff --git a/bin/menu/console.js b/bin/menu/console.js index 2e2bfa6..4cfbe43 100644 --- a/bin/menu/console.js +++ b/bin/menu/console.js @@ -22,6 +22,42 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; exports.__esModule = true; exports.ConsolePrinter = void 0; var interface_1 = require("./interface"); @@ -31,7 +67,22 @@ var ConsolePrinter = /** @class */ (function () { this._path = []; this._selectedIndex = 0; this._config = config; + readline.emitKeypressEvents(process.stdin); + process.stdin.setRawMode(true); } + ConsolePrinter.prototype.keypress = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, new Promise(function (resolve) { + var listener = function (_letter, key) { + process.stdin.removeListener('keypress', listener); + resolve(key); + }; + process.stdin.on('keypress', listener); + })]; + }); + }); + }; ConsolePrinter.prototype.printMenu = function (curMenu) { console.clear(); for (var i = 0; i < curMenu.length; i++) { @@ -42,49 +93,65 @@ var ConsolePrinter = /** @class */ (function () { } }; ConsolePrinter.prototype.getSelection = function () { - var _this = this; - var curMenu = this._config; - this.printMenu(curMenu); - // get user input - readline.emitKeypressEvents(process.stdin); - process.stdin.setRawMode(true); - process.stdin.on('keypress', function (_letter, key) { - if (key.ctrl && key.name === 'c') { - process.exit(); - } - else if (key.name === 'up') { - _this._selectedIndex--; - if (_this._selectedIndex < 0) { - _this._selectedIndex = 0; - } - } - else if (key.name === 'down') { - _this._selectedIndex++; - if (_this._selectedIndex > curMenu.length - 1) { - _this._selectedIndex = curMenu.length - 1; - } - } - else if (key.name === 'left') { - if (_this._path.length > 0) { - _this._path.pop(); - } - } - else if (key.name === 'right' || key.name === 'enter') { - if (curMenu[_this._selectedIndex].type === interface_1.MenuType.SubMenu) { - _this._path.push(_this._selectedIndex); - _this._selectedIndex = 0; - } - else { - process.exit(); - } - } - curMenu = _this._config; - for (var i = 0; i < _this._path.length; i++) { - curMenu = curMenu[_this._path[i]].subMenu; - } - _this.printMenu(curMenu); + return __awaiter(this, void 0, void 0, function () { + var _this = this; + return __generator(this, function (_a) { + return [2 /*return*/, new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () { + var curMenu, key, i; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + curMenu = this._config; + _a.label = 1; + case 1: + if (!true) return [3 /*break*/, 3]; + // print menu + this.printMenu(curMenu); + return [4 /*yield*/, this.keypress()]; + case 2: + key = _a.sent(); + if (key.ctrl && key.name === 'c') { + process.exit(); + } + else if (key.name === 'up') { + this._selectedIndex--; + if (this._selectedIndex < 0) { + this._selectedIndex = 0; + } + } + else if (key.name === 'down') { + this._selectedIndex++; + if (this._selectedIndex > curMenu.length - 1) { + this._selectedIndex = curMenu.length - 1; + } + } + else if (key.name === 'left') { + if (this._path.length > 0) { + this._path.pop(); + this._selectedIndex = 0; + } + } + else if (key.name === 'right' || key.name === 'return') { + this._path.push(this._selectedIndex); + this._selectedIndex = 0; + } + curMenu = this._config; + for (i = 0; i < this._path.length; i++) { + if (curMenu[this._path[i]].type === interface_1.MenuType.SubMenu) { + curMenu = curMenu[this._path[i]].subMenu; + } + else { + resolve(curMenu[this._path[i]]); + return [2 /*return*/]; + } + } + return [3 /*break*/, 1]; + case 3: return [2 /*return*/]; + } + }); + }); })]; + }); }); - return this._config[this._selectedIndex]; }; return ConsolePrinter; }()); diff --git a/bin/menu/menu.js b/bin/menu/menu.js index 09f6b9e..916e294 100644 --- a/bin/menu/menu.js +++ b/bin/menu/menu.js @@ -1,4 +1,40 @@ "use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; exports.__esModule = true; exports.Menu = void 0; var console_1 = require("./console"); @@ -11,7 +47,11 @@ var Menu = /** @class */ (function () { : new oled_1.OledPrinter(config); } Menu.prototype.getSelection = function () { - return this._printer.getSelection(); + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this._printer.getSelection()]; + }); + }); }; return Menu; }()); diff --git a/bin/menu/oled.js b/bin/menu/oled.js index 6d405cc..aa30692 100644 --- a/bin/menu/oled.js +++ b/bin/menu/oled.js @@ -1,4 +1,40 @@ "use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; exports.__esModule = true; exports.OledPrinter = void 0; /*const i2cbus = openSync(1); @@ -19,7 +55,11 @@ var OledPrinter = /** @class */ (function () { this._config = config; } OledPrinter.prototype.getSelection = function () { - return this._config[0]; + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this._config[0]]; + }); + }); }; return OledPrinter; }()); diff --git a/package.json b/package.json index 29fc0f8..927abbf 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,6 @@ { + "name": "z3r0haxx", + "version": "1.0.0", "scripts": { "clean": "rm -rf bin/*", "build": "npm run clean && tsc --project tsconfig.json", diff --git a/src/main.ts b/src/main.ts index 5cc8fc5..41e3651 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,31 +1,51 @@ import { Menu } from './menu/menu'; import { MenuType } from './menu/interface'; -const menu = new Menu([ - { - display: "df -h", - type: MenuType.ExecCommand, - command: ["df", "-h"], - }, - { - display: "Games", - type: MenuType.SubMenu, - subMenu: [ - { - display: "Chess", - type: MenuType.ExecCommand, - command: ["df", "-h"], - }, - ], - }, - { - display: "Reboot", - type: MenuType.Reboot, - }, - { - display: "Shutdown", - type: MenuType.Shutdown, - }, -], true); +class Main { + private readonly _menu = [ + { + display: "df -h", + type: MenuType.ExecCommand, + command: ["df", "-h"], + }, + { + display: "Games", + type: MenuType.SubMenu, + subMenu: [ + { + display: "Chess", + type: MenuType.ExecCommand, + command: ["df", "-h"], + }, + ], + }, + { + display: "Reboot", + type: MenuType.Reboot, + }, + { + display: "Shutdown", + type: MenuType.Shutdown, + }, + ]; -menu.getSelection(); + public async runAsync(): Promise { + while (true) { + const selected = await new Menu(this._menu, process.env['CONSOLE'] === '1').getSelection(); + switch(selected.type) { + case MenuType.Shutdown: + process.exit(); + case MenuType.Reboot: + process.exit(); + case MenuType.ExecCommand: + break; + } + } + } +} + +async function run() { + await new Main().runAsync(); +} + +run(); diff --git a/src/menu/console.ts b/src/menu/console.ts index bf47bfa..2df9235 100644 --- a/src/menu/console.ts +++ b/src/menu/console.ts @@ -1,6 +1,8 @@ import { MenuConfig, MenuPrinter, MenuType } from './interface'; import * as readline from 'readline'; +type Key = {name: string, ctrl: boolean}; + export class ConsolePrinter implements MenuPrinter { private _path: number[] = []; private _selectedIndex: number = 0; @@ -8,6 +10,18 @@ export class ConsolePrinter implements MenuPrinter { constructor(config: MenuConfig[]) { this._config = config; + readline.emitKeypressEvents(process.stdin); + process.stdin.setRawMode(true); + } + + private async keypress(): Promise { + return new Promise((resolve) => { + const listener = (_letter: string, key: Key): void => { + process.stdin.removeListener('keypress', listener); + resolve(key); + } + process.stdin.on('keypress', listener); + }); } private printMenu(curMenu: MenuConfig[]): void { @@ -20,44 +34,47 @@ export class ConsolePrinter implements MenuPrinter { } } - public getSelection(): MenuConfig { - let curMenu = this._config; - this.printMenu(curMenu); + public async getSelection(): Promise { + return new Promise(async (resolve) => { + let curMenu = this._config; + while (true) { + // print menu + this.printMenu(curMenu); - // get user input - readline.emitKeypressEvents(process.stdin); - process.stdin.setRawMode(true); - process.stdin.on('keypress', (_letter, key: any) => { - if (key.ctrl && key.name === 'c') { - process.exit(); - } else if (key.name === 'up') { - this._selectedIndex--; - if (this._selectedIndex < 0) { - this._selectedIndex = 0; - } - } else if (key.name ==='down') { - this._selectedIndex++ - if (this._selectedIndex > curMenu.length - 1) { - this._selectedIndex = curMenu.length - 1; - } - } else if (key.name === 'left') { - if (this._path.length > 0) { - this._path.pop(); - } - } else if (key.name === 'right' || key.name === 'enter') { - if (curMenu[this._selectedIndex].type === MenuType.SubMenu) { + // get user input + const key = await this.keypress(); + + if (key.ctrl && key.name === 'c') { + process.exit(); + } else if (key.name === 'up') { + this._selectedIndex--; + if (this._selectedIndex < 0) { + this._selectedIndex = 0; + } + } else if (key.name ==='down') { + this._selectedIndex++ + if (this._selectedIndex > curMenu.length - 1) { + this._selectedIndex = curMenu.length - 1; + } + } else if (key.name === 'left') { + if (this._path.length > 0) { + this._path.pop(); + this._selectedIndex = 0; + } + } else if (key.name === 'right' || key.name === 'return') { this._path.push(this._selectedIndex); this._selectedIndex = 0; - } else { - process.exit() + } + curMenu = this._config; + for (let i = 0; i < this._path.length; i++) { + if (curMenu[this._path[i]].type === MenuType.SubMenu) { + curMenu = curMenu[this._path[i]].subMenu!; + } else { + resolve(curMenu[this._path[i]]); + return; + } } } - curMenu = this._config; - for (let i = 0; i < this._path.length; i++) { - curMenu = curMenu[this._path[i]].subMenu!; - } - this.printMenu(curMenu); }); - return this._config[this._selectedIndex]; } } diff --git a/src/menu/interface.ts b/src/menu/interface.ts index 39df059..ada68ca 100644 --- a/src/menu/interface.ts +++ b/src/menu/interface.ts @@ -13,5 +13,5 @@ export interface MenuConfig { } export interface MenuPrinter { - getSelection(): MenuConfig; + getSelection(): Promise; } diff --git a/src/menu/menu.ts b/src/menu/menu.ts index d953072..17a1fc5 100644 --- a/src/menu/menu.ts +++ b/src/menu/menu.ts @@ -11,7 +11,7 @@ export class Menu { : new OledPrinter(config); } - public getSelection(): MenuConfig { + public async getSelection(): Promise { return this._printer.getSelection(); } } diff --git a/src/menu/oled.ts b/src/menu/oled.ts index ef03b5f..5045e7b 100644 --- a/src/menu/oled.ts +++ b/src/menu/oled.ts @@ -24,7 +24,7 @@ export class OledPrinter implements MenuPrinter { this._config = config; } - public getSelection(): MenuConfig { + public async getSelection(): Promise { return this._config[0]; } }