Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion package/Editor/Modules/SyntaxHighlighting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,28 @@ string Eval(Match m)
if (colorDict.TryGetValue("link", out var col))
{
var displayUrl = link.Value.Substring(linkPrefix.Length).TrimEnd(')');
line += $" <a href=\"{link.Groups["hyperlink"].Value}\" line=\"{link.Groups["line"].Value}\"><color={col}>in {displayUrl}</color></a>";

// Trim the preceding path from the filename.
if (NeedleConsoleSettings.instance.StacktraceFilenameMode == NeedleConsoleSettings.StacktraceFilename.Compact)
{
var lastSlashIndex = displayUrl.LastIndexOf("/", StringComparison.Ordinal);
if (lastSlashIndex != -1)
{
displayUrl = displayUrl[(lastSlashIndex + 1)..];
}
}

var lineIndex = link.Groups["line"].Value;
line = NeedleConsoleSettings.instance.StacktraceFilenameMode switch
{
NeedleConsoleSettings.StacktraceFilename.Full
=> $"{line} <a href=\"{link.Groups["hyperlink"].Value}\" line=\"{lineIndex}\"><color={col}>in {displayUrl}</color></a>",
NeedleConsoleSettings.StacktraceFilename.Compact
=> $"{line} <a href=\"{link.Groups["hyperlink"].Value}\" line=\"{lineIndex}\"><color={col}>{displayUrl}</color></a>",
NeedleConsoleSettings.StacktraceFilename.Inline
=> $"<a href=\"{link.Groups["hyperlink"].Value}\" line=\"{lineIndex}\">{line}<color={col}>:{lineIndex}</color></a>",
_ => throw new ArgumentOutOfRangeException(),
};
}
else
line += link.Value;
Expand Down
92 changes: 91 additions & 1 deletion package/Editor/NeedleConsole.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.IO;
using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Unity.Profiling;
using UnityEditor;
Expand All @@ -10,6 +11,21 @@ namespace Needle.Console
{
public static class NeedleConsole
{
/// <summary>
/// Matches namespaces - "XX.YY.ZZ" is split into the groups "XX.YY" and "ZZ".<br/>
/// Also handles generics inside "&lt;" and "&gt;".
/// </summary>
private static readonly Regex namespaceCompactRegex = new Regex(@"([^<>.\s]+(?:\.[^<>.\s]+)*)(\.)([^<>.(]+)", RegexOptions.Compiled);
private static readonly Regex paramsRegex = new Regex(@"\((?!at)(.*?)\)", RegexOptions.Compiled);
private static readonly Regex paramsArgumentRegex = new Regex(@"([ (])([^),]+?) (.+?)([\),])", RegexOptions.Compiled);
private static readonly Regex paramsRefRegex = new Regex(@"\b ?ref ?\b", RegexOptions.Compiled);
private static readonly MatchEvaluator namespaceReplacer = NamespaceReplacer;
private static readonly MatchEvaluator paramReplacer = ParamReplacer;

private static int namespaceLinkStartIndex;
private static int namespaceMatchIndex;
private static string namespaceStored;
private static int namespaceStartIndex;

[HyperlinkCallback(Href = "OpenNeedleConsoleSettings")]
private static void OpenNeedleConsoleUserPreferences()
Expand Down Expand Up @@ -120,6 +136,49 @@ public static void Apply(ref string stacktrace)
}
}

if (foundPrefix)
{
if (
settings.StacktraceNamespaceMode == NeedleConsoleSettings.StacktraceNamespace.Compact ||
settings.StacktraceNamespaceMode == NeedleConsoleSettings.StacktraceNamespace.CompactNoReturnType)
{
namespaceLinkStartIndex = line.IndexOf(" (at ", StringComparison.Ordinal);
namespaceMatchIndex = 0;
namespaceStartIndex = -1;
namespaceStored = "";

line = namespaceCompactRegex.Replace(line, namespaceReplacer);

// If the class name was stripped out along with the namespaces, add
// it back in here.
int methodIndexEndIndex = line.IndexOf('(');
if (methodIndexEndIndex != -1 && line.IndexOf('.', 0, methodIndexEndIndex) == -1)
{
int classIndex = namespaceStored.LastIndexOf('.');
if (classIndex != -1)
{
namespaceStored = namespaceStored[(classIndex + 1)..];
}
line = line.Insert(namespaceStartIndex, $"{namespaceStored}.");
}

// Remove the return type.
if (settings.StacktraceNamespaceMode == NeedleConsoleSettings.StacktraceNamespace.CompactNoReturnType)
{
if (namespaceStartIndex != -1)
{
line = line[namespaceStartIndex..];
}
}
}

if (settings.StacktraceParamsMode != NeedleConsoleSettings.StacktraceParams.Full)
{
line = paramsRefRegex.Replace(line, "");
line = paramsRegex.Replace(line, paramReplacer);
}
}

if (foundPrefix && settings.UseSyntaxHighlighting)
SyntaxHighlighting.AddSyntaxHighlighting(ref line);

Expand Down Expand Up @@ -152,5 +211,36 @@ public static void Apply(ref string stacktrace)
// ignore
}
}

private static string NamespaceReplacer(Match match)
{
namespaceMatchIndex++;

// Prevent replacing stuff in the filename link.
if (namespaceLinkStartIndex != -1 && match.Index >= namespaceLinkStartIndex)
return match.Value;

// At this point there's no wa to differentiate between a generic type parameter and "Class.Method",
// causing the class name to be stripped which we don't want.
// Store this so that the class name can be added back at the start after all replacements have happened.
if (namespaceMatchIndex == 1)
{
namespaceStartIndex = match.Index;
namespaceStored = match.Groups[1].Value;
}

return match.Groups[3].Value;
}

private static string ParamReplacer(Match match)
{
return NeedleConsoleSettings.instance.StacktraceParamsMode switch
{
NeedleConsoleSettings.StacktraceParams.TypesOnly => paramsArgumentRegex.Replace(match.Value, "$1$2$4"),
NeedleConsoleSettings.StacktraceParams.NamesOnly => paramsArgumentRegex.Replace(match.Value, "$1$3$4"),
NeedleConsoleSettings.StacktraceParams.Compact => "()",
_ => throw new ArgumentOutOfRangeException(),
};
}
}
}
25 changes: 25 additions & 0 deletions package/Editor/Settings/NeedleConsoleSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,28 @@ internal enum StacktraceOrientations
Horizontal,
Auto,
}
[Serializable, Flags]
internal enum StacktraceNamespace
{
Full,
Compact,
CompactNoReturnType,
}
[Serializable, Flags]
internal enum StacktraceParams
{
Full,
TypesOnly,
NamesOnly,
Compact,
}
[Serializable]
internal enum StacktraceFilename
{
Full,
Compact,
Inline,
}

[SerializeField]
internal bool Enabled = true;
Expand Down Expand Up @@ -129,6 +151,9 @@ public void UpdateCurrentTheme()
public Font CustomLogEntryFont;

public StacktraceOrientations StacktraceOrientation = StacktraceOrientations.Vertical;
public StacktraceNamespace StacktraceNamespaceMode = StacktraceNamespace.Full;
public StacktraceParams StacktraceParamsMode = StacktraceParams.Full;
public StacktraceFilename StacktraceFilenameMode = StacktraceFilename.Full;
public float StacktraceOrientationAutoHeight = 300;
public bool UseStacktraceIgnoreFilters = true;
public string[] StacktraceIgnoreFilters = new string[] { };
Expand Down
24 changes: 17 additions & 7 deletions package/Editor/Settings/NeedleConsoleSettingsProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,23 @@ public override void OnGUI(string searchContext)
if (_scope.changed) NeedleConsoleProjectSettings.RaiseColorsChangedEvent();
}

settings.StacktraceOrientation = (NeedleConsoleSettings.StacktraceOrientations)EditorGUILayout.EnumPopup("Stacktrace Orientation", settings.StacktraceOrientation);
using (new EditorGUI.DisabledScope(settings.StacktraceOrientation != NeedleConsoleSettings.StacktraceOrientations.Auto))
{
var windowHeight = Math.Max(300, Screen.height);
EditorGUI.indentLevel++;
settings.StacktraceOrientationAutoHeight = EditorGUILayout.IntSlider(new GUIContent("Auto Height (in pixel)", "The height at which the stacktrace orientation will switch from Vertical to Horizontal when Stacktrace Orientation is set to Auto."), (int)settings.StacktraceOrientationAutoHeight, 100, windowHeight);
EditorGUI.indentLevel--;
GUILayout.Space(10);
EditorGUILayout.LabelField("Experimental > Stacktrace", EditorStyles.boldLabel);
using (var _scope = new EditorGUI.ChangeCheckScope()) {
settings.StacktraceOrientation = (NeedleConsoleSettings.StacktraceOrientations)EditorGUILayout.EnumPopup("Orientation", settings.StacktraceOrientation);
using (new EditorGUI.DisabledScope(settings.StacktraceOrientation != NeedleConsoleSettings.StacktraceOrientations.Auto))
{
var windowHeight = Math.Max(300, Screen.height);
EditorGUI.indentLevel++;
settings.StacktraceOrientationAutoHeight = EditorGUILayout.IntSlider(new GUIContent("Auto Height (in pixel)", "The height at which the stacktrace orientation will switch from Vertical to Horizontal when Stacktrace Orientation is set to Auto."), (int)settings.StacktraceOrientationAutoHeight, 100, windowHeight);
EditorGUI.indentLevel--;
}

settings.StacktraceNamespaceMode = (NeedleConsoleSettings.StacktraceNamespace)EditorGUILayout.EnumPopup("Namespace", settings.StacktraceNamespaceMode);
settings.StacktraceParamsMode = (NeedleConsoleSettings.StacktraceParams)EditorGUILayout.EnumPopup("Parameters", settings.StacktraceParamsMode);
settings.StacktraceFilenameMode = (NeedleConsoleSettings.StacktraceFilename)EditorGUILayout.EnumPopup("Filename", settings.StacktraceFilenameMode);

if (_scope.changed) ThemeEditedOrChanged?.Invoke();
}

// using (new GUILayout.HorizontalScope())
Expand Down