using QFSW.QC.Comparators; using System; using System.Collections.Generic; using System.Linq; namespace QFSW.QC { /// /// Provides a filtered and sorted list of suggestions for a given context using IQcSuggestors and IQcSuggestionFilter /// public class QuantumSuggestor { private readonly IQcSuggestor[] _suggestors; private readonly IQcSuggestionFilter[] _suggestionFilters; private readonly List _suggestionBuffer = new List(); /// /// Creates a Quantum Suggestor with a custom set of suggestors an suggestion filters. /// /// The IQcSuggestors to use in this Quantum Suggestor. /// /// The IQcSuggestionFilters to use in this Quantum Suggestor. public QuantumSuggestor(IEnumerable suggestors, IEnumerable suggestionFilters) { _suggestors = suggestors.ToArray(); _suggestionFilters = suggestionFilters.ToArray(); } /// /// Creates a Quantum Suggestor with the default injected suggestors and suggestion filters. /// public QuantumSuggestor() : this( new InjectionLoader().GetInjectedInstances(), new InjectionLoader().GetInjectedInstances()) { } /// /// Gets suggestions for a given context. /// /// The context to get suggestions for. /// Options for the suggestor. /// The sorted and filtered suggestions for the provided context. public IEnumerable GetSuggestions(SuggestionContext context, SuggestorOptions options) { PreprocessContext(ref context); // Get and filter suggestions IEnumerable suggestions = _suggestors .SelectMany(x => x.GetSuggestions(context, options)) .Where(x => IsSuggestionPermitted(x, context)); _suggestionBuffer.Clear(); _suggestionBuffer.AddRange(suggestions); // Sort suggestions AlphanumComparator comparator = new AlphanumComparator(); IOrderedEnumerable sortedSuggestions = _suggestionBuffer .OrderBy(x => x.PrimarySignature.Length) .ThenBy(x => x.PrimarySignature, comparator) .ThenBy(x => x.SecondarySignature.Length) .ThenBy(x => x.SecondarySignature, comparator); if (options.Fuzzy) { StringComparison comparisonType = options.CaseSensitive ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase; sortedSuggestions = sortedSuggestions .OrderBy(x => x.PrimarySignature.IndexOf(context.Prompt, comparisonType)); } // Return suggestions to user return sortedSuggestions; } private void PreprocessContext(ref SuggestionContext context) { // Strip the scope on the provided prompt in the context to improve suggestions // We want to allow incomplete scope reduction on the prompt so that you get suggestions // as if you had finished the scope properly TextProcessing.ReduceScopeOptions options = TextProcessing.ReduceScopeOptions.Default; options.ReduceIncompleteScope = true; context.Prompt = context.Prompt.ReduceScope(options); } private bool IsSuggestionPermitted(IQcSuggestion suggestion, SuggestionContext context) { // LINQ alternative produces too much garbage // ReSharper disable once LoopCanBeConvertedToQuery foreach (IQcSuggestionFilter filter in _suggestionFilters) { if (!filter.IsSuggestionPermitted(suggestion, context)) { return false; } } return true; } } }