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; private _config: MenuConfig[]; private _curMenu: MenuConfig[]; constructor(config: MenuConfig[]) { this._config = config; this._curMenu = 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(): void { console.clear(); for (let i = 0; i < this._curMenu.length; i++) { const line = (i === this._selectedIndex ? "> " : " ") + this._curMenu[i].display; console.log(line); } } public async getSelection(): Promise { return new Promise(async (resolve) => { while (true) { // print menu this.printMenu(); // 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 > this._curMenu.length - 1) { this._selectedIndex = this._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._curMenu = this._config; for (let i = 0; i < this._path.length; i++) { if (this._curMenu[this._path[i]].type === MenuType.SubMenu) { this._curMenu = this._curMenu[this._path[i]].subMenu!; this._selectedIndex = 0; } else { resolve(this._curMenu[this._path[i]]); this._path.pop(); return; } } } }); } }