| 1 | using System.Text.Json; |
| 2 | using CascadeIDE.Services; |
| 3 | using DotnetDebug.Core; |
| 4 | |
| 5 | namespace CascadeIDE.Features.IdeMcp.Execution; |
| 6 | |
| 7 | /// <summary>MCP DAP: шагание, стоп, стек, снимок, переменные кадра.</summary> |
| 8 | internal sealed partial class IdeMcpCommandExecutor |
| 9 | { |
| 10 | private void RegisterDapDebugStepping(Action<string, Handler> add) |
| 11 | { |
| 12 | add(Services.IdeCommands.DebugContinue, async (_, ct) => |
| 13 | { |
| 14 | try { return await _vm.DapDebug.ContinueAsync(ct).ConfigureAwait(false); } |
| 15 | catch (Exception ex) { return "# " + ex.Message; } |
| 16 | }); |
| 17 | |
| 18 | add(Services.IdeCommands.DebugStepOver, async (_, ct) => |
| 19 | { |
| 20 | try { return await _vm.DapDebug.StepOverAsync(ct).ConfigureAwait(false); } |
| 21 | catch (Exception ex) { return "# " + ex.Message; } |
| 22 | }); |
| 23 | |
| 24 | add(Services.IdeCommands.DebugStepInto, async (_, ct) => |
| 25 | { |
| 26 | try { return await _vm.DapDebug.StepIntoAsync(ct).ConfigureAwait(false); } |
| 27 | catch (Exception ex) { return "# " + ex.Message; } |
| 28 | }); |
| 29 | |
| 30 | add(Services.IdeCommands.DebugStepOut, async (_, ct) => |
| 31 | { |
| 32 | try { return await _vm.DapDebug.StepOutAsync(ct).ConfigureAwait(false); } |
| 33 | catch (Exception ex) { return "# " + ex.Message; } |
| 34 | }); |
| 35 | |
| 36 | add(Services.IdeCommands.DebugStop, async (_, ct) => |
| 37 | { |
| 38 | try { return await _vm.DapDebug.StopAsync(ct).ConfigureAwait(false); } |
| 39 | catch (Exception ex) { return "# " + ex.Message; } |
| 40 | }); |
| 41 | |
| 42 | add(Services.IdeCommands.DebugStopContext, async (args, ct) => |
| 43 | { |
| 44 | try |
| 45 | { |
| 46 | var opts = ParseDapFrameInspectionOptions(args); |
| 47 | return await _vm.DapDebug.StopContextAsync(opts, ct).ConfigureAwait(false); |
| 48 | } |
| 49 | catch (Exception ex) { return "# " + ex.Message; } |
| 50 | }); |
| 51 | |
| 52 | add(Services.IdeCommands.DebugStackTrace, async (_, ct) => |
| 53 | { |
| 54 | try { return await _vm.DapDebug.StackTraceFromSnapshotAsync(ct).ConfigureAwait(false); } |
| 55 | catch (Exception ex) { return "# " + ex.Message; } |
| 56 | }); |
| 57 | |
| 58 | add(Services.IdeCommands.GetDebugSnapshot, async (_, ct) => |
| 59 | { |
| 60 | try { return await _actions.GetDebugSnapshotAsync(ct).ConfigureAwait(false); } |
| 61 | catch (Exception ex) { return "# Error: " + ex.Message; } |
| 62 | }); |
| 63 | |
| 64 | add(Services.IdeCommands.DebugVariables, async (args, ct) => |
| 65 | { |
| 66 | var frameIndex = McpCommandJsonArgs.Int(args, "frame_index", 0); |
| 67 | try { return await _vm.DapDebug.VariablesAsync(frameIndex, ct).ConfigureAwait(false); } |
| 68 | catch (Exception ex) { return "# " + ex.Message; } |
| 69 | }); |
| 70 | } |
| 71 | |
| 72 | private static DapFrameInspectionOptions ParseDapFrameInspectionOptions(IReadOnlyDictionary<string, JsonElement>? args) |
| 73 | { |
| 74 | var fast = McpCommandJsonArgs.Bool(args, "fast"); |
| 75 | var format = McpCommandJsonArgs.String(args, "format"); |
| 76 | var formatJson = string.Equals(format, "json", StringComparison.OrdinalIgnoreCase); |
| 77 | return new DapFrameInspectionOptions |
| 78 | { |
| 79 | FrameIndex = McpCommandJsonArgs.Int(args, "frame_index", 0), |
| 80 | Fast = fast, |
| 81 | MaxDepth = McpCommandJsonArgs.OptionalInt32(args, "max_depth"), |
| 82 | MaxChildrenPerNode = McpCommandJsonArgs.OptionalInt32(args, "max_children_per_node"), |
| 83 | TimeBudgetMs = McpCommandJsonArgs.OptionalInt32(args, "time_budget_ms"), |
| 84 | FormatJson = formatJson, |
| 85 | JsonIndented = McpCommandJsonArgs.OptionalBool(args, "json_indented") ?? true, |
| 86 | }; |
| 87 | } |
| 88 | } |
| 89 | |