Forge
csharpdeeb25a2
1#nullable enable
2using System.Collections.ObjectModel;
3using CascadeIDE.Contracts;
4using CascadeIDE.Models;
5
6namespace CascadeIDE.Features.Launch.Application;
7
8/// <summary>
9/// Pre-resolve launch profile + MSBuild для F5 из главного окна (профиль / стартовый <c>.csproj</c>).
10/// </summary>
11[ApplicationOrchestrator("debug-launch-f5-ui")]
12public static class DebugLaunchForF5Orchestrator
13{
14 /// <summary>
15 /// Перед DAP: эвристика стартового проекта, затем пайплайн <see cref="LaunchPreResolvePipelineUnit"/> и <see cref="MsBuildDebugTargetResolver"/>.
16 /// </summary>
17 public static async Task<DebugLaunchResolution?> TryResolveAsync(
18 ObservableCollection<SolutionItem> solutionRoots,
19 string? currentFilePath,
20 string? selectedSolutionItemFullPath,
21 Func<string?> getStartupCsprojFullPath,
22 Action<string> applyStartupProject,
23 string? solutionPath,
24 string? solutionDirectory,
25 IDotnetCommandRunner dotnetRunner,
26 Func<string, string, Task> showDebugInfoAsync,
27 CancellationToken cancellationToken = default)
28 {
29 ApplyInferredStartupIfNeeded(
30 solutionRoots,
31 currentFilePath,
32 selectedSolutionItemFullPath,
33 getStartupCsprojFullPath,
34 applyStartupProject);
35
36 var hasSolution = !string.IsNullOrEmpty(solutionPath);
37 var hasWorkspaceRoot = !string.IsNullOrEmpty(solutionDirectory);
38
39 var startupCsprojFull = LaunchProjectPathResolver.NormalizeExistingProjectFileFullPath(getStartupCsprojFullPath());
40 var preResolve = hasSolution && hasWorkspaceRoot
41 ? LaunchPreResolvePipelineUnit.Default.Compose(
42 solutionPath!,
43 explicitProfileName: null,
44 solutionDirectory: solutionDirectory!,
45 startupProjectFullPath: startupCsprojFull)
46 : new LaunchPreResolvePipelineSnapshot(
47 Profile: null,
48 ProfileProjectCsprojFullPath: null,
49 Readiness: LaunchReadinessUnit.Default.Compose(
50 hasSolutionPath: hasSolution,
51 hasWorkspaceRoot: hasWorkspaceRoot,
52 profileId: null,
53 profileProjectRelative: null,
54 profileProjectFullPath: null,
55 startupProjectFullPath: startupCsprojFull),
56 McpResolveError: null);
57
58 var resolvedProfile = preResolve.Profile;
59 var readiness = preResolve.Readiness;
60 if (!readiness.CanAttemptResolve)
61 return null;
62
63 if (readiness.Source == LaunchReadinessSource.Profile && resolvedProfile is { } launchProfile &&
64 !string.IsNullOrEmpty(readiness.SelectedProjectFullPath))
65 {
66 var (target, err) = await MsBuildDebugTargetResolver
67 .TryResolveAsync(readiness.SelectedProjectFullPath, dotnetRunner, launchProfile.Configuration, cancellationToken)
68 .ConfigureAwait(false);
69 if (!string.IsNullOrEmpty(target))
70 return DebugLaunchFromProfile.ToResolution(launchProfile, target);
71
72 if (!string.IsNullOrEmpty(err))
73 await showDebugInfoAsync("Стартовый проект", err).ConfigureAwait(false);
74 return null;
75 }
76
77 if (!string.IsNullOrEmpty(readiness.SelectedProjectFullPath))
78 {
79 var (target, err) = await MsBuildDebugTargetResolver
80 .TryResolveAsync(
81 readiness.SelectedProjectFullPath,
82 dotnetRunner,
83 LaunchProfilesStore.DefaultConfiguration,
84 cancellationToken)
85 .ConfigureAwait(false);
86 if (!string.IsNullOrEmpty(target))
87 return new DebugLaunchResolution(target, null, null, null, OpenLaunchBrowser: false, LaunchUrl: null);
88
89 if (!string.IsNullOrEmpty(err))
90 await showDebugInfoAsync("Стартовый проект", err).ConfigureAwait(false);
91 }
92
93 return null;
94 }
95
96 internal static void ApplyInferredStartupIfNeeded(
97 ObservableCollection<SolutionItem> solutionRoots,
98 string? currentFilePath,
99 string? selectedSolutionItemFullPath,
100 Func<string?> getStartupCsprojFullPath,
101 Action<string> applyStartupProject)
102 {
103 if (StartupProjectDebugInferenceProjection.HasPersistedStartupPointingToExistingFile(getStartupCsprojFullPath()))
104 return;
105
106 var inferred = StartupProjectDebugInferenceProjection.TryInferCanonicalCsproj(
107 solutionRoots,
108 currentFilePath,
109 selectedSolutionItemFullPath);
110 if (!string.IsNullOrEmpty(inferred))
111 applyStartupProject(inferred);
112 }
113}
114
View only · write via MCP/CIDE