Node.js中通过readline控制光标位置的问题

问题描述 投票:0回答:1

我正在 Node.js 中设计一个控制台应用程序,使用 readline 来控制光标位置并获取用户输入。这是我为此编写的一个库:

// 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};

这是该库的示例测试:

// 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();

虽然代码看起来很简单,但是控制台中的界面打印超出了我的理解范围。我无法推断光标如何在不同的 readline 方法中移动。以下是我的问题总结:

  1. 使用当前代码,即使在用户给出任何输入之前,也会在当前位置再次打印选项。尽管选项重新打印在问题的同一行上,但光标位于 Enter Your Choice: 之后。我不知道这里发生了什么。选项不应重新打印,即使重新打印后,光标也不是位于打印末尾,而是位于问题末尾:

  1. 问题位于指定行,但不位于指定列。我在其他一些测试中检查了这一点,readline.question在当前光标行打印问题,但它总是从第一列打印,而不是从当前光标列打印。

  2. 如果我取消注释此行

this.io.write(`\x1b[${row};${col}H`);

并评论这个

// readline.cursorTo(process.stdout, col, row);

我几乎得到了想要的输出:

但是 readline.question 的问题仍然存在,它仍然在特定行上打印,但不是从指定列打印,而是仅从第一列打印。

  1. 当我使用 readline-sync 而不是 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);
    };

但是我看不到用户输入。当用户提供任何输入并且输入未显示在屏幕上时,光标不会移动:

所以我需要了解这两行在打印和光标定位的上下文中发生了什么

readline.cursorTo(process.stdout, col, row);
readline.question(question, callback);

感谢并抱歉问了这么长的问题。

javascript node.js readline read-eval-print-loop readline-sync
1个回答
0
投票

对源代码进行一些调查后,我发现:

  1. 当您执行不带结束符的 io.write 操作时,内容将由 readline 存储,因为它假定您仍在编辑同一行。随后的 io.question 将触发一个提示,将内容推到后面并在该行的前面呈现消息(我不知道为什么)。请参阅Readline.line

  2. io.question总是将内部光标移动到x=0,参见kRefreshLine

我本来建议在所有 io.write 上附加 endline,但这会导致消息的最后一行在重新渲染期间被清除,您可以继续使用终端转义代码或使用带有 endline 的 io.write 并手动重新渲染最后一行重新渲染时的消息行。

对于问题的列位置,您唯一能做的就是在问题提示前面手动添加空格。

© www.soinside.com 2019 - 2024. All rights reserved.