143 lines
5.1 KiB
C#
143 lines
5.1 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|