#if UNITY_EDITOR using MonKey.Extensions; using MonKey.Internal; using MonKey.Settings.Internal; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading; using UnityEditor; using UnityEngine; using Component = UnityEngine.Component; using Object = UnityEngine.Object; using ThreadPriority = System.Threading.ThreadPriority; namespace MonKey.Editor.Internal { [InitializeOnLoad] public class CommandManager : EditorSingleton, IMonKeySingleton { static CommandManager() { SessionID = "MC_CommandManager"; } public static bool ReadyForPlayMode; public static string CommandHistory = "Command History"; #region SINGLETON private static CommandManager instance; #endregion #region REGISTERING public bool IsLoading { get; private set; } private readonly List infoToAdd = new List(); public string CurrentAssemblyLoading; public string CurrentClassLoading; public int AssemblyAnalyzed; public int TotalAssemblies; private readonly int amountSleepThreshold = 10; public bool onlyScanSpecified; private string[] assembliesToExclude; private string[] nameSpacesToExclude; public event Action OnCommandLoadingDone; #endregion public const int MaxCommandShown = 15; private const int CommandFoundCountForAliases = 15; private readonly CommandInfo defaultInfo = new CommandInfo() { Action = null, CommandHelp = "No Command Found", CommandName = "No Command Found", CommandOrder = 0 }; internal readonly Dictionary CategoriesByName = new Dictionary(); internal readonly List BaseCategories = new List(); internal readonly Dictionary CommandsByName = new Dictionary(); public Dictionary WordAliases = new Dictionary(); public int CommandCount => CommandsByName.Count; public void PostInstanceCreation() { MonKeyInternalSettings.FindInstance(); MonkeyStyle.FindInstance(); MonkeyLocalizationFile.FindInstance(); Instance.OnEnable(); /*f (CommandConsoleWindow.CurrentPanel) CommandConsoleWindow.CurrentPanel.CloseOrSetInactive();*/ } public void OnEnable() { InitAliases(); AutoCompleteManager.InitializeManager(); MonkeyEditorUtils.EditorUpdatePlug(this); MonKeySelectionUtils.PluginImporter(); RetrieveAllCommands(); } private void InitAliases() { WordAliases = new Dictionary { { "Select", "Find" }, { "Find", "Select" }, { "Create", "New" }, { "New", "Create" }, { "Instantiate", "New" }, { "Prefab", "Instance" }, { "Place", "Move" }, { "Raycast", "Collision" }, { "Search", "Find" }, { "Copy", "Duplicate" }, { "Duplicate", "Copy" }, { "Clone", "Duplicate" }, { "UnSelect", "Clear" }, { "Deselect", "Clear" } }; } public static void RetrieveAll() { if (!instance) FindInstance(); if (!EditorApplication.isPlayingOrWillChangePlaymode && instance) { if (DebugLog) Debug.Log("Retrieving on did reload"); instance.OnEnable(); } } private Thread commandsRetrieving; public void RetrieveAllCommands(bool force = false) { /* if (!instance) FindInstance();*/ try { if (DebugLog) Debug.Log("Retrieving"); if (!force) { if (CommandCount > 0) { if (DebugLog) Debug.Log("Canceled because some commands already found"); return; } if (commandsRetrieving != null) { if (commandsRetrieving.IsAlive) { if (DebugLog) Debug.Log("Canceled because thread is alive"); return; } } } if (DebugLog) Debug.Log("NOT CANCELED"); EditorApplication.update -= AddAllFoundCommand; EditorApplication.update += AddAllFoundCommand; HotKeysManager.Reset(); lock (infoToAdd) { infoToAdd.Clear(); } onlyScanSpecified = MonKeyInternalSettings.Instance.OnlyScanSpecified; assembliesToExclude = MonKeyInternalSettings.Instance.ExcludedAssemblies.Split(';'); nameSpacesToExclude = MonKeyInternalSettings.Instance.ExcludedNameSpaces.Split(';'); CommandsByName.Clear(); TypeManager.Clear(); IsLoading = true; if (commandsRetrieving != null && commandsRetrieving.ThreadState == ThreadState.Running) commandsRetrieving?.Abort(); commandsRetrieving = new Thread(CheckCommandsForAllAssemblies) { IsBackground = true, Priority = ThreadPriority.Normal, }; commandsRetrieving.Start(); } catch (Exception e) { // Unity is not ready yet for instance creation Debug.Log("MonKey error: \n" + e); return; } } #region REGISTERING private void AddAllFoundCommand() { if (!IsLoading) { lock (infoToAdd) { if (infoToAdd.Count > 0) { foreach (var info in infoToAdd) { AddCommand(info.CommandName, info); } } infoToAdd.Clear(); OnCommandLoadingDone?.Invoke(); BaseCategories.Sort(); CommandCategory history = new CommandCategory(); history.CategoryName = CommandHistory; if (!BaseCategories.Contains(history.CategoryName)) BaseCategories.Insert(0, history.CategoryName); if (!CategoriesByName.ContainsKey(history.CategoryName)) CategoriesByName.Add(history.CategoryName, history); EditorApplication.update -= AddAllFoundCommand; } } else { lock (infoToAdd) { foreach (var info in infoToAdd) { AddCommand(info.CommandName, info); } infoToAdd.Clear(); } } } private void AddCommand(string name, CommandInfo action) { if (!CommandsByName.ContainsKey(name)) { if (DebugLog) { Debug.Log("Adding new command: " + name); } CommandsByName.Add(name, action); if (action.HasQuickName) { if (!CommandsByName.ContainsKey(action.CommandQuickName)) { CommandsByName.Add(action.CommandQuickName, action); } else if (CommandsByName[action.CommandQuickName].CommandOrder > action.CommandOrder) { CommandsByName[action.CommandQuickName] = action; } } if (action.HasHotKeys) { HotKeysManager.RegisterCommandHotKey(action); } } } private void CheckCommandsForAllAssemblies() { try { IEnumerable selectedAssemblies = AppDomain.CurrentDomain.GetAssemblies() .Where(_ => { int i = 0; foreach (var assemblyPrefix in assembliesToExclude) { if (assemblyPrefix.IsNullOrEmpty()) { continue; } if (_.GetName().Name.Contains(assemblyPrefix)) { if (onlyScanSpecified) { return true; } else { if (DebugLog) { Debug.Log("Assembly Excluded: " + _.FullName); } return false; } } if (i > amountSleepThreshold) { Thread.Sleep(0); i = 0; } i++; } if (DebugLog) { Debug.Log("Assembly Added: " + _.FullName); } if (onlyScanSpecified) { return false; } else return true; }).OrderByDescending(_ => _ == Assembly.GetExecutingAssembly()); var assemblies = selectedAssemblies.ToArray(); assemblies = assemblies.OrderByDescending(_ => _.FullName == "Assembly-CSharp").ToArray(); TotalAssemblies = assemblies.Length; AssemblyAnalyzed = 0; CheckCommandsForAssemblies(assemblies); } catch (Exception e) { Debug.LogError("MonKey: An Exception (" + e + ") \n \n was raised when reading commands "); // RetrieveAllCommands(true); } } private void CheckCommandsForAssemblies(IEnumerable selectedAssemblies) { foreach (var assembly in selectedAssemblies) { CurrentAssemblyLoading = assembly.GetName().Name; if (DebugLog) { Debug.Log("Checking Assembly ".Bold() + CurrentAssemblyLoading); } try { CheckCommandsFromAssembly(assembly); } catch (Exception e) { Debug.LogError("MonKey: An Exception (" + e + ") \n \n was raised when reading commands " + "from assembly '" + assembly + "'"); // RetrieveAllCommands(true); } lock (this) { AssemblyAnalyzed++; } } if (DebugLog) { Debug.Log("Done!"); } IsLoading = false; } private void CheckCommandsFromAssembly(Assembly assembly) { int i = 0; IEnumerable types = assembly.GetTypes().Where(_ => { foreach (var nameSpace in nameSpacesToExclude) { if (nameSpace.IsNullOrEmpty()) { continue; } if (_.Namespace.Contains(nameSpace)) { return false; } } return true; }); // int prevCommandCount = CommandCount; foreach (var type in types) { CurrentClassLoading = type.Name; if (DebugLog) { Debug.Log("Checking Type :" + CurrentClassLoading); } try { RegisterUnityType(type); RegisterCommandsFromType(type); } catch (Exception e) { Debug.LogError("MonKey: An Exception \n(" + e + ") \n \n was raised when reading commands " + "from type '" + type + "'"); // RetrieveAllCommands(true); } i++; if (i > amountSleepThreshold) { i = 0; Thread.Sleep(0); } } // if(CommandCount>prevCommandCount) // Debug.Log(assembly.FullName); } private static void RegisterUnityType(Type type) { lock (TypeManager.AllEditorTypes) { if (type.FullName == null) { return; } if (type.FullName.Contains("UnityEditor") || type.IsSubclassOf(typeof(UnityEditor.Editor)) || type.IsSubclassOf(typeof(EditorWindow))) { if (!TypeManager.AllEditorTypes.ContainsKey(type.FullName)) { TypeManager.AllEditorTypes.Add(type.FullName, type); } return; } } lock (TypeManager.AllMonoBehaviorObjectTypes) { if (type.IsSubclassOf(typeof(MonoBehaviour))) { if (type.FullName != null && !TypeManager.AllMonoBehaviorObjectTypes.ContainsKey(type.FullName)) { TypeManager.AllMonoBehaviorObjectTypes.Add(type.FullName, type); } return; } } lock (TypeManager.AllScriptableObjectTypes) { if (type.IsSubclassOf(typeof(ScriptableObject))) { if (type.FullName != null && !TypeManager.AllScriptableObjectTypes.ContainsKey(type.FullName)) { TypeManager.AllScriptableObjectTypes.Add(type.FullName, type); } return; } } lock (TypeManager.AllComponentObjectTypes) { if (type.IsSubclassOf(typeof(Component))) { if (type.FullName != null && !TypeManager.AllComponentObjectTypes.ContainsKey(type.FullName)) { TypeManager.AllComponentObjectTypes.Add(type.FullName, type); } return; } } lock (TypeManager.AllObjectsTypes) { if (type.IsSubclassOf(typeof(Object))) { if (type.FullName != null && !TypeManager.AllObjectsTypes.ContainsKey(type.FullName)) { TypeManager.AllObjectsTypes.Add(type.FullName, type); } } } } public void RegisterCommandsFromType(Type type) { foreach (var methodInfo in type.GetMethods(BindingFlags.Public | BindingFlags.Default | BindingFlags.NonPublic | BindingFlags.Static)) { try { var quickCommandAttributes = methodInfo.GetCustomAttributes(typeof(Command), true); if (quickCommandAttributes.Length > 0) { foreach (var commandAttribute in (methodInfo.GetCustomAttributes(typeof(Command), true))) { if (DebugLog) { Debug.Log("Console Command Found! :".Bold().Colored(Color.green) + methodInfo.Name); } CheckCommandStatuses(type, commandAttribute, methodInfo, false); } } else { foreach (var commandAttribute in methodInfo.GetCustomAttributes(typeof(MenuItem), true)) { if (DebugLog) { Debug.Log("Menu Item Found! :".Bold().Colored(Color.green) + methodInfo.Name); } MenuItem item = (MenuItem)commandAttribute; if (item.validate) { continue; } if (methodInfo.GetCustomAttributes(typeof(MenuItemCommandLink), true).Length > 0) { continue; } CheckCommandStatuses(type, commandAttribute, methodInfo, true); } } } catch (Exception e) { Debug.LogErrorFormat("MonKey: An Exception was raised when " + "trying to retrieve a command " + "from method {0} in type {1}, assemble {2}: {3}", methodInfo.Name, type.Name, type.Assembly.GetName().Name, e); // RetrieveAllCommands(true); } } } private void CheckCommandStatuses(Type actionProvider, object commandAttribute, MethodInfo methodInfo, bool menuItem) { Command command = commandAttribute as Command; var validationName = CheckValidationMethod(actionProvider , methodInfo, command, out var validationDelegate); var hotKey = FindHotKey(methodInfo, command); var commandParamsInfos = FindParameters(methodInfo); if (command == null && commandParamsInfos != null && commandParamsInfos.Count > 0) { return; } AddCommandInfo(methodInfo, validationDelegate, command, validationName, hotKey, commandParamsInfos); } private void AddCommandInfo(MethodInfo methodInfo, MethodInfo validationDelegate, Command command, string validationMessage, KeyCombination hotKey, List paramInfos) { lock (infoToAdd) { if (DebugLog) { Debug.Log("Adding Command HotKeyInfo"); } string menuItemName = methodInfo.Name.NicifyVariableName(); if (command == null) { object[] items = methodInfo.GetCustomAttributes(typeof(MenuItem), false); if (items.Length > 0) { MenuItem item = (MenuItem)items[0]; int startOfName = item.menuItem.LastIndexOf("/", StringComparison.Ordinal); int endOfName = hotKey != null ? item.menuItem.LastIndexOf(" ", StringComparison.Ordinal) - 1 : item.menuItem.Length - 1; menuItemName = item.menuItem.Substring(startOfName + 1, endOfName - startOfName); } } CommandInfo info = new CommandInfo() { Action = methodInfo, ValidationMethod = validationDelegate, AlwaysShow = command != null && command.AlwaysShow, CommandHelp = command?.Help, CommandName = (command != null) ? command.Name : menuItemName, CommandQuickName = (command != null) ? command.QuickName : null, CommandOrder = (command != null) ? command.Order : Int32.MaxValue, CommandValidationMessage = validationMessage, HotKey = hotKey, IgnoreHotKeyConflict = command != null && command.IgnoreHotKeyConflict, CommandParameterInfo = paramInfos, IsMenuItem = command == null, Category = command == null ? "Unity Menus" : command.Category }; infoToAdd.Add(info); AddCategories(info); } } private void AddCategories(CommandInfo info) { string[] categories = info.Category.Split('/'); string path = ""; for (int i = 0; i < categories.Length; i++) { path += categories[i]; if (!CategoriesByName.ContainsKey(path)) { CommandCategory cat = new CommandCategory(); cat.CategoryName = categories[i]; if (i > 0) { cat.ParentCategoryName = path.Replace("/" + categories[i], ""); } else { BaseCategories.Add(path); } CategoriesByName.Add(path, cat); } else if (categories.Length > 1 && i < categories.Length - 1) { CommandCategory main = CategoriesByName[path]; main.AddSubCategory(path + "/" + categories[i + 1]); } path += "/"; } CategoriesByName[info.Category].AddCommandName(info.CommandName); } private KeyCombination FindHotKey(MethodInfo methodInfo, Command command) { if (DebugLog) { Debug.Log("Finding Hot Keys"); } var menuItemAttributes = methodInfo.GetCustomAttributes(typeof(MenuItem), true); if (command != null && !command.MenuItemLink.IsNullOrEmpty()) { MethodInfo overrideInfo = null; if (command.MenuItemLinkTypeOwner == null) { if (methodInfo.DeclaringType != null) { overrideInfo = methodInfo.DeclaringType.GetMethod( command.MenuItemLink, BindingFlags.Static | BindingFlags.Default | BindingFlags.NonPublic | BindingFlags.Public); } } else { Type linkOwner = null; int thresh = 0; foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) { try { foreach (Type t in a.GetTypes()) { if (t.Name == command.MenuItemLinkTypeOwner) { linkOwner = t; } } if (thresh > amountSleepThreshold) { thresh = 0; Thread.Sleep(0); } } catch (Exception) { // potential reflection errors will be handlded elsewhere } thresh++; } if (linkOwner != null) { overrideInfo = linkOwner.GetMethod( command.MenuItemLink, BindingFlags.Static | BindingFlags.Default | BindingFlags.NonPublic | BindingFlags.Public); } } if (overrideInfo != null) { menuItemAttributes = overrideInfo.GetCustomAttributes(typeof(MenuItem), true); } } if (menuItemAttributes.Length > 0) { if (DebugLog) { Debug.Log("Finding Menu Item Hot Keys"); } var item = menuItemAttributes[0] as MenuItem; if (item != null) { int lastIndex = item.menuItem.LastIndexOf(' '); if (lastIndex == item.menuItem.Length - 1) { lastIndex = item.menuItem.Substring(0, item.menuItem.Length - 1) .LastIndexOf(' '); } if (lastIndex == -1) { return null; } var hotKey = item.menuItem .Substring(item.menuItem.LastIndexOf(' ')); hotKey = hotKey.Replace(" ", ""); bool startsWithSpecialCharacter = hotKey.StartsWith(KeyCombination.KeySymbol.ToString()); if (!startsWithSpecialCharacter) { foreach (var modifierKeysAlias in KeyCombination.ModifierKeysAliases.Keys) { if (hotKey.StartsWith(modifierKeysAlias)) { startsWithSpecialCharacter = true; break; } } } if (startsWithSpecialCharacter) { if (DebugLog) { Debug.Log("Making Menu Hot Key Readable"); } return new KeyCombination(hotKey); } return null; } } return null; } private static string CheckValidationMethod(Type actionProvider, MethodInfo methodInfo, Command command, out MethodInfo validationDelegate) { if (DebugLog) { Debug.Log("Finding Validation Method"); } string validationHelp = ""; MethodInfo validation = null; if (command != null && (!command.ValidationMethodName.IsNullOrEmpty() || command.DefaultValidation != DefaultValidation.NONE)) { if (command.ValidationMethodName.IsNullOrEmpty()) { validation = ValidationUtilities.GetValidationMethod(command.DefaultValidation); } else { string validationMethodName = command.ValidationMethodName; validation = actionProvider.GetMethod(validationMethodName, BindingFlags.Public | BindingFlags.Default | BindingFlags.NonPublic | BindingFlags.Static); if (validation == null) { Debug.LogWarningFormat("The command '{0}' was associated with " + "a validation method named '{1}', " + "but no static method of such name could be found", methodInfo.Name, command.ValidationMethodName); } } } else { var menuItemAttributes = methodInfo.GetCustomAttributes(typeof(MenuItem), true); if (menuItemAttributes.Length > 0) { MenuItem item = (MenuItem)menuItemAttributes[0]; string menuItemName = item.menuItem; foreach (var validationMethod in actionProvider.GetMethods(BindingFlags.Public | BindingFlags.Default | BindingFlags.NonPublic | BindingFlags.Static)) { var attrbs = validationMethod.GetCustomAttributes(typeof(MenuItem), true); if (attrbs.Length > 0) { MenuItem potentialValidation = (MenuItem)attrbs[0]; if (potentialValidation.validate && potentialValidation.menuItem == menuItemName) { validation = validationMethod; break; } } } } } validationDelegate = validation; if (validation != null) { var validations = validation.GetCustomAttributes(typeof(CommandValidation) , true); if (validations.Length > 0) { var quickCommandValidation = validations[0] as CommandValidation; if (quickCommandValidation != null) { validationHelp = quickCommandValidation .InvalidCommandMessage; } } } return validationHelp; } private static List FindParameters(MethodInfo methodInfo) { if (DebugLog) { Debug.LogFormat("Checking parameters for method {0}", methodInfo.Name); } ParameterInfo[] parameterInfos = methodInfo.GetParameters(); CommandParameter[] parameterAttributes = (CommandParameter[])methodInfo.GetCustomAttributes(typeof(CommandParameter), false); List commandInfos = new List(parameterInfos.Length); for (int i = 0; i < parameterInfos.Length; i++) { commandInfos.Add(null); } for (int i = 0; i < parameterInfos.Length; i++) { CommandParameter[] parameterCommandAttributes = (CommandParameter[])parameterInfos[i].GetCustomAttributes(typeof(CommandParameter), false); if (parameterCommandAttributes.Length > 0) { parameterCommandAttributes[0].Order = i; AddParameterInfo(methodInfo, parameterCommandAttributes[0], parameterInfos, commandInfos); } } foreach (var attribute in parameterAttributes) { AddParameterInfo(methodInfo, attribute, parameterInfos, commandInfos); } for (int i = 0; i < commandInfos.Count; i++) { if (commandInfos[i] == null) { commandInfos[i] = new CommandParameterInfo(parameterInfos[i], i); } } return commandInfos; } private static void AddParameterInfo(MethodInfo methodInfo, CommandParameter attribute, ParameterInfo[] parameterInfos, List commandInfos) { if (DebugLog) { Debug.LogFormat("Checking parameter info for method {0}", methodInfo.Name); } if (attribute == null || methodInfo == null) { Debug.LogWarning("MonKey | Error when parsing a command : no attribute or method info found"); return; } if (parameterInfos == null || attribute.Order >= parameterInfos.Length) { Debug.LogWarningFormat("Monkey Commander Warning:" + " A command Parameter for the Command '{0}'" + " was associated with the order '{1}', " + "but the method does not have that many" + " parameters", methodInfo.Name, attribute.Order); return; } MethodInfo autoCompleteMethod = null; if (attribute.HasAutoCompleteMethod) { if (methodInfo.DeclaringType != null) { autoCompleteMethod = methodInfo.DeclaringType.GetMethod(attribute.AutoCompleteMethodName, BindingFlags.Public | BindingFlags.Default | BindingFlags.NonPublic | BindingFlags.Static); } if (autoCompleteMethod != null && (!autoCompleteMethod.ReturnType.IsSubclassOf( typeof(GenericCommandParameterAutoComplete)) && autoCompleteMethod.ReturnType != typeof(GenericCommandParameterAutoComplete) || autoCompleteMethod.GetParameters().Length != 0)) { autoCompleteMethod = null; } if (autoCompleteMethod == null) { Debug.LogWarningFormat("Monkey Commander Warning:A parameter for the " + "command '{0}' was linked to an auto complete method named '{1}'," + " but no static method of such name could be found, " + "or the method does not return a CommandParameterAutoComplete", methodInfo.Name, attribute.AutoCompleteMethodName); } } MethodInfo defaultValueMethod = null; if (attribute.HasDefaultValueMethod) { if (methodInfo.DeclaringType != null) { defaultValueMethod = methodInfo.DeclaringType.GetMethod(attribute.DefaultValueMethod, BindingFlags.Public | BindingFlags.Default | BindingFlags.NonPublic | BindingFlags.Static); } if (defaultValueMethod != null) { //default values for array members must be done differently /*if (parameterInfos[attribute.Order].ParameterType.IsArray) { if(defaultValueMethod.ReturnType != parameterInfos[attribute.Order].ParameterType.GetElementType()) defaultValueMethod = null; }else*/ if (defaultValueMethod.ReturnType != parameterInfos[attribute.Order].ParameterType || defaultValueMethod.GetParameters().Length != 0) { defaultValueMethod = null; } } if (defaultValueMethod == null) { Debug.LogWarningFormat("Monkey Commander Warning:A parameter for the " + "command '{0}' was linked to a default value method named '{1}'," + " but no static method of such name could be found, " + "or the method does not return the same type than the specified parameter", methodInfo.Name, attribute.DefaultValueMethod); } } CommandParameterInfo info = new CommandParameterInfo( attribute, parameterInfos[attribute.Order], autoCompleteMethod, defaultValueMethod); commandInfos[attribute.Order] = info; } #endregion #region COMMAND SEARCH public CommandInfo GetCommand(string name) { return CommandsByName[name]; } public IEnumerable CommandNames { get { return CommandsByName.Keys; } } public CommandInfo GetCommandInfo(string name) { if (CommandsByName.ContainsKey(name)) { return CommandsByName[name]; } return null; } public bool IsCommandAuthorized(CommandInfo info) { if (!MonKeyInternalSettings.Instance.IncludeMenuItems && info.IsMenuItem) { return false; } if (info.IsMenuItem && MonKeyInternalSettings.Instance.IncludeOnlyMenuItemsWithHotKeys && !info.HasHotKeys) { return false; } return true; } public CommandInfo BestMatchingAction(params string[] searchTerms) { if (searchTerms.Length > 0 && searchTerms.Any(_ => !_.IsNullOrEmpty())) { return CommandsByName[StringExt.OrderStringsBySearchScore(CommandsByName.Keys, false, searchTerms) .First(_ => IsCommandAuthorized(CommandsByName[_]))]; } return defaultInfo; } public IEnumerable ActionByMatch(params string[] searchTerms) { if (DebugLog) { Debug.Log("Searching for actions.. " + EditorApplication.timeSinceStartup); } if (searchTerms.Length > 0 && searchTerms.Any(_ => !_.IsNullOrEmpty())) { List foundCommands = new List(CommandsByName.Count); IEnumerable firstSearch; //not dependent on the option right now (performance satisfying) /* if (MonKeyInternalSettings.Instance.UseAdvancedFuzzySearch) {*/ firstSearch = CommandNames.Where(_ => { if (!_.ToLower().Contains(searchTerms[0])) { var x = StringExt.MatchResultSet(new List { _.ToLower() }, searchTerms[0]); return x.Count > 0; } return true; }); firstSearch = CommandNames; firstSearch = StringExt.OrderStringsBySearchScore(firstSearch, true, searchTerms) .ThenBy(_ => !CommandsByName[_].HasQuickName) .ThenBy(_ => CommandsByName[_].CommandOrder); /* } else { firstSearch = StringExt.OrderStringsBySearchScore(CommandsByName.Keys, false, searchTerms) .ThenBy(_ => !CommandsByName[_].HasQuickName) .ThenBy(_ => CommandsByName[_].CommandOrder); }*/ foreach (var name in firstSearch) { if (!foundCommands.Contains(CommandsByName[name]) && IsCommandAuthorized(CommandsByName[name])) { foundCommands.Add(CommandsByName[name]); } } if (DebugLog) { Debug.Log("Search done! " + EditorApplication.timeSinceStartup); } FindByAliases(searchTerms, foundCommands); if (foundCommands.Count > 0) { if (MonKeyInternalSettings.Instance.PutInvalidCommandAtEndOfSearch) { return foundCommands.OrderByDescending(_ => !_.HasValidation || _.IsValid); } return foundCommands.Take(MaxCommandShown); } } return new CommandInfo[0]; } private void FindByAliases(string[] searchTerms, List foundCommands) { if (foundCommands.Count < CommandFoundCountForAliases) { List orderedAliases = StringExt.OrderStringsBySearchScore(WordAliases.Keys, false, searchTerms).ToList(); if (orderedAliases.Any()) { foreach (var name in StringExt .OrderStringsBySearchScore(CommandsByName.Keys, false, WordAliases[orderedAliases.ElementAt(0)]) .ThenBy(_ => CommandsByName[_].CommandOrder)) { if (!foundCommands.Contains(CommandsByName[name]) && IsCommandAuthorized(CommandsByName[name])) { foundCommands.Add(CommandsByName[name]); } } } } } public IEnumerable AlwaysShownCommands { get { return CommandsByName.Values .Where(_ => _.AlwaysShow) .Distinct() .OrderBy(_ => _.CommandOrder) .ThenByDescending(_ => !_.HasValidation || _.IsValid); } } #endregion } /*private class Test { public void GenerateAndSortAutoComplete(string searchTerms) { typesOrdered = objectsPerName.Where(type => { if (!type.Value.Name.ToLower().Contains(searchTerms)) { //Use Fuzzy Match instead default one var x = StringExt.MatchResultSet(new List { type.Value.Name.NicifyVariableName().ToLower() }, searchTerms); return x.Count > 0; } return true; }) .Convert(_ => _.Value) .OrderByDescending(type => type.Name.NicifyVariableName().ToLower().WordSearchScore(false, searchTerms)) .Take(MaxPick) .ToArray(); } }*/ } #endif