
const EventEmitter = require("events");
const MuteStream = require("mute-stream");
const readline = require("readline");
const ansiEscapes = require("ansi-escapes");
const { fromEvent } = require("rxjs");
const option = {
type: "list",
name: "name",
messege: "select your name: ",
choices: [
{
value: "sam",
name: "sam",
},
{
value: "zhangsan",
name: "zhangsan",
},
{
value: "rainbow",
name: "rainbow",
},
],
};
function Prompt(option) {
return new Promise((resolve, reject) => {
try {
const list = new List(option);
list.render();
list.on("exit", function (answers) {
resolve(answers);
});
} catch (e) {
reject(e);
}
});
}
class List extends EventEmitter {
constructor(option) {
super();
const { name, messege, choices } = option;
this.name = name;
this.messege = messege;
this.choices = choices;
this.intput = process.stdin;
const ms = new MuteStream();
ms.pipe(process.stdout);
this.output = ms;
this.rl = readline.createInterface({
input: this.intput,
output: this.output,
});
this.selected = 0;
this.height = 0;
this.keypress = fromEvent(this.rl.input, "keypress").forEach(
this.onkeypress
);
this.haveSelected = false;
}
onkeypress = (keymap) => {
const key = keymap[1];
switch (key.name) {
case "down":
this.selected++;
if (this.selected > this.choices.length - 1) {
this.selected = 0;
}
this.render();
break;
case "up":
this.selected--;
if (this.selected < 0) {
this.selected = this.choices.length - 1;
}
this.render();
break;
case "return":
this.haveSelected = true;
this.render();
this.close();
this.emit("exit", this.choices[this.selected]);
break;
default:
break;
}
};
render() {
this.output.unmute();
this.clean();
this.output.write(this.getContent());
this.output.mute();
}
getContent() {
let title =
"\x1B[32m?\x1B[39m \x1B[1m" +
this.messege +
"\x1B[22m\x1B[0m\x1B[0m\x1B[2m(Use arrow keys)\x1B[22m \n";
if (!this.haveSelected) {
this.choices.forEach((choice, index) => {
if (index === this.selected) {
if (index === this.choices.length - 1) {
title += "\x1B[36m> " + choice.name + "\x1B[39m";
} else {
title += "\x1B[36m> " + choice.name + "\x1B[39m \n";
}
} else {
if (index === this.choices.length - 1) {
title += " " + choice.name;
} else {
title += " " + choice.name + "\n";
}
}
});
} else {
const name = this.choices[this.selected].name;
title =
"\x1B[32m?\x1B[39m \x1B[1m" +
this.messege +
"\x1B[22m\x1B[0m\x1B[36m" +
name +
"\x1B[39m\x1B[0m \n";
}
this.height = this.choices.length + 1;
return title;
}
clean() {
const emptyLines = ansiEscapes.eraseLines(this.height);
this.output.write(emptyLines);
}
close() {
this.output.unmute();
this.rl.output.end();
this.rl.pause();
this.rl.close();
}
}
Prompt(option).then((answer) => {
console.log("answer~~", answer);
});