1package chat
2
3import (
4 "encoding/json"
5
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"
10)
11
12// -----------------------------------------------------------------------------
13// Diagnostics Tool
14// -----------------------------------------------------------------------------
15
16// DiagnosticsToolMessageItem is a message item that represents a diagnostics tool call.
17type DiagnosticsToolMessageItem struct {
18 *baseToolMessageItem
19}
20
21var _ ToolMessageItem = (*DiagnosticsToolMessageItem)(nil)
22
23// NewDiagnosticsToolMessageItem creates a new [DiagnosticsToolMessageItem].
24func NewDiagnosticsToolMessageItem(
25 sty *styles.Styles,
26 toolCall message.ToolCall,
27 result *message.ToolResult,
28 canceled bool,
29) ToolMessageItem {
30 return newBaseToolMessageItem(sty, toolCall, result, &DiagnosticsToolRenderContext{}, canceled)
31}
32
33// DiagnosticsToolRenderContext renders diagnostics tool messages.
34type DiagnosticsToolRenderContext struct{}
35
36// RenderTool implements the [ToolRenderer] interface.
37func (d *DiagnosticsToolRenderContext) RenderTool(sty *styles.Styles, width int, opts *ToolRenderOpts) string {
38 cappedWidth := cappedMessageWidth(width)
39 if opts.IsPending() {
40 return pendingTool(sty, "Diagnostics", opts.Anim)
41 }
42
43 var params tools.DiagnosticsParams
44 _ = json.Unmarshal([]byte(opts.ToolCall.Input), ¶ms)
45
46 // Show "project" if no file path, otherwise show the file path.
47 mainParam := "project"
48 if params.FilePath != "" {
49 mainParam = fsext.PrettyPath(params.FilePath)
50 }
51
52 header := toolHeader(sty, opts.Status, "Diagnostics", cappedWidth, opts.Compact, mainParam)
53 if opts.Compact {
54 return header
55 }
56
57 if earlyState, ok := toolEarlyStateContent(sty, opts, cappedWidth); ok {
58 return joinToolParts(header, earlyState)
59 }
60
61 if opts.HasEmptyResult() {
62 return header
63 }
64
65 bodyWidth := cappedWidth - toolBodyLeftPaddingTotal
66 body := sty.Tool.Body.Render(toolOutputPlainContent(sty, opts.Result.Content, bodyWidth, opts.ExpandedContent))
67 return joinToolParts(header, body)
68}