#nullable enable
namespace T3.Editor.Gui.Help;
///
/// Identifies a documentation topic shown in the : either an operator
/// (by symbol id) or a ui: UI topic (by its help-index key). Value-equality makes it usable as a
/// history entry.
///
internal readonly record struct HelpTopic(Guid SymbolId, string? UiTopicKey)
{
internal static HelpTopic ForOperator(Guid symbolId) => new(symbolId, null);
/// Accepts both a full ui:Id key and a bare id; normalizes so both forms dedupe in history.
internal static HelpTopic ForUiTopic(string keyOrId)
{
var key = keyOrId.StartsWith(UiPrefix, StringComparison.Ordinal) ? keyOrId : UiPrefix + keyOrId;
return new HelpTopic(Guid.Empty, key);
}
internal bool IsEmpty => SymbolId == Guid.Empty && UiTopicKey == null;
private const string UiPrefix = "ui:";
}
///
/// Resolves a ui: topic to its display title and markdown doc. A bespoke
/// .help/embedded/<id>.md snippet wins over the topic registry's doc, so a documentation
/// icon can carry hand-written content while still falling back to the shared ui: topic body.
///
internal static class UiTopicDocs
{
///
/// True if the id names a known topic (registry entry or embedded snippet);
/// may still be null for a registry topic whose doc hasn't been written yet.
///
internal static bool TryGet(string keyOrId, out string title, out string? markdown)
{
var key = keyOrId.StartsWith("ui:", StringComparison.Ordinal) ? keyOrId : "ui:" + keyOrId;
if (_cache.TryGetValue(key, out var cached))
{
title = cached.Title;
markdown = cached.Doc;
return cached.Found;
}
var id = key.Substring(3);
var doc = EmbeddedHelpLoader.TryLoad(id);
var resolvedTitle = id;
var found = doc != null;
if (HelpIndex.TryGetTopic(key, out var topic) && topic != null)
{
resolvedTitle = topic.Term;
found = true;
if (doc == null && !string.IsNullOrWhiteSpace(topic.Doc))
doc = topic.Doc;
}
_cache[key] = (found, resolvedTitle, doc);
title = resolvedTitle;
markdown = doc;
return found;
}
private static readonly Dictionary _cache = new();
}