private CompletionList MergeAndPruneCompletionLists( IEnumerable <CompletionContext> completionLists, TextSpan contextSpan, bool isExclusive) { var displayNameToItemsMap = new Dictionary <string, List <CompletionItem> >(); CompletionItem suggestionModeItem = null; foreach (var completionList in completionLists) { Contract.Assert(completionList != null); foreach (var item in completionList.Items) { Contract.Assert(item != null); AddToDisplayMap(item, displayNameToItemsMap); } // first one wins suggestionModeItem = suggestionModeItem ?? completionList.SuggestionModeItem; } if (displayNameToItemsMap.Count == 0) { return(CompletionList.Empty); } // TODO(DustinCa): Revisit performance of this. var totalItems = displayNameToItemsMap.Values.Flatten().ToList(); totalItems.Sort(); return(CompletionList.Create( contextSpan, totalItems.ToImmutableArray(), this.GetRules(), suggestionModeItem, isExclusive)); }
private CompletionList MergeAndPruneCompletionLists( IEnumerable <CompletionContext> completionContexts, TextSpan defaultSpan, bool isExclusive) { // See if any contexts changed the completion list span. If so, the first context that // changed it 'wins' and picks the span that will be used for all items in the completion // list. If no contexts changed it, then just use the default span provided by the service. var finalCompletionListSpan = completionContexts.FirstOrDefault(c => c.CompletionListSpan != defaultSpan)?.CompletionListSpan ?? defaultSpan; var displayNameToItemsMap = new Dictionary <string, List <CompletionItem> >(); CompletionItem suggestionModeItem = null; foreach (var context in completionContexts) { Contract.Assert(context != null); foreach (var item in context.Items) { Contract.Assert(item != null); AddToDisplayMap(item, displayNameToItemsMap); } // first one wins suggestionModeItem = suggestionModeItem ?? context.SuggestionModeItem; } if (displayNameToItemsMap.Count == 0) { return(CompletionList.Empty); } // TODO(DustinCa): Revisit performance of this. var totalItems = displayNameToItemsMap.Values.Flatten().ToList(); totalItems.Sort(); return(CompletionList.Create( finalCompletionListSpan, totalItems.ToImmutableArray(), this.GetRules(), suggestionModeItem, isExclusive)); }
private Model( DisconnectedBufferGraph disconnectedBufferGraph, CompletionList originalList, ImmutableArray<PresentationItem> totalItems, ImmutableArray<PresentationItem> filteredItems, PresentationItem selectedItem, ImmutableArray<CompletionItemFilter> completionItemFilters, ImmutableDictionary<CompletionItemFilter, bool> filterState, IReadOnlyDictionary<CompletionItem, string> completionItemToFilterText, bool isHardSelection, bool isUnique, bool useSuggestionMode, PresentationItem suggestionModeItem, PresentationItem defaultSuggestionModeItem, CompletionTrigger trigger, ITrackingPoint commitSpanEndPoint, bool dismissIfEmpty) { Contract.ThrowIfNull(selectedItem); Contract.ThrowIfFalse(totalItems.Length != 0, "Must have at least one item."); Contract.ThrowIfFalse(filteredItems.Length != 0, "Must have at least one filtered item."); Contract.ThrowIfFalse(filteredItems.Contains(selectedItem) || defaultSuggestionModeItem == selectedItem, "Selected item must be in filtered items."); _disconnectedBufferGraph = disconnectedBufferGraph; this.OriginalList = originalList; this.TotalItems = totalItems; this.FilteredItems = filteredItems; this.FilterState = filterState; this.SelectedItem = selectedItem; this.CompletionItemFilters = completionItemFilters; this.CompletionItemToFilterText = completionItemToFilterText; this.IsHardSelection = isHardSelection; this.IsUnique = isUnique; this.UseSuggestionMode = useSuggestionMode; this.SuggestionModeItem = suggestionModeItem; this.DefaultSuggestionModeItem = defaultSuggestionModeItem; this.Trigger = trigger; this.CommitTrackingSpanEndPoint = commitSpanEndPoint; this.DismissIfEmpty = dismissIfEmpty; }
public static RoslynCompletionSet Create(IImageMonikerService imageMonikerService, IMruCompletionService mruCompletionService, CompletionList completionList, CompletionService completionService, ITextView textView, string moniker, string displayName, ITrackingSpan applicableTo) { if (imageMonikerService == null) throw new ArgumentNullException(nameof(imageMonikerService)); if (mruCompletionService == null) throw new ArgumentNullException(nameof(mruCompletionService)); if (completionList == null) throw new ArgumentNullException(nameof(completionList)); if (completionService == null) throw new ArgumentNullException(nameof(completionService)); if (textView == null) throw new ArgumentNullException(nameof(textView)); if (moniker == null) throw new ArgumentNullException(nameof(moniker)); if (displayName == null) throw new ArgumentNullException(nameof(displayName)); if (applicableTo == null) throw new ArgumentNullException(nameof(applicableTo)); var completions = new List<Completion>(completionList.Items.Length); var remainingFilters = new List<KeyValuePair<RoslynIntellisenseFilter, int>>(RoslynIntellisenseFilters.CreateFilters(imageMonikerService).Select((a, index) => new KeyValuePair<RoslynIntellisenseFilter, int>(a, index))); var filters = new List<KeyValuePair<RoslynIntellisenseFilter, int>>(remainingFilters.Count); foreach (var item in completionList.Items) { if (string.IsNullOrEmpty(item.DisplayText)) continue; for (int i = remainingFilters.Count - 1; i >= 0; i--) { var kv = remainingFilters[i]; foreach (var tag in kv.Key.Tags) { if (item.Tags.Contains(tag)) { remainingFilters.RemoveAt(i); filters.Add(kv); break; } } } completions.Add(new RoslynCompletion(imageMonikerService, item)); } filters.Sort((a, b) => a.Value - b.Value); var completionBuilders = new List<Completion>(); return new RoslynCompletionSet(mruCompletionService, completionService, textView, moniker, displayName, applicableTo, completions, completionBuilders, filters.Select(a => a.Key).ToArray()); }
private Model( Document triggerDocument, DisconnectedBufferGraph disconnectedBufferGraph, CompletionList originalList, ImmutableArray<CompletionItem> filteredItems, CompletionItem selectedItem, ImmutableArray<CompletionItemFilter> completionItemFilters, ImmutableDictionary<CompletionItemFilter, bool> filterState, string filterText, bool isHardSelection, bool isUnique, bool useSuggestionMode, CompletionItem suggestionModeItem, CompletionTrigger trigger, ITrackingPoint commitSpanEndPoint, bool dismissIfEmpty) { Contract.ThrowIfFalse(originalList.Items.Length != 0, "Must have at least one item."); Contract.ThrowIfNull(selectedItem); this.TriggerDocument = triggerDocument; _disconnectedBufferGraph = disconnectedBufferGraph; this.OriginalList = originalList; this.FilteredItems = filteredItems; this.FilterState = filterState; this.SelectedItem = selectedItem; this.CompletionItemFilters = completionItemFilters; this.FilterText = filterText; this.IsHardSelection = isHardSelection; this.IsUnique = isUnique; this.Trigger = trigger; this.CommitTrackingSpanEndPoint = commitSpanEndPoint; this.DismissIfEmpty = dismissIfEmpty; this.UseSuggestionMode = useSuggestionMode; this.SuggestionModeItem = suggestionModeItem ?? CreateDefaultSuggestionModeItem(); }
internal static async Task <(IReadOnlyList <CompletionItem>, bool)> BuildCompletionItemsSync( Document document, SourceText sourceText, long cacheId, int position, CSharpCompletionService completionService, CSharpCompletionList completions, TextSpan typedSpan, bool expectingImportedItems, bool isSuggestionMode) { var completionsBuilder = new List <CompletionItem>(completions.Items.Length); var seenUnimportedCompletions = false; var commitCharacterRuleCache = new Dictionary <ImmutableArray <CharacterSetModificationRule>, IReadOnlyList <char> >(); var commitCharacterRuleBuilder = new HashSet <char>(); var completionTasksAndProviderNames = completions.Items.SelectAsArray((document, completionService), (completion, arg) => { var providerName = completion.GetProviderName(); if (providerName is TypeImportCompletionProvider or ExtensionMethodImportCompletionProvider) { return(null, providerName); }
public static Model CreateModel( Document triggerDocument, DisconnectedBufferGraph disconnectedBufferGraph, CompletionList originalList, CompletionItem selectedItem, bool isHardSelection, bool isUnique, bool useSuggestionMode, CompletionTrigger trigger, CompletionService completionService, Workspace workspace) { ImmutableArray<PresentationItem> totalItems; CompletionItem suggestionModeItem = originalList.SuggestionModeItem; PresentationItem suggestionModePresentationItem; PresentationItem defaultSuggestionModePresentationItem; // Get the set of actual filters used by all the completion items // that are in the list. var actualFiltersSeen = new HashSet<CompletionItemFilter>(); foreach (var item in originalList.Items) { foreach (var filter in CompletionItemFilter.AllFilters) { if (filter.Matches(item)) { actualFiltersSeen.Add(filter); } } } // The set of filters we'll want to show the user are the filters that are actually // used by our completion items. i.e. there's no reason to show the "field" filter // if none of completion items is actually a field. var actualItemFilters = CompletionItemFilter.AllFilters.Where(actualFiltersSeen.Contains) .ToImmutableArray(); // By default we do not filter anything out. ImmutableDictionary<CompletionItemFilter, bool> filterState = null; if (completionService != null && workspace != null && workspace.Kind != WorkspaceKind.Interactive && // TODO (https://github.com/dotnet/roslyn/issues/5107): support in interactive workspace.Options.GetOption(InternalFeatureOnOffOptions.Snippets) && trigger.Kind != CompletionTriggerKind.Snippets) { // In order to add snippet expansion notes to completion item descriptions, update // all of the provided CompletionItems to DescriptionModifyingCompletionItem which will proxy // requests to the original completion items and add the snippet expansion note to // the description if necessary. We won't do this if the list was triggered to show // snippet shortcuts. var totalItemsBuilder = ArrayBuilder<PresentationItem>.GetInstance(); foreach (var item in originalList.Items) { totalItemsBuilder.Add(new DescriptionModifyingPresentationItem(item, completionService)); } totalItems = totalItemsBuilder.ToImmutableAndFree(); defaultSuggestionModePresentationItem = new DescriptionModifyingPresentationItem( CreateDefaultSuggestionModeItem(), completionService, isSuggestionModeItem: true); suggestionModePresentationItem = suggestionModeItem != null ? new DescriptionModifyingPresentationItem(suggestionModeItem, completionService, isSuggestionModeItem: true) : null; } else { totalItems = originalList.Items.Select(item => new SimplePresentationItem(item, completionService)).ToImmutableArray<PresentationItem>(); defaultSuggestionModePresentationItem = new SimplePresentationItem(CreateDefaultSuggestionModeItem(), completionService, isSuggestionModeItem: true); suggestionModePresentationItem = suggestionModeItem != null ? new SimplePresentationItem(suggestionModeItem, completionService, isSuggestionModeItem: true) : null; } var selectedPresentationItem = totalItems.FirstOrDefault(it => it.Item == selectedItem); return new Model( triggerDocument, disconnectedBufferGraph, originalList, totalItems, totalItems, selectedPresentationItem, actualItemFilters, filterState, "", isHardSelection, isUnique, useSuggestionMode, suggestionModePresentationItem, defaultSuggestionModePresentationItem, trigger, GetDefaultTrackingSpanEnd(originalList.Span, disconnectedBufferGraph), originalList.Rules.DismissIfEmpty); }
public static Model CreateModel( Document triggerDocument, DisconnectedBufferGraph disconnectedBufferGraph, CompletionList originalList, bool useSuggestionMode, CompletionTrigger trigger) { var selectedItem = originalList.Items.First(); var isHardSelection = false; var isUnique = false; // Get the set of actual filters used by all the completion items // that are in the list. var actualFiltersSeen = new HashSet<CompletionItemFilter>(); foreach (var item in originalList.Items) { foreach (var filter in CompletionItemFilter.AllFilters) { if (filter.Matches(item)) { actualFiltersSeen.Add(filter); } } } // The set of filters we'll want to show the user are the filters that are actually // used by our completion items. i.e. there's no reason to show the "field" filter // if none of completion items is actually a field. var actualItemFilters = CompletionItemFilter.AllFilters.Where(actualFiltersSeen.Contains) .ToImmutableArray(); // By default we do not filter anything out. ImmutableDictionary<CompletionItemFilter, bool> filterState = null; return new Model( triggerDocument, disconnectedBufferGraph, originalList, originalList.Items, selectedItem, actualItemFilters, filterState, "", isHardSelection, isUnique, useSuggestionMode, originalList.SuggestionModeItem, trigger, GetDefaultTrackingSpanEnd(originalList.Span, disconnectedBufferGraph), originalList.Rules.DismissIfEmpty); }
internal static async Task <(IReadOnlyList <CompletionItem>, bool)> BuildCompletionItemsAsync( Document document, SourceText sourceText, long cacheId, int position, CSharpCompletionService completionService, CSharpCompletionList completions, TextSpan typedSpan, bool expectingImportedItems, bool isSuggestionMode) { var completionsBuilder = new List <CompletionItem>(completions.Items.Length); var seenUnimportedCompletions = false; var commitCharacterRuleCache = new Dictionary <ImmutableArray <CharacterSetModificationRule>, IReadOnlyList <char> >(); var commitCharacterRuleBuilder = new HashSet <char>(); var isOverrideOrPartialCompletion = completions.Items.Length > 0 && completions.Items[0].GetProviderName() is OverrideCompletionProvider or PartialMethodCompletionProvider; for (int i = 0; i < completions.Items.Length; i++) { var completion = completions.Items[i]; string labelText = completion.DisplayTextPrefix + completion.DisplayText + completion.DisplayTextSuffix; string?insertText; string?filterText = null; List <LinePositionSpanTextChange>?additionalTextEdits = null; InsertTextFormat insertTextFormat = InsertTextFormat.PlainText; TextSpan changeSpan; string? sortText; bool hasAfterInsertStep = false; if (completion.IsComplexTextEdit) { // The completion is somehow expensive. Currently, this one of two categories: import completion, or override/partial // completion. Debug.Assert(completion.GetProviderName() is OverrideCompletionProvider or PartialMethodCompletionProvider or TypeImportCompletionProvider or ExtensionMethodImportCompletionProvider); changeSpan = typedSpan; if (isOverrideOrPartialCompletion) { // For override and partial completion, we don't want to use the DisplayText as the insert text because they contain // characters that will affect our ability to asynchronously resolve the change later. insertText = completion.FilterText; sortText = GetSortText(completion, labelText, expectingImportedItems); hasAfterInsertStep = true; } else { insertText = completion.DisplayText; sortText = '1' + completion.SortText; seenUnimportedCompletions = true; } } else { // For non-complex completions, just await the text edit. It's cheap enough that it doesn't impact our ability // to pop completions quickly // If the completion item is the misc project name, skip it. if (completion.DisplayText == Configuration.OmniSharpMiscProjectName) { continue; } GetCompletionInfo( sourceText, position, completion, await completionService.GetChangeAsync(document, completion), typedSpan, labelText, expectingImportedItems, out insertText, out filterText, out sortText, out insertTextFormat, out changeSpan, out additionalTextEdits); } var commitCharacters = BuildCommitCharacters(completion.Rules.CommitCharacterRules, isSuggestionMode, commitCharacterRuleCache, commitCharacterRuleBuilder); completionsBuilder.Add(new CompletionItem { Label = labelText, TextEdit = GetChangeForTextAndSpan(insertText !, changeSpan, sourceText), InsertTextFormat = insertTextFormat, AdditionalTextEdits = additionalTextEdits, SortText = sortText, FilterText = filterText, Kind = GetCompletionItemKind(completion.Tags), Detail = completion.InlineDescription, Data = (cacheId, i), Preselect = completion.Rules.SelectionBehavior == CompletionItemSelectionBehavior.HardSelection, CommitCharacters = commitCharacters, HasAfterInsertStep = hasAfterInsertStep, });