| 1 | using System.Text.Json; |
| 2 | using Microsoft.CodeAnalysis; |
| 3 | |
| 4 | namespace CascadeIDE.Services; |
| 5 | |
| 6 | /// <summary>Минимизация контекста для чата: только диагностики и сигнатуры (встроенный Roslyn).</summary> |
| 7 | public sealed class ContextMinimizer |
| 8 | { |
| 9 | private readonly CSharpLanguageService _languageService; |
| 10 | |
| 11 | public ContextMinimizer(CSharpLanguageService languageService) |
| 12 | { |
| 13 | _languageService = languageService; |
| 14 | } |
| 15 | |
| 16 | /// <summary>Возвращает компактный текст: блок Diagnostics (file:line:severity: id: message) и блок Signatures.</summary> |
| 17 | /// <param name="filePath">Путь к файлу (для .cs используется анализ).</param> |
| 18 | /// <param name="sourceText">Исходный код файла.</param> |
| 19 | /// <param name="ct">Отмена.</param> |
| 20 | /// <returns>Строка для подмешивания в системное/первое сообщение; пустая, если не C# или при ошибке.</returns> |
| 21 | public string Minimize(string filePath, string sourceText, CancellationToken ct = default) |
| 22 | { |
| 23 | if (string.IsNullOrEmpty(filePath) || !filePath.EndsWith(".cs", StringComparison.OrdinalIgnoreCase)) |
| 24 | return string.Empty; |
| 25 | |
| 26 | var diagnostics = _languageService.GetDiagnosticsForFile(filePath, sourceText, ct); |
| 27 | var signatures = _languageService.GetSignatureStringsForFile(filePath, sourceText, ct); |
| 28 | if (diagnostics.Count == 0 && signatures.Count == 0) |
| 29 | return string.Empty; |
| 30 | |
| 31 | var sb = new System.Text.StringBuilder(); |
| 32 | if (diagnostics.Count > 0) |
| 33 | { |
| 34 | sb.Append("## Diagnostics\n"); |
| 35 | var fileName = System.IO.Path.GetFileName(filePath); |
| 36 | foreach (var d in diagnostics) |
| 37 | { |
| 38 | var (line, col) = RoslynLinePositionMapper.ToEditorLineColumn(d.Location.GetLineSpan().StartLinePosition); |
| 39 | sb.Append(fileName).Append('(').Append(line.Value).Append(',').Append(col.Value).Append("): ") |
| 40 | .Append(d.Severity == DiagnosticSeverity.Error ? "error" : "warning") |
| 41 | .Append(' ').Append(d.Id).Append(": ").Append(d.GetMessage()).Append('\n'); |
| 42 | } |
| 43 | } |
| 44 | if (signatures.Count > 0) |
| 45 | { |
| 46 | sb.Append("## Signatures\n"); |
| 47 | foreach (var sig in signatures) |
| 48 | sb.Append(sig).Append('\n'); |
| 49 | } |
| 50 | return sb.ToString(); |
| 51 | } |
| 52 | |
| 53 | /// <summary>Диагностики по файлу в виде JSON для MCP (ide_get_current_file_diagnostics): массив { id, message, severity, line, column } (line/column 1-based). Только .cs.</summary> |
| 54 | public string GetDiagnosticsJson(string filePath, string sourceText, CancellationToken ct = default) |
| 55 | { |
| 56 | if (string.IsNullOrEmpty(filePath) || !filePath.EndsWith(".cs", StringComparison.OrdinalIgnoreCase)) |
| 57 | return "[]"; |
| 58 | var diagnostics = _languageService.GetDiagnosticsForFile(filePath, sourceText, ct); |
| 59 | var list = diagnostics.Select(d => |
| 60 | { |
| 61 | var (line, col) = RoslynLinePositionMapper.ToEditorLineColumn(d.Location.GetLineSpan().StartLinePosition); |
| 62 | return new { id = d.Id, message = d.GetMessage(), severity = d.Severity == DiagnosticSeverity.Error ? "error" : "warning", line = line.Value, column = col.Value }; |
| 63 | }).ToList(); |
| 64 | return JsonSerializer.Serialize(list); |
| 65 | } |
| 66 | } |
| 67 | |