Forge
csharpdeeb25a2
1#nullable enable
2
3using CascadeIDE.Cockpit.DataBus;
4using CascadeIDE.Models;
5
6namespace CascadeIDE.Features.SolutionWarmup.Application;
7
8/// <summary>Агрегированная строка статуса фона для полосы на PFD (ADR 0141).</summary>
9public static class PfdBackgroundStatusPresentation
10{
11 public sealed record Snapshot(
12 bool Show,
13 bool IsCaution,
14 string? Text);
15
16 public static Snapshot Compute(
17 string? workspaceRoot,
18 string? solutionPath,
19 SolutionWarmupStateChanged? warmup,
20 HybridIndexStateChanged? hci,
21 bool hciReindexPending,
22 HybridIndexSettings hybridIndex)
23 {
24 var warmupForScope = MatchesScope(warmup?.WorkspaceRoot, warmup?.SolutionPath, workspaceRoot, solutionPath)
25 ? warmup
26 : null;
27 var hciForScope = MatchesScope(hci?.WorkspaceRoot, hci?.SolutionPath, workspaceRoot, solutionPath)
28 ? hci
29 : null;
30
31 var warmupRunning = warmupForScope?.Lifecycle == SolutionWarmupLifecycle.Running;
32 // Cancelled (scope_changed) — штатная отмена при смене solution, не показываем как ошибку.
33 var warmupCaution = warmupForScope?.Lifecycle == SolutionWarmupLifecycle.Partial;
34 var hciError = !string.IsNullOrWhiteSpace(hciForScope?.LastError);
35 var hciPending = hybridIndex.Enabled
36 && hybridIndex.AutoReindexOnSolutionOpen
37 && !string.IsNullOrWhiteSpace(workspaceRoot)
38 && (hciReindexPending || hciForScope is null);
39
40 if (hciError)
41 {
42 return new Snapshot(
43 true,
44 true,
45 "Index error — open HCI for details");
46 }
47
48 if (warmupCaution)
49 {
50 var detail = string.IsNullOrWhiteSpace(warmupForScope?.Detail)
51 ? "Warm-up incomplete"
52 : $"Warm-up: {warmupForScope!.Detail}";
53 return new Snapshot(true, true, detail);
54 }
55
56 if (warmupRunning && hciPending)
57 return new Snapshot(true, false, "Preparing workspace…");
58
59 if (warmupRunning)
60 return new Snapshot(true, false, "Warming workspace…");
61
62 if (hciPending)
63 return new Snapshot(true, false, "Indexing workspace…");
64
65 return new Snapshot(false, false, null);
66 }
67
68 internal static bool MatchesScope(
69 string? eventWorkspaceRoot,
70 string? eventSolutionPath,
71 string? workspaceRoot,
72 string? solutionPath)
73 {
74 if (string.IsNullOrWhiteSpace(workspaceRoot))
75 return false;
76
77 if (!pathEquals(eventWorkspaceRoot, workspaceRoot))
78 return false;
79
80 if (string.IsNullOrWhiteSpace(solutionPath))
81 return string.IsNullOrWhiteSpace(eventSolutionPath);
82
83 return pathEquals(eventSolutionPath, solutionPath);
84 }
85
86 private static bool pathEquals(string? a, string? b)
87 {
88 if (string.IsNullOrWhiteSpace(a) && string.IsNullOrWhiteSpace(b))
89 return true;
90 if (string.IsNullOrWhiteSpace(a) || string.IsNullOrWhiteSpace(b))
91 return false;
92
93 try
94 {
95 return string.Equals(
96 Path.GetFullPath(a.Trim()),
97 Path.GetFullPath(b.Trim()),
98 StringComparison.OrdinalIgnoreCase);
99 }
100 catch
101 {
102 return string.Equals(a.Trim(), b.Trim(), StringComparison.OrdinalIgnoreCase);
103 }
104 }
105}
106
View only · write via MCP/CIDE