diff options
| author | adamdottv <[email protected]> | 2025-06-26 12:47:17 -0500 |
|---|---|---|
| committer | adamdottv <[email protected]> | 2025-06-26 12:47:17 -0500 |
| commit | 5358d43b74a908de866dd0123caf80b9a7d09fee (patch) | |
| tree | 62f1ef2a84cd5bb9a5fe139a518cbc82b6fb81d2 | |
| parent | f777347bac6e610b8b5cf2428131fb40aee254df (diff) | |
| download | opencode-5358d43b74a908de866dd0123caf80b9a7d09fee.tar.gz opencode-5358d43b74a908de866dd0123caf80b9a7d09fee.zip | |
feat(tui): show lsp diagnostics for edit and write tools
| -rw-r--r-- | packages/tui/internal/components/chat/message.go | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/packages/tui/internal/components/chat/message.go b/packages/tui/internal/components/chat/message.go index 4f0293de5..f547907ee 100644 --- a/packages/tui/internal/components/chat/message.go +++ b/packages/tui/internal/components/chat/message.go @@ -397,6 +397,11 @@ func renderToolInvocation( body, styles.WhitespaceStyle(t.Background()), ) + + // Add diagnostics at the bottom if they exist + if diagnostics := renderDiagnostics(metadata, filename); diagnostics != "" { + body += "\n" + renderContentBlock(diagnostics, WithFullWidth(), WithBorderColor(t.Error())) + } } } case "write": @@ -404,6 +409,11 @@ func renderToolInvocation( title = fmt.Sprintf("WRITE %s", relative(filename)) if content, ok := toolArgsMap["content"].(string); ok { body = renderFile(filename, content) + + // Add diagnostics at the bottom if they exist + if diagnostics := renderDiagnostics(metadata, filename); diagnostics != "" { + body += "\n" + renderContentBlock(diagnostics, WithFullWidth(), WithBorderColor(t.Error())) + } } } case "bash": @@ -685,3 +695,81 @@ func extension(path string) string { } return ext } + +// Diagnostic represents an LSP diagnostic +type Diagnostic struct { + Range struct { + Start struct { + Line int `json:"line"` + Character int `json:"character"` + } `json:"start"` + } `json:"range"` + Severity int `json:"severity"` + Message string `json:"message"` +} + +// renderDiagnostics formats LSP diagnostics for display in the TUI +func renderDiagnostics(metadata client.MessageMetadata_Tool_AdditionalProperties, filePath string) string { + diagnosticsData, ok := metadata.Get("diagnostics") + if !ok { + return "" + } + + // diagnosticsData should be a map[string][]Diagnostic + diagnosticsMap, ok := diagnosticsData.(map[string]interface{}) + if !ok { + return "" + } + + fileDiagnostics, ok := diagnosticsMap[filePath] + if !ok { + return "" + } + + diagnosticsList, ok := fileDiagnostics.([]interface{}) + if !ok { + return "" + } + + var errorDiagnostics []string + for _, diagInterface := range diagnosticsList { + diagMap, ok := diagInterface.(map[string]interface{}) + if !ok { + continue + } + + // Parse the diagnostic + var diag Diagnostic + diagBytes, err := json.Marshal(diagMap) + if err != nil { + continue + } + if err := json.Unmarshal(diagBytes, &diag); err != nil { + continue + } + + // Only show error diagnostics (severity === 1) + if diag.Severity != 1 { + continue + } + + line := diag.Range.Start.Line + 1 // 1-based + column := diag.Range.Start.Character + 1 // 1-based + errorDiagnostics = append(errorDiagnostics, fmt.Sprintf("Error [%d:%d] %s", line, column, diag.Message)) + } + + if len(errorDiagnostics) == 0 { + return "" + } + + t := theme.CurrentTheme() + var result strings.Builder + for _, diagnostic := range errorDiagnostics { + if result.Len() > 0 { + result.WriteString("\n") + } + result.WriteString(styles.NewStyle().Foreground(t.Error()).Render(diagnostic)) + } + + return result.String() +} |
