Private
Public Access
1
0

TUI refactor

- Clean up, improved startup logic, initial conversation load
- Moved converation/message business logic (mostly) into `model/tui`
This commit is contained in:
2024-09-16 00:48:45 +00:00
parent 1570988b98
commit 443c8096d3
11 changed files with 431 additions and 350 deletions

View File

@@ -9,33 +9,42 @@ package tui
import (
"fmt"
"git.mlow.ca/mlow/lmcli/pkg/api"
"git.mlow.ca/mlow/lmcli/pkg/lmcli"
"git.mlow.ca/mlow/lmcli/pkg/tui/model"
"git.mlow.ca/mlow/lmcli/pkg/tui/shared"
"git.mlow.ca/mlow/lmcli/pkg/tui/views/chat"
"git.mlow.ca/mlow/lmcli/pkg/tui/views/conversations"
tea "github.com/charmbracelet/bubbletea"
)
// Application model
type Model struct {
shared.Shared
state shared.View
chat chat.Model
conversations conversations.Model
type LaunchOptions struct {
InitialConversation *api.Conversation
InitialView shared.View
}
func initialModel(ctx *lmcli.Context, values shared.Values) Model {
type Model struct {
App *model.AppModel
view shared.View
chat chat.Model
conversations conversations.Model
Width int
Height int
}
func initialModel(ctx *lmcli.Context, opts LaunchOptions) Model {
m := Model{
Shared: shared.Shared{
Ctx: ctx,
Values: &values,
App: &model.AppModel{
Ctx: ctx,
Conversation: opts.InitialConversation,
},
view: opts.InitialView,
}
m.state = shared.StateChat
m.chat = chat.Chat(m.Shared)
m.conversations = conversations.Conversations(m.Shared)
sharedData := shared.Shared{}
m.chat = chat.Chat(m.App, sharedData)
m.conversations = conversations.Conversations(m.App, sharedData)
return m
}
@@ -44,16 +53,14 @@ func (m Model) Init() tea.Cmd {
m.conversations.Init(),
m.chat.Init(),
func() tea.Msg {
return shared.MsgViewChange(m.state)
return shared.MsgViewChange(m.view)
},
)
}
func (m *Model) handleGlobalInput(msg tea.KeyMsg) (bool, tea.Cmd) {
// delegate input to the active child state first, only handling it at the
// global level if the child state does not
var cmds []tea.Cmd
switch m.state {
switch m.view {
case shared.StateChat:
handled, cmd := m.chat.HandleInput(msg)
cmds = append(cmds, cmd)
@@ -88,8 +95,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, cmd
}
case shared.MsgViewChange:
m.state = shared.View(msg)
switch m.state {
m.view = shared.View(msg)
switch m.view {
case shared.StateChat:
m.chat.HandleResize(m.Width, m.Height)
case shared.StateConversations:
@@ -101,7 +108,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
var cmd tea.Cmd
switch m.state {
switch m.view {
case shared.StateConversations:
m.conversations, cmd = m.conversations.Update(msg)
case shared.StateChat:
@@ -115,7 +122,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
func (m Model) View() string {
switch m.state {
switch m.view {
case shared.StateConversations:
return m.conversations.View()
case shared.StateChat:
@@ -124,9 +131,30 @@ func (m Model) View() string {
return ""
}
func Launch(ctx *lmcli.Context, convShortname string) error {
p := tea.NewProgram(initialModel(ctx, shared.Values{ConvShortname: convShortname}), tea.WithAltScreen())
if _, err := p.Run(); err != nil {
type LaunchOption func(*LaunchOptions)
func WithInitialConversation(conv *api.Conversation) LaunchOption {
return func(opts *LaunchOptions) {
opts.InitialConversation = conv
}
}
func WithInitialView(view shared.View) LaunchOption {
return func(opts *LaunchOptions) {
opts.InitialView = view
}
}
func Launch(ctx *lmcli.Context, options ...LaunchOption) error {
opts := &LaunchOptions{
InitialView: shared.StateChat,
}
for _, opt := range options {
opt(opts)
}
program := tea.NewProgram(initialModel(ctx, *opts), tea.WithAltScreen())
if _, err := program.Run(); err != nil {
return fmt.Errorf("Error running program: %v", err)
}
return nil