Skip to content
This repository was archived by the owner on Sep 18, 2025. It is now read-only.

Commit a23e1a3

Browse files
committed
cleanup nested tool rendering
1 parent 9a69a31 commit a23e1a3

4 files changed

Lines changed: 38 additions & 29 deletions

File tree

internal/tui/components/chat/list.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,19 @@ type messageListCmp struct {
4646
// and reverse ordering (newest messages at bottom).
4747
func NewMessagesListCmp(app *app.App) MessageListCmp {
4848
defaultKeymaps := list.DefaultKeymap()
49-
defaultKeymaps.NDown.SetEnabled(false)
50-
defaultKeymaps.NUp.SetEnabled(false)
49+
defaultKeymaps.Up.SetEnabled(false)
50+
defaultKeymaps.Down.SetEnabled(false)
51+
defaultKeymaps.NDown = key.NewBinding(
52+
key.WithKeys("ctrl+j"),
53+
)
54+
defaultKeymaps.NUp = key.NewBinding(
55+
key.WithKeys("ctrl+k"),
56+
)
5157
defaultKeymaps.Home = key.NewBinding(
52-
key.WithKeys("ctrl+g"),
58+
key.WithKeys("ctrl+shift+up"),
5359
)
5460
defaultKeymaps.End = key.NewBinding(
55-
key.WithKeys("ctrl+G"),
61+
key.WithKeys("ctrl+shift+down"),
5662
)
5763
return &messageListCmp{
5864
app: app,

internal/tui/components/chat/messages/renderer.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"time"
88

99
"github.com/charmbracelet/lipgloss/v2"
10+
"github.com/charmbracelet/lipgloss/v2/tree"
1011
"github.com/charmbracelet/x/ansi"
1112
"github.com/opencode-ai/opencode/internal/config"
1213
"github.com/opencode-ai/opencode/internal/diff"
@@ -93,7 +94,7 @@ func (pb *paramBuilder) build() []string {
9394
func (br baseRenderer) renderWithParams(v *toolCallCmp, toolName string, args []string, contentRenderer func() string) string {
9495
width := v.textWidth()
9596
if v.isNested {
96-
width -= 3 // Adjust for nested tool call indentation
97+
width -= 4 // Adjust for nested tool call indentation
9798
}
9899
header := makeHeader(toolName, width, args...)
99100
if v.isNested {
@@ -495,11 +496,15 @@ func (tr agentRenderer) Render(v *toolCallCmp) string {
495496
args := newParamBuilder().addMain(prompt).build()
496497

497498
header := makeHeader("Task", v.textWidth(), args...)
498-
parts := []string{header}
499+
t := tree.Root(header)
500+
499501
for _, call := range v.nestedToolCalls {
500-
parts = append(parts, call.View())
502+
t.Child(call.View())
501503
}
502504

505+
parts := []string{
506+
t.Enumerator(tree.RoundedEnumerator).String(),
507+
}
503508
if v.result.ToolCallID == "" {
504509
v.spinning = true
505510
parts = append(parts, v.anim.View())

internal/tui/components/chat/messages/tool.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -138,18 +138,16 @@ func (m *toolCallCmp) View() string {
138138
box := m.style()
139139

140140
if !m.call.Finished && !m.cancelled {
141+
if m.isNested {
142+
return box.Render(m.renderPending())
143+
}
141144
return box.PaddingLeft(1).Render(m.renderPending())
142145
}
143146

144147
r := registry.lookup(m.call.Name)
145148

146149
if m.isNested {
147-
return box.Render(
148-
lipgloss.JoinHorizontal(lipgloss.Left,
149-
" └ ",
150-
r.Render(m),
151-
),
152-
)
150+
return box.Render(r.Render(m))
153151
}
154152
return box.PaddingLeft(1).Render(r.Render(m))
155153
}
@@ -212,9 +210,6 @@ func (m *toolCallCmp) SetIsNested(isNested bool) {
212210

213211
// renderPending displays the tool name with a loading animation for pending tool calls
214212
func (m *toolCallCmp) renderPending() string {
215-
if m.isNested {
216-
return fmt.Sprintf("└ %s: %s", prettifyToolName(m.call.Name), m.anim.View())
217-
}
218213
return fmt.Sprintf("%s: %s", prettifyToolName(m.call.Name), m.anim.View())
219214
}
220215

internal/tui/components/core/list/keys.go

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package list
22

3-
import "github.com/charmbracelet/bubbles/v2/key"
3+
import (
4+
"github.com/charmbracelet/bubbles/v2/key"
5+
"github.com/opencode-ai/opencode/internal/tui/layout"
6+
)
47

58
type KeyMap struct {
69
Down,
@@ -12,8 +15,7 @@ type KeyMap struct {
1215
HalfPageDown,
1316
HalfPageUp,
1417
Home,
15-
End,
16-
Submit key.Binding
18+
End key.Binding
1719
}
1820

1921
func DefaultKeymap() KeyMap {
@@ -48,23 +50,24 @@ func DefaultKeymap() KeyMap {
4850
End: key.NewBinding(
4951
key.WithKeys("shift+g", "end"),
5052
),
51-
Submit: key.NewBinding(
52-
key.WithKeys("enter", "space"),
53-
key.WithHelp("enter/space", "select"),
54-
),
5553
}
5654
}
5755

5856
// FullHelp implements help.KeyMap.
59-
func (k KeyMap) FullHelp() [][]key.Binding { return nil }
57+
func (k KeyMap) FullHelp() [][]key.Binding {
58+
m := [][]key.Binding{}
59+
slice := layout.KeyMapToSlice(k)
60+
for i := 0; i < len(slice); i += 4 {
61+
end := min(i+4, len(slice))
62+
m = append(m, slice[i:end])
63+
}
64+
return m
65+
}
6066

6167
// ShortHelp implements help.KeyMap.
6268
func (k KeyMap) ShortHelp() []key.Binding {
6369
return []key.Binding{
64-
key.NewBinding(
65-
key.WithKeys("up", "down"),
66-
key.WithHelp("↓↑", "navigate"),
67-
),
68-
k.Submit,
70+
k.Up,
71+
k.Down,
6972
}
7073
}

0 commit comments

Comments
 (0)