Added Search page and AutoCompleter

This commit is contained in:
Sinai
2021-04-23 21:50:58 +10:00
parent eb58ab5327
commit f509a985e7
27 changed files with 1070 additions and 318 deletions

View File

@ -1,69 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityExplorer.Core;
namespace UnityExplorer.Core.CSharp
{
public struct Suggestion
{
public enum Contexts
{
Namespace,
Keyword,
Other
}
// ~~~~ Instance ~~~~
public readonly string Prefix;
public readonly string Addition;
public readonly Contexts Context;
public string Full => Prefix + Addition;
public Color TextColor => GetTextColor();
public Suggestion(string addition, string prefix, Contexts type)
{
Addition = addition;
Prefix = prefix;
Context = type;
}
private Color GetTextColor()
{
switch (Context)
{
case Contexts.Namespace: return Color.grey;
case Contexts.Keyword: return keywordColor;
default: return Color.white;
}
}
// ~~~~ Static ~~~~
public static HashSet<string> Namespaces => m_namespaces ?? GetNamespaces();
private static HashSet<string> m_namespaces;
public static HashSet<string> Keywords => throw new NotImplementedException("TODO!"); // m_keywords ?? (m_keywords = new HashSet<string>(CSLexerHighlighter.validKeywordMatcher.Keywords));
//private static HashSet<string> m_keywords;
private static readonly Color keywordColor = new Color(80f / 255f, 150f / 255f, 215f / 255f);
private static HashSet<string> GetNamespaces()
{
HashSet<string> set = new HashSet<string>(
AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(GetTypes)
.Where(x => x.IsPublic && !string.IsNullOrEmpty(x.Namespace))
.Select(x => x.Namespace));
return m_namespaces = set;
IEnumerable<Type> GetTypes(Assembly asm) => asm.TryGetTypes();
}
}
}

View File

@ -120,7 +120,7 @@ namespace UnityExplorer
}
// cache for GetBaseTypes
internal static readonly Dictionary<string, Type[]> s_cachedTypeInheritance = new Dictionary<string, Type[]>();
internal static readonly Dictionary<string, Type[]> s_cachedBaseTypes = new Dictionary<string, Type[]>();
/// <summary>
/// Get all base types of the provided Type, including itself.
@ -137,7 +137,7 @@ namespace UnityExplorer
var name = type.AssemblyQualifiedName;
if (s_cachedTypeInheritance.TryGetValue(name, out Type[] ret))
if (s_cachedBaseTypes.TryGetValue(name, out Type[] ret))
return ret;
List<Type> list = new List<Type>();
@ -150,11 +150,52 @@ namespace UnityExplorer
ret = list.ToArray();
s_cachedTypeInheritance.Add(name, ret);
s_cachedBaseTypes.Add(name, ret);
return ret;
}
// cache for GetImplementationsOf
internal static readonly Dictionary<Type, HashSet<Type>> s_cachedTypeInheritance = new Dictionary<Type, HashSet<Type>>();
internal static int s_lastAssemblyCount;
/// <summary>
/// Get all non-abstract implementations of the provided type (include itself, if not abstract) in the current AppDomain.
/// </summary>
/// <param name="baseType">The base type, which can optionally be abstract / interface.</param>
/// <returns>All implementations of the type in the current AppDomain.</returns>
public static HashSet<Type> GetImplementationsOf(this Type baseType, bool allowAbstract)
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
if (!s_cachedTypeInheritance.ContainsKey(baseType) || assemblies.Length != s_lastAssemblyCount)
{
if (assemblies.Length != s_lastAssemblyCount)
{
s_cachedTypeInheritance.Clear();
s_lastAssemblyCount = assemblies.Length;
}
var set = new HashSet<Type>();
if (!baseType.IsAbstract && !baseType.IsInterface)
set.Add(baseType);
foreach (var asm in assemblies)
{
foreach (var t in asm.TryGetTypes().Where(t => allowAbstract || (!t.IsAbstract && !t.IsInterface)))
{
if (baseType.IsAssignableFrom(t) && !set.Contains(t))
set.Add(t);
}
}
s_cachedTypeInheritance.Add(baseType, set);
}
return s_cachedTypeInheritance[baseType];
}
/// <summary>
/// Safely get all valid Types inside an Assembly.
/// </summary>

View File

@ -5,7 +5,7 @@ using System.Text;
namespace UnityExplorer.Core.Search
{
internal enum ChildFilter
public enum ChildFilter
{
Any,
RootObject,

View File

@ -5,11 +5,11 @@ using System.Text;
namespace UnityExplorer.Core.Search
{
internal enum SceneFilter
public enum SceneFilter
{
Any,
Asset,
ActivelyLoaded,
DontDestroyOnLoad,
Explicit,
HideAndDontSave,
}
}

View File

@ -5,7 +5,7 @@ using System.Text;
namespace UnityExplorer.Core.Search
{
internal enum SearchContext
public enum SearchContext
{
UnityObject,
GameObject,

View File

@ -4,15 +4,16 @@ using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityExplorer.Core.Runtime;
namespace UnityExplorer.Core.Search
{
public static class SearchProvider
{
internal static object[] StaticClassSearch(string input)
internal static List<object> StaticClassSearch(string input)
{
var list = new List<Type>();
var list = new List<object>();
var nameFilter = "";
if (!string.IsNullOrEmpty(input))
@ -29,7 +30,7 @@ namespace UnityExplorer.Core.Search
}
}
return list.ToArray();
return list;
}
internal static string[] s_instanceNames = new string[]
@ -46,7 +47,7 @@ namespace UnityExplorer.Core.Search
"<instance>k__BackingField",
};
internal static object[] SingletonSearch(string input)
internal static List<object> SingletonSearch(string input)
{
var instances = new List<object>();
@ -72,12 +73,31 @@ namespace UnityExplorer.Core.Search
}
}
return instances.ToArray();
return instances;
}
internal static object[] UnityObjectSearch(string input, string customTypeInput, SearchContext context,
ChildFilter childFilter, SceneFilter sceneFilter, string sceneName = null)
private static bool Filter(Scene scene, SceneFilter filter)
{
switch (filter)
{
case SceneFilter.Any:
return true;
case SceneFilter.DontDestroyOnLoad:
return scene == SceneHandler.DontDestroyScene;
case SceneFilter.HideAndDontSave:
return scene == SceneHandler.AssetScene;
case SceneFilter.ActivelyLoaded:
return scene != SceneHandler.DontDestroyScene && scene != SceneHandler.AssetScene;
default:
return false;
}
}
internal static List<object> UnityObjectSearch(string input, string customTypeInput, SearchContext context,
ChildFilter childFilter, SceneFilter sceneFilter)
{
var results = new List<object>();
Type searchType = null;
switch (context)
{
@ -91,13 +111,15 @@ namespace UnityExplorer.Core.Search
if (string.IsNullOrEmpty(customTypeInput))
{
ExplorerCore.LogWarning("Custom Type input must not be empty!");
return null;
return results;
}
if (ReflectionUtility.GetTypeByName(customTypeInput) is Type customType)
{
if (typeof(UnityEngine.Object).IsAssignableFrom(customType))
searchType = customType;
else
ExplorerCore.LogWarning($"Custom type '{customType.FullName}' is not assignable from UnityEngine.Object!");
}
else
ExplorerCore.LogWarning($"Could not find a type by the name '{customTypeInput}'!");
break;
@ -106,11 +128,11 @@ namespace UnityExplorer.Core.Search
searchType = typeof(UnityEngine.Object); break;
}
if (searchType == null)
return null;
return results;
var allObjects = RuntimeProvider.Instance.FindObjectsOfTypeAll(searchType);
var results = new List<object>();
// perform filter comparers
@ -121,20 +143,11 @@ namespace UnityExplorer.Core.Search
bool canGetGameObject = (sceneFilter != SceneFilter.Any || childFilter != ChildFilter.Any)
&& (context == SearchContext.GameObject || typeof(Component).IsAssignableFrom(searchType));
string sceneFilterString = null;
if (!canGetGameObject)
{
if (context != SearchContext.UnityObject && (sceneFilter != SceneFilter.Any || childFilter != ChildFilter.Any))
ExplorerCore.LogWarning($"Type '{searchType}' cannot have Scene or Child filters applied to it");
}
else
{
if (sceneFilter == SceneFilter.DontDestroyOnLoad)
sceneFilterString = "DontDestroyOnLoad";
else if (sceneFilter == SceneFilter.Explicit)
//sceneFilterString = SearchPage.Instance.m_sceneDropdown.options[SearchPage.Instance.m_sceneDropdown.value].text;
sceneFilterString = sceneName;
}
foreach (var obj in allObjects)
{
@ -157,12 +170,9 @@ namespace UnityExplorer.Core.Search
switch (context)
{
case SearchContext.GameObject:
if (go.scene.name != sceneFilterString)
continue;
break;
case SearchContext.Custom:
case SearchContext.Component:
if (go.scene.name != sceneFilterString)
if (!Filter(go.scene, sceneFilter))
continue;
break;
}
@ -184,7 +194,7 @@ namespace UnityExplorer.Core.Search
results.Add(obj);
}
return results.ToArray();
return results;
}
}
}