An editor-side validator used when the external Slang toolchain (slangc) is not present. It implements ISlangValidator and returns no diagnostics, exposes an informational Explain() diagnostic that states validation is unavailable, and holds a user-facing Reason and static shared instance.
using Editor.Prism.Core;
namespace Editor.Prism.Toolchain;
/// <summary>
/// The validator used when no Slang toolchain is present.
/// <para>
/// This is not a stub, it is the contract. Slang <em>emission</em> is pure text generation from the
/// typed IR and has no dependency on any toolchain, so <c>.slang</c> files are still written on save
/// and every graph still compiles, previews and renders. What is lost is an independent second opinion
/// on our own emitter — which is worth having and worth offering, but never worth blocking on.
/// </para>
/// <para>
/// <see cref="Validate"/> therefore returns an empty list rather than an error: an absent optional tool
/// is not a problem with the user's shader. <see cref="Explain"/> exists for the one place that should
/// mention it — a grey status chip with a one-click install link, no modal and no nag.
/// </para>
/// </summary>
public sealed class NullSlangValidator : ISlangValidator
{
static readonly Task<IReadOnlyList<Diagnostic>> s_empty =
Task.FromResult<IReadOnlyList<Diagnostic>>( Array.Empty<Diagnostic>() );
/// <summary>The shared instance. This type holds no state worth allocating twice.</summary>
public static readonly NullSlangValidator Instance = new();
/// <summary>Create a fallback validator, optionally recording why there is no toolchain.</summary>
public NullSlangValidator( string reason = null )
{
Reason = string.IsNullOrWhiteSpace( reason )
? "No Slang toolchain was found."
: reason.Trim();
}
/// <summary>Always false. Callers show a "not validated" chip rather than an error.</summary>
public bool Available => false;
/// <summary>Always null.</summary>
public string Version => null;
/// <summary>Why validation is unavailable, phrased for a tooltip.</summary>
public string Reason { get; }
/// <summary>Never produces diagnostics and never throws.</summary>
public Task<IReadOnlyList<Diagnostic>> Validate( SlangValidationRequest request, CancellationToken ct ) => s_empty;
/// <summary>
/// A single informational diagnostic for the Slang tab's banner. Deliberately not returned from
/// <see cref="Validate"/>: the diagnostics list is for problems with the shader, and this is not one.
/// </summary>
public IReadOnlyList<Diagnostic> Explain() => new[]
{
Diagnostic.Info( DiagnosticCode.SlangUnavailable,
"Slang output is generated but not validated",
null,
$"{Reason} Install it from Preferences to have slangc independently check the module Prism " +
"emits. Nothing about graph editing, .shader generation, compiling or the preview depends on it." )
};
/// <inheritdoc/>
public override string ToString() => "slang: not validated";
}