| 1 | namespace CascadeIDE.Services.Presentation; |
| 2 | |
| 3 | /// <summary>Токены грамматики <c>presentation</c> из <c>settings.toml</c> (ADR 0017 § грамматика).</summary> |
| 4 | public readonly record struct PresentationGrammarTokens( |
| 5 | char ScreenOpen, |
| 6 | char ScreenClose, |
| 7 | string ScreenSeparator, |
| 8 | string ZoneSeparator, |
| 9 | string PfdZoneIdentifier, |
| 10 | string ForwardZoneIdentifier, |
| 11 | string MfdZoneIdentifier) |
| 12 | { |
| 13 | /// <summary>Канон для встроенных тестов и поведения «только <c>topology</c> без <c>[display.screens.grammar]</c>» — совпадает с samples.</summary> |
| 14 | public static PresentationGrammarTokens Default => new('(', ')', " ", "+", "P", "F", "M"); |
| 15 | |
| 16 | /// <summary>Разбор полей TOML; пустые строки заменяются дефолтами. При дубликатах между тремя идентификаторами якорей — сброс на дефолт.</summary> |
| 17 | public static PresentationGrammarTokens FromSettings( |
| 18 | string? brackets, |
| 19 | string? betweenScreens, |
| 20 | string? betweenZones, |
| 21 | string? pfdZoneIdentifier = null, |
| 22 | string? forwardZoneIdentifier = null, |
| 23 | string? mfdZoneIdentifier = null) |
| 24 | { |
| 25 | var markers = string.IsNullOrEmpty(brackets) ? "()" : brackets.Trim(); |
| 26 | if (markers.Length != 2) |
| 27 | markers = "()"; |
| 28 | var sep = string.IsNullOrEmpty(betweenScreens) ? " " : betweenScreens; |
| 29 | var zone = string.IsNullOrEmpty(betweenZones) ? "+" : betweenZones; |
| 30 | |
| 31 | var def = Default; |
| 32 | var pfd = NormId(pfdZoneIdentifier, def.PfdZoneIdentifier); |
| 33 | var fwd = NormId(forwardZoneIdentifier, def.ForwardZoneIdentifier); |
| 34 | var mfd = NormId(mfdZoneIdentifier, def.MfdZoneIdentifier); |
| 35 | |
| 36 | if (!AreZoneTokensUnique(pfd, fwd, mfd)) |
| 37 | { |
| 38 | pfd = def.PfdZoneIdentifier; |
| 39 | fwd = def.ForwardZoneIdentifier; |
| 40 | mfd = def.MfdZoneIdentifier; |
| 41 | } |
| 42 | |
| 43 | return new(markers[0], markers[1], sep, zone, pfd, fwd, mfd); |
| 44 | } |
| 45 | |
| 46 | private static string NormId(string? value, string defaultValue) |
| 47 | { |
| 48 | if (string.IsNullOrWhiteSpace(value)) |
| 49 | return defaultValue; |
| 50 | var t = value.Trim(); |
| 51 | return t.Length > 0 ? t : defaultValue; |
| 52 | } |
| 53 | |
| 54 | private static bool AreZoneTokensUnique(string pfd, string fwd, string mfd) |
| 55 | { |
| 56 | var set = new HashSet<string>(StringComparer.OrdinalIgnoreCase); |
| 57 | foreach (var t in new[] { pfd, fwd, mfd }) |
| 58 | { |
| 59 | if (t.Length == 0 || !set.Add(t)) |
| 60 | return false; |
| 61 | } |
| 62 | |
| 63 | return true; |
| 64 | } |
| 65 | } |
| 66 | |