Handle more signals #61

Manually merged
asdf merged 2 commits from handle-signals into develop 2019-10-25 02:01:42 +00:00
2 changed files with 37 additions and 20 deletions

View File

@ -56,16 +56,29 @@ func moveCursorToward(dir string, amount int) {
}
}
// Exit performs cleanup operations before exiting the application
func Exit() {
CleanupTerm()
os.Exit(0)
}
// InitTerm sets the terminal modes appropriate for Bombadillo
func InitTerm() {
SetCharMode()
Tput("rmam") // turn off line wrapping
Tput("smcup") // use alternate screen
}
// CleanupTerm reverts changs to terminal mode made by InitTerm
func CleanupTerm() {
moveCursorToward("down", 500)
moveCursorToward("right", 500)
SetLineMode()
fmt.Print("\n")
fmt.Print("\033[?25h")
Tput("smam") // turn off line wrap
Tput("rmcup") // use alternate screen
os.Exit(0)
fmt.Print("\033[?25h") // reenables cursor blinking
Tput("smam") // turn on line wrap
Tput("rmcup") // stop using alternate screen
}
func Clear(dir string) {

36
main.go
View File

@ -112,7 +112,7 @@ func loadConfig() error {
if lowerkey == "configlocation" {
// The config defaults to the home folder.
// Users cannot really edit this value. But
// a compile time override is available.
// a compile time override is available.
// It is still stored in the ini and as a part
// of the options map.
continue
@ -140,7 +140,6 @@ func loadConfig() error {
func initClient() error {
bombadillo = MakeClient(" ((( Bombadillo ))) ")
cui.SetCharMode()
Review

This was moved to cui.InitTerm() which is now executed directly in main(). I'm not sure on the full impact of this move.

This was moved to cui.InitTerm() which is now executed directly in main(). I'm not sure on the full impact of this move.
Review

I see no reason that should be a problem.

I see no reason that should be a problem.
Review

Yeah upon further investigation it looks ok to me too, I was just a bit worried about error handling.

Yeah upon further investigation it looks ok to me too, I was just a bit worried about error handling.
err := loadConfig()
if bombadillo.Options["tlscertificate"] != "" && bombadillo.Options["tlskey"] != "" {
bombadillo.Certs.LoadCertificate(bombadillo.Options["tlscertificate"], bombadillo.Options["tlskey"])
@ -148,16 +147,22 @@ func initClient() error {
return err
}
// In the event of SIGCONT, ensure the display is shown correctly. Accepts a
// signal, blocking until it is received. Once not blocked, corrects terminal
// display settings. Loops indefinitely, does not return.
func handleSIGCONT(c <-chan os.Signal) {
// In the event of specific signals, ensure the display is shown correctly.
// Accepts a signal, blocking until it is received. Once not blocked, corrects
// terminal display settings as appropriate for that signal. Loops
// indefinitely, does not return.
func handleSignals(c <-chan os.Signal) {
for {
<-c
cui.Tput("rmam") // turn off line wrapping
cui.Tput("smcup") // use alternate screen
cui.SetCharMode()
bombadillo.Draw()
switch <-c {
Review

I have not used channels a lot (though did recently for a game I made...plummet, available on my tildegit). We are in a goroutine so it wont matter, but just for my own knowledge: this line will block until a signal is received, yeah?

I have not used channels a lot (though did recently for a game I made...plummet, available on my tildegit). We are in a goroutine so it wont matter, but just for my own knowledge: this line will block until a signal is received, yeah?
Review

That's correct. It's a buffered channel, and blocks until a value is received.

This is the first time I've used channels, but they are interesting and work well.

The general logic here is that signal.Notify listens for the specified signals, then sends them to the channel when they are received. In this goroutine, the channel is blocked until it gets a signal, and then it does the appropriate thing.

You can assign the value from a channel using x := <- c like you have done in plummet. You can also just do <- c if you just want to wait until it receives a value, but don't actually want to do anything with that value.

The way it is being used here, you could also write it as:
x := <-c
switch x {
case ...

This is also the first time I'm seeing the select statement, so thanks for the prompt on that.

btw plummet is pretty cool! A nice little game.

That's correct. It's a buffered channel, and blocks until a value is received. This is the first time I've used channels, but they are interesting and work well. The general logic here is that `signal.Notify` listens for the specified signals, then sends them to the channel when they are received. In this goroutine, the channel is blocked until it gets a signal, and then it does the appropriate thing. You can assign the value from a channel using `x := <- c` like you have done in plummet. You can also just do `<- c` if you just want to wait until it receives a value, but don't actually want to do anything with that value. The way it is being used here, you could also write it as: x := <-c switch x { case ... This is also the first time I'm seeing the [select](https://tour.golang.org/concurrency/5) statement, so thanks for the prompt on that. btw plummet is pretty cool! A nice little game.
case syscall.SIGTSTP:
cui.CleanupTerm()
syscall.Kill(syscall.Getpid(), syscall.SIGSTOP)
Review

I would have never found this :( The documentation for the syscall lib is the one really swampy place in golang.

I would have never found this :( The documentation for the syscall lib is the one really swampy place in golang.
Review

Yeah, documentation is a bit light, and it seems like a lot of the code is automatically generated.

I actually found this by searching around. This is the same way that other languages perform this task. Also, in the shell, the command is very similar:

kill -s SIGNAL pid

Also - syscall is also apparently deprecated, but I'm not sure when it is going to be replaced. I guess eventually this will have to be rewritten slightly.

Yeah, documentation is a bit light, and it seems like a lot of the code is automatically generated. I actually found this by searching around. This is the same way that other languages perform this task. Also, in the shell, the command is very similar: kill -s SIGNAL pid Also - syscall is also apparently deprecated, but I'm not sure when it is going to be replaced. I guess eventually this will have to be rewritten slightly.
case syscall.SIGCONT:
cui.InitTerm()
bombadillo.Draw()
case syscall.SIGINT:
cui.Exit()
}
}
}
@ -174,8 +179,7 @@ func main() {
// So that we can open files from gemini
mc = mailcap.NewMailcap()
cui.Tput("rmam") // turn off line wrapping
cui.Tput("smcup") // use alternate screen
cui.InitTerm()
defer cui.Exit()
err := initClient()
if err != nil {
@ -183,10 +187,10 @@ func main() {
panic(err)
}
// watch for SIGCONT, send it to be handled
// watch for signals, send them to be handled
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGCONT)
go handleSIGCONT(c)
signal.Notify(c, syscall.SIGTSTP, syscall.SIGCONT, syscall.SIGINT)
go handleSignals(c)
// Start polling for terminal size changes
go bombadillo.GetSize()