Forge
csharpdeeb25a2
1namespace CascadeIDE.Services;
2
3/// <summary>Формы melody (<c>c:</c>) из command-first каталога <see cref="IntentMelodyAliases.BundledRelativePath"/> (ADR 0109).</summary>
4public static class IntentMelodyCatalog
5{
6 /// <inheritdoc cref="IntentMelodyAliases.GetCatalogSnapshot"/>
7 public static bool TryGetRoot(string slug, out MelodyRootEntry entry)
8 {
9 var roots = IntentMelodyAliases.GetCatalogSnapshot().Roots;
10 var key = slug.Trim().ToLowerInvariant();
11 return roots.TryGetValue(key, out entry);
12 }
13
14 /// <summary>Параметрический melody-корень по <c>command_id</c> (0..1 на команду в каталоге).</summary>
15 public static bool TryGetParametricRootByCommandId(string commandId, out MelodyRootEntry entry)
16 {
17 entry = default;
18 if (string.IsNullOrWhiteSpace(commandId))
19 return false;
20
21 foreach (var root in IntentMelodyAliases.GetCatalogSnapshot().Roots.Values)
22 {
23 if (root.Shape != IntentMelodyShape.Parametric)
24 continue;
25 if (!string.Equals(root.CommandId, commandId.Trim(), StringComparison.OrdinalIgnoreCase))
26 continue;
27
28 entry = root;
29 return true;
30 }
31
32 return false;
33 }
34
35 /// <summary>Реестр <c>[[tail_wire_class]]</c> по id (lower).</summary>
36 public static bool TryGetTailWireClass(string wireClassId, out TailWireClassEntry wire)
37 {
38 var id = wireClassId.Trim().ToLowerInvariant();
39 return IntentMelodyAliases.GetCatalogSnapshot().TailWireClasses.TryGetValue(id, out wire);
40 }
41}
42
43public readonly record struct MelodyRootEntry(
44 string Slug,
45 string CommandId,
46 IntentMelodyShape Shape,
47 bool ShowUsageHintIfBareSlug,
48 string? TailSignature,
49 string? WireClass,
50 string? ChordCommit,
51 string? PaletteHintSlug,
52 /// <summary>Строка подсказки палитры (c:…); если пусто — шаблон <c>c:slug:&lt;start&gt;:&lt;end&gt;</c> в <c>ParametricIntentMelody</c>.</summary>
53 string? PaletteUsageHint = null,
54 /// <summary>Категория строки палитры; если пусто — общий fallback.</summary>
55 string? PaletteUsageCategory = null);
56
57public enum IntentMelodyShape
58{
59 Simple,
60 Parametric,
61}
62
63/// <remarks>ADR 0109 <c>[[tail_wire_class]].kind</c>.</remarks>
64public enum TailWireKind
65{
66 SingleRemainder,
67 DelimitedSlots,
68}
69
70/// <param name="BetweenSlotsSeparators">Для <see cref="TailWireKind.DelimitedSlots"/> — литералы между целочисленными слотами (обычно <c>:</c> и/или пробел).</param>
71public readonly record struct TailWireClassEntry(string Id, TailWireKind Kind, string[] BetweenSlotsSeparators);
72
73public sealed record IntentMelodyCatalogSnapshot(
74 IReadOnlyDictionary<string, MelodyRootEntry> Roots,
75 IReadOnlyDictionary<string, TailWireClassEntry> TailWireClasses,
76 IReadOnlyDictionary<string, SlashRouteEntry> SlashRoutes);
77
78public static class IntentSlashCatalog
79{
80 /// <inheritdoc cref="IntentMelodyAliases.GetCatalogSnapshot"/>
81 public static IReadOnlyDictionary<string, SlashRouteEntry> SlashRoutes =>
82 IntentMelodyAliases.GetCatalogSnapshot().SlashRoutes;
83
84 public static bool TryGetRoute(string slashPath, out SlashRouteEntry entry)
85 {
86 var key = NormalizeSlashPath(slashPath);
87 return SlashRoutes.TryGetValue(key, out entry);
88 }
89
90 internal static string NormalizeSlashPath(string? slashPath)
91 {
92 if (string.IsNullOrWhiteSpace(slashPath))
93 return "";
94
95 var t = slashPath.Trim();
96 if (t.Length == 0)
97 return "";
98
99 if (t[0] != '/')
100 t = "/" + t;
101
102 return t;
103 }
104}
105
View only · write via MCP/CIDE