internal static bool MatchesFilterText( CompletionHelper helper, RoslynCompletionItem item, string filterText, CompletionTriggerKind initialTriggerKind, CompletionFilterReason filterReason, ImmutableArray <string> recentItems) { // For the deletion we bake in the core logic for how matching should work. // This way deletion feels the same across all languages that opt into deletion // as a completion trigger. // Specifically, to avoid being too aggressive when matching an item during // completion, we require that the current filter text be a prefix of the // item in the list. if (filterReason == CompletionFilterReason.Deletion && initialTriggerKind == CompletionTriggerKind.Deletion) { return(item.FilterText.GetCaseInsensitivePrefixLength(filterText) > 0); } // If the user hasn't typed anything, and this item was preselected, or was in the // MRU list, then we definitely want to include it. if (filterText.Length == 0) { if (item.Rules.MatchPriority > MatchPriority.Default) { return(true); } if (!recentItems.IsDefault && ItemManager.GetRecentItemIndex(recentItems, item) <= 0) { return(true); } } // Checks if the given completion item matches the pattern provided so far. // A completion item is checked against the pattern by see if it's // CompletionItem.FilterText matches the item. That way, the pattern it checked // against terms like "IList" and not IList<> return(helper.MatchesPattern(item.FilterText, filterText, CultureInfo.CurrentCulture)); }
/// <summary> /// Filter currentCompletionList according to the current filter text. Roslyn's completion does not /// handle this automatically. /// </summary> static async Task <CompletionModel> FilterModelAsync( RoslynCompilationWorkspace compilationWorkspace, SourceText sourceText, CompletionModel model, CompletionHelper helper, CancellationToken ct) { if (model == null) { return(null); } CompletionItem bestFilterMatch = null; var bestFilterMatchIndex = 0; var document = compilationWorkspace.GetSubmissionDocument(sourceText.Container); var newFilteredCompletions = new List <CompletionItem> (); foreach (var item in model.TotalItems) { var completion = item; // TODO: Better range checking on delete before queuing up filtering (see TODO in HandleChange) if (completion.Span.Start > sourceText.Length) { continue; } var filterText = GetFilterText(sourceText, completion); // CompletionRules.MatchesFilterText seems to always return false when filterText is // empty. if (filterText != String.Empty && !helper.MatchesPattern( completion.FilterText, filterText, CultureInfo.CurrentCulture)) { continue; } var itemDetail = String.Empty; var symbols = await SymbolCompletionItem.GetSymbolsAsync(completion, document, ct) .ConfigureAwait(false); var overloads = symbols.OfType <IMethodSymbol> ().ToArray(); if (overloads.Length > 0) { itemDetail = overloads [0].ToMonacoSignatureString(); if (overloads.Length > 1) { itemDetail += $" (+ {overloads.Length - 1} overload(s))"; } } completion = completion.AddProperty(itemDetailPropertyName, itemDetail); newFilteredCompletions.Add(completion); if (bestFilterMatch == null || helper.CompareItems( completion, bestFilterMatch, filterText, CultureInfo.CurrentCulture) > 0) { bestFilterMatch = completion; bestFilterMatchIndex = newFilteredCompletions.Count - 1; } } if (newFilteredCompletions.Count == 0) { return(null); } return(model .WithFilteredItems(newFilteredCompletions) .WithSelectedItem(bestFilterMatch, bestFilterMatchIndex) .WithText(sourceText)); }
// ref: RoslynPad -- https://github.com/aelij/RoslynPad private static bool MatchesFilterText(CompletionHelper helper, CompletionItem item, SourceText text, Dictionary <TextSpan, string> textSpanToText) { var filterText = GetFilterText(item, text, textSpanToText); return(string.IsNullOrEmpty(filterText) || helper.MatchesPattern(item.FilterText, filterText, CultureInfo.InvariantCulture)); }