Jump to file/line in the Unity console window callstack via this helper window
// MIT License | |
// | |
// Copyright (c) 2018 Sabresaurus | |
// | |
// Permission is hereby granted, free of charge, to any person obtaining a copy | |
// of this software and associated documentation files (the "Software"), to deal | |
// in the Software without restriction, including without limitation the rights | |
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
// copies of the Software, and to permit persons to whom the Software is | |
// furnished to do so, subject to the following conditions: | |
// | |
// The above copyright notice and this permission notice shall be included in all | |
// copies or substantial portions of the Software. | |
// | |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
// SOFTWARE. | |
using System; | |
using System.Reflection; | |
using UnityEditor; | |
using UnityEngine; | |
public class ConsoleCallStackHelper : EditorWindow | |
{ | |
Vector2 scrollPosition = Vector2.zero; | |
[MenuItem("Tools/Call Stack")] | |
static void Init() | |
{ | |
ConsoleCallStackHelper window = EditorWindow.GetWindow<ConsoleCallStackHelper>(); | |
window.Show(); | |
window.titleContent = new GUIContent("Call Stack"); | |
} | |
private void OnGUI() | |
{ | |
Color backgroundColor = GUI.backgroundColor; | |
Type consoleWindowType = Type.GetType("UnityEditor.ConsoleWindow, UnityEditor", true); | |
UnityEngine.Object[] windows = Resources.FindObjectsOfTypeAll(consoleWindowType); | |
if (windows.Length > 0) | |
{ | |
// Fetch the active callstack from the console window | |
FieldInfo fieldInfo = consoleWindowType.GetField("m_ActiveText", BindingFlags.Instance | BindingFlags.NonPublic); | |
string output = (string)fieldInfo.GetValue(windows[0]); | |
GUIStyle style = new GUIStyle(GUI.skin.label); | |
style.wordWrap = true; | |
style.richText = true; | |
style.normal.background = EditorGUIUtility.whiteTexture; | |
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition); | |
GUI.backgroundColor = new Color(1, 1, 1, 0.25f); | |
// Split the callstack into lines | |
string[] lines = output.Split('\n'); | |
foreach (string line in lines) | |
{ | |
string displayLine = line; | |
int firstIndex = line.LastIndexOf(" (at Assets/", StringComparison.InvariantCultureIgnoreCase); | |
// Wrap the line in bold tags | |
if (firstIndex != -1) | |
{ | |
displayLine = displayLine.Insert(firstIndex + 5, "<b>"); | |
displayLine = displayLine.Insert(displayLine.Length - 1, "</b>"); | |
} | |
// Click the line if valid | |
if (GUILayout.Button(displayLine, style)) | |
{ | |
if (firstIndex != -1) | |
{ | |
// Valid target, jump to the line in the file | |
string trimmed = line.Substring(firstIndex + 5, line.Length - firstIndex - 6); | |
string[] splitLine = trimmed.Split(':'); | |
AssetDatabase.OpenAsset(AssetDatabase.LoadMainAssetAtPath(splitLine[0]), int.Parse(splitLine[1])); | |
} | |
} | |
// Show a rollover cursor on valid targets | |
if (firstIndex != -1) | |
{ | |
Rect rect = GUILayoutUtility.GetLastRect(); | |
EditorGUIUtility.AddCursorRect(rect, MouseCursor.Link); | |
} | |
} | |
GUI.backgroundColor = backgroundColor; | |
EditorGUILayout.EndScrollView(); | |
} | |
} | |
void OnInspectorUpdate() | |
{ | |
// Repaint 10 times a second in case they clicked a new log entry | |
Repaint(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment