How to wait for user input in go generate script?

huangapple go评论81阅读模式
英文:

How to wait for user input in go generate script?

问题

我正在为一个项目开发一个代码生成器,有时需要在继续之前等待用户输入。然而,我发现当通过go generate运行时,通常的读取用户输入的方法不会等待用户输入后再继续执行。但是,如果以通常的go run方式运行脚本,程序会按预期等待用户输入(但这对我来说不是一个选项)。

我的问题是:有没有办法在通过go generate运行时让程序暂停并等待用户输入?

我看到了如何在控制台中从标准输入读取数据?这个问题,虽然相关,但并不完全相同。

这是一个示例:

main.go

package main

import (
	"bufio"
	"log"
	"os"
)

func main() {
	for isFileOk := checkFile(); !isFileOk; {
		log.Println("File requires manual update.")
		log.Println("Hit [RETURN] when resolved.")

		scanner := bufio.NewScanner(os.Stdin)
		for scanner.Scan() {
			break
		}
		isFileOk = checkFile()
	}
}

func checkFile() bool {
	return false
}

generate.go

package main

//go:generate go run main.go

通过go run main.go运行,循环的每一次迭代后会等待我按回车键,然后再进行下一次迭代。通过go generate generate.go运行,循环会一直迭代而不等待。

你可能会注意到,我实际上并不需要从用户那里读取任何数据,我只需要从用户那里得到一些反馈,告诉我他们已经完成了文件的更新。如果有其他方法可以让程序在用户完成后暂停,那也可以。


注意:我还尝试过使用bufio.Readerfmt.Scanln()io.ReadAll(os.Stdin)代替bufio.Scanner,但结果相同。

英文:

I'm working on a code generator for a project and sometimes need to wait for user input before proceeding. However, I'm finding that the usual methods of reading user input do not wait for the user to enter something before moving on when run through go generate. However, if I run the script in the usual go run way, the program waits for user input as expected (this is not an option for me though).

What I'm asking is: is there a way to have a program hang and wait for user input when run through go generate?

I've seen How can I read from standard input in the console? and, while related, this is not exactly the same question.

Here's a sample:

main.go

package main

import (
	"bufio"
	"log"
	"os"
)

func main() {
	for isFileOk := checkFile(); !isFileOk; {
		log.Println("File requires manual update.")
		log.Println("Hit [RETURN] when resolved.")

		scanner := bufio.NewScanner(os.Stdin)
		for scanner.Scan() {
			break
		}
		isFileOk = checkFile()
	}
}

func checkFile() bool {
	return false
}

generate.go

package main

//go:generate go run main.go

Running go run main.go, a single iteration of the loop executes and then waits for me to hit return before moving to the next iteration. Running go generate generate.go, the loop iterates over and over without waiting.

You'll likely notice that I don't really need to read any data from the user, instead I only need to get some sort of feedback from the user that they are done updating the file. If there's another way to have the program hang until the user is done, that would be fine as well.


Note: I've also tried using bufio.Reader, fmt.Scanln(), and io.ReadAll(os.Stdin) instead of bufio.Scanner but get the same result.

答案1

得分: 2

go generate generate.go 将使用 exec.Command 分叉 main.gogo generate 没有为 main.go 设置 stdin,因此 main.go 无法从 os.Stdin 读取键盘输入。

另一种方法是直接从 /dev/tty(Unix)或系统 API(Windows)读取键盘事件:

package main

import (
        "fmt"
        "log"

        "github.com/eiannone/keyboard"
)

func main() {
        if err := keyboard.Open(); err != nil {
                panic(err)
        }
        defer func() {
                _ = keyboard.Close()
        }()

        for isFileOk := checkFile(); !isFileOk; {
                log.Println("文件需要手动更新。")
                log.Println("解决后按下 [RETURN] 键。")

                char, key, err := keyboard.GetKey()
                if err != nil {
                        panic(err)
                }
                fmt.Println(char, key, err)

                if key == keyboard.KeyEsc {
                        return
                }
        }
}

func checkFile() bool {
        return false
}
英文:

go generate generate.go will fork main.go using exec.Command, go generate did not set a stdin for main.go, so main.go could not read keyboard input from os.Stdin.

Another way is reading keyboard event directly from /dev/tty(unix) or System API(win):

package main

import (
        "fmt"
        "log"

        "github.com/eiannone/keyboard"
)

func main() {
        if err := keyboard.Open(); err != nil {
                panic(err)
        }
        defer func() {
                _ = keyboard.Close()
        }()

        for isFileOk := checkFile(); !isFileOk; {
                log.Println("File requires manual update.")
                log.Println("Hit [RETURN] when resolved.")

                char, key, err := keyboard.GetKey()
                if err != nil {
                        panic(err)
                }
                fmt.Println(char, key, err)

                if key == keyboard.KeyEsc {
                        return
                }
        }
}

func checkFile() bool {
        return false
}

huangapple
  • 本文由 发表于 2021年10月26日 15:43:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/69719233.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定