using T3.Core.Operator; namespace T3.Editor.UiModel.Helpers; /// /// Provides collection of examples operators for each symbol. /// /// /// Should be updated on editor startup. The only stores symbolIds to prevent references to /// outdated types after structural changes. /// /// /// Should be "occasionally" structural changes like creating or renaming symbols. /// internal static class ExampleSymbolLinking { internal static Dictionary> ExampleIdsForSymbolsId { get; } = new(50); public static IReadOnlyList GetExampleIds(Guid id) { return ExampleIdsForSymbolsId.TryGetValue(id, out var exampleIds) ? exampleIds : _emptyIdList; } public static bool TryGetExamples(Guid symbolId, out IReadOnlyList examples) { examples = _noSymbolUis; if (!ExampleIdsForSymbolsId.TryGetValue(symbolId, out var exampleIds)) return false; if (exampleIds.Count == 0) return false; var newList = new List(examples.Count); foreach (var id in exampleIds) { if (SymbolUiRegistry.TryGetSymbolUi(id, out var symbolUi)) newList.Add(symbolUi); } examples = newList; return true; } // Todo: unlink Examples implementation from naming - this should be done in a different way via attribute, guid links, etc. internal static void UpdateExampleLinks() { ExampleIdsForSymbolsId.Clear(); const string exampleSuffix = "Example"; const string examplesSuffix = "Examples"; var potentialExamples = new List<(Range correspondingNameRange, SymbolUi exampleSymbol)>(); var symbolUiCollection = EditorSymbolPackage.AllSymbolUis.ToList(); Dictionary> symbolsByName = new(capacity: symbolUiCollection.Count); foreach (var symbolUi in symbolUiCollection) { var potentialExampleSymbol = symbolUi.Symbol; var name = potentialExampleSymbol.Name; var hashCode = name.GetHashCode(); if (!symbolsByName.TryGetValue(hashCode, out var symbolsWithName)) { symbolsWithName = []; symbolsByName.Add(hashCode, symbolsWithName); } symbolsWithName.Add(potentialExampleSymbol); var lastChar = name[^1]; var endsWithS = lastChar == 's'; var endsWithE = lastChar == 'e'; if(!endsWithS && !endsWithE) continue; var index = endsWithS ? name.IndexOf(examplesSuffix, StringComparison.Ordinal) : name.IndexOf(exampleSuffix, StringComparison.Ordinal); if (index < 0) continue; potentialExamples.Add((..index, symbolUi)); } foreach (var (correspondingSymbolNameRange, exampleSymbol) in potentialExamples) { var name = exampleSymbol.Symbol.Name[correspondingSymbolNameRange]; var gotSymbol = symbolsByName.TryGetValue(name.GetHashCode(), out var symbolsWithName); if (!gotSymbol) continue; foreach (var symbol in symbolsWithName) { if (!ExampleIdsForSymbolsId.TryGetValue(symbol.Id, out var exampleList)) { exampleList = []; ExampleIdsForSymbolsId.Add(symbol.Id, exampleList); } exampleList.Add(exampleSymbol.Symbol.Id); } } Log.Debug($"Found {ExampleIdsForSymbolsId.Sum(x=> x.Value.Count)} examples for {ExampleIdsForSymbolsId.Count} operators out of {potentialExamples.Count} potential examples"); } private static readonly List _emptyIdList = []; private static readonly IReadOnlyList _noSymbolUis = []; }