Skip to content

Commit 216e6d0

Browse files
authored
Merge pull request #507 from dgageot/fix-tui
Fix #501
2 parents e6ef20f + f15aee7 commit 216e6d0

3 files changed

Lines changed: 46 additions & 41 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package markdown
2+
3+
import (
4+
"github.com/charmbracelet/glamour/v2"
5+
allstyles "github.com/charmbracelet/glamour/v2/styles"
6+
)
7+
8+
func uintPtr(u uint) *uint { return &u }
9+
10+
func NewRenderer(width int) *glamour.TermRenderer {
11+
customDarkStyle := *allstyles.DefaultStyles["dark"]
12+
13+
customDarkStyle.Document.Margin = uintPtr(0)
14+
customDarkStyle.Document.BlockPrefix = ""
15+
customDarkStyle.Document.BlockSuffix = ""
16+
17+
r, _ := glamour.NewTermRenderer(
18+
glamour.WithWordWrap(min(width, 120)),
19+
glamour.WithStyles(customDarkStyle),
20+
)
21+
return r
22+
}

pkg/tui/components/message/message.go

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import (
77

88
"github.com/charmbracelet/bubbles/v2/spinner"
99
tea "github.com/charmbracelet/bubbletea/v2"
10-
"github.com/charmbracelet/glamour/v2"
10+
"github.com/charmbracelet/lipgloss/v2"
1111

12+
"github.com/docker/cagent/pkg/tui/components/markdown"
1213
"github.com/docker/cagent/pkg/tui/core/layout"
1314
"github.com/docker/cagent/pkg/tui/styles"
1415
"github.com/docker/cagent/pkg/tui/types"
@@ -23,23 +24,21 @@ type Model interface {
2324

2425
// messageModel implements Model
2526
type messageModel struct {
26-
message *types.Message
27-
renderer *glamour.TermRenderer
28-
width int
29-
height int
30-
focused bool
31-
spinner spinner.Model
27+
message *types.Message
28+
width int
29+
height int
30+
focused bool
31+
spinner spinner.Model
3232
}
3333

3434
// New creates a new message view
35-
func New(msg *types.Message, renderer *glamour.TermRenderer) Model {
35+
func New(msg *types.Message) *messageModel {
3636
return &messageModel{
37-
message: msg,
38-
width: 80, // Default width
39-
height: 1, // Will be calculated
40-
focused: false,
41-
spinner: spinner.New(spinner.WithSpinner(spinner.Points)),
42-
renderer: renderer,
37+
message: msg,
38+
width: 80, // Default width
39+
height: 1, // Will be calculated
40+
focused: false,
41+
spinner: spinner.New(spinner.WithSpinner(spinner.Points)),
4342
}
4443
}
4544

@@ -73,26 +72,26 @@ func (mv *messageModel) View() string {
7372
return mv.Render(mv.width)
7473
}
7574

76-
// MessageView specific methods
77-
7875
// Render renders the message view content
79-
func (mv *messageModel) Render(int) string {
76+
func (mv *messageModel) Render(width int) string {
8077
msg := mv.message
8178
switch msg.Type {
8279
case types.MessageTypeSpinner:
8380
return mv.spinner.View()
8481
case types.MessageTypeUser:
85-
if rendered, err := mv.renderer.Render("> " + msg.Content); err == nil {
86-
return strings.TrimRight(rendered, "\n\r\t ")
82+
s := lipgloss.NewStyle().PaddingLeft(1).BorderLeft(true).BorderStyle(lipgloss.ThickBorder())
83+
if rendered, err := markdown.NewRenderer(width - len(s.Render(""))).Render(msg.Content); err == nil {
84+
return s.Render(strings.TrimRight(rendered, "\n\r\t "))
8785
}
86+
8887
return msg.Content
8988
case types.MessageTypeAssistant:
9089
if msg.Content == "" {
9190
return mv.spinner.View()
9291
}
9392

9493
text := senderPrefix(msg.Sender) + msg.Content
95-
rendered, err := mv.renderer.Render(text)
94+
rendered, err := markdown.NewRenderer(width).Render(text)
9695
if err != nil {
9796
return text
9897
}
@@ -104,15 +103,15 @@ func (mv *messageModel) Render(int) string {
104103
}
105104
text := "Thinking: " + senderPrefix(msg.Sender) + msg.Content
106105
// Render through the markdown renderer to ensure proper wrapping to width
107-
rendered, err := mv.renderer.Render(text)
106+
rendered, err := markdown.NewRenderer(width).Render(text)
108107
if err != nil {
109108
return styles.MutedStyle.Italic(true).Render(text)
110109
}
111110
// Strip ANSI from inner rendering so muted style fully applies
112111
clean := stripANSI(strings.TrimRight(rendered, "\n\r\t "))
113112
return styles.MutedStyle.Italic(true).Render(clean)
114113
case types.MessageTypeShellOutput:
115-
if rendered, err := mv.renderer.Render(fmt.Sprintf("```console\n%s\n```", msg.Content)); err == nil {
114+
if rendered, err := markdown.NewRenderer(width).Render(fmt.Sprintf("```console\n%s\n```", msg.Content)); err == nil {
116115
return strings.TrimRight(rendered, "\n\r\t ")
117116
}
118117
return msg.Content

pkg/tui/components/messages/messages.go

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@ import (
77
"github.com/charmbracelet/bubbles/v2/help"
88
"github.com/charmbracelet/bubbles/v2/key"
99
tea "github.com/charmbracelet/bubbletea/v2"
10-
"github.com/charmbracelet/glamour/v2"
11-
"github.com/charmbracelet/glamour/v2/styles"
1210
"github.com/charmbracelet/lipgloss/v2"
1311

1412
"github.com/docker/cagent/pkg/app"
1513
"github.com/docker/cagent/pkg/runtime"
1614
"github.com/docker/cagent/pkg/tools"
15+
"github.com/docker/cagent/pkg/tui/components/markdown"
1716
"github.com/docker/cagent/pkg/tui/components/message"
1817
"github.com/docker/cagent/pkg/tui/components/tool"
1918
"github.com/docker/cagent/pkg/tui/core"
@@ -53,7 +52,6 @@ type renderedItem struct {
5352

5453
// model implements Model
5554
type model struct {
56-
renderer *glamour.TermRenderer
5755
messages []types.Message
5856
views []layout.Model
5957
width int
@@ -207,18 +205,6 @@ func (m *model) SetSize(width, height int) tea.Cmd {
207205
width = 10
208206
}
209207

210-
// Build a custom style
211-
customDarkStyle := *styles.DefaultStyles["dark"]
212-
customDarkStyle.Document.Margin = uintPtr(0)
213-
214-
// Initialize or update renderer
215-
if r, err := glamour.NewTermRenderer(
216-
glamour.WithWordWrap(min(width, 120)),
217-
glamour.WithStyles(customDarkStyle),
218-
); err == nil {
219-
m.renderer = r
220-
}
221-
222208
// Update all views with new size
223209
for _, view := range m.views {
224210
view.SetSize(width, 0)
@@ -626,13 +612,13 @@ func (m *model) PlainTextTranscript() string {
626612
}
627613

628614
func (m *model) createToolCallView(msg *types.Message) layout.Model {
629-
view := tool.New(msg, m.app, m.renderer)
615+
view := tool.New(msg, m.app, markdown.NewRenderer(m.width))
630616
view.SetSize(m.width, 0)
631617
return view
632618
}
633619

634620
func (m *model) createMessageView(msg *types.Message) layout.Model {
635-
view := message.New(msg, m.renderer)
621+
view := message.New(msg)
636622
view.SetSize(m.width, 0)
637623
return view
638624
}
@@ -703,5 +689,3 @@ func toolResultLabel(msg types.Message) string {
703689
}
704690
return fmt.Sprintf("Tool Result (%s)", name)
705691
}
706-
707-
func uintPtr(u uint) *uint { return &u }

0 commit comments

Comments
 (0)