Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to clear line when using readline prompt / setPrompt in Node

I'm having trouble clearing a line in stdout when using readline prompt.

I code similar to this:

import readline from 'readline'

const rl = readline.createInterface(process.stdin, process.stdout)
let input = ''

readline.emitKeypressEvents(process.stdin)
process.stdin.on('keypress', registerInput)

function registerInput (str, key) {
  if (key.name === 'backspace') {
    input = input.slice(0, input.length - 1)
  } else {
    input += str
  }
  if (input === '42') {
    input = ''
    console.log(' ✓')
    nextPrompt()
  }
}

function nextPrompt () {
  readline.clearLine(process.stdout, 0)
  rl.setPrompt('What is the meaning of life? ')
  rl.prompt()
}

nextPrompt()

In the real code, arithmetic questions are generated.

Here is a screen capture of the output.

What happens

The cursor resets (using .prompt(false) keeps cursor in position), but the input is still there in the new prompt.

Expected

The input 42 should not appear in the new prompt on the next line.

Why am I using .on('keypress' instead of rl.on('line'? I want the response in the game to be snap, avoiding pressing enter.

What I have tried:

  • readline.clearLine(process.stdout, -1)
  • readline.clearLine(process.stdout, 1)
  • readline.clearLine(process.stdin, 0)
  • process.stdout.clearLine()

Environment

I'm using node v6.0.0 and babel-cli v6.7.7 (here babel just for the import statement, but in the real code I use object-rest-spread and therefor need babel). Here is a gist of the generated code if you do not have babel installed.

Question

Is rl.prompt incompatible with readline.clearLine? How can this be solved?

like image 206
arve0 Avatar asked Oct 19 '22 10:10

arve0


1 Answers

I solved it like this:

import readline from 'readline'

let input = ''
let question = 'What is the meaning of life? '

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
})
readline.emitKeypressEvents(process.stdin)
process.stdin.on('keypress', registerInput)

function registerInput (str, key) {
  if (key.name === 'backspace') {
    input = input.slice(0, input.length - 1)
  } else {
    const numbers = '1 2 3 4 5 6 7 8 9 0'.split(' ')
    if (numbers.indexOf(str) !== -1) {
      input += str
    }
  }
  if (input === '42') {
    console.log(' ✓')
    input = ''
  }
  render(question, input)
}

function render (question, input) {
  readline.clearLine(process.stdout, 0)
  readline.cursorTo(process.stdout, 0)
  process.stdout.write(question + input)
}

render(question, input)

But the question remains, why is rl.prompt incompatible with readline.clearLine?

I'm guessing that prompt does something similar to my approach behind the curtains. A resetPromptInput would be nice.

like image 193
arve0 Avatar answered Oct 21 '22 00:10

arve0