From 23e7a95083a8d875420c90e0479647f18a278c5f Mon Sep 17 00:00:00 2001 From: Kujtim Hoxha Date: Fri, 11 Apr 2025 18:54:13 +0200 Subject: intiial layout --- internal/tui/components/chat/editor.go | 62 ++++++++++++++++++++++++++++ internal/tui/components/chat/messages.go | 21 ++++++++++ internal/tui/components/chat/sidebar.go | 21 ++++++++++ internal/tui/components/dialog/permission.go | 2 +- internal/tui/components/repl/editor.go | 48 +++++++++++---------- 5 files changed, 132 insertions(+), 22 deletions(-) create mode 100644 internal/tui/components/chat/editor.go create mode 100644 internal/tui/components/chat/messages.go create mode 100644 internal/tui/components/chat/sidebar.go (limited to 'internal/tui/components') diff --git a/internal/tui/components/chat/editor.go b/internal/tui/components/chat/editor.go new file mode 100644 index 000000000..0b7617174 --- /dev/null +++ b/internal/tui/components/chat/editor.go @@ -0,0 +1,62 @@ +package chat + +import ( + "github.com/charmbracelet/bubbles/key" + "github.com/charmbracelet/bubbles/textarea" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/kujtimiihoxha/termai/internal/tui/layout" + "github.com/kujtimiihoxha/termai/internal/tui/styles" +) + +type editorCmp struct { + textarea textarea.Model +} + +func (m *editorCmp) Init() tea.Cmd { + return textarea.Blink +} + +func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + var cmd tea.Cmd + m.textarea, cmd = m.textarea.Update(msg) + return m, cmd +} + +func (m *editorCmp) View() string { + style := lipgloss.NewStyle().Padding(0, 0, 0, 1).Bold(true) + + return lipgloss.JoinHorizontal(lipgloss.Top, style.Render(">"), m.textarea.View()) +} + +func (m *editorCmp) SetSize(width, height int) { + m.textarea.SetWidth(width - 3) // account for the prompt and padding right + m.textarea.SetHeight(height) +} + +func (m *editorCmp) GetSize() (int, int) { + return m.textarea.Width(), m.textarea.Height() +} + +func (m *editorCmp) BindingKeys() []key.Binding { + return layout.KeyMapToSlice(m.textarea.KeyMap) +} + +func NewEditorCmp() tea.Model { + ti := textarea.New() + ti.Prompt = " " + ti.ShowLineNumbers = false + ti.BlurredStyle.Base = ti.BlurredStyle.Base.Background(styles.Background) + ti.BlurredStyle.CursorLine = ti.BlurredStyle.CursorLine.Background(styles.Background) + ti.BlurredStyle.Placeholder = ti.BlurredStyle.Placeholder.Background(styles.Background) + ti.BlurredStyle.Text = ti.BlurredStyle.Text.Background(styles.Background) + + ti.FocusedStyle.Base = ti.FocusedStyle.Base.Background(styles.Background) + ti.FocusedStyle.CursorLine = ti.FocusedStyle.CursorLine.Background(styles.Background) + ti.FocusedStyle.Placeholder = ti.FocusedStyle.Placeholder.Background(styles.Background) + ti.FocusedStyle.Text = ti.BlurredStyle.Text.Background(styles.Background) + ti.Focus() + return &editorCmp{ + textarea: ti, + } +} diff --git a/internal/tui/components/chat/messages.go b/internal/tui/components/chat/messages.go new file mode 100644 index 000000000..691954767 --- /dev/null +++ b/internal/tui/components/chat/messages.go @@ -0,0 +1,21 @@ +package chat + +import tea "github.com/charmbracelet/bubbletea" + +type messagesCmp struct{} + +func (m *messagesCmp) Init() tea.Cmd { + return nil +} + +func (m *messagesCmp) Update(tea.Msg) (tea.Model, tea.Cmd) { + return m, nil +} + +func (m *messagesCmp) View() string { + return "Messages" +} + +func NewMessagesCmp() tea.Model { + return &messagesCmp{} +} diff --git a/internal/tui/components/chat/sidebar.go b/internal/tui/components/chat/sidebar.go new file mode 100644 index 000000000..afdd241f4 --- /dev/null +++ b/internal/tui/components/chat/sidebar.go @@ -0,0 +1,21 @@ +package chat + +import tea "github.com/charmbracelet/bubbletea" + +type sidebarCmp struct{} + +func (m *sidebarCmp) Init() tea.Cmd { + return nil +} + +func (m *sidebarCmp) Update(tea.Msg) (tea.Model, tea.Cmd) { + return m, nil +} + +func (m *sidebarCmp) View() string { + return "Sidebar" +} + +func NewSidebarCmp() tea.Model { + return &sidebarCmp{} +} diff --git a/internal/tui/components/dialog/permission.go b/internal/tui/components/dialog/permission.go index 465f475d5..088697d55 100644 --- a/internal/tui/components/dialog/permission.go +++ b/internal/tui/components/dialog/permission.go @@ -441,7 +441,7 @@ func NewPermissionDialogCmd(permission permission.PermissionRequest) tea.Cmd { layout.WithSinglePaneBordered(true), layout.WithSinglePaneFocusable(true), layout.WithSinglePaneActiveColor(styles.Warning), - layout.WithSignlePaneBorderText(map[layout.BorderPosition]string{ + layout.WithSinglePaneBorderText(map[layout.BorderPosition]string{ layout.TopMiddleBorder: " Permission Required ", }), ) diff --git a/internal/tui/components/repl/editor.go b/internal/tui/components/repl/editor.go index 37ac275e3..e9493129d 100644 --- a/internal/tui/components/repl/editor.go +++ b/internal/tui/components/repl/editor.go @@ -156,30 +156,36 @@ func (m *editorCmp) Cancel() tea.Cmd { } func (m *editorCmp) Send() tea.Cmd { - return func() tea.Msg { - messages, err := m.app.Messages.List(m.sessionID) - if err != nil { - return util.ReportError(err) - } - if hasUnfinishedMessages(messages) { - return util.ReportWarn("Assistant is still working on the previous message") - } - a, err := agent.NewCoderAgent(m.app) - if err != nil { - return util.ReportError(err) - } + if m.cancelMessage != nil { + return util.ReportWarn("Assistant is still working on the previous message") + } - content := strings.Join(m.editor.GetBuffer().Lines(), "\n") - ctx, cancel := context.WithCancel(m.app.Context) - m.cancelMessage = cancel - go func() { - defer cancel() - a.Generate(ctx, m.sessionID, content) - m.cancelMessage = nil - }() + messages, err := m.app.Messages.List(m.sessionID) + if err != nil { + return util.ReportError(err) + } + if hasUnfinishedMessages(messages) { + return util.ReportWarn("Assistant is still working on the previous message") + } + + a, err := agent.NewCoderAgent(m.app) + if err != nil { + return util.ReportError(err) + } - return m.editor.Reset() + content := strings.Join(m.editor.GetBuffer().Lines(), "\n") + if len(content) == 0 { + return util.ReportWarn("Message is empty") } + ctx, cancel := context.WithCancel(m.app.Context) + m.cancelMessage = cancel + go func() { + defer cancel() + a.Generate(ctx, m.sessionID, content) + m.cancelMessage = nil + }() + + return m.editor.Reset() } func (m *editorCmp) View() string { -- cgit v1.2.3