Forge
csharpdeeb25a2
1using CascadeIDE.Features.Editor.Application.Monaco;
2
3namespace CascadeIDE.Features.Editor.Application;
4
5/// <summary>Breakpoint / debug-line / agent-reveal decorations for Monaco host.</summary>
6public static class MonacoEditorDebugMapper
7{
8 public static IReadOnlyList<CideEditorDecoration> ToBreakpointDecorations(
9 string text,
10 IReadOnlyList<int> breakpointLines)
11 {
12 if (breakpointLines.Count == 0)
13 return Array.Empty<CideEditorDecoration>();
14
15 var list = new List<CideEditorDecoration>(breakpointLines.Count);
16 foreach (var line in breakpointLines)
17 {
18 if (line < 1)
19 continue;
20 var (offset, length) = WholeLineSpan(text, line);
21 if (length <= 0)
22 continue;
23 list.Add(new CideEditorDecoration(
24 offset,
25 length,
26 "cide-breakpoint-line",
27 "Breakpoint",
28 IsWholeLine: true,
29 GlyphMarginClassName: "cide-breakpoint-glyph"));
30 }
31
32 return list;
33 }
34
35 public static IReadOnlyList<CideEditorDecoration> ToDebugLineDecoration(string text, int debugLine)
36 {
37 if (debugLine < 1)
38 return Array.Empty<CideEditorDecoration>();
39
40 var (offset, length) = WholeLineSpan(text, debugLine);
41 if (length <= 0)
42 return Array.Empty<CideEditorDecoration>();
43
44 return
45 [
46 new CideEditorDecoration(
47 offset,
48 length,
49 "cide-debug-line",
50 "Current debug line",
51 IsWholeLine: true,
52 GlyphMarginClassName: "cide-debug-arrow"),
53 ];
54 }
55
56 public static IReadOnlyList<CideEditorDecoration> ToAgentRevealDecorations(
57 string text,
58 int startLine,
59 int endLine)
60 {
61 if (startLine < 1 || endLine < startLine)
62 return Array.Empty<CideEditorDecoration>();
63
64 var list = new List<CideEditorDecoration>(endLine - startLine + 1);
65 for (var line = startLine; line <= endLine; line++)
66 {
67 var (offset, length) = WholeLineSpan(text, line);
68 if (length <= 0)
69 continue;
70 list.Add(new CideEditorDecoration(
71 offset,
72 length,
73 AgentRevealClassForLine(line, startLine, endLine),
74 null,
75 IsWholeLine: true));
76 }
77
78 return list;
79 }
80
81 private static string AgentRevealClassForLine(int line, int startLine, int endLine)
82 {
83 const string baseClass = "cide-agent-reveal-line";
84 if (startLine == endLine)
85 return $"{baseClass} cide-agent-reveal-single";
86 if (line == startLine)
87 return $"{baseClass} cide-agent-reveal-top";
88 if (line == endLine)
89 return $"{baseClass} cide-agent-reveal-bottom";
90 return $"{baseClass} cide-agent-reveal-middle";
91 }
92
93 private static (int Offset, int Length) WholeLineSpan(string text, int lineOneBased)
94 {
95 if (string.IsNullOrEmpty(text) || lineOneBased < 1)
96 return (0, 0);
97
98 var lineStart = 0;
99 var line = 1;
100 for (var i = 0; i < text.Length && line < lineOneBased; i++)
101 {
102 if (text[i] == '\n')
103 {
104 line++;
105 lineStart = i + 1;
106 }
107 }
108
109 if (line != lineOneBased)
110 return (0, 0);
111
112 var lineEnd = text.IndexOf('\n', lineStart);
113 if (lineEnd < 0)
114 lineEnd = text.Length;
115 else
116 lineEnd++;
117
118 return (lineStart, Math.Max(1, lineEnd - lineStart));
119 }
120}
121
View only · write via MCP/CIDE