83 lines
2.4 KiB
TypeScript
83 lines
2.4 KiB
TypeScript
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<Key> {
|
|
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<MenuConfig> {
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|