Forge
csharpdeeb25a2
1#nullable enable
2using CascadeIDE.Contracts;
3namespace CascadeIDE.Features.Workspace.DataAcquisition;
4
5/// <summary>Поиск файла решения (.slnx / .sln / .slnf) относительно пути к исходнику.</summary>
6[IoBoundary]
7public static class SolutionFileLocator
8{
9 /// <summary>
10 /// Поднимается от каталога с <paramref name="sourceFilePath"/> к родителям и возвращает первый найденный
11 /// файл решения в этой директории (приоритет: .slnx, затем .sln, затем .slnf; при нескольких — лексикографически первый).
12 /// </summary>
13 public static string? TryFindSolutionForSourceFile(string sourceFilePath)
14 {
15 if (string.IsNullOrWhiteSpace(sourceFilePath))
16 return null;
17 if (!File.Exists(sourceFilePath))
18 return null;
19
20 var dir = Path.GetDirectoryName(CanonicalFilePath.Normalize(sourceFilePath));
21 while (!string.IsNullOrEmpty(dir))
22 {
23 var found = TryFindSolutionInDirectory(dir);
24 if (found is not null)
25 return found;
26 dir = Directory.GetParent(dir)?.FullName;
27 }
28
29 return null;
30 }
31
32 /// <summary>Ищет один файл решения в каталоге (без подъёма вверх по дереву).</summary>
33 public static string? TryFindSolutionInDirectory(string directory)
34 {
35 if (!Directory.Exists(directory))
36 return null;
37
38 static string? PickFirst(IEnumerable<string> files)
39 {
40 var arr = files as string[] ?? files.ToArray();
41 return arr.Length == 0 ? null : arr.OrderBy(static f => f, StringComparer.OrdinalIgnoreCase).First();
42 }
43
44 var slnx = Directory.GetFiles(directory, "*.slnx", SearchOption.TopDirectoryOnly);
45 var sln = Directory.GetFiles(directory, "*.sln", SearchOption.TopDirectoryOnly);
46 var slnf = Directory.GetFiles(directory, "*.slnf", SearchOption.TopDirectoryOnly);
47 return PickFirst(slnx) ?? PickFirst(sln) ?? PickFirst(slnf);
48 }
49
50 /// <summary>Нужно ли загрузить найденное решение вместо текущего контекста IDE (разные пути после нормализации).</summary>
51 public static bool NeedsLoadSolutionBeforeBreakpoint(string? foundSolutionPath, string? currentWorkspaceSolutionPath)
52 {
53 if (string.IsNullOrWhiteSpace(foundSolutionPath) || !File.Exists(foundSolutionPath))
54 return false;
55 var candidate = CanonicalFilePath.Normalize(foundSolutionPath);
56 if (string.IsNullOrWhiteSpace(currentWorkspaceSolutionPath))
57 return true;
58 var current = CanonicalFilePath.Normalize(currentWorkspaceSolutionPath.Trim());
59 return !PathsReferToSameFile(candidate, current);
60 }
61
62 private static bool PathsReferToSameFile(string a, string b)
63 {
64 if (CanonicalFilePath.TryNormalize(a, out var na) && CanonicalFilePath.TryNormalize(b, out var nb))
65 return string.Equals(na, nb, StringComparison.OrdinalIgnoreCase);
66 return string.Equals(a, b, StringComparison.OrdinalIgnoreCase);
67 }
68}
69
View only · write via MCP/CIDE