I am designing a console app in Node.js using readline to control the cursor positions and get user input. Here is a library I have written for the same:
// ReadLine.js
const readline = require("readline");
const readSync = require("readline-sync");
const inStream = process.stdin;
const outStream = process.stdout;
class ReadLine {
constructor() {
this.io = readline.createInterface({input: inStream, output: outStream});
}
setEvent(event, callback) {
this.io.on(event, callback);
};
exit() {
this.io.close();
}
// Move Cursor to Row,Col Position
moveTo(row, col) {
readline.cursorTo(process.stdout, col, row);
// this.io.write(`\x1b[${row};${col}H`);
};
clearRow(row) {
this.moveTo(row, 0);
this.io.write(`\x1b[0K`); // Clears from the cursor to the end of the row
};
// Write text at current cursor position
write(msg) {
this.io.write(msg);
};
// Write text at specific Row,Col Position
writeAt(row, col, msg) {
this.moveTo(row, col);
this.write(msg);
};
// Ask a question, wait for an input
ask(question, callback) {
this.io.question(question, callback);
// const answer = readSync.question(question);
// callback(answer);
};
}
module.exports = {ReadLine};
And here is a sample test for this library:
// ReadCli.js
console.clear();
const ReadLine = require("./ReadLine");
const io = new ReadLine.ReadLine();
io.setEvent("close", process.exit);
const Ask = () => {
const choices = ["Print Fibonacci", "Exit"];
let row = 0;
const col = 3;
choices.forEach(choice => io.writeAt(++row, col, `${row} ${choice}`));
io.moveTo(++row, col);
io.ask("Enter Your Choice: ", answer => {
const lastChoice = choices.length;
switch(Number.parseInt(answer)) {
case lastChoice:
io.clearRow(++row);
io.writeAt(row, col, "Goodbye");
io.exit();
break;
default:
io.writeAt(++row, col, "Wrong Choice Entered");
}
Ask();
});
};
Ask();
Although the code seems straightforward, the interface printing in the console is beyond my understanding. I cannot deduce how the cursor is moving around different readline methods. Here is a summary of my problems:
- With the current code, the choices are printed again even before the user has given any input, at the current position. Although the choices are re-printed on the same line of question, the cursor is positioned just after Enter Your Choice: <cursor_position>. I have no idea what's happening here. The choices should not be re-printed, and even after re-printing the cursor is not positioned at the end of printing, but at the end of the question:
The question is positioned at the specified row, but not at the specified column. I checked this on some other tests, readline.question prints the question at the current cursor row, but it always prints from the first column, not from the current cursor column.
If I uncomment this line
this.io.write(`\x1b[${row};${col}H`);
and comment this
// readline.cursorTo(process.stdout, col, row);
I got almost the desired output:
But the problem with readline.question still persists, it's still printing on the specific row, but not from the specified column, but from the first column only.
- None of the problems occur when I use readline-sync instead of readline:
const readSync = require("readline-sync");
// Ask a question, wait for an input
ask(question, callback) {
// this.io.question(question, callback);
const answer = readSync.question(question);
callback(answer);
};
But I can't see the user input. Cursor doesn't move when user provide any input and input is not shown on screen:
So I need to understand what's happening with these two lines in the context of printing and cursor positioning
readline.cursorTo(process.stdout, col, row);
readline.question(question, callback);
Thanks and sorry for such a long question.



