Skip to content

[BUG] fails to read more than one line under certain conditions #36

Description

@obfusk

Using read to prompt multiple times fails after the first line when:

  • input is non-interactive (e.g. file/pipe); and
  • use is asynchronous wrt "nesting" (replacing setTimeout(f) with f() seems to "fix" the issue)

Test case x.js

const read = require("read")
const f = () => read({ prompt: ">" }, (e, line) => {
  if (e) { throw e }
  console.log("got:", line)
  setTimeout(f)
})
f()

Interactive user input in terminal: works

$ node x.js 
> foo
got: foo
> bar
got: bar
> baz
got: baz
> ^D

Non-interactive input from file/pipe: only reads first line

$ node x.js <<< $'foo\nbar\nbaz' 
> foo
got: foo
> $ 

Solution?

I've replaced my use of read with the following code, which has fewer features but works:

const _readline = require("readline")
const _rl_buf   = []

const read_line = (prompt = null) =>
  new Promise((resolve, reject) => {
    const p = prompt || "", i = process.stdin, o = process.stdout
    if (_rl_buf.length) {
      if (p) { o.write(p) }
      resolve(_rl_buf.shift())
      return
    }
    const rl = _readline.createInterface({
      input: i, output: o, prompt: p, terminal: false
    })
    let done = false
    const f = (g, h = null) => {
      if (!done) { done = true; rl.close(); g() }
      else if (h) { h() }
    }
    rl.on("line"  , line => f(() => resolve(line),
                              () => _rl_buf.push(line)))
    rl.on("close" , ()   => f(() => resolve(null)))
    rl.on("error" , e    => f(() => reject(e)))
    rl.prompt()
  })

const f = () => read_line("> ").then(line => {
  if (line == null) { return }
  console.log("got:", line)
  setTimeout(f)
})
f()
$ node y.js 
> foo
got: foo
> bar
got: bar
> baz
got: baz
> $ node y.js <<< $'foo\nbar\nbaz' 
> got: foo
> got: bar
> got: baz
> $

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions