tui: add focus switching between input/messages view

This commit is contained in:
Matt Low 2024-03-12 17:50:10 +00:00
parent 98e92d1ff4
commit 3f7f34812f

View File

@ -2,7 +2,6 @@ package tui
// The terminal UI for lmcli, launched from the `lmcli chat` command // The terminal UI for lmcli, launched from the `lmcli chat` command
// TODO: // TODO:
// - mode/focus changing between input and message selection
// - binding to open selected message/input in $EDITOR // - binding to open selected message/input in $EDITOR
import ( import (
@ -19,6 +18,13 @@ import (
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
) )
type focusState int
const (
focusInput focusState = iota
focusMessages
)
type model struct { type model struct {
ctx *lmcli.Context ctx *lmcli.Context
convShortname string convShortname string
@ -30,6 +36,7 @@ type model struct {
err error err error
// ui state // ui state
focus focusState
isWaiting bool isWaiting bool
status string // a general status message status string // a general status message
@ -81,7 +88,25 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) { switch msg := msg.(type) {
case tea.KeyMsg: case tea.KeyMsg:
cmd = m.handleKeyMsg(msg) switch msg.String() {
case "ctrl+c":
return m, tea.Quit
case "q":
if m.focus != focusInput {
return m, tea.Quit
}
default:
var inputHandled tea.Cmd
switch m.focus {
case focusInput:
inputHandled = m.handleInputKey(msg)
case focusMessages:
inputHandled = m.handleMessagesKey(msg)
}
if inputHandled != nil {
return m, inputHandled
}
}
case tea.WindowSizeMsg: case tea.WindowSizeMsg:
m.content.Width = msg.Width m.content.Width = msg.Width
m.content.Height = msg.Height - m.input.Height() - lipgloss.Height(m.footerView()) m.content.Height = msg.Height - m.input.Height() - lipgloss.Height(m.footerView())
@ -161,14 +186,23 @@ func initialModel(ctx *lmcli.Context, convShortname string) model {
m.isWaiting = false m.isWaiting = false
m.status = "Press ctrl+s to send" m.status = "Press ctrl+s to send"
return m return m
} }
func (m *model) handleKeyMsg(msg tea.KeyMsg) tea.Cmd { func (m *model) handleMessagesKey(msg tea.KeyMsg) tea.Cmd {
switch msg.String() { switch msg.String() {
case "ctrl+c", "q": case "tab":
return tea.Quit m.focus = focusInput
m.input.Focus()
}
return nil
}
func (m *model) handleInputKey(msg tea.KeyMsg) tea.Cmd {
switch msg.String() {
case "esc":
m.focus = focusMessages
m.input.Blur()
case "ctrl+s": case "ctrl+s":
userInput := strings.TrimSpace(m.input.Value()) userInput := strings.TrimSpace(m.input.Value())
if strings.TrimSpace(userInput) == "" { if strings.TrimSpace(userInput) == "" {
@ -186,11 +220,7 @@ func (m *model) handleKeyMsg(msg tea.KeyMsg) tea.Cmd {
m.isWaiting = true m.isWaiting = true
m.status = "Waiting for response... (Press 's' to stop)" m.status = "Waiting for response... (Press 's' to stop)"
return m.promptLLM() return m.promptLLM()
case "s":
// TOOD: stop response
break
} }
return nil return nil
} }