@@ -0,0 +1,194 @@
6+ "github.com/charmbracelet/crush/internal/agent/tools"
7+ "github.com/charmbracelet/crush/internal/fsext"
8+ "github.com/charmbracelet/crush/internal/message"
9+ "github.com/charmbracelet/crush/internal/ui/styles"
12+// -----------------------------------------------------------------------------
14+// -----------------------------------------------------------------------------
16+// GlobToolMessageItem is a message item that represents a glob tool call.
17+type GlobToolMessageItem struct {
21+var _ ToolMessageItem = (*GlobToolMessageItem)(nil)
23+// NewGlobToolMessageItem creates a new [GlobToolMessageItem].
24+func NewGlobToolMessageItem(
26+ toolCall message.ToolCall,
27+ result *message.ToolResult,
30+ return newBaseToolMessageItem(sty, toolCall, result, &GlobToolRenderContext{}, canceled)
33+// GlobToolRenderContext renders glob tool messages.
34+type GlobToolRenderContext struct{}
36+// RenderTool implements the [ToolRenderer] interface.
37+func (g *GlobToolRenderContext) RenderTool(sty *styles.Styles, width int, opts *ToolRenderOpts) string {
38+ cappedWidth := cappedMessageWidth(width)
39+ if !opts.ToolCall.Finished && !opts.Canceled {
40+ return pendingTool(sty, "Glob", opts.Anim)
43+ var params tools.GlobParams
44+ if err := json.Unmarshal([]byte(opts.ToolCall.Input), ¶ms); err != nil {
45+ return toolErrorContent(sty, &message.ToolResult{Content: "Invalid parameters"}, cappedWidth)
48+ toolParams := []string{params.Pattern}
49+ if params.Path != "" {
50+ toolParams = append(toolParams, "path", params.Path)
53+ header := toolHeader(sty, opts.Status(), "Glob", cappedWidth, opts.Nested, toolParams...)
58+ if earlyState, ok := toolEarlyStateContent(sty, opts, cappedWidth); ok {
59+ return joinToolParts(header, earlyState)
62+ if opts.Result == nil || opts.Result.Content == "" {
66+ bodyWidth := cappedWidth - toolBodyLeftPaddingTotal
67+ body := sty.Tool.Body.Render(toolOutputPlainContent(sty, opts.Result.Content, bodyWidth, opts.Expanded))
68+ return joinToolParts(header, body)
71+// -----------------------------------------------------------------------------
73+// -----------------------------------------------------------------------------
75+// GrepToolMessageItem is a message item that represents a grep tool call.
76+type GrepToolMessageItem struct {
80+var _ ToolMessageItem = (*GrepToolMessageItem)(nil)
82+// NewGrepToolMessageItem creates a new [GrepToolMessageItem].
83+func NewGrepToolMessageItem(
85+ toolCall message.ToolCall,
86+ result *message.ToolResult,
89+ return newBaseToolMessageItem(sty, toolCall, result, &GrepToolRenderContext{}, canceled)
92+// GrepToolRenderContext renders grep tool messages.
93+type GrepToolRenderContext struct{}
95+// RenderTool implements the [ToolRenderer] interface.
96+func (g *GrepToolRenderContext) RenderTool(sty *styles.Styles, width int, opts *ToolRenderOpts) string {
97+ cappedWidth := cappedMessageWidth(width)
98+ if !opts.ToolCall.Finished && !opts.Canceled {
99+ return pendingTool(sty, "Grep", opts.Anim)
102+ var params tools.GrepParams
103+ if err := json.Unmarshal([]byte(opts.ToolCall.Input), ¶ms); err != nil {
104+ return toolErrorContent(sty, &message.ToolResult{Content: "Invalid parameters"}, cappedWidth)
107+ toolParams := []string{params.Pattern}
108+ if params.Path != "" {
109+ toolParams = append(toolParams, "path", params.Path)
111+ if params.Include != "" {
112+ toolParams = append(toolParams, "include", params.Include)
114+ if params.LiteralText {
115+ toolParams = append(toolParams, "literal", "true")
118+ header := toolHeader(sty, opts.Status(), "Grep", cappedWidth, opts.Nested, toolParams...)
123+ if earlyState, ok := toolEarlyStateContent(sty, opts, cappedWidth); ok {
124+ return joinToolParts(header, earlyState)
127+ if opts.Result == nil || opts.Result.Content == "" {
131+ bodyWidth := cappedWidth - toolBodyLeftPaddingTotal
132+ body := sty.Tool.Body.Render(toolOutputPlainContent(sty, opts.Result.Content, bodyWidth, opts.Expanded))
133+ return joinToolParts(header, body)
136+// -----------------------------------------------------------------------------
138+// -----------------------------------------------------------------------------
140+// LSToolMessageItem is a message item that represents an ls tool call.
141+type LSToolMessageItem struct {
142+ *baseToolMessageItem
145+var _ ToolMessageItem = (*LSToolMessageItem)(nil)
147+// NewLSToolMessageItem creates a new [LSToolMessageItem].
148+func NewLSToolMessageItem(
150+ toolCall message.ToolCall,
151+ result *message.ToolResult,
154+ return newBaseToolMessageItem(sty, toolCall, result, &LSToolRenderContext{}, canceled)
157+// LSToolRenderContext renders ls tool messages.
158+type LSToolRenderContext struct{}
160+// RenderTool implements the [ToolRenderer] interface.
161+func (l *LSToolRenderContext) RenderTool(sty *styles.Styles, width int, opts *ToolRenderOpts) string {
162+ cappedWidth := cappedMessageWidth(width)
163+ if !opts.ToolCall.Finished && !opts.Canceled {
164+ return pendingTool(sty, "List", opts.Anim)
167+ var params tools.LSParams
168+ if err := json.Unmarshal([]byte(opts.ToolCall.Input), ¶ms); err != nil {
169+ return toolErrorContent(sty, &message.ToolResult{Content: "Invalid parameters"}, cappedWidth)
176+ path = fsext.PrettyPath(path)
178+ header := toolHeader(sty, opts.Status(), "List", cappedWidth, opts.Nested, path)
183+ if earlyState, ok := toolEarlyStateContent(sty, opts, cappedWidth); ok {
184+ return joinToolParts(header, earlyState)
187+ if opts.Result == nil || opts.Result.Content == "" {
191+ bodyWidth := cappedWidth - toolBodyLeftPaddingTotal
192+ body := sty.Tool.Body.Render(toolOutputPlainContent(sty, opts.Result.Content, bodyWidth, opts.Expanded))
193+ return joinToolParts(header, body)