You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
142 lines
5.1 KiB
142 lines
5.1 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.Linq; |
|
using UnityEngine; |
|
using UnityEngine.UIElements; |
|
using UnityEditor.ShaderGraph.Drawing; |
|
using UnityEditor.Searcher; |
|
|
|
namespace UnityEditor.ShaderGraph |
|
{ |
|
public class SearchWindowAdapter : SearcherAdapter |
|
{ |
|
readonly VisualTreeAsset m_DefaultItemTemplate; |
|
public override bool HasDetailsPanel => false; |
|
|
|
public SearchWindowAdapter(string title) : base(title) |
|
{ |
|
m_DefaultItemTemplate = Resources.Load<VisualTreeAsset>("SearcherItem"); |
|
} |
|
|
|
private SearcherItem GetFirstChildItem(SearcherItem item) |
|
{ |
|
if (item.Children.Count != 0) |
|
{ |
|
SearcherItem childIterator = null; |
|
// Discard searcher item for selection if it is a category, get next best child item from it instead |
|
// There is no utility in selecting category headers/titles, only the leaf entries |
|
childIterator = item.Children[0]; |
|
while (childIterator != null && childIterator.Children.Count != 0) |
|
{ |
|
childIterator = childIterator.Children[0]; |
|
} |
|
|
|
item = childIterator; |
|
} |
|
|
|
return item; |
|
} |
|
|
|
private int ComputeScoreForMatch(string[] queryTerms, SearcherItem matchItem) |
|
{ |
|
// Scoring Criteria: |
|
// - Exact name match is most preferred. |
|
// - Partial name match is next. |
|
// - Exact synonym match is next. |
|
// - Partial synonym match is next. |
|
// - No match is last. |
|
int score = 0; |
|
|
|
// Split the entry name so that we can remove suffix that looks like "Clamp: In(4)" |
|
var nameSansSuffix = matchItem.Name.Split(':').First(); |
|
|
|
int nameCharactersMatched = 0; |
|
|
|
foreach (var queryWord in queryTerms) |
|
{ |
|
if (nameSansSuffix.Contains(queryWord, StringComparison.OrdinalIgnoreCase)) |
|
{ |
|
score += 100000; |
|
nameCharactersMatched += queryWord.Length; |
|
} |
|
|
|
// Check for synonym matches -- give a bonus to each |
|
if (matchItem.Synonyms != null) |
|
{ |
|
foreach (var syn in matchItem.Synonyms) |
|
{ |
|
if (syn.Equals(queryWord, StringComparison.OrdinalIgnoreCase)) |
|
{ |
|
score += 10000; |
|
} |
|
else if (syn.Contains(queryWord, StringComparison.OrdinalIgnoreCase)) |
|
{ |
|
score += 1000; |
|
score -= (syn.Length - queryWord.Length); |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (nameCharactersMatched > 0) |
|
{ |
|
int unmatchedCharacters = (nameSansSuffix.Length - nameCharactersMatched); |
|
score -= unmatchedCharacters; |
|
} |
|
|
|
return score; |
|
} |
|
|
|
public override SearcherItem OnSearchResultsFilter(IEnumerable<SearcherItem> searchResults, string searchQuery) |
|
{ |
|
if (searchQuery.Length == 0) |
|
return GetFirstChildItem(searchResults.FirstOrDefault()); |
|
|
|
// Sort results by length so that shorter length results are prioritized |
|
// prevents entries with short names getting stuck at end of list after entries with longer names when both contain the same word |
|
searchResults = searchResults.OrderBy(x => x.Name.Length).ToList(); |
|
|
|
var bestMatch = GetFirstChildItem(searchResults.FirstOrDefault()); |
|
int bestScore = 0; |
|
List<int> visitedItems = new List<int>(); |
|
var queryTerms = searchQuery.Split(' '); |
|
foreach (var result in searchResults) |
|
{ |
|
var currentItem = GetFirstChildItem(result); |
|
|
|
if (currentItem.Parent != null) |
|
{ |
|
SearcherItem parentItem = currentItem.Parent; |
|
foreach (var matchItem in parentItem.Children) |
|
{ |
|
if (visitedItems.Contains(matchItem.Id)) |
|
continue; |
|
|
|
int currentScore = ComputeScoreForMatch(queryTerms, matchItem); |
|
if (currentScore > bestScore) |
|
{ |
|
bestScore = currentScore; |
|
bestMatch = matchItem; |
|
} |
|
|
|
visitedItems.Add(matchItem.Id); |
|
} |
|
} |
|
} |
|
|
|
return bestMatch; |
|
} |
|
} |
|
|
|
internal class SearchNodeItem : SearcherItem |
|
{ |
|
public NodeEntry NodeGUID; |
|
|
|
public SearchNodeItem(string name, NodeEntry nodeGUID, string[] synonyms, |
|
string help = " ", List<SearchNodeItem> children = null) : base(name) |
|
{ |
|
NodeGUID = nodeGUID; |
|
Synonyms = synonyms; |
|
} |
|
} |
|
}
|
|
|