Skip to content

Commit

Permalink
chore(error): API and docs refinements
Browse files Browse the repository at this point in the history
  • Loading branch information
bdunderscore committed Dec 21, 2023
1 parent fa75f35 commit b407402
Show file tree
Hide file tree
Showing 19 changed files with 278 additions and 216 deletions.
2 changes: 1 addition & 1 deletion Editor/API/BuildContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public sealed partial class BuildContext
/// </summary>
public UnityObject AssetContainer { get; private set; }

public bool Successful => !_report.Errors.Any(e => e.TheError.Category >= ErrorCategory.Error);
public bool Successful => !_report.Errors.Any(e => e.TheError.Severity >= ErrorSeverity.Error);

private Dictionary<Type, object> _state = new Dictionary<Type, object>();
private Dictionary<Type, IExtensionContext> _extensions = new Dictionary<Type, IExtensionContext>();
Expand Down
3 changes: 3 additions & 0 deletions Editor/ErrorReporting/ErrorContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

namespace nadena.dev.ndmf
{
/// <summary>
/// Holds a single error and information about where the error originated from.
/// </summary>
public struct ErrorContext
{
public IError TheError;
Expand Down
69 changes: 63 additions & 6 deletions Editor/ErrorReporting/ErrorReport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Immutable;
using System.Linq;
using System.Runtime.ExceptionServices;
using JetBrains.Annotations;
using nadena.dev.ndmf.localization;
using nadena.dev.ndmf.runtime;
using UnityEngine;
Expand Down Expand Up @@ -78,6 +79,9 @@ public void Dispose()
}
}

/// <summary>
/// Contains any errors or warnings issued during a single build operation.
/// </summary>
public sealed class ErrorReport
{
internal static List<ErrorReport> Reports = new List<ErrorReport>();
Expand All @@ -93,9 +97,18 @@ private ErrorReport(string avatarName, string avatarPath)
Errors = ImmutableList<ErrorContext>.Empty;
}

/// <summary>
/// The name of the avatar being processed
/// </summary>
public string AvatarName { get; }
/// <summary>
/// The path (from the scene root) of the avatar being processed
/// </summary>
public string AvatarRootPath { get; }

/// <summary>
/// A list of reported errors.
/// </summary>
public ImmutableList<ErrorContext> Errors { get; private set; }

internal ErrorContext CurrentContext = new ErrorContext();
Expand Down Expand Up @@ -128,14 +141,19 @@ internal static ErrorReport Create(GameObject root, bool isClone)
return report;
}

public void AddError(IError error)
internal void AddError(IError error)
{
var context = CurrentContext;
context.TheError = error;

Errors = Errors.Add(context);
}

/// <summary>
/// Adds an error to the currently active error report. If no error report is active, the error will simply be
/// logged to the debug log.
/// </summary>
/// <param name="error"></param>
public static void ReportError(IError error)
{
if (error is StackTraceError e)
Expand All @@ -157,12 +175,24 @@ public static void ReportError(IError error)
CurrentReport?.AddError(error);
}

public static void ReportError(Localizer localizer, ErrorCategory errorCategory, string key,
/// <summary>
/// Helper to report a SimpleError.
/// </summary>
/// <param name="localizer">The Localizer used to look up translations</param>
/// <param name="errorSeverity">The severity of the error</param>
/// <param name="key">The prefix used to find localization keys</param>
/// <param name="args">Inline substitutions and unity objects to reference from the error</param>
public static void ReportError(Localizer localizer, ErrorSeverity errorSeverity, string key,
params object[] args)
{
ReportError(new InlineError(localizer, errorCategory, key, args));
ReportError(new InlineError(localizer, errorSeverity, key, args));
}

/// <summary>
/// Helper to report an exception. This will generate an error of InternalError severity.
/// </summary>
/// <param name="e">Exception to report</param>
/// <param name="additionalStackTrace">Additional information to append to the stack trace</param>
public static void ReportException(Exception e, string additionalStackTrace = null)
{
var report = CurrentReport;
Expand All @@ -178,6 +208,11 @@ public static void ReportException(Exception e, string additionalStackTrace = nu
report?.ReportedExceptions?.Add(e);
}

/// <summary>
/// Attempts to find the original avatar that generated the report.
/// </summary>
/// <param name="av">The avatar root</param>
/// <returns>true if the avatar was found, otherwise false</returns>
public bool TryResolveAvatar(out GameObject av)
{
var scene = SceneManager.GetActiveScene();
Expand Down Expand Up @@ -206,7 +241,12 @@ public bool TryResolveAvatar(out GameObject av)
return false;
}

public static IDisposable WithContextObject(UnityObject obj)
/// <summary>
/// Returns a disposable scope, within which all errors will reference a specific UnityObject.
/// </summary>
/// <param name="obj">The object to reference (can be null)</param>
/// <returns>A disposable that will remove the object from the current scope when disposed.</returns>
public static IDisposable WithContextObject([CanBeNull] UnityObject obj)
{
if (obj == null || CurrentReport == null) return new NullScope();

Expand All @@ -216,7 +256,14 @@ public static IDisposable WithContextObject(UnityObject obj)
return scope;
}

public static T WithContextObject<T>(UnityObject obj, Func<T> func)
/// <summary>
/// Executes a function, within which any errors will reference a specific UnityObject.
/// Thrown exceptions will automatically be logged.
/// </summary>
/// <param name="obj">The object to reference</param>
/// <param name="func">The function to invoke</param>
/// <returns>The return value of func()</returns>
public static T WithContextObject<T>([CanBeNull] UnityObject obj, Func<T> func)
{
using (WithContextObject(obj))
{
Expand All @@ -232,7 +279,14 @@ public static T WithContextObject<T>(UnityObject obj, Func<T> func)
}
}

public static void WithContextObject(UnityObject obj, Action action)
/// <summary>
/// Executes a function, within which any errors will reference a specific UnityObject.
/// Thrown exceptions will automatically be logged.
/// </summary>
/// <param name="obj">The object to reference</param>
/// <param name="func">The function to invoke</param>
/// <returns>The return value of func()</returns>
public static void WithContextObject([CanBeNull] UnityObject obj, Action action)
{
using (WithContextObject(obj))
{
Expand Down Expand Up @@ -294,6 +348,9 @@ public static List<ErrorContext> CaptureErrors(Action action)
return report.Errors.ToList();
}

/// <summary>
/// Clears all error reports.
/// </summary>
public static void Clear()
{
Reports.Clear();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
namespace nadena.dev.ndmf
{
public enum ErrorCategory
/// <summary>
/// Indicates the severity of a reported error.
/// </summary>
public enum ErrorSeverity
{
/// <summary>
/// Informational messages that indicate an unusual configuration that might be an error.
Expand Down
File renamed without changes.
21 changes: 20 additions & 1 deletion Editor/ErrorReporting/IError.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,30 @@

namespace nadena.dev.ndmf
{
/// <summary>
/// A base interface for custom NDMF error reports.
/// </summary>
public interface IError
{
ErrorCategory Category { get; }
/// <summary>
/// The severity of the error
/// </summary>
ErrorSeverity Severity { get; }
/// <summary>
/// Creates a VisualElement used to display the error in the error report window.
/// </summary>
/// <param name="report">The report this error is in</param>
/// <returns>A VisualElement to display</returns>
VisualElement CreateVisualElement(ErrorReport report);
/// <summary>
/// Formats the error as a string, suitable for being dumped to the unity log.
/// </summary>
/// <returns></returns>
string ToMessage();
/// <summary>
/// Adds a reference to a context object that might be helpful for tracking down the error.
/// </summary>
/// <param name="obj"></param>
void AddReference(ObjectReference obj);
}
}
8 changes: 4 additions & 4 deletions Editor/ErrorReporting/InlineError.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@

namespace nadena.dev.ndmf
{
public class InlineError : SimpleError
internal class InlineError : SimpleError
{
private readonly string[] _subst;

public InlineError(Localizer localizer, ErrorCategory errorCategory, string key, params object[] args)
public InlineError(Localizer localizer, ErrorSeverity errorSeverity, string key, params object[] args)
{
Localizer = localizer;
Category = errorCategory;
Severity = errorSeverity;
TitleKey = key;

_subst = Array.ConvertAll(args, o => o?.ToString());
Expand All @@ -34,7 +34,7 @@ public InlineError(Localizer localizer, ErrorCategory errorCategory, string key,
}

protected override Localizer Localizer { get; }
public override ErrorCategory Category { get; }
public override ErrorSeverity Severity { get; }
protected override string TitleKey { get; }

protected override string[] DetailsSubst => _subst;
Expand Down
48 changes: 47 additions & 1 deletion Editor/ErrorReporting/SimpleError.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,56 @@

namespace nadena.dev.ndmf
{
/// <summary>
/// Base class for errors that obtain their messages from the Localization system.
/// </summary>
public abstract class SimpleError : IError
{
private static readonly Regex Pattern = new Regex("\\{([0-9])\\}");

/// <summary>
/// The Localizer to use to look up strings.
/// </summary>
protected abstract Localizer Localizer { get; }

/// <summary>
/// The key to use for the title of the error. By default, all other keys are derived from this TitleKey.
/// </summary>
protected abstract string TitleKey { get; }
/// <summary>
/// The key to use for the details section of the error display. By default, this is the TitleKey + `:description`.
/// </summary>
protected virtual string DetailsKey => TitleKey + ":description";
/// <summary>
/// String substitutions to insert into the details section of the error display. You can reference these with
/// e.g. `{0}`.
/// </summary>
protected virtual string[] DetailsSubst => Array.Empty<string>();
/// <summary>
/// The key to use for the hint section of the error display. By default, this is the TitleKey + `:hint`.
/// This section should be used to provide a hint to the user about how to resolve the error.
/// </summary>
protected virtual string HintKey => TitleKey + ":hint";
/// <summary>
/// String substitutions to insert into the hint section of the error display. You can reference these with
/// e.g. `{0}`.
/// </summary>
protected virtual string[] HintSubst => Array.Empty<string>();

/// <summary>
/// Any ObjectReferences to display to the user; the user will be able to click to jump to these objects.
/// </summary>
protected List<ObjectReference> _references = new List<ObjectReference>();
/// <summary>
/// Any ObjectReferences to display to the user; the user will be able to click to jump to these objects.
/// By default this just returns the `_references` protected field.
/// </summary>
public virtual ObjectReference[] References => _references.ToArray();

public abstract ErrorCategory Category { get; }
/// <summary>
/// The severity of the error.
/// </summary>
public abstract ErrorSeverity Severity { get; }

public virtual VisualElement CreateVisualElement(ErrorReport report)
{
Expand All @@ -44,16 +78,28 @@ public virtual string ToMessage()
return title;
}

/// <summary>
/// Returns the formatted title of the error.
/// </summary>
/// <returns></returns>
public string FormatTitle()
{
return Localizer.GetLocalizedString(TitleKey);
}

/// <summary>
/// Returns the formatted details message for the error.
/// </summary>
/// <returns></returns>
public string FormatDetails()
{
return SafeSubst(DetailsKey, DetailsSubst);
}

/// <summary>
/// Returns the formatted hint message for the error.
/// </summary>
/// <returns></returns>
public string FormatHint()
{
return SafeSubst(HintKey, HintSubst);
Expand Down
4 changes: 2 additions & 2 deletions Editor/ErrorReporting/StackTraceError.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace nadena.dev.ndmf
{
public class StackTraceError : SimpleError
internal class StackTraceError : SimpleError
{
private Exception _e;
private string _stackTrace;
Expand All @@ -27,7 +27,7 @@ public StackTraceError(Exception e, string additionalStackTrace = null)

protected override Localizer Localizer => NDMFLocales.L;
protected override string TitleKey => "Errors:InternalError";
public override ErrorCategory Category => ErrorCategory.InternalError;
public override ErrorSeverity Severity => ErrorSeverity.InternalError;

protected override string[] DetailsSubst => new []
{
Expand Down
Loading

0 comments on commit b407402

Please sign in to comment.