[GH-ISSUE #247] terminal is left scrambled when the app exits #136

Closed
opened 2026-03-03 16:22:43 +03:00 by kerem · 5 comments
Owner

Originally created by @alessio on GitHub (Oct 9, 2020).
Original GitHub issue: https://github.com/mum4k/termdash/issues/247

Originally assigned to: @mum4k on GitHub.

Hi,

One of my colleagues has written a gorgeous terminal-based block explorer application using termdash: https://github.com/Tosch110/gex

While testing his application, I've noticed that when the app crashes, the terminal is left in bad state - pretty much as described in this upstream bug https://github.com/nsf/termbox-go/issues/182#issuecomment-424324441.
Generally, I'd love to restore the terminal state so that users can continue working in the same terminal session after my app exits.

Any advice would be greatly appreciated.
Thanks for considering.

Originally created by @alessio on GitHub (Oct 9, 2020). Original GitHub issue: https://github.com/mum4k/termdash/issues/247 Originally assigned to: @mum4k on GitHub. Hi, One of my colleagues has written a gorgeous terminal-based block explorer application using `termdash`: https://github.com/Tosch110/gex While testing his application, I've noticed that when the app crashes, the terminal is left in bad state - pretty much as described in this upstream bug https://github.com/nsf/termbox-go/issues/182#issuecomment-424324441. Generally, I'd love to restore the terminal state so that users can continue working in the same terminal session after my app exits. Any advice would be greatly appreciated. Thanks for considering.
kerem 2026-03-03 16:22:43 +03:00
  • closed this issue
  • added the
    question
    label
Author
Owner

@mum4k commented on GitHub (Oct 13, 2020):

Hi @alessio, thank you for sharing the link to gex with me, that looks awesome!

Thank you for reporting this, I agree that it would be ideal if the terminal is correctly returned into the CLI mode even after unexpected crashes. I have a request if I may. Before we deep dive into termbox-go and figure out how to recover the terminal during a panic - would you be willing to give tcell a try? tcell is aiming to be a "newer and better" terminal layer. Termdash can now work with either one of the two, so it should be trivial to test. Here is some documentation for the tcell integration:

https://github.com/mum4k/termdash/wiki/Tcell-API

And an example of use is in the termdashdemo:
github.com/mum4k/termdash@2a7dafa3a8/termdashdemo/termdashdemo.go (L487-L490)

There is a chance that the cleanup will just work with tcell, however even if it doesn't it might be a better time investment if we focus on fixing the interaction with tcell than investing into termbox-go.

Please let me know what you find out.

<!-- gh-comment-id:707446914 --> @mum4k commented on GitHub (Oct 13, 2020): Hi @alessio, thank you for sharing the link to `gex` with me, that looks awesome! Thank you for reporting this, I agree that it would be ideal if the terminal is correctly returned into the CLI mode even after unexpected crashes. I have a request if I may. Before we deep dive into `termbox-go` and figure out how to recover the terminal during a panic - would you be willing to give `tcell` a try? [tcell](https://github.com/gdamore/tcell) is aiming to be a "newer and better" terminal layer. Termdash can now work with either one of the two, so it should be trivial to test. Here is some documentation for the `tcell` integration: https://github.com/mum4k/termdash/wiki/Tcell-API And an example of use is in the `termdashdemo`: https://github.com/mum4k/termdash/blob/2a7dafa3a835dbe45d9a6eaa2f22e184666c8065/termdashdemo/termdashdemo.go#L487-L490 There is a chance that the cleanup will just work with `tcell`, however even if it doesn't it might be a better time investment if we focus on fixing the interaction with `tcell` than investing into `termbox-go`. Please let me know what you find out.
Author
Owner

@alessio commented on GitHub (Oct 15, 2020):

Hey @mum4k - thanks for taking the time!

tcell does not seem to provide a better experience

<!-- gh-comment-id:709181910 --> @alessio commented on GitHub (Oct 15, 2020): Hey @mum4k - thanks for taking the time! `tcell` does not seem to provide a better experience
Author
Owner

@mum4k commented on GitHub (Oct 15, 2020):

Thank you @alessio for giving tcell a try. Since both termbox-go and tcell have this problem, it is likely that there is some cleanup code we could be calling even on an application panic.

I will look into it and try to identify some improvement. Once we know how to perform a correct cleanup, we can use Go's recover functionality to catch a panic and recover the terminal before finally crashing.

<!-- gh-comment-id:709587600 --> @mum4k commented on GitHub (Oct 15, 2020): Thank you @alessio for giving `tcell` a try. Since both `termbox-go` and `tcell` have this problem, it is likely that there is some cleanup code we could be calling even on an application panic. I will look into it and try to identify some improvement. Once we know how to perform a correct cleanup, we can use Go's recover functionality to catch a panic and recover the terminal before finally crashing.
Author
Owner

@mum4k commented on GitHub (Oct 19, 2020):

@alessio, after looking at this a bit more and reminding myself of how panic handling works in Go, I don't think we have a good solution available. At least not in the infrastructure layer provided by termdash. The relevant part of the Go spec:

https://golang.org/ref/spec#Handling_panics

While executing a function F, an explicit call to panic or a run-time panic terminates the execution of F. Any functions deferred by F are then executed as usual. Next, any deferred functions run by F's caller are run, and so on up to any deferred by the top-level function in the executing goroutine. At that point, the program is terminated and the error condition is reported, including the value of the argument to panic. This termination sequence is called panicking.

To clean and reset the terminal correctly, we need to make sure the Close method on termbox or tcell gets executed. E.g. the demo defers that call here:
github.com/mum4k/termdash@2a7dafa3a8/termdashdemo/termdashdemo.go (L499)

My assumption is that the panics you are dealing with originate in a different goroutine than the one that defers the call to the close method. Based on the definition in the spec - only deferred functions in the panicking goroutine get executed, then the program terminates. Since in Go other goroutines have no means of affecting or catching a panic in a separate goroutine, no code in termdash can change this behavior.

The best solution I can think of needs to be done in the code that uses termdash. You could include a deferred call to recover() in the main goroutine of your application (the one that could potentially panic). This recover would call the mentioned Close method. Note that the objects the Close method is defined on aren't thread safe, so the deferred function would have to terminate termdash correctly before calling Close. Otherwise the call to Close could result in more unspecified behavior. Correct termination of termdash can be done by canceling the context used by termdash which if thread safe from any goroutine:

github.com/mum4k/termdash@2a7dafa3a8/termdashdemo/termdashdemo.go (L528)

Please let me know if this helps or if you think there is a way how we can fix this in the infrastructure layer.

<!-- gh-comment-id:711497140 --> @mum4k commented on GitHub (Oct 19, 2020): @alessio, after looking at this a bit more and reminding myself of how panic handling works in Go, I don't think we have a good solution available. At least not in the infrastructure layer provided by `termdash`. The relevant part of the Go spec: https://golang.org/ref/spec#Handling_panics *While executing a function F, an explicit call to panic or a run-time panic terminates the execution of F. Any functions deferred by F are then executed as usual. Next, any deferred functions run by F's caller are run, and so on up to any deferred by the top-level function in the* **executing goroutine**. *At that point, the program is terminated and the error condition is reported, including the value of the argument to panic. This termination sequence is called panicking.* To clean and reset the terminal correctly, we need to make sure the `Close` method on `termbox` or `tcell` gets executed. E.g. the demo defers that call here: https://github.com/mum4k/termdash/blob/2a7dafa3a835dbe45d9a6eaa2f22e184666c8065/termdashdemo/termdashdemo.go#L499 My assumption is that the panics you are dealing with originate in a different goroutine than the one that defers the call to the close method. Based on the definition in the spec - only deferred functions in the panicking goroutine get executed, then the program terminates. Since in Go other goroutines have no means of affecting or catching a panic in a separate goroutine, no code in termdash can change this behavior. The best solution I can think of needs to be done in the code that uses `termdash`. You could include a deferred call to `recover()` in the main goroutine of your application (the one that could potentially panic). This recover would call the mentioned `Close` method. Note that the objects the `Close` method is defined on aren't thread safe, so the deferred function would have to terminate `termdash` correctly before calling `Close`. Otherwise the call to `Close` could result in more unspecified behavior. Correct termination of `termdash` can be done by canceling the context used by termdash which if thread safe from any goroutine: https://github.com/mum4k/termdash/blob/2a7dafa3a835dbe45d9a6eaa2f22e184666c8065/termdashdemo/termdashdemo.go#L528 Please let me know if this helps or if you think there is a way how we can fix this in the infrastructure layer.
Author
Owner

@mum4k commented on GitHub (Nov 10, 2020):

Going to close this for now, but please feel free to reopen if you have further questions or ideas how to solve this at the termdash layer.

<!-- gh-comment-id:724448062 --> @mum4k commented on GitHub (Nov 10, 2020): Going to close this for now, but please feel free to reopen if you have further questions or ideas how to solve this at the termdash layer.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/termdash#136
No description provided.