A game about forced loneliness, made by TACStudios
at master 5.2 kB view raw
1using System; 2using System.Collections.Generic; 3using System.Linq; 4using UnityEngine; 5using UnityEngine.UIElements; 6using UnityEditor.ShaderGraph.Drawing; 7using UnityEditor.Searcher; 8 9namespace UnityEditor.ShaderGraph 10{ 11 public class SearchWindowAdapter : SearcherAdapter 12 { 13 readonly VisualTreeAsset m_DefaultItemTemplate; 14 public override bool HasDetailsPanel => false; 15 16 public SearchWindowAdapter(string title) : base(title) 17 { 18 m_DefaultItemTemplate = Resources.Load<VisualTreeAsset>("SearcherItem"); 19 } 20 21 private SearcherItem GetFirstChildItem(SearcherItem item) 22 { 23 if (item.Children.Count != 0) 24 { 25 SearcherItem childIterator = null; 26 // Discard searcher item for selection if it is a category, get next best child item from it instead 27 // There is no utility in selecting category headers/titles, only the leaf entries 28 childIterator = item.Children[0]; 29 while (childIterator != null && childIterator.Children.Count != 0) 30 { 31 childIterator = childIterator.Children[0]; 32 } 33 34 item = childIterator; 35 } 36 37 return item; 38 } 39 40 private int ComputeScoreForMatch(string[] queryTerms, SearcherItem matchItem) 41 { 42 // Scoring Criteria: 43 // - Exact name match is most preferred. 44 // - Partial name match is next. 45 // - Exact synonym match is next. 46 // - Partial synonym match is next. 47 // - No match is last. 48 int score = 0; 49 50 // Split the entry name so that we can remove suffix that looks like "Clamp: In(4)" 51 var nameSansSuffix = matchItem.Name.Split(':').First(); 52 53 int nameCharactersMatched = 0; 54 55 foreach (var queryWord in queryTerms) 56 { 57 if (nameSansSuffix.Contains(queryWord, StringComparison.OrdinalIgnoreCase)) 58 { 59 score += 100000; 60 nameCharactersMatched += queryWord.Length; 61 } 62 63 // Check for synonym matches -- give a bonus to each 64 if (matchItem.Synonyms != null) 65 { 66 foreach (var syn in matchItem.Synonyms) 67 { 68 if (syn.Equals(queryWord, StringComparison.OrdinalIgnoreCase)) 69 { 70 score += 10000; 71 } 72 else if (syn.Contains(queryWord, StringComparison.OrdinalIgnoreCase)) 73 { 74 score += 1000; 75 score -= (syn.Length - queryWord.Length); 76 } 77 } 78 } 79 } 80 81 if (nameCharactersMatched > 0) 82 { 83 int unmatchedCharacters = (nameSansSuffix.Length - nameCharactersMatched); 84 score -= unmatchedCharacters; 85 } 86 87 return score; 88 } 89 90 public override SearcherItem OnSearchResultsFilter(IEnumerable<SearcherItem> searchResults, string searchQuery) 91 { 92 if (searchQuery.Length == 0) 93 return GetFirstChildItem(searchResults.FirstOrDefault()); 94 95 // Sort results by length so that shorter length results are prioritized 96 // prevents entries with short names getting stuck at end of list after entries with longer names when both contain the same word 97 searchResults = searchResults.OrderBy(x => x.Name.Length).ToList(); 98 99 var bestMatch = GetFirstChildItem(searchResults.FirstOrDefault()); 100 int bestScore = 0; 101 List<int> visitedItems = new List<int>(); 102 var queryTerms = searchQuery.Split(' '); 103 foreach (var result in searchResults) 104 { 105 var currentItem = GetFirstChildItem(result); 106 107 if (currentItem.Parent != null) 108 { 109 SearcherItem parentItem = currentItem.Parent; 110 foreach (var matchItem in parentItem.Children) 111 { 112 if (visitedItems.Contains(matchItem.Id)) 113 continue; 114 115 int currentScore = ComputeScoreForMatch(queryTerms, matchItem); 116 if (currentScore > bestScore) 117 { 118 bestScore = currentScore; 119 bestMatch = matchItem; 120 } 121 122 visitedItems.Add(matchItem.Id); 123 } 124 } 125 } 126 127 return bestMatch; 128 } 129 } 130 131 internal class SearchNodeItem : SearcherItem 132 { 133 public NodeEntry NodeGUID; 134 135 public SearchNodeItem(string name, NodeEntry nodeGUID, string[] synonyms, 136 string help = " ", List<SearchNodeItem> children = null) : base(name) 137 { 138 NodeGUID = nodeGUID; 139 Synonyms = synonyms; 140 } 141 } 142}