peterh / liner

Pure Go line editor with history, inspired by linenoise
MIT License
1.05k stars 132 forks source link

Stop prompt attempts on non-terminal stdout #4

Closed frou closed 10 years ago

frou commented 10 years ago

Hi - thanks for the cool package. I noticed that it's assumed that standard output is a terminal if the parent has set TERM, but that doesn't hold when shell output redirection is used. Before my changes, *State.refresh will panic in case (C) due to trying to work out how to maintain the line editor in the non-existent columns of a normal file.

I don't think my changes mess anything else up, but let me know what you think.

Desktop $ cat x.go
package main

import (
    "fmt"
    "strconv"

    "github.com/frou/liner"
)

func main() {
    ln := liner.NewLiner()
    defer ln.Close()

    var accum int
    for {
        s, err := ln.Prompt("$ ")
        if err != nil {
            fmt.Println("error:", err)
            return
        }

        n, _ := strconv.Atoi(s)
        accum += n
        fmt.Println(accum)
    }
}

(A)
Desktop $ go run x.go
$ 2
2
$ 4
6
$ 8
14
$ error: EOF

Desktop $ cat >input.txt
3
9
27

(B)
Desktop $ go run x.go <input.txt
$ 3
3
$ 9
12
$ 27
39
$ error: EOF

(C)
Desktop $ go run x.go <input.txt >output.txt
Desktop $ cat output.txt
error: standard output is not a terminal
peterh commented 10 years ago

Thanks for the patch!

My first instinct is that !isatty should behave the same as TERM=dumb. Upon further reflection, I can see arguments on both sides. Since you're the first one to notice, your proposed behaviour wins by default.

Pushed.

frou commented 10 years ago

The world of ttys, line disciplines, cursor addressing and all that is fairly arcane to me, which is why I was glad to find your package. Pure Go and no dependencies to boot makes it a gem! I'm using it in the interpreter for a little Lispy language I'm putting together.