fix(tui): quit on signal cancellation
This commit is contained in:
parent
5da91640e6
commit
37017c6763
18
tui/tui.go
18
tui/tui.go
@ -81,6 +81,8 @@ type refreshResultMsg struct {
|
||||
manual bool
|
||||
}
|
||||
|
||||
type contextDoneMsg struct{}
|
||||
|
||||
type Item struct {
|
||||
Title string `json:"title"`
|
||||
Subtitle string `json:"subtitle,omitempty"`
|
||||
@ -342,7 +344,6 @@ func Run(ctx context.Context, opts Options) error {
|
||||
}
|
||||
defer restoreTerminalOutput(output)
|
||||
model := newModel(opts)
|
||||
model.ctx = ctx
|
||||
if width, height, ok := terminalSize(input, output); ok {
|
||||
model.width = width
|
||||
model.height = height
|
||||
@ -352,6 +353,7 @@ func Run(ctx context.Context, opts Options) error {
|
||||
}
|
||||
runCtx, stopSignals := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)
|
||||
defer stopSignals()
|
||||
model.ctx = runCtx
|
||||
program := tea.NewProgram(
|
||||
model,
|
||||
tea.WithContext(runCtx),
|
||||
@ -736,7 +738,7 @@ type itemGroup struct {
|
||||
}
|
||||
|
||||
func (m model) Init() tea.Cmd {
|
||||
return m.refreshTickCmd()
|
||||
return tea.Batch(m.refreshTickCmd(), m.contextDoneCmd())
|
||||
}
|
||||
|
||||
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
@ -756,6 +758,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
case refreshResultMsg:
|
||||
m.finishRefresh(typed)
|
||||
return m, nil
|
||||
case contextDoneMsg:
|
||||
return m, tea.Quit
|
||||
case tea.MouseMsg:
|
||||
if typed.Action == tea.MouseActionMotion && typed.Button == tea.MouseButtonNone {
|
||||
if m.menuOpen {
|
||||
@ -1527,6 +1531,16 @@ func (m model) refreshTickCmd() tea.Cmd {
|
||||
})
|
||||
}
|
||||
|
||||
func (m model) contextDoneCmd() tea.Cmd {
|
||||
if m.ctx == nil {
|
||||
return nil
|
||||
}
|
||||
return func() tea.Msg {
|
||||
<-m.ctx.Done()
|
||||
return contextDoneMsg{}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *model) startRefresh(manual bool) tea.Cmd {
|
||||
if m.refresh == nil {
|
||||
if manual {
|
||||
|
||||
@ -1322,6 +1322,21 @@ func TestRefreshCurrentStatusUsesGitcrawlSourceLanguage(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestContextDoneQuitsModelForSignalCleanup(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
m := newModel(Options{Title: "archive", Items: []Item{{Title: "alpha"}}})
|
||||
m.ctx = ctx
|
||||
cmd := m.contextDoneCmd()
|
||||
if cmd == nil {
|
||||
t.Fatal("context done command missing")
|
||||
}
|
||||
cancel()
|
||||
updated, quit := m.Update(cmd())
|
||||
if _, ok := updated.(model); !ok || quit == nil {
|
||||
t.Fatalf("context cancellation should return quit command, updated=%T quit=%v", updated, quit)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHelpPaneRendersUniversalControls(t *testing.T) {
|
||||
m := newModel(Options{
|
||||
Title: "archive",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user