fixup! wip: refactor: API

This commit is contained in:
Rob Watson 2025-05-10 07:36:39 +02:00
parent c6f21b194a
commit 888ac7d67d
2 changed files with 25 additions and 29 deletions

View File

@ -2,7 +2,6 @@ package main
import (
"context"
"errors"
"fmt"
"log/slog"
"os"
@ -90,7 +89,7 @@ func run() error {
}
})
ui, err := terminal.StartUI(ctx, terminal.StartParams{
ui, err := terminal.NewUI(ctx, terminal.Params{
EventBus: bus,
Dispatcher: func(cmd event.Command) {
logger.Info("Command dispatched", "cmd", cmd.Name())
@ -112,18 +111,11 @@ func run() error {
}
defer ui.Close()
errUIClosed := errors.New("UI closed")
g.Go(func() error {
ui.Wait()
logger.Info("UI closed!")
return errUIClosed
})
g.Go(func() error { return ui.Run(ctx) })
if err := g.Wait(); err == errUIClosed {
logger.Info("UI closed, exiting")
if err := g.Wait(); err == terminal.ErrUserClosed {
return nil
} else {
logger.Error("UI closed with error", "err", err)
return fmt.Errorf("errgroup.Wait: %w", err)
}
}

View File

@ -3,6 +3,7 @@ package terminal
import (
"cmp"
"context"
"errors"
"fmt"
"log/slog"
"maps"
@ -46,7 +47,7 @@ type UI struct {
clipboardAvailable bool
rtmpURL, rtmpsURL string
buildInfo domain.BuildInfo
doneC chan struct{}
appExitC chan error
logger *slog.Logger
// tview state
@ -92,9 +93,9 @@ type ScreenCapture struct {
Width, Height int
}
// StartParams contains the parameters for starting a new terminal user
// Params contains the parameters for starting a new terminal user
// interface.
type StartParams struct {
type Params struct {
EventBus *event.Bus
Dispatcher func(event.Command)
Logger *slog.Logger
@ -103,8 +104,9 @@ type StartParams struct {
Screen *Screen // Screen may be nil.
}
// StartUI starts the terminal user interface.
func StartUI(ctx context.Context, params StartParams) (*UI, error) {
// NewUI creates the user interface. Call [Run] on the *UI instance to block
// until it is completed.
func NewUI(ctx context.Context, params Params) (*UI, error) {
app := tview.NewApplication()
var screen tcell.Screen
@ -210,7 +212,7 @@ func StartUI(ctx context.Context, params StartParams) (*UI, error) {
eventBus: params.EventBus,
dispatch: params.Dispatcher,
clipboardAvailable: params.ClipboardAvailable,
doneC: make(chan struct{}, 1),
appExitC: make(chan error, 1),
buildInfo: params.BuildInfo,
logger: params.Logger,
app: app,
@ -236,8 +238,6 @@ func StartUI(ctx context.Context, params StartParams) (*UI, error) {
app.SetInputCapture(ui.inputCaptureHandler)
app.SetAfterDrawFunc(ui.afterDrawHandler)
go ui.run(ctx)
return ui, nil
}
@ -264,23 +264,28 @@ func (ui *UI) renderAboutView() {
ui.aboutView.AddItem(tview.NewTextView().SetDynamicColors(true).SetText("[grey]?[-] About"), 1, 0, false)
}
func (ui *UI) run(ctx context.Context) {
var ErrUserClosed = errors.New("user closed UI")
// Run runs the user interface. It always returns a non-nil error, which will
// be [ErrUserClosed] if the user voluntarily closed the UI.
func (ui *UI) Run(ctx context.Context) error {
eventC := ui.eventBus.Register()
defer ui.eventBus.Deregister(eventC)
go func() {
defer close(ui.doneC)
if err := ui.app.Run(); err != nil {
err := ui.app.Run()
if err != nil {
ui.logger.Error("Error in UI run loop, exiting", "err", err)
}
ui.appExitC <- err
}()
for {
select {
case evt, ok := <-eventC:
if !ok {
return
// should never happen
return errors.New("event channel closed")
}
ui.app.QueueUpdateDraw(func() {
switch evt := evt.(type) {
@ -307,12 +312,11 @@ func (ui *UI) run(ctx context.Context) {
default:
ui.logger.Warn("unhandled event", "event", evt)
}
})
case <-ctx.Done():
return
case <-ui.doneC:
return
return ctx.Err()
case err := <-ui.appExitC:
return cmp.Or(err, ErrUserClosed)
}
}
}
@ -819,7 +823,7 @@ func (ui *UI) Close() {
// Wait waits for the terminal user interface to finish.
func (ui *UI) Wait() {
<-ui.doneC
<-ui.appExitC
}
func (ui *UI) addDestination() {