| 1 | namespace CascadeIDE.Services; |
| 2 | |
| 3 | /// <summary>Формы melody (<c>c:</c>) из command-first каталога <see cref="IntentMelodyAliases.BundledRelativePath"/> (ADR 0109).</summary> |
| 4 | public 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 | |
| 43 | public 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:<start>:<end></c> в <c>ParametricIntentMelody</c>.</summary> |
| 53 | string? PaletteUsageHint = null, |
| 54 | /// <summary>Категория строки палитры; если пусто — общий fallback.</summary> |
| 55 | string? PaletteUsageCategory = null); |
| 56 | |
| 57 | public enum IntentMelodyShape |
| 58 | { |
| 59 | Simple, |
| 60 | Parametric, |
| 61 | } |
| 62 | |
| 63 | /// <remarks>ADR 0109 <c>[[tail_wire_class]].kind</c>.</remarks> |
| 64 | public enum TailWireKind |
| 65 | { |
| 66 | SingleRemainder, |
| 67 | DelimitedSlots, |
| 68 | } |
| 69 | |
| 70 | /// <param name="BetweenSlotsSeparators">Для <see cref="TailWireKind.DelimitedSlots"/> — литералы между целочисленными слотами (обычно <c>:</c> и/или пробел).</param> |
| 71 | public readonly record struct TailWireClassEntry(string Id, TailWireKind Kind, string[] BetweenSlotsSeparators); |
| 72 | |
| 73 | public sealed record IntentMelodyCatalogSnapshot( |
| 74 | IReadOnlyDictionary<string, MelodyRootEntry> Roots, |
| 75 | IReadOnlyDictionary<string, TailWireClassEntry> TailWireClasses, |
| 76 | IReadOnlyDictionary<string, SlashRouteEntry> SlashRoutes); |
| 77 | |
| 78 | public 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 | |