Update tui error handling
- Allow each view to position error banners where they choose - Add global 'esc' key handler to dismiss errors
This commit is contained in:
parent
d9d1b02ef3
commit
02228d65ac
@ -13,7 +13,7 @@ type ViewModel interface {
|
|||||||
// View methods
|
// View methods
|
||||||
Header(width int) string
|
Header(width int) string
|
||||||
// Render the view's main content into a container of the given dimensions
|
// Render the view's main content into a container of the given dimensions
|
||||||
Content(width, height int) string
|
Content(width, height int, errors string) string
|
||||||
Footer(width int) string
|
Footer(width int) string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +60,14 @@ func (m *Model) Init() tea.Cmd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) handleGlobalInput(msg tea.KeyMsg) tea.Cmd {
|
func (m *Model) handleGlobalInput(msg tea.KeyMsg) tea.Cmd {
|
||||||
|
switch msg.String() {
|
||||||
|
case "esc":
|
||||||
|
if len(m.errs) > 0 {
|
||||||
|
m.errs = m.errs[1:]
|
||||||
|
return shared.KeyHandled(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
view, cmd := m.views[m.activeView].Update(msg)
|
view, cmd := m.views[m.activeView].Update(msg)
|
||||||
m.views[m.activeView] = view
|
m.views[m.activeView] = view
|
||||||
if cmd != nil {
|
if cmd != nil {
|
||||||
@ -108,10 +116,16 @@ func (m *Model) View() string {
|
|||||||
errBanners := make([]string, len(m.errs))
|
errBanners := make([]string, len(m.errs))
|
||||||
for idx, err := range m.errs {
|
for idx, err := range m.errs {
|
||||||
errBanners[idx] = tuiutil.ErrorBanner(err, m.width)
|
errBanners[idx] = tuiutil.ErrorBanner(err, m.width)
|
||||||
fixedUIHeight += tuiutil.Height(errBanners[idx])
|
|
||||||
}
|
}
|
||||||
|
var errors string
|
||||||
|
if len(errBanners) > 0 {
|
||||||
|
errors = lipgloss.JoinVertical(lipgloss.Left, errBanners...)
|
||||||
|
} else {
|
||||||
|
errors = ""
|
||||||
|
}
|
||||||
|
fixedUIHeight += tuiutil.Height(errors)
|
||||||
|
|
||||||
content := m.views[m.activeView].Content(m.width, m.height-fixedUIHeight)
|
content := m.views[m.activeView].Content(m.width, m.height-fixedUIHeight, errors)
|
||||||
|
|
||||||
sections := make([]string, 0, 4)
|
sections := make([]string, 0, 4)
|
||||||
if header != "" {
|
if header != "" {
|
||||||
@ -123,9 +137,6 @@ func (m *Model) View() string {
|
|||||||
if footer != "" {
|
if footer != "" {
|
||||||
sections = append(sections, footer)
|
sections = append(sections, footer)
|
||||||
}
|
}
|
||||||
for _, errBanner := range errBanners {
|
|
||||||
sections = append(sections, errBanner)
|
|
||||||
}
|
|
||||||
return lipgloss.JoinVertical(lipgloss.Left, sections...)
|
return lipgloss.JoinVertical(lipgloss.Left, sections...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +83,7 @@ type Model struct {
|
|||||||
stopSignal chan struct{}
|
stopSignal chan struct{}
|
||||||
chatReplyChunks chan provider.Chunk
|
chatReplyChunks chan provider.Chunk
|
||||||
persistence bool // whether we will save new messages in the conversation
|
persistence bool // whether we will save new messages in the conversation
|
||||||
|
promptCaching bool // whether prompt caching is enabled
|
||||||
|
|
||||||
// UI state
|
// UI state
|
||||||
focus focusState
|
focus focusState
|
||||||
|
@ -245,7 +245,7 @@ func (m *Model) conversationMessagesView() string {
|
|||||||
return sb.String()
|
return sb.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) Content(width, height int) string {
|
func (m *Model) Content(width, height int, errors string) string {
|
||||||
// calculate clamped input height to accomodate input text
|
// calculate clamped input height to accomodate input text
|
||||||
// minimum 4 lines, maximum half of content area
|
// minimum 4 lines, maximum half of content area
|
||||||
inputHeight := max(4, min(height/2, m.input.LineCount()))
|
inputHeight := max(4, min(height/2, m.input.LineCount()))
|
||||||
@ -255,7 +255,15 @@ func (m *Model) Content(width, height int) string {
|
|||||||
// remaining height towards content
|
// remaining height towards content
|
||||||
m.content.Width, m.content.Height = width, height-tuiutil.Height(input)
|
m.content.Width, m.content.Height = width, height-tuiutil.Height(input)
|
||||||
content := m.content.View()
|
content := m.content.View()
|
||||||
return lipgloss.JoinVertical(lipgloss.Left, content, input)
|
|
||||||
|
var sections []string
|
||||||
|
if errors != "" {
|
||||||
|
sections = []string{content, errors, input}
|
||||||
|
} else {
|
||||||
|
sections = []string{content, input}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lipgloss.JoinVertical(lipgloss.Left, sections...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) Header(width int) string {
|
func (m *Model) Header(width int) string {
|
||||||
|
@ -218,9 +218,13 @@ func (m *Model) Header(width int) string {
|
|||||||
return styles.Header.Width(width).Render(header)
|
return styles.Header.Width(width).Render(header)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) Content(width int, height int) string {
|
func (m *Model) Content(width int, height int, errors string) string {
|
||||||
m.content.Width, m.content.Height = width, height
|
m.content.Width, m.content.Height = width, height
|
||||||
return m.content.View()
|
content := m.content.View()
|
||||||
|
if errors != "" {
|
||||||
|
content += errors
|
||||||
|
}
|
||||||
|
return content
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) Footer(width int) string {
|
func (m *Model) Footer(width int) string {
|
||||||
|
@ -121,11 +121,15 @@ func (m *Model) Header(width int) string {
|
|||||||
return styles.Header.Width(width).Render(header)
|
return styles.Header.Width(width).Render(header)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) Content(width, height int) string {
|
func (m *Model) Content(width, height int, errors string) string {
|
||||||
// TODO: see Header()
|
// TODO: see Header()
|
||||||
currentModel := " Active model: " + m.App.ActiveModel(lipgloss.NewStyle())
|
currentModel := " Active model: " + m.App.ActiveModel(lipgloss.NewStyle())
|
||||||
m.modelList.Width, m.modelList.Height = width, height - 2
|
m.modelList.Width, m.modelList.Height = width, height - 2
|
||||||
return "\n" + currentModel + "\n" + m.modelList.View()
|
content := "\n" + currentModel + "\n" + m.modelList.View()
|
||||||
|
if errors != "" {
|
||||||
|
content += errors
|
||||||
|
}
|
||||||
|
return content
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) Footer(width int) string {
|
func (m *Model) Footer(width int) string {
|
||||||
|
Loading…
Reference in New Issue
Block a user