Forge
csharpdeeb25a2
1using CascadeIDE.Contracts;
2
3namespace CascadeIDE.Cockpit.ComputingUnits.IdeHealth;
4
5/// <summary>
6/// CCU «текст из скаляров» (реализует <see cref="ICockpitComputeUnit"/>, ADR 0097): чистое форматирование IDE Health без VM/DAP.
7/// Собирает <see cref="IdeHealthSegmentInput"/>; живые зависимости — в <see cref="IdeHealthSnapshotUnit"/>.
8/// </summary>
9[ComputingUnit]
10public sealed class IdeHealthFormattingUnit : ICockpitComputeUnit
11{
12 /// <summary>Единственный экземпляр свёртки (без состояния).</summary>
13 public static IdeHealthFormattingUnit Default { get; } = new();
14
15 private IdeHealthFormattingUnit()
16 {
17 }
18
19 public IdeHealthSegmentInput BuildSegment(bool isBuilding) =>
20 BuildSegment(new BuildStateSnapshot(isBuilding));
21
22 public IdeHealthSegmentInput BuildSegment(BuildStateSnapshot s)
23 {
24 if (s.IsBuilding)
25 {
26 return new IdeHealthSegmentInput(
27 "Build: running…",
28 "BUILD…",
29 IsBuildRunning: true,
30 Stratum: IdeHealthStratum.Solution,
31 Scope: IdeHealthScope.Solution);
32 }
33
34 var line = s.LastBuildSucceeded switch
35 {
36 true when s.LastExitCode is int ok => $"Build: idle · last OK (exit {ok})",
37 true => "Build: idle · last OK",
38 false when s.LastExitCode is int fail => $"Build: idle · last failed (exit {fail})",
39 false => "Build: idle · last failed",
40 _ => "Build: idle"
41 };
42 return new IdeHealthSegmentInput(
43 line,
44 "READY",
45 IsBuildRunning: false,
46 Stratum: IdeHealthStratum.Solution,
47 Scope: IdeHealthScope.Solution);
48 }
49
50 public IdeHealthSegmentInput TestsSegment(string? lastTestSummary, int impactedTestsBadge)
51 {
52 var line = !string.IsNullOrWhiteSpace(lastTestSummary)
53 ? $"Tests: {lastTestSummary}"
54 : $"Tests: impacted {impactedTestsBadge}";
55 var cockpit = !string.IsNullOrWhiteSpace(lastTestSummary)
56 ? (lastTestSummary.Length > 36 ? string.Concat(lastTestSummary.AsSpan(0, 33), "…") : lastTestSummary)
57 : $"imp {impactedTestsBadge}";
58 return new IdeHealthSegmentInput(line, cockpit, Stratum: IdeHealthStratum.Solution, Scope: IdeHealthScope.Solution);
59 }
60
61 public IdeHealthSegmentInput DebugSegment(
62 bool hasActiveSession,
63 bool executionStopped,
64 int stackFrameCount,
65 int variableCount)
66 {
67 if (!hasActiveSession)
68 return new IdeHealthSegmentInput("Debug: idle", "DBG · —", Stratum: IdeHealthStratum.Solution, Scope: IdeHealthScope.Solution);
69
70 if (executionStopped)
71 {
72 var line = $"Debug: paused · frames {stackFrameCount}, vars {variableCount}";
73 var shortLine = $"DBG · pause · {stackFrameCount}fr";
74 return new IdeHealthSegmentInput(line, shortLine, Stratum: IdeHealthStratum.Solution, Scope: IdeHealthScope.Solution);
75 }
76
77 return new IdeHealthSegmentInput("Debug: running…", "DBG · run", Stratum: IdeHealthStratum.Solution, Scope: IdeHealthScope.Solution);
78 }
79
80 public IdeHealthSegmentInput GitSegment(string gitLine, string gitCockpitShort) =>
81 new(gitLine, gitCockpitShort, Stratum: IdeHealthStratum.Workspace);
82
83 public IdeHealthSegmentInput ProjectBuildSegment(string projectPath, bool isBuilding) =>
84 ProjectBuildSegment(projectPath, new BuildStateSnapshot(isBuilding));
85
86 public IdeHealthSegmentInput ProjectBuildSegment(string projectPath, BuildStateSnapshot s)
87 {
88 if (s.IsBuilding)
89 {
90 return new IdeHealthSegmentInput(
91 $"Build[{projectPath}]: running…",
92 "BUILD…",
93 IsBuildRunning: true,
94 Stratum: IdeHealthStratum.Solution,
95 Scope: IdeHealthScope.Project,
96 ProjectPath: projectPath);
97 }
98
99 var tail = s.LastBuildSucceeded switch
100 {
101 true when s.LastExitCode is int ok => $"idle · last OK (exit {ok})",
102 true => "idle · last OK",
103 false when s.LastExitCode is int fail => $"idle · last failed (exit {fail})",
104 false => "idle · last failed",
105 _ => "idle"
106 };
107 return new IdeHealthSegmentInput(
108 $"Build[{projectPath}]: {tail}",
109 "READY",
110 IsBuildRunning: false,
111 Stratum: IdeHealthStratum.Solution,
112 Scope: IdeHealthScope.Project,
113 ProjectPath: projectPath);
114 }
115
116 public IdeHealthSegmentInput ProjectTestsSegment(string projectPath, string? summary, int impactedTestsBadge)
117 {
118 var normalizedSummary = string.IsNullOrWhiteSpace(summary)
119 ? $"impacted {impactedTestsBadge}"
120 : summary;
121 return new IdeHealthSegmentInput(
122 $"Tests[{projectPath}]: {normalizedSummary}",
123 normalizedSummary.Length > 36 ? string.Concat(normalizedSummary.AsSpan(0, 33), "…") : normalizedSummary,
124 Stratum: IdeHealthStratum.Solution,
125 Scope: IdeHealthScope.Project,
126 ProjectPath: projectPath);
127 }
128
129 public IdeHealthSegmentInput ProjectDebugSegment(string projectPath, string summary) =>
130 new(
131 $"Debug[{projectPath}]: {summary}",
132 summary.Length > 36 ? string.Concat(summary.AsSpan(0, 33), "…") : summary,
133 Stratum: IdeHealthStratum.Solution,
134 Scope: IdeHealthScope.Project,
135 ProjectPath: projectPath);
136
137 /// <summary>Собирает снимок из уже вычисленных скаляров (удобно для тестов и провайдера).</summary>
138 public IdeHealthInputSnapshot Compose(
139 BuildStateSnapshot buildState,
140 string? lastTestSummary,
141 int impactedTestsBadge,
142 bool hasDebugSession,
143 bool debugExecutionStopped,
144 int debugStackFrameCount,
145 int debugVariableCount,
146 string gitLine,
147 string gitCockpitShort) =>
148 IdeHealthStrataComposer.Compose(
149 new IdeHealthWorkspaceInput(GitSegment(gitLine, gitCockpitShort)),
150 new IdeHealthSolutionInput(
151 BuildSegment(buildState),
152 TestsSegment(lastTestSummary, impactedTestsBadge),
153 DebugSegment(hasDebugSession, debugExecutionStopped, debugStackFrameCount, debugVariableCount)));
154}
155
View only · write via MCP/CIDE