Forge
csharpdeeb25a2
1#nullable enable
2
3namespace CascadeIDE.Services;
4
5/// <summary>Имена видов связей в ответе <c>get_code_navigation_context</c> (режим <c>related</c> / основа <c>subgraph</c>).</summary>
6public static class CodeNavigationRelatedKinds
7{
8 public const string PartialPeer = "partial_peer";
9 public const string ProjectPeer = "project_peer";
10 public const string XamlCodeBehindPair = "xaml_codebehind_pair";
11 public const string TestCounterpart = "test_counterpart";
12 public const string SameNamespace = "same_namespace";
13 public const string SameDirectory = "same_directory";
14
15 internal static readonly string[] All =
16 [
17 PartialPeer,
18 ProjectPeer,
19 XamlCodeBehindPair,
20 TestCounterpart,
21 SameNamespace,
22 SameDirectory
23 ];
24
25 /// <summary>Каноническое имя вида или <c>null</c>, если токен не известен.</summary>
26 public static string? TryCanonicalKind(string? token)
27 {
28 if (string.IsNullOrWhiteSpace(token))
29 return null;
30 var s = token.Trim();
31 foreach (var k in All)
32 {
33 if (string.Equals(k, s, StringComparison.OrdinalIgnoreCase))
34 return k;
35 }
36
37 return null;
38 }
39}
40
41/// <summary>
42/// Фильтр по видам связей: <c>include_kinds</c> — белый список (если задан и непустой);
43/// <c>exclude_kinds</c> — вычитание. Неизвестные токены в списках игнорируются; если в <c>include</c> не осталось ни одного известного вида — считается «без ограничения по include».
44/// </summary>
45public readonly struct CodeNavigationKindFilter
46{
47 private readonly HashSet<string>? _include;
48 private readonly HashSet<string> _exclude;
49
50 private CodeNavigationKindFilter(HashSet<string>? include, HashSet<string> exclude)
51 {
52 _include = include;
53 _exclude = exclude;
54 }
55
56 /// <summary><c>null</c> — без белого списка (все виды, кроме исключённых).</summary>
57 public IReadOnlyList<string>? EffectiveIncludeKinds =>
58 _include is null ? null : _include.OrderBy(x => x, StringComparer.Ordinal).ToList();
59
60 /// <summary>Канонические исключённые виды (может быть пустым).</summary>
61 public IReadOnlyList<string> EffectiveExcludeKinds =>
62 _exclude.Count == 0 ? Array.Empty<string>() : _exclude.OrderBy(x => x, StringComparer.Ordinal).ToList();
63
64 public static CodeNavigationKindFilter Create(IReadOnlyList<string>? includeKinds, IReadOnlyList<string>? excludeKinds)
65 {
66 var exclude = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
67 if (excludeKinds is not null)
68 {
69 foreach (var t in excludeKinds)
70 {
71 var c = CodeNavigationRelatedKinds.TryCanonicalKind(t);
72 if (c is not null)
73 exclude.Add(c);
74 }
75 }
76
77 HashSet<string>? include = null;
78 if (includeKinds is not null && includeKinds.Count > 0)
79 {
80 include = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
81 foreach (var t in includeKinds)
82 {
83 var c = CodeNavigationRelatedKinds.TryCanonicalKind(t);
84 if (c is not null)
85 include.Add(c);
86 }
87
88 if (include.Count == 0)
89 include = null;
90 }
91
92 return new CodeNavigationKindFilter(include, exclude);
93 }
94
95 public bool Allows(string kind)
96 {
97 if (string.IsNullOrEmpty(kind))
98 return false;
99 if (_include is not null && !_include.Contains(kind))
100 return false;
101 if (_exclude.Contains(kind))
102 return false;
103 return true;
104 }
105}
106
View only · write via MCP/CIDE