diff --git a/package/Editor/Modules/SyntaxHighlighting.cs b/package/Editor/Modules/SyntaxHighlighting.cs
index 0dfb19f..64bb9ba 100644
--- a/package/Editor/Modules/SyntaxHighlighting.cs
+++ b/package/Editor/Modules/SyntaxHighlighting.cs
@@ -204,7 +204,28 @@ string Eval(Match m)
if (colorDict.TryGetValue("link", out var col))
{
var displayUrl = link.Value.Substring(linkPrefix.Length).TrimEnd(')');
- line += $" in {displayUrl}";
+
+ // 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} in {displayUrl}",
+ NeedleConsoleSettings.StacktraceFilename.Compact
+ => $"{line} {displayUrl}",
+ NeedleConsoleSettings.StacktraceFilename.Inline
+ => $"{line}:{lineIndex}",
+ _ => throw new ArgumentOutOfRangeException(),
+ };
}
else
line += link.Value;
diff --git a/package/Editor/NeedleConsole.cs b/package/Editor/NeedleConsole.cs
index 5a36442..b9fcc58 100644
--- a/package/Editor/NeedleConsole.cs
+++ b/package/Editor/NeedleConsole.cs
@@ -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;
@@ -10,6 +11,21 @@ namespace Needle.Console
{
public static class NeedleConsole
{
+ ///
+ /// Matches namespaces - "XX.YY.ZZ" is split into the groups "XX.YY" and "ZZ".
+ /// Also handles generics inside "<" and ">".
+ ///
+ 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()
@@ -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);
@@ -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(),
+ };
+ }
}
}
diff --git a/package/Editor/Settings/NeedleConsoleSettings.cs b/package/Editor/Settings/NeedleConsoleSettings.cs
index c9976d0..67cca34 100644
--- a/package/Editor/Settings/NeedleConsoleSettings.cs
+++ b/package/Editor/Settings/NeedleConsoleSettings.cs
@@ -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;
@@ -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[] { };
diff --git a/package/Editor/Settings/NeedleConsoleSettingsProvider.cs b/package/Editor/Settings/NeedleConsoleSettingsProvider.cs
index 0b22794..a30ad3f 100644
--- a/package/Editor/Settings/NeedleConsoleSettingsProvider.cs
+++ b/package/Editor/Settings/NeedleConsoleSettingsProvider.cs
@@ -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())