6

In a golang program I'm reading the Os.Stdin input from a bufio.Reader.

After enter is pressed, the program reads the input and it is then printed onto the console. Is it possible to not print the input onto the console? After reading it, I process the input and reprint it (and no longer need the original input).

I read the data like this:

inputReader := bufio.NewReader(os.Stdin)
for {
    outgoing, _ := inputReader.ReadString('\n')
    outs <- outgoing
}
Nevermore
  • 7,141
  • 5
  • 42
  • 64

3 Answers3

3

I cannot think to other methods than to use ANSI escape codes to clear the terminal and move the cursor to a specific location (in your case to column 1:row 1).

var screen *bytes.Buffer = new(bytes.Buffer)
var output *bufio.Writer = bufio.NewWriter(os.Stdout)

And here are some basic helper methods to ease your job working with terminal.

// Move cursor to given position
func moveCursor(x int, y int) {
    fmt.Fprintf(screen, "\033[%d;%dH", x, y)
}

// Clear the terminal
func clearTerminal() {
    output.WriteString("\033[2J")
}

Then inside your function you need to clear the terminal and move the cursor to the first column and first row of the terminal window. At the end you have to output the computed result.

for {
    outgoing, err := input.ReadString('\n')

    if err != nil {
        break
    }

    if _, err := fmt.Sscanf(outgoing, "%f", input); err != nil {
        fmt.Println("Input error!")
        continue
    }

    // Clear console
    clearTerminal()
    moveCursor(1,1)

    fmt.Println(outs) // prints the computed result
}
Endre Simo
  • 11,330
  • 2
  • 40
  • 49
1

It seems you are looking for a terminal-specific function to disable echo. This is usually used when writing passwords on the terminal (you can type but you don't see the characters).

I suggest you give a try to terminal.ReadPassword it should work nicely and probably in the most cross-platform compatible way.

prompt := ""
t := terminal.NewTerminal(os.Stdin, prompt)
for {
    outgoing, err := t.ReadPassword(prompt)
    if err != nil {
        log.Fatalln(err)
    }
    outs <- outgoing
}
toqueteos
  • 771
  • 1
  • 6
  • 14
  • This doesn't work on Windows if you're running the go generated .exe from within something like Cygwin, or an Msys2 bash prompt. Is there another way? – GodEater Nov 06 '17 at 16:37
  • @GodEater That's either a bug on the Go library or a bug in how Cygwin or Msys2 implement bash in Windows. Besides that I have no clue, sorry. – toqueteos Nov 06 '17 at 17:48
  • According to the docs, you're supposed to put the terminal into raw mode first, and the terminal package has a MakeRaw() function, but it takes a file descriptor... Presumably the file descriptor is for os.Stdin in this case, but I've no clue how to get that... – weberc2 Aug 09 '18 at 00:40
1

other than crypto/ssh/terminal;

package main

import (
    "bufio"
    "fmt"
    "os"
    "os/exec"
)

func raw(start bool) error {
    r := "raw"
    if !start {
        r = "-raw"
    }

    rawMode := exec.Command("stty", r)
    rawMode.Stdin = os.Stdin
    err := rawMode.Run()
    if err != nil {
        return err
    }

    return rawMode.Wait()
}

// http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x361.html
func main() {
    var rs []rune
    raw(true)
    for {
        inp := bufio.NewReader(os.Stdin)
        r, _, err := inp.ReadRune()
        if err != nil {
            raw(false)
            panic(err)
        }

        if r == '\x03' { // ctrl+c
            break
        } else if r == '\r' { // enter
            fmt.Print(string(rs), "\n\r")
            rs = []rune{}
            continue
        } else if r == '\u007f' { // backspace
            fmt.Printf("\033[1D\033[K")
            continue
        }

        rs = append(rs, r)
    }

    raw(false)
}
Rafael Quintela
  • 1,908
  • 2
  • 12
  • 14