summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authoradamdottv <[email protected]>2025-06-30 14:04:48 -0500
committeradamdottv <[email protected]>2025-06-30 14:04:56 -0500
commit5a107b275ce784405d7ff68e193499e8822fe90d (patch)
tree0b827be922641c6b95631c47758c3a6aed373716
parentdd5736fe5fc463a52d5a82bf513fbcb6b8ae08fd (diff)
downloadopencode-5a107b275ce784405d7ff68e193499e8822fe90d.tar.gz
opencode-5a107b275ce784405d7ff68e193499e8822fe90d.zip
fix(tui): layout issues
-rw-r--r--packages/tui/internal/components/chat/messages.go88
-rw-r--r--packages/tui/internal/components/commands/commands.go14
-rw-r--r--packages/tui/internal/components/dialog/help.go9
-rw-r--r--packages/tui/internal/layout/flex.go10
-rw-r--r--packages/tui/internal/tui/tui.go109
5 files changed, 92 insertions, 138 deletions
diff --git a/packages/tui/internal/components/chat/messages.go b/packages/tui/internal/components/chat/messages.go
index ab9ef65ec..bfbae3938 100644
--- a/packages/tui/internal/components/chat/messages.go
+++ b/packages/tui/internal/components/chat/messages.go
@@ -10,7 +10,6 @@ import (
"github.com/charmbracelet/lipgloss/v2"
"github.com/sst/opencode-sdk-go"
"github.com/sst/opencode/internal/app"
- "github.com/sst/opencode/internal/components/commands"
"github.com/sst/opencode/internal/components/dialog"
"github.com/sst/opencode/internal/layout"
"github.com/sst/opencode/internal/styles"
@@ -39,7 +38,6 @@ type messagesComponent struct {
viewport viewport.Model
spinner spinner.Model
attachments viewport.Model
- commands commands.CommandsComponent
cache *MessageCache
rendering bool
showToolDetails bool
@@ -49,7 +47,7 @@ type renderFinishedMsg struct{}
type ToggleToolDetailsMsg struct{}
func (m *messagesComponent) Init() tea.Cmd {
- return tea.Batch(m.viewport.Init(), m.spinner.Tick, m.commands.Init())
+ return tea.Batch(m.viewport.Init(), m.spinner.Tick)
}
func (m *messagesComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
@@ -100,10 +98,6 @@ func (m *messagesComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.spinner = spinner
cmds = append(cmds, cmd)
- updated, cmd := m.commands.Update(msg)
- m.commands = updated.(commands.CommandsComponent)
- cmds = append(cmds, cmd)
-
return m, tea.Batch(cmds...)
}
@@ -271,8 +265,8 @@ func (m *messagesComponent) renderView() {
))
}
- m.viewport.SetHeight(m.height - lipgloss.Height(m.header()))
- m.viewport.SetContent("\n" + strings.Join(centered, "\n") + "\n")
+ m.viewport.SetHeight(m.height - lipgloss.Height(m.header()) + 1)
+ m.viewport.SetContent("\n" + strings.Join(centered, "\n"))
}
func (m *messagesComponent) header() string {
@@ -309,9 +303,6 @@ func (m *messagesComponent) header() string {
}
func (m *messagesComponent) View() string {
- if len(m.app.Messages) == 0 {
- return m.home()
- }
t := theme.CurrentTheme()
if m.rendering {
return lipgloss.Place(
@@ -334,70 +325,6 @@ func (m *messagesComponent) View() string {
Render(header + "\n" + m.viewport.View())
}
-func (m *messagesComponent) home() string {
- t := theme.CurrentTheme()
- baseStyle := styles.NewStyle().Background(t.Background())
- base := baseStyle.Render
- muted := styles.NewStyle().Foreground(t.TextMuted()).Background(t.Background()).Render
-
- open := `
-█▀▀█ █▀▀█ █▀▀ █▀▀▄
-█░░█ █░░█ █▀▀ █░░█
-▀▀▀▀ █▀▀▀ ▀▀▀ ▀ ▀ `
- code := `
-█▀▀ █▀▀█ █▀▀▄ █▀▀
-█░░ █░░█ █░░█ █▀▀
-▀▀▀ ▀▀▀▀ ▀▀▀ ▀▀▀`
-
- logo := lipgloss.JoinHorizontal(
- lipgloss.Top,
- muted(open),
- base(code),
- )
- // cwd := app.Info.Path.Cwd
- // config := app.Info.Path.Config
-
- versionStyle := styles.NewStyle().
- Foreground(t.TextMuted()).
- Background(t.Background()).
- Width(lipgloss.Width(logo)).
- Align(lipgloss.Right)
- version := versionStyle.Render(m.app.Version)
-
- logoAndVersion := strings.Join([]string{logo, version}, "\n")
- logoAndVersion = lipgloss.PlaceHorizontal(
- m.width,
- lipgloss.Center,
- logoAndVersion,
- styles.WhitespaceStyle(t.Background()),
- )
- m.commands.SetBackgroundColor(t.Background())
- commands := lipgloss.PlaceHorizontal(
- m.width,
- lipgloss.Center,
- m.commands.View(),
- styles.WhitespaceStyle(t.Background()),
- )
-
- lines := []string{}
- lines = append(lines, logoAndVersion)
- lines = append(lines, "")
- lines = append(lines, "")
- // lines = append(lines, base("cwd ")+muted(cwd))
- // lines = append(lines, base("config ")+muted(config))
- // lines = append(lines, "")
- lines = append(lines, commands)
-
- return lipgloss.Place(
- m.width,
- m.height,
- lipgloss.Center,
- lipgloss.Center,
- baseStyle.Render(strings.Join(lines, "\n")),
- styles.WhitespaceStyle(t.Background()),
- )
-}
-
func (m *messagesComponent) SetSize(width, height int) tea.Cmd {
if m.width == width && m.height == height {
return nil
@@ -412,7 +339,6 @@ func (m *messagesComponent) SetSize(width, height int) tea.Cmd {
m.viewport.SetHeight(height - lipgloss.Height(m.header()))
m.attachments.SetWidth(width + 40)
m.attachments.SetHeight(3)
- m.commands.SetSize(width, height)
m.renderView()
return nil
}
@@ -476,19 +402,11 @@ func NewMessagesComponent(app *app.App) MessagesComponent {
attachments := viewport.New()
vp.KeyMap = viewport.KeyMap{}
- t := theme.CurrentTheme()
- commandsView := commands.New(
- app,
- commands.WithBackground(t.Background()),
- commands.WithLimit(6),
- )
-
return &messagesComponent{
app: app,
viewport: vp,
spinner: s,
attachments: attachments,
- commands: commandsView,
showToolDetails: true,
cache: NewMessageCache(),
tail: true,
diff --git a/packages/tui/internal/components/commands/commands.go b/packages/tui/internal/components/commands/commands.go
index 68f6503e0..dbd001497 100644
--- a/packages/tui/internal/components/commands/commands.go
+++ b/packages/tui/internal/components/commands/commands.go
@@ -14,7 +14,6 @@ import (
)
type CommandsComponent interface {
- tea.Model
tea.ViewModel
SetSize(width, height int) tea.Cmd
SetBackgroundColor(color compat.AdaptiveColor)
@@ -43,19 +42,6 @@ func (c *commandsComponent) SetBackgroundColor(color compat.AdaptiveColor) {
c.background = &color
}
-func (c *commandsComponent) Init() tea.Cmd {
- return nil
-}
-
-func (c *commandsComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
- switch msg := msg.(type) {
- case tea.WindowSizeMsg:
- c.width = msg.Width
- c.height = msg.Height
- }
- return c, nil
-}
-
func (c *commandsComponent) View() string {
t := theme.CurrentTheme()
diff --git a/packages/tui/internal/components/dialog/help.go b/packages/tui/internal/components/dialog/help.go
index 78cbd7042..4107384f8 100644
--- a/packages/tui/internal/components/dialog/help.go
+++ b/packages/tui/internal/components/dialog/help.go
@@ -20,10 +20,7 @@ type helpDialog struct {
}
func (h *helpDialog) Init() tea.Cmd {
- return tea.Batch(
- h.commandsComponent.Init(),
- h.viewport.Init(),
- )
+ return h.viewport.Init()
}
func (h *helpDialog) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
@@ -38,10 +35,6 @@ func (h *helpDialog) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
h.commandsComponent.SetSize(msg.Width-4, msg.Height-6)
}
- // Update commands component first to get the latest content
- _, cmdCmd := h.commandsComponent.Update(msg)
- cmds = append(cmds, cmdCmd)
-
// Update viewport content
h.viewport.SetContent(h.commandsComponent.View())
diff --git a/packages/tui/internal/layout/flex.go b/packages/tui/internal/layout/flex.go
index f164a03dc..c7d9ee1bc 100644
--- a/packages/tui/internal/layout/flex.go
+++ b/packages/tui/internal/layout/flex.go
@@ -73,10 +73,7 @@ func Render(opts FlexOptions, items ...FlexItem) string {
}
// Calculate available space for grow items
- availableSpace := mainAxisSize - totalFixedSize
- if availableSpace < 0 {
- availableSpace = 0
- }
+ availableSpace := max(mainAxisSize-totalFixedSize, 0)
// Calculate size for each grow item
growItemSize := 0
@@ -164,10 +161,7 @@ func Render(opts FlexOptions, items ...FlexItem) string {
}
// Apply justification
- remainingSpace := mainAxisSize - totalActualSize
- if remainingSpace < 0 {
- remainingSpace = 0
- }
+ remainingSpace := max(mainAxisSize-totalActualSize, 0)
// Calculate spacing based on justification
var spaceBefore, spaceBetween, spaceAfter int
diff --git a/packages/tui/internal/tui/tui.go b/packages/tui/internal/tui/tui.go
index 67538e804..4fb3e90dc 100644
--- a/packages/tui/internal/tui/tui.go
+++ b/packages/tui/internal/tui/tui.go
@@ -17,6 +17,7 @@ import (
"github.com/sst/opencode/internal/commands"
"github.com/sst/opencode/internal/completions"
"github.com/sst/opencode/internal/components/chat"
+ cmdcomp "github.com/sst/opencode/internal/components/commands"
"github.com/sst/opencode/internal/components/dialog"
"github.com/sst/opencode/internal/components/modal"
"github.com/sst/opencode/internal/components/status"
@@ -425,13 +426,13 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
func (a appModel) View() string {
- messagesView := a.messages.View()
editorView := a.editor.View()
-
- editorHeight := lipgloss.Height(editorView)
- if editorHeight < 5 {
- editorHeight = 5
+ lines := a.editor.Lines()
+ messagesView := a.messages.View()
+ if a.app.Session.ID == "" {
+ messagesView = a.home()
}
+ editorHeight := max(lines, 5)
t := theme.CurrentTheme()
centeredEditorView := lipgloss.PlaceHorizontal(
@@ -445,7 +446,7 @@ func (a appModel) View() string {
layout.FlexOptions{
Direction: layout.Column,
Width: a.width,
- Height: a.height - 1, // Leave room for status bar
+ Height: a.height,
},
layout.FlexItem{
View: messagesView,
@@ -453,15 +454,18 @@ func (a appModel) View() string {
},
layout.FlexItem{
View: centeredEditorView,
- FixedSize: editorHeight,
+ FixedSize: 5,
},
+ // layout.FlexItem{
+ // View: a.status.View(),
+ // FixedSize: 1,
+ // },
)
- if a.editor.Lines() > 1 {
+ if lines > 1 {
editorWidth := min(a.width, 80)
editorX := (a.width - editorWidth) / 2
- editorY := a.height - editorHeight - 1 // Position from bottom, accounting for status bar
-
+ editorY := a.height - editorHeight
mainLayout = layout.PlaceOverlay(
editorX,
editorY,
@@ -476,7 +480,7 @@ func (a appModel) View() string {
a.completions.SetWidth(editorWidth)
overlay := a.completions.View()
overlayHeight := lipgloss.Height(overlay)
- editorY := a.height - editorHeight - 1
+ editorY := a.height - editorHeight + 1
mainLayout = layout.PlaceOverlay(
editorX,
@@ -486,23 +490,82 @@ func (a appModel) View() string {
)
}
- components := []string{
- mainLayout,
- a.status.View(),
- }
- appView := strings.Join(components, "\n")
-
if a.modal != nil {
- appView = a.modal.Render(appView)
+ mainLayout = a.modal.Render(mainLayout)
}
-
- appView = a.toastManager.RenderOverlay(appView)
-
+ mainLayout = a.toastManager.RenderOverlay(mainLayout)
if theme.CurrentThemeUsesAnsiColors() {
- appView = util.ConvertRGBToAnsi16Colors(appView)
+ mainLayout = util.ConvertRGBToAnsi16Colors(mainLayout)
}
+ return mainLayout + "\n" + a.status.View()
+}
- return appView
+func (a appModel) home() string {
+ t := theme.CurrentTheme()
+ baseStyle := styles.NewStyle().Background(t.Background())
+ base := baseStyle.Render
+ muted := styles.NewStyle().Foreground(t.TextMuted()).Background(t.Background()).Render
+
+ open := `
+█▀▀█ █▀▀█ █▀▀ █▀▀▄
+█░░█ █░░█ █▀▀ █░░█
+▀▀▀▀ █▀▀▀ ▀▀▀ ▀ ▀ `
+ code := `
+█▀▀ █▀▀█ █▀▀▄ █▀▀
+█░░ █░░█ █░░█ █▀▀
+▀▀▀ ▀▀▀▀ ▀▀▀ ▀▀▀`
+
+ logo := lipgloss.JoinHorizontal(
+ lipgloss.Top,
+ muted(open),
+ base(code),
+ )
+ // cwd := app.Info.Path.Cwd
+ // config := app.Info.Path.Config
+
+ versionStyle := styles.NewStyle().
+ Foreground(t.TextMuted()).
+ Background(t.Background()).
+ Width(lipgloss.Width(logo)).
+ Align(lipgloss.Right)
+ version := versionStyle.Render(a.app.Version)
+
+ logoAndVersion := strings.Join([]string{logo, version}, "\n")
+ logoAndVersion = lipgloss.PlaceHorizontal(
+ a.width,
+ lipgloss.Center,
+ logoAndVersion,
+ styles.WhitespaceStyle(t.Background()),
+ )
+ commandsView := cmdcomp.New(
+ a.app,
+ cmdcomp.WithBackground(t.Background()),
+ cmdcomp.WithLimit(6),
+ )
+ cmds := lipgloss.PlaceHorizontal(
+ a.width,
+ lipgloss.Center,
+ commandsView.View(),
+ styles.WhitespaceStyle(t.Background()),
+ )
+
+ lines := []string{}
+ lines = append(lines, logoAndVersion)
+ lines = append(lines, "")
+ lines = append(lines, "")
+ // lines = append(lines, base("cwd ")+muted(cwd))
+ // lines = append(lines, base("config ")+muted(config))
+ // lines = append(lines, "")
+ lines = append(lines, cmds)
+
+ return lipgloss.Place(
+ a.width,
+ a.height-5,
+ lipgloss.Center,
+ lipgloss.Center,
+ baseStyle.Render(strings.Join(lines, "\n")),
+ styles.WhitespaceStyle(t.Background()),
+ )
}
func (a appModel) executeCommand(command commands.Command) (tea.Model, tea.Cmd) {