protected override async Task<IEnumerable<CompletionItem>> GetItemsWorkerAsync(Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken)
 {
     return await document.GetUnionResultsFromDocumentAndLinks(
        UnionCompletionItemComparer.Instance,
        async (doc, ct) => await GetSpeculativeTCompletions(doc, position, ct).ConfigureAwait(false),
        cancellationToken).ConfigureAwait(false);
 }
Beispiel #2
0
        private Model(
            DisconnectedBufferGraph disconnectedBufferGraph,
            IList<CompletionItem> totalItems,
            IList<CompletionItem> filteredItems,
            CompletionItem selectedItem,
            ImmutableArray<CompletionItemFilter> completionItemFilters,
            ImmutableDictionary<CompletionItemFilter, bool> filterState,
            IReadOnlyDictionary<CompletionItem, string> completionItemToFilterText,
            bool isHardSelection,
            bool isUnique,
            bool useSuggestionCompletionMode,
            CompletionItem builder,
            CompletionItem defaultBuilder,
            CompletionTriggerInfo triggerInfo,
            ITrackingPoint commitSpanEndPoint,
            bool dismissIfEmpty)
        {
            Contract.ThrowIfFalse(totalItems.Count != 0, "Must have at least one item.");

            _disconnectedBufferGraph = disconnectedBufferGraph;
            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.UseSuggestionCompletionMode = useSuggestionCompletionMode;
            this.Builder = builder;
            this.DefaultBuilder = defaultBuilder;
            this.TriggerInfo = triggerInfo;
            this.CommitTrackingSpanEndPoint = commitSpanEndPoint;
            this.DismissIfEmpty = dismissIfEmpty;
        }
        protected override async Task<IEnumerable<CompletionItem>> GetItemsWorkerAsync(Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

            if (tree.IsInNonUserCode(position, cancellationToken))
            {
                return null;
            }

            var targetToken = tree.FindTokenOnLeftOfPosition(position, cancellationToken).GetPreviousTokenIfTouchingWord(position);
            if (targetToken.IsKind(SyntaxKind.AliasKeyword) && targetToken.Parent.IsKind(SyntaxKind.ExternAliasDirective))
            {
                var compilation = await document.GetCSharpCompilationAsync(cancellationToken).ConfigureAwait(false);
                var aliases = compilation.ExternalReferences.SelectMany(r => r.Properties.Aliases).ToSet();

                if (aliases.Any())
                {
                    var root = await tree.GetRootAsync(cancellationToken).ConfigureAwait(false);
                    var usedAliases = root.ChildNodes().OfType<ExternAliasDirectiveSyntax>().Where(e => !e.Identifier.IsMissing).Select(e => e.Identifier.ValueText);
                    aliases.RemoveRange(usedAliases);
                    aliases.Remove(MetadataReferenceProperties.GlobalAlias);
                    var textChangeSpan = CompletionUtilities.GetTextChangeSpan(await document.GetTextAsync(cancellationToken).ConfigureAwait(false), position);
                    return aliases.Select(e =>
                        new CompletionItem(this, e, textChangeSpan, glyph: Glyph.Namespace));
                }
            }

            return SpecializedCollections.EmptyEnumerable<CompletionItem>();
        }
            public bool?MatchesFilterText(CompletionItem item, string filterText, CompletionTriggerInfo triggerInfo, CompletionFilterReason filterReason)
            {
                // 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.Preselect || _completionService.GetMRUIndex(item) < 0)
                    {
                        return(true);
                    }
                }

                if (IsAllDigits(filterText))
                {
                    // The user is just typing a number.  We never want this to match against
                    // anything we would put in a completion list.
                    return(false);
                }

                var match = _patternMatcher.MatchPatternFirstOrNullable(
                    _completionService.GetCultureSpecificQuirks(item.FilterText),
                    _completionService.GetCultureSpecificQuirks(filterText));

                return(match != null);
            }
Beispiel #5
0
        private Model(
            DisconnectedBufferGraph disconnectedBufferGraph,
            IList<CompletionItem> totalItems,
            IList<CompletionItem> filteredItems,
            CompletionItem selectedItem,
            bool isHardSelection,
            bool isUnique,
            bool useSuggestionCompletionMode,
            CompletionItem builder,
            CompletionItem defaultBuilder,
            CompletionTriggerInfo triggerInfo,
            ITrackingPoint commitSpanEndPoint,
            bool dismissIfEmpty)
        {
            Contract.ThrowIfNull(selectedItem);
            Contract.ThrowIfFalse(totalItems.Count != 0, "Must have at least one item.");
            Contract.ThrowIfFalse(filteredItems.Count != 0, "Must have at least one filtered item.");
            Contract.ThrowIfFalse(filteredItems.Contains(selectedItem) || defaultBuilder == selectedItem, "Selected item must be in filtered items.");

            _disconnectedBufferGraph = disconnectedBufferGraph;
            this.TotalItems = totalItems;
            this.FilteredItems = filteredItems;
            this.SelectedItem = selectedItem;
            this.IsHardSelection = isHardSelection;
            this.IsUnique = isUnique;
            this.UseSuggestionCompletionMode = useSuggestionCompletionMode;
            this.Builder = builder;
            this.DefaultBuilder = defaultBuilder;
            this.TriggerInfo = triggerInfo;
            this.CommitTrackingSpanEndPoint = commitSpanEndPoint;
            this.DismissIfEmpty = dismissIfEmpty;
        }
        private static async Task <CompletionList> GetCompletionListAsync(
            CompletionListProvider provider,
            Document documentOpt,
            SourceText text,
            int position,
            CompletionTriggerInfo triggerInfo,
            CancellationToken cancellationToken)
        {
            if (provider is TextCompletionProvider)
            {
                return(((TextCompletionProvider)provider).GetCompletionList(text, position, triggerInfo, cancellationToken));
            }

            if (documentOpt != null)
            {
                var context = new CompletionListContext(documentOpt, position, triggerInfo, cancellationToken);

                await provider.ProduceCompletionListAsync(context).ConfigureAwait(false);

                return(new CompletionList(context.GetItems(), context.Builder, context.IsExclusive));
            }

            Contract.Fail("Should never get here.");

            return(null);
        }
        /// <summary>
        /// Returns the <see cref="CompletionList"/> for the specified <paramref name="position"/>
        /// in the <paramref name="document"/>.
        /// </summary>
        public static Task<CompletionList> GetCompletionListAsync(
            Document document,
            int position,
            CompletionTriggerInfo triggerInfo,
            OptionSet options = null,
            IEnumerable<CompletionListProvider> providers = null,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (document == null)
            {
                throw new ArgumentNullException(nameof(document));
            }

            var completionService = document.GetLanguageService<ICompletionService>();
            if (completionService != null)
            {
                options = options ?? document.Project.Solution.Workspace.Options;
                providers = providers ?? GetDefaultCompletionListProviders(document);

                return completionService.GetCompletionListAsync(document, position, triggerInfo, options, providers, cancellationToken);
            }
            else
            {
                if (s_emptyCompletionListTask == null)
                {
                    var value = Task.FromResult(new CompletionList(ImmutableArray<CompletionItem>.Empty));
                    Interlocked.CompareExchange(ref s_emptyCompletionListTask, value, null);
                }

                return s_emptyCompletionListTask;
            }
        }
        protected override async Task<bool> IsExclusiveAsync(Document document, int caretPosition, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
            var token = syntaxTree.FindTokenOnLeftOfPosition(caretPosition, cancellationToken)
                                  .GetPreviousTokenIfTouchingWord(caretPosition);

            return IsAfterNameColonArgument(token) || IsAfterNameEqualsArgument(token);
        }
        protected override async Task<IEnumerable<CompletionItem>> GetItemsWorkerAsync(Document document, int position, CompletionTriggerInfo triggerInfo, System.Threading.CancellationToken cancellationToken)
        {
            var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
            if (!tree.IsEntirelyWithinCrefSyntax(position, cancellationToken))
            {
                return null;
            }

            var token = tree.FindTokenOnLeftOfPosition(position, cancellationToken);
            token = token.GetPreviousTokenIfTouchingWord(position);
            if (token.Kind() == SyntaxKind.None)
            {
                return null;
            }

            var result = SpecializedCollections.EmptyEnumerable<ISymbol>();

            // To get a Speculative SemanticModel (which is much faster), we need to 
            // walk up to the node the DocumentationTrivia is attached to.
            var parentNode = token.GetAncestor<DocumentationCommentTriviaSyntax>().ParentTrivia.Token.Parent;
            var semanticModel = await document.GetSemanticModelForNodeAsync(parentNode, cancellationToken).ConfigureAwait(false);

            // cref ""|, ""|"", ""a|""
            if (token.IsKind(SyntaxKind.DoubleQuoteToken, SyntaxKind.SingleQuoteToken) && token.Parent.IsKind(SyntaxKind.XmlCrefAttribute))
            {
                result = semanticModel.LookupSymbols(token.SpanStart)
                                        .FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation);

                result = result.Concat(GetOperatorsAndIndexers(token, semanticModel, cancellationToken));
            }
            else if (IsSignatureContext(token))
            {
                result = semanticModel.LookupNamespacesAndTypes(token.SpanStart)
                                        .FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation);
            }
            else if (token.IsKind(SyntaxKind.DotToken) && token.Parent.IsKind(SyntaxKind.QualifiedCref))
            {
                // cref "a.|"
                var parent = token.Parent as QualifiedCrefSyntax;
                var leftType = semanticModel.GetTypeInfo(parent.Container, cancellationToken).Type;
                var leftSymbol = semanticModel.GetSymbolInfo(parent.Container, cancellationToken).Symbol;

                var container = leftSymbol ?? leftType;

                result = semanticModel.LookupSymbols(token.SpanStart, container: (INamespaceOrTypeSymbol)container)
                                        .FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation);

                if (container is INamedTypeSymbol)
                {
                    result = result.Concat(((INamedTypeSymbol)container).InstanceConstructors);
                }
            }

            return await CreateItemsAsync(document.Project.Solution.Workspace, semanticModel,
                position, result, token, cancellationToken).ConfigureAwait(false);
        }
Beispiel #10
0
 public Task <IEnumerable <CompletionItemGroup> > GetGroupsAsync(
     SourceText text,
     int position,
     CompletionTriggerInfo triggerInfo,
     IEnumerable <ICompletionProvider> completionProviders,
     OptionSet options,
     CancellationToken cancellationToken)
 {
     return(GetGroupsAsync(null, text, position, triggerInfo, completionProviders, options, cancellationToken));
 }
 public async Task<IEnumerable<CompletionItemGroup>> GetGroupsAsync(
     Document document,
     int position,
     CompletionTriggerInfo triggerInfo,
     IEnumerable<ICompletionProvider> completionProviders,
     CancellationToken cancellationToken)
 {
     var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
     return await GetGroupsAsync(document, text, position, triggerInfo, completionProviders, document.Project.Solution.Workspace.Options, cancellationToken).ConfigureAwait(false);
 }
        public override CompletionList GetCompletionList(SourceText text, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken = default(CancellationToken))
        {
            var items = this.GetItems(text, position, triggerInfo, cancellationToken);
            if (items == null || !items.Any())
            {
                return null;
            }

            return new CompletionList(items);
        }
Beispiel #13
0
        public async Task <IEnumerable <CompletionItemGroup> > GetGroupsAsync(
            Document document,
            int position,
            CompletionTriggerInfo triggerInfo,
            IEnumerable <ICompletionProvider> completionProviders,
            CancellationToken cancellationToken)
        {
            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            return(await GetGroupsAsync(document, text, position, triggerInfo, completionProviders, document.Project.Solution.Workspace.Options, cancellationToken).ConfigureAwait(false));
        }
        private static async Task <CompletionList> GetCompletionListAsync(
            CompletionListProvider provider,
            Document document,
            int position,
            CompletionTriggerInfo triggerInfo,
            CancellationToken cancellationToken)
        {
            var context = new CompletionListContext(document, position, triggerInfo, cancellationToken);

            await provider.ProduceCompletionListAsync(context).ConfigureAwait(false);

            return(new CompletionList(context.GetItems(), context.Builder, context.IsExclusive));
        }
        protected override async Task<IEnumerable<CompletionItem>> GetItemsWorkerAsync(Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

            DeclarationModifiers modifiers;
            SyntaxToken token;
            if (!IsPartialCompletionContext(tree, position, cancellationToken, out modifiers, out token))
            {
                return null;
            }

            return await CreatePartialItemsAsync(document, position, modifiers, token, cancellationToken).ConfigureAwait(false);
        }
        protected override async Task<IEnumerable<CompletionItem>> GetItemsWorkerAsync(Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

            // first try to get the #r string literal token.  If we couldn't, then we're not in a #r
            // reference directive and we immediately bail.
            SyntaxToken stringLiteral;
            if (!TryGetStringLiteralToken(tree, position, out stringLiteral, cancellationToken))
            {
                return null;
            }

            var documentPath = document.Project.IsSubmission ? null : document.FilePath;
            var textChangeSpan = this.GetTextChangeSpan(stringLiteral, position);

            var gacHelper = new GlobalAssemblyCacheCompletionHelper(this, textChangeSpan, itemRules: ItemRules.Instance);
            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
            var snapshot = text.FindCorrespondingEditorTextSnapshot();
            if (snapshot == null)
            {
                // Passing null to GetFileSystemDiscoveryService raises an exception.
                // Instead, return here since there is no longer snapshot for this document.
                return null;
            }

            var assemblyReferenceResolver = document.Project.CompilationOptions.MetadataReferenceResolver as AssemblyReferenceResolver;
            if (assemblyReferenceResolver == null)
            {
                return null;
            }

            var metadataFileResolver = assemblyReferenceResolver.PathResolver as MetadataFileReferenceResolver;
            if (metadataFileResolver == null)
            {
                return null;
            }

            var fileSystemHelper = new FileSystemCompletionHelper(
                this, textChangeSpan,
                GetFileSystemDiscoveryService(snapshot),
                Glyph.OpenFolder,
                Glyph.Assembly,
                searchPaths: metadataFileResolver.SearchPaths,
                allowableExtensions: new[] { ".dll", ".exe" },
                exclude: path => path.Contains(","),
                itemRules: ItemRules.Instance);

            var pathThroughLastSlash = this.GetPathThroughLastSlash(stringLiteral, position);
            return gacHelper.GetItems(pathThroughLastSlash, documentPath).Concat(
                fileSystemHelper.GetItems(pathThroughLastSlash, documentPath));
        }
Beispiel #17
0
 private static Task <CompletionItemGroup> GetGroupAsync(
     ICompletionProvider provider,
     Document documentOpt,
     SourceText text,
     int position,
     CompletionTriggerInfo triggerInfo,
     CancellationToken cancellationToken)
 {
     return(provider is ITextCompletionProvider
         ? Task.FromResult(((ITextCompletionProvider)provider).GetGroup(text, position, triggerInfo, cancellationToken))
         : documentOpt != null
             ? provider.GetGroupAsync(documentOpt, position, triggerInfo, cancellationToken)
             : SpecializedTasks.Default <CompletionItemGroup>());
 }
        protected override async Task<CompletionItem> GetBuilderAsync(Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (triggerInfo.TriggerReason == CompletionTriggerReason.TypeCharCommand)
            {
                var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

                if (triggerInfo.IsDebugger)
                {
                    // Aggressive Intellisense in the debugger: always show the builder 
                    return CreateEmptyBuilder(text, position);
                }

                var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
                var token = tree
                    .FindTokenOnLeftOfPosition(position, cancellationToken)
                    .GetPreviousTokenIfTouchingWord(position);

                if (token.Kind() == SyntaxKind.None)
                {
                    return null;
                }

                var semanticModel = await document.GetSemanticModelForNodeAsync(token.Parent, cancellationToken).ConfigureAwait(false);
                var typeInferrer = document.GetLanguageService<ITypeInferenceService>();

                if (IsLambdaExpression(semanticModel, position, token, typeInferrer, cancellationToken))
                {
                    return CreateBuilder(text, position, CSharpFeaturesResources.LambdaExpression, CSharpFeaturesResources.AutoselectDisabledDueToPotentialLambdaDeclaration);
                }
                else if (IsAnonymousObjectCreation(token))
                {
                    return CreateBuilder(text, position, CSharpFeaturesResources.MemberName, CSharpFeaturesResources.AutoselectDisabledDueToPossibleExplicitlyNamesAnonTypeMemCreation);
                }
                else if (token.IsPreProcessorExpressionContext())
                {
                    return CreateEmptyBuilder(text, position);
                }
                else if (IsImplicitArrayCreation(semanticModel, token, position, typeInferrer, cancellationToken))
                {
                    return CreateBuilder(text, position, CSharpFeaturesResources.ImplicitArrayCreation, CSharpFeaturesResources.AutoselectDisabledDueToPotentialImplicitArray);
                }
                else if (token.IsKindOrHasMatchingText(SyntaxKind.FromKeyword) || token.IsKindOrHasMatchingText(SyntaxKind.JoinKeyword))
                {
                    return CreateBuilder(text, position, CSharpFeaturesResources.RangeVariable, CSharpFeaturesResources.AutoselectDisabledDueToPotentialRangeVariableDecl);
                }
            }

            return null;
        }
            public bool? IsBetterFilterMatch(CompletionItem item1, CompletionItem item2, string filterText, CompletionTriggerInfo triggerInfo, CompletionFilterReason filterReason)
            {
                var match1 = _patternMatcher.MatchPatternFirstOrNullable(
                            _completionService.GetCultureSpecificQuirks(item1.FilterText),
                            _completionService.GetCultureSpecificQuirks(filterText));
                var match2 = _patternMatcher.MatchPatternFirstOrNullable(
                            _completionService.GetCultureSpecificQuirks(item2.FilterText),
                            _completionService.GetCultureSpecificQuirks(filterText));

                if (match1 != null && match2 != null)
                {
                    var result = match1.Value.CompareTo(match2.Value);
                    if (result != 0)
                    {
                        return result < 0;
                    }
                }
                else if (match1 != null)
                {
                    return true;
                }
                else if (match2 != null)
                {
                    return false;
                }

                // If they both seemed just as good, but they differ on preselection, then
                // item1 is better if it is preselected, otherwise it it worse.
                if (item1.Preselect != item2.Preselect)
                {
                    return item1.Preselect;
                }

                // Prefer things with a keyword glyph, if the filter texts are the same.
                if (item1.Glyph != item2.Glyph && item1.FilterText == item2.FilterText)
                {
                    return item1.Glyph == Glyph.Keyword;
                }

                // They matched on everything, including preselection values.  Item1 is better if it
                // has a lower MRU index.

                var item1MRUIndex = _completionService.GetMRUIndex(item1);
                var item2MRUIndex = _completionService.GetMRUIndex(item2);

                // The one with the lower index is the better one.
                return item1MRUIndex < item2MRUIndex;
            }
        private ImmutableArray<CompletionItem> GetItems(SourceText text, Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var line = text.Lines.GetLineFromPosition(position);
            var lineText = text.ToString(TextSpan.FromBounds(line.Start, position));
            var match = s_directiveRegex.Match(lineText);
            if (!match.Success)
            {
                return ImmutableArray<CompletionItem>.Empty;
            }

            var quotedPathGroup = match.Groups[1];
            var quotedPath = quotedPathGroup.Value;
            var endsWithQuote = PathCompletionUtilities.EndsWithQuote(quotedPath);
            if (endsWithQuote && (position >= line.Start + match.Length))
            {
                return ImmutableArray<CompletionItem>.Empty;
            }

            var buffer = text.Container.GetTextBuffer();
            var snapshot = text.FindCorrespondingEditorTextSnapshot();
            if (snapshot == null)
            {
                return ImmutableArray<CompletionItem>.Empty;
            }

            var fileSystem = CurrentWorkingDirectoryDiscoveryService.GetService(snapshot);

            // TODO: https://github.com/dotnet/roslyn/issues/5263
            // Avoid dependency on a specific resolver.
            // The search paths should be provided by specialized workspaces:
            // - InteractiveWorkspace for interactive window 
            // - ScriptWorkspace for loose .csx files (we don't have such workspace today)
            var searchPaths = (document.Project.CompilationOptions.SourceReferenceResolver as SourceFileResolver)?.SearchPaths ?? ImmutableArray<string>.Empty;

            var helper = new FileSystemCompletionHelper(
                this,
                GetTextChangeSpan(text, position, quotedPathGroup),
                fileSystem,
                Glyph.OpenFolder,
                Glyph.CSharpFile,
                searchPaths: searchPaths,
                allowableExtensions: new[] { ".csx" },
                itemRules: ItemRules.Instance);

            var pathThroughLastSlash = this.GetPathThroughLastSlash(text, position, quotedPathGroup);

            return helper.GetItems(pathThroughLastSlash, documentPath: null);
        }
            public void ComputeModel(
                ICompletionService completionService,
                CompletionTriggerInfo triggerInfo,
                IEnumerable<ICompletionProvider> completionProviders,
                bool isDebugger)
            {
                AssertIsForeground();

                // If we've already computed a model then we can just ignore this request and not
                // generate any tasks.
                if (this.Computation.InitialUnfilteredModel != null)
                {
                    return;
                }

                new ModelComputer(this, completionService, triggerInfo, completionProviders, isDebugger).Do();
            }
        public CompletionListContext(
            Document document,
            int position,
            CompletionTriggerInfo triggerInfo,
            CancellationToken cancellationToken)
        {
            if (document == null)
            {
                throw new ArgumentNullException(nameof(document));
            }

            this.Document = document;
            this.Position = position;
            this.TriggerInfo = triggerInfo;
            this.CancellationToken = cancellationToken;

            this._itemsBuilder = ImmutableArray.CreateBuilder<CompletionItem>();
        }
Beispiel #23
0
        public CompletionListContext(
            Document document,
            int position,
            CompletionTriggerInfo triggerInfo,
            CancellationToken cancellationToken)
        {
            if (document == null)
            {
                throw new ArgumentNullException(nameof(document));
            }

            this.Document          = document;
            this.Position          = position;
            this.TriggerInfo       = triggerInfo;
            this.CancellationToken = cancellationToken;

            this._itemsBuilder = ImmutableArray.CreateBuilder <CompletionItem>();
        }
        public async Task<CompletionItemGroup> GetGroupAsync(Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            if (!triggerInfo.IsAugment)
            {
                return null;
            }

            var builder = await this.GetBuilderAsync(document, position, triggerInfo, cancellationToken).ConfigureAwait(false);
            if (builder == null)
            {
                return null;
            }

            return new CompletionItemGroup(
                SpecializedCollections.EmptyEnumerable<CompletionItem>(),
                builder,
                isExclusive: false);
        }
        private ImmutableArray<CompletionItem> GetItems(SourceText text, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var line = text.Lines.GetLineFromPosition(position);
            var lineText = text.ToString(TextSpan.FromBounds(line.Start, position));
            var match = s_directiveRegex.Match(lineText);
            if (!match.Success)
            {
                return ImmutableArray<CompletionItem>.Empty;
            }

            var quotedPathGroup = match.Groups[1];
            var quotedPath = quotedPathGroup.Value;
            var endsWithQuote = PathCompletionUtilities.EndsWithQuote(quotedPath);
            if (endsWithQuote && (position >= line.Start + match.Length))
            {
                return ImmutableArray<CompletionItem>.Empty;
            }

            var buffer = text.Container.GetTextBuffer();
            var snapshot = text.FindCorrespondingEditorTextSnapshot();
            if (snapshot == null)
            {
                return ImmutableArray<CompletionItem>.Empty;
            }

            var fileSystem = PathCompletionUtilities.GetCurrentWorkingDirectoryDiscoveryService(snapshot);

            var searchPaths = ImmutableArray.Create<string>(fileSystem.CurrentDirectory);

            var helper = new FileSystemCompletionHelper(
                this,
                GetTextChangeSpan(text, position, quotedPathGroup),
                fileSystem,
                Glyph.OpenFolder,
                Glyph.CSharpFile,
                searchPaths: searchPaths,
                allowableExtensions: new[] { ".csx" },
                itemRules: ItemRules.Instance);

            var pathThroughLastSlash = this.GetPathThroughLastSlash(text, position, quotedPathGroup);

            return helper.GetItems(pathThroughLastSlash, documentPath: null);
        }
        protected override async Task<IEnumerable<CompletionItem>> GetItemsWorkerAsync(
            Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            if (document != null && document.SourceCodeKind == SourceCodeKind.Interactive)
            {
                // the provider might be invoked in non-interactive context:
                Workspace ws;
                if (Workspace.TryGetWorkspace(document.GetTextAsync(cancellationToken).WaitAndGetResult(cancellationToken).Container, out ws))
                {
                    var workspace = ws as InteractiveWorkspace;
                    if (workspace != null)
                    {
                        var window = workspace.Engine.CurrentWindow;
                        var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                        if (tree.IsBeforeFirstToken(position, cancellationToken) &&
                            tree.IsPreProcessorKeywordContext(position, cancellationToken))
                        {
                            var textChangeSpan = await this.GetTextChangeSpanAsync(document, position, cancellationToken).ConfigureAwait(false);
                            var list = new List<CompletionItem>();

                            IInteractiveWindowCommands commands = window.GetInteractiveCommands();
                            if (commands != null)
                            {
                                foreach (var command in commands.GetCommands())
                                {
                                    foreach (var commandName in command.Names)
                                    {
                                        list.Add(new CSharpCompletionItem(
                                            workspace, this, commandName, textChangeSpan, c => Task.FromResult(command.Description.ToSymbolDisplayParts()), glyph: Glyph.Intrinsic));
                                    }
                                }
                            }

                            return list;
                        }
                    }
                }
            }

            return SpecializedCollections.EmptyEnumerable<CompletionItem>();
        }
                public ModelComputer(
                    Session session,
                    ICompletionService completionService,
                    CompletionTriggerInfo triggerInfo,
                    IEnumerable<ICompletionProvider> completionProviders,
                    bool isDebugger)
                {
                    _session = session;
                    _completionService = completionService;
                    _options = session.Controller.SubjectBuffer.TryGetOptions();
                    _triggerInfo = triggerInfo;
                    _subjectBufferCaretPosition = session.Controller.TextView.GetCaretPoint(session.Controller.SubjectBuffer).Value;
                    _completionProviders = completionProviders;

                    _text = _subjectBufferCaretPosition.Snapshot.AsText();

                    _includeBuilder = session.Controller.SubjectBuffer.GetOption(Options.EditorCompletionOptions.UseSuggestionMode);

                    _disconnectedBufferGraph = new DisconnectedBufferGraph(session.Controller.SubjectBuffer, session.Controller.TextView.TextBuffer);
                }
        protected override async Task<IEnumerable<CompletionItem>> GetItemsWorkerAsync(Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            using (Logger.LogBlock(FunctionId.Completion_SnippetCompletionProvider_GetItemsWorker_CSharp, cancellationToken))
            {
                var workspace = document.Project.Solution.Workspace;
                if (!workspace.CanApplyChange(ApplyChangesKind.ChangeDocument) ||
                     workspace.Kind == WorkspaceKind.Debugger)
                {
                    return SpecializedCollections.EmptyEnumerable<CompletionItem>();
                }

                var optionService = workspace.Services.GetService<IOptionService>();
                if (!optionService.GetOption(CSharpCompletionOptions.IncludeSnippets))
                {
                    return SpecializedCollections.EmptyEnumerable<CompletionItem>();
                }

                return await document.GetUnionResultsFromDocumentAndLinks(UnionCompletionItemComparer.Instance, async (d, c) => await GetSnippetsForDocumentAsync(d, position, workspace, c).ConfigureAwait(false), cancellationToken).ConfigureAwait(false);
            }
        }
Beispiel #29
0
        /// <summary>
        /// Returns true if the completion item matches the filter text typed so far.  Returns 'true'
        /// iff the completion item matches and should be included in the filtered completion
        /// results, or false if it should not be.
        /// </summary>
        public virtual bool MatchesFilterText(CompletionItem item, string filterText, CompletionTriggerInfo triggerInfo, CompletionFilterReason filterReason)
        {
            // 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.Preselect || _completionService.GetMRUIndex(item) < 0)
                {
                    return true;
                }
            }

            if (IsAllDigits(filterText))
            {
                // The user is just typing a number.  We never want this to match against
                // anything we would put in a completion list.
                return false;
            }

            return GetMatch(item, filterText) != null;
        }
        private static async Task <CompletionList> GetCompletionListAsync(
            CompletionListProvider provider,
            Document document,
            int position,
            CompletionTriggerInfo triggerInfo,
            OptionSet options,
            CancellationToken cancellationToken)
        {
            var context = new CompletionListContext(document, position, triggerInfo, options, cancellationToken);

            if (document.SupportsSyntaxTree)
            {
                var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                if (!root.FullSpan.IntersectsWith(position))
                {
                    try
                    {
                        // Trying to track down source of https://github.com/dotnet/roslyn/issues/9325
                        var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

                        ReportException(position, root, sourceText);
                    }
                    catch (Exception e) when(FatalError.ReportWithoutCrash(e))
                    {
                    }
                }
                else
                {
                    await provider.ProduceCompletionListAsync(context).ConfigureAwait(false);
                }
            }
            else
            {
                await provider.ProduceCompletionListAsync(context).ConfigureAwait(false);
            }

            return(new CompletionList(context.GetItems(), context.Builder, context.IsExclusive));
        }
            public bool? MatchesFilterText(CompletionItem item, string filterText, CompletionTriggerInfo triggerInfo, CompletionFilterReason filterReason)
            {
                // 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.Preselect || _completionService.GetMRUIndex(item) < 0)
                    {
                        return true;
                    }
                }

                if (IsAllDigits(filterText))
                {
                    // The user is just typing a number.  We never want this to match against
                    // anything we would put in a completion list.
                    return false;
                }

                var match = _patternMatcher.MatchPatternFirstOrNullable(
                            _completionService.GetCultureSpecificQuirks(item.FilterText),
                            _completionService.GetCultureSpecificQuirks(filterText));
                return match != null;
            }
        protected override async Task<IEnumerable<CompletionItem>> GetItemsWorkerAsync(
            Document document,
            int position,
            CompletionTriggerInfo triggerInfo,
            CancellationToken cancellationToken)
        {
            var span = new TextSpan(position, 0);
            var semanticModel = await document.GetSemanticModelForSpanAsync(span, cancellationToken).ConfigureAwait(false);
            var syntaxTree = semanticModel.SyntaxTree;

            var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
            var semanticFacts = document.GetLanguageService<ISemanticFactsService>();

            if (syntaxFacts.IsInNonUserCode(syntaxTree, position, cancellationToken) ||
                semanticFacts.IsPreProcessorDirectiveContext(semanticModel, position, cancellationToken))
            {
                return SpecializedCollections.EmptyEnumerable<CompletionItem>();
            }

            if (!syntaxTree.IsRightOfDotOrArrowOrColonColon(position, cancellationToken))
            {
                return SpecializedCollections.EmptyEnumerable<CompletionItem>();
            }

            var node = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken)
                                 .GetPreviousTokenIfTouchingWord(position)
                                 .Parent;

            if (node.Kind() == SyntaxKind.ExplicitInterfaceSpecifier)
            {
                return await GetCompletionsOffOfExplicitInterfaceAsync(
                    document, semanticModel, position, ((ExplicitInterfaceSpecifierSyntax)node).Name, cancellationToken).ConfigureAwait(false);
            }

            return SpecializedCollections.EmptyEnumerable<CompletionItem>();
        }
 public virtual bool? ShouldSoftSelectItem(CompletionItem item, string filterText, CompletionTriggerInfo triggerInfo)
 {
     return filterText.Length == 0 && !item.Preselect;
 }
Beispiel #34
0
 /// <summary>
 /// Returns the <see cref="CompletionList"/> for the specified position in the document.
 /// </summary>
 public static Task <CompletionList> GetCompletionListAsync(Document document, int position, CompletionTriggerInfo triggerInfo, IEnumerable <CompletionListProvider> completionProviders = null, CancellationToken cancellationToken = default(CancellationToken))
 {
     return(document.GetLanguageService <ICompletionService>().GetCompletionListAsync(document, position, triggerInfo, completionProviders, cancellationToken));
 }
        protected override async Task<IEnumerable<CompletionItem>> GetItemsWorkerAsync(
            Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
            if (syntaxTree.IsInNonUserCode(position, cancellationToken))
            {
                return null;
            }

            var token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken);
            token = token.GetPreviousTokenIfTouchingWord(position);

            if (token.Kind() != SyntaxKind.OpenParenToken && token.Kind() != SyntaxKind.CommaToken)
            {
                return null;
            }

            var attributeArgumentList = token.Parent as AttributeArgumentListSyntax;
            var attributeSyntax = token.Parent.Parent as AttributeSyntax;
            if (attributeSyntax == null || attributeArgumentList == null)
            {
                return null;
            }

            // We actually want to collect two sets of named parameters to present the user.  The
            // normal named parameters that come from the attribute constructors.  These will be
            // presented like "foo:".  And also the named parameters that come from the writable
            // fields/properties in the attribute.  These will be presented like "bar =".  

            var existingNamedParameters = GetExistingNamedParameters(attributeArgumentList, position);

            var workspace = document.Project.Solution.Workspace;
            var semanticModel = await document.GetSemanticModelForNodeAsync(attributeSyntax, cancellationToken).ConfigureAwait(false);
            var nameColonItems = await GetNameColonItemsAsync(workspace, semanticModel, position, token, attributeSyntax, existingNamedParameters, cancellationToken).ConfigureAwait(false);
            var nameEqualsItems = await GetNameEqualsItemsAsync(workspace, semanticModel, position, token, attributeSyntax, existingNamedParameters, cancellationToken).ConfigureAwait(false);

            // If we're after a name= parameter, then we only want to show name= parameters.
            if (IsAfterNameEqualsArgument(token))
            {
                return nameEqualsItems;
            }

            return nameColonItems.Concat(nameEqualsItems);
        }
Beispiel #36
0
        /// <summary>
        /// Returns true if the completion item matches the filter text typed so far.  Returns 'true'
        /// iff the completion item matches and should be included in the filtered completion
        /// results, or false if it should not be.
        /// </summary>
        public virtual bool MatchesFilterText(CompletionItem item, string filterText, CompletionTriggerInfo triggerInfo, CompletionFilterReason filterReason)
        {
            // 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.Preselect || _completionService.GetMRUIndex(item) < 0)
                {
                    return(true);
                }
            }

            if (IsAllDigits(filterText))
            {
                // The user is just typing a number.  We never want this to match against
                // anything we would put in a completion list.
                return(false);
            }

            return(GetMatch(item, filterText) != null);
        }
        protected override async Task<bool> IsExclusiveAsync(Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            // We're exclusive if this context could only be an object initializer and not also a
            // collection initializer. If we're initializing something that could be initialized as
            // an object or as a collection, say we're not exclusive. That way the rest of
            // intellisense can be used in the collection intializer.
            // 
            // Consider this case:

            // class c : IEnumerable<int> 
            // { 
            // public void Add(int addend) { }
            // public int foo; 
            // }

            // void foo()
            // {
            //    var b = new c {|
            // }

            // There we could initialize b using either an object initializer or a collection
            // initializer. Since we don't know which the user will use, we'll be non-exclusive, so
            // the other providers can help the user write the collection initializer, if they want
            // to.
            var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

            if (tree.IsInNonUserCode(position, cancellationToken))
            {
                return false;
            }

            var token = tree.FindTokenOnLeftOfPosition(position, cancellationToken);
            token = token.GetPreviousTokenIfTouchingWord(position);

            if (token.Parent == null)
            {
                return false;
            }

            var expression = token.Parent.Parent as ExpressionSyntax;
            if (expression == null)
            {
                return false;
            }

            var semanticModel = await document.GetSemanticModelForNodeAsync(expression, cancellationToken).ConfigureAwait(false);
            var initializedType = semanticModel.GetTypeInfo(expression, cancellationToken).Type;
            if (initializedType == null)
            {
                return false;
            }

            // Non-exclusive if initializedType can be initialized as a collection.
            if (initializedType.CanSupportCollectionInitializer())
            {
                return false;
            }

            // By default, only our member names will show up.
            return true;
        }
        protected override async Task<IEnumerable<CompletionItem>> GetItemsWorkerAsync(Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
            var token = tree.FindTokenOnLeftOfPosition(position, cancellationToken);
            var parentTrivia = token.GetAncestor<DocumentationCommentTriviaSyntax>();

            if (parentTrivia == null)
            {
                return null;
            }

            var items = new List<CompletionItem>();
            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
            var span = CompletionUtilities.GetTextChangeSpan(text, position);

            var attachedToken = parentTrivia.ParentTrivia.Token;
            if (attachedToken.Kind() == SyntaxKind.None)
            {
                return null;
            }

            var semanticModel = await document.GetSemanticModelForNodeAsync(attachedToken.Parent, cancellationToken).ConfigureAwait(false);

            ISymbol declaredSymbol = null;
            var memberDeclaration = attachedToken.GetAncestor<MemberDeclarationSyntax>();
            if (memberDeclaration != null)
            {
                declaredSymbol = semanticModel.GetDeclaredSymbol(memberDeclaration, cancellationToken);
            }
            else
            {
                var typeDeclaration = attachedToken.GetAncestor<TypeDeclarationSyntax>();
                if (typeDeclaration != null)
                {
                    declaredSymbol = semanticModel.GetDeclaredSymbol(typeDeclaration, cancellationToken);
                }
            }

            if (declaredSymbol != null)
            {
                items.AddRange(GetTagsForSymbol(declaredSymbol, span, parentTrivia, token));
            }

            if (token.Parent.Kind() == SyntaxKind.XmlEmptyElement || token.Parent.Kind() == SyntaxKind.XmlText ||
                (token.Parent.IsKind(SyntaxKind.XmlElementEndTag) && token.IsKind(SyntaxKind.GreaterThanToken)) ||
                (token.Parent.IsKind(SyntaxKind.XmlName) && token.Parent.IsParentKind(SyntaxKind.XmlEmptyElement)))
            {
                if (token.Parent.Parent.Kind() == SyntaxKind.XmlElement)
                {
                    items.AddRange(GetNestedTags(span));
                }

                if (token.Parent.Parent.Kind() == SyntaxKind.XmlElement && ((XmlElementSyntax)token.Parent.Parent).StartTag.Name.LocalName.ValueText == ListTagName)
                {
                    items.AddRange(GetListItems(span));
                }

                if (token.Parent.IsParentKind(SyntaxKind.XmlEmptyElement) & token.Parent.Parent.IsParentKind(SyntaxKind.XmlElement))
                {
                    var element = (XmlElementSyntax)token.Parent.Parent.Parent;
                    if (element.StartTag.Name.LocalName.ValueText == ListTagName)
                    {
                        items.AddRange(GetListItems(span));
                    }
                }

                if (token.Parent.Parent.Kind() == SyntaxKind.XmlElement && ((XmlElementSyntax)token.Parent.Parent).StartTag.Name.LocalName.ValueText == ListHeaderTagName)
                {
                    items.AddRange(GetListHeaderItems(span));
                }

                if (token.Parent.Parent is DocumentationCommentTriviaSyntax)
                {
                    items.AddRange(GetTopLevelSingleUseNames(parentTrivia, span));
                    items.AddRange(GetTopLevelRepeatableItems(span));
                }
            }

            if (token.Parent.Kind() == SyntaxKind.XmlElementStartTag)
            {
                var startTag = (XmlElementStartTagSyntax)token.Parent;

                if (token == startTag.GreaterThanToken && startTag.Name.LocalName.ValueText == ListTagName)
                {
                    items.AddRange(GetListItems(span));
                }

                if (token == startTag.GreaterThanToken && startTag.Name.LocalName.ValueText == ListHeaderTagName)
                {
                    items.AddRange(GetListHeaderItems(span));
                }
            }

            items.AddRange(GetAlwaysVisibleItems(span));
            return items;
        }
        public async Task <CompletionList> GetCompletionListAsync(
            Document document,
            int position,
            CompletionTriggerInfo triggerInfo,
            OptionSet options,
            IEnumerable <CompletionListProvider> providers,
            CancellationToken cancellationToken)
        {
            options   = options ?? document.Project.Solution.Workspace.Options;
            providers = providers ?? GetDefaultCompletionProviders();

            var completionProviderToIndex = GetCompletionProviderToIndex(providers);
            var completionRules           = GetCompletionRules();

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            IEnumerable <CompletionListProvider> triggeredProviders;

            switch (triggerInfo.TriggerReason)
            {
            case CompletionTriggerReason.TypeCharCommand:
                triggeredProviders = providers.Where(p => p.IsTriggerCharacter(text, position - 1, options)).ToList();
                break;

            case CompletionTriggerReason.BackspaceOrDeleteCommand:
                triggeredProviders = this.TriggerOnBackspace(text, position, triggerInfo, options)
                        ? providers
                        : SpecializedCollections.EmptyEnumerable <CompletionListProvider>();
                break;

            default:
                triggeredProviders = providers;
                break;
            }

            // Now, ask all the triggered providers if they can provide a group.
            var providersAndLists = new List <ProviderList>();

            foreach (var provider in triggeredProviders)
            {
                var completionList = await GetCompletionListAsync(provider, document, position, triggerInfo, options, cancellationToken).ConfigureAwait(false);

                if (completionList != null)
                {
                    providersAndLists.Add(new ProviderList {
                        Provider = provider, List = completionList
                    });
                }
            }

            // See if there was a group provided that was exclusive and had items in it.  If so, then
            // that's all we'll return.
            var firstExclusiveList = providersAndLists.FirstOrDefault(
                t => t.List.IsExclusive && t.List.Items.Any());

            if (firstExclusiveList != null)
            {
                return(MergeAndPruneCompletionLists(SpecializedCollections.SingletonEnumerable(firstExclusiveList.List), completionRules));
            }

            // If no exclusive providers provided anything, then go through the remaining
            // triggered list and see if any provide items.
            var nonExclusiveLists = providersAndLists.Where(t => !t.List.IsExclusive).ToList();

            // If we still don't have any items, then we're definitely done.
            if (!nonExclusiveLists.Any(g => g.List.Items.Any()))
            {
                return(null);
            }

            // If we do have items, then ask all the other (non exclusive providers) if they
            // want to augment the items.
            var usedProviders                = nonExclusiveLists.Select(g => g.Provider);
            var nonUsedProviders             = providers.Except(usedProviders);
            var nonUsedNonExclusiveProviders = new List <ProviderList>();

            foreach (var provider in nonUsedProviders)
            {
                var completionList = await GetCompletionListAsync(provider, document, position, triggerInfo, options, cancellationToken).ConfigureAwait(false);

                if (completionList != null && !completionList.IsExclusive)
                {
                    nonUsedNonExclusiveProviders.Add(new ProviderList {
                        Provider = provider, List = completionList
                    });
                }
            }

            var allProvidersAndLists = nonExclusiveLists.Concat(nonUsedNonExclusiveProviders).ToList();

            if (allProvidersAndLists.Count == 0)
            {
                return(null);
            }

            // Providers are ordered, but we processed them in our own order.  Ensure that the
            // groups are properly ordered based on the original providers.
            allProvidersAndLists.Sort((p1, p2) => completionProviderToIndex[p1.Provider] - completionProviderToIndex[p2.Provider]);
            return(MergeAndPruneCompletionLists(allProvidersAndLists.Select(g => g.List), completionRules));
        }
Beispiel #40
0
 /// <summary>
 /// Returns true if the completion item should be "soft" selected, or false if it should be "hard"
 /// selected.
 /// </summary>
 public virtual bool ShouldSoftSelectItem(CompletionItem item, string filterText, CompletionTriggerInfo triggerInfo)
 {
     return(filterText.Length == 0 && !item.Preselect);
 }
Beispiel #41
0
 protected abstract bool TriggerOnBackspace(SourceText text, int position, CompletionTriggerInfo triggerInfo, OptionSet options);
Beispiel #42
0
        /// <summary>
        /// Returns true if item1 is a better completion item than item2 given the provided filter
        /// text, or false if it is not better.
        /// </summary>
        public virtual bool IsBetterFilterMatch(CompletionItem item1, CompletionItem item2, string filterText, CompletionTriggerInfo triggerInfo, CompletionFilterReason filterReason)
        {
            var patternMatcher = GetPatternMatcher(_completionService.GetCultureSpecificQuirks(filterText));
            var match1         = patternMatcher.GetFirstMatch(_completionService.GetCultureSpecificQuirks(item1.FilterText));
            var match2         = patternMatcher.GetFirstMatch(_completionService.GetCultureSpecificQuirks(item2.FilterText));

            if (match1 != null && match2 != null)
            {
                var result = CompareMatches(match1.Value, match2.Value, item1, item2);
                if (result != 0)
                {
                    return(result < 0);
                }
            }
            else if (match1 != null)
            {
                return(true);
            }
            else if (match2 != null)
            {
                return(false);
            }

            // If they both seemed just as good, but they differ on preselection, then
            // item1 is better if it is preselected, otherwise it it worse.
            if (item1.Preselect != item2.Preselect)
            {
                return(item1.Preselect);
            }

            // Prefer things with a keyword glyph, if the filter texts are the same.
            if (item1.Glyph != item2.Glyph && item1.FilterText == item2.FilterText)
            {
                return(item1.Glyph == Glyph.Keyword);
            }

            // They matched on everything, including preselection values.  Item1 is better if it
            // has a lower MRU index.

            var item1MRUIndex = _completionService.GetMRUIndex(item1);
            var item2MRUIndex = _completionService.GetMRUIndex(item2);

            // The one with the lower index is the better one.
            return(item1MRUIndex < item2MRUIndex);
        }
Beispiel #43
0
        public static Model CreateModel(
            DisconnectedBufferGraph disconnectedBufferGraph,
            TextSpan defaultTrackingSpanInSubjectBuffer,
            ImmutableArray<CompletionItem> totalItems,
            CompletionItem selectedItem,
            bool isHardSelection,
            bool isUnique,
            bool useSuggestionCompletionMode,
            CompletionItem builder,
            CompletionTriggerInfo triggerInfo,
            ICompletionService completionService,
            Workspace workspace)
        {
            var updatedTotalItems = totalItems;
            CompletionItem updatedSelectedItem = selectedItem;
            CompletionItem updatedBuilder = builder;
            CompletionItem updatedDefaultBuilder = GetDefaultBuilder(defaultTrackingSpanInSubjectBuffer);

            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) &&
                triggerInfo.TriggerReason != CompletionTriggerReason.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 updatedTotalItemsBuilder = ImmutableArray.CreateBuilder<CompletionItem>();
                updatedSelectedItem = null;

                foreach (var item in totalItems)
                {
                    var updatedItem = new DescriptionModifyingCompletionItem(item, completionService, workspace);
                    updatedTotalItemsBuilder.Add(updatedItem);

                    if (item == selectedItem)
                    {
                        updatedSelectedItem = updatedItem;
                    }
                }

                updatedTotalItems = updatedTotalItemsBuilder.AsImmutable();

                updatedBuilder = null;
                if (builder != null)
                {
                    updatedBuilder = new DescriptionModifyingCompletionItem(builder, completionService, workspace);
                }

                updatedDefaultBuilder = new DescriptionModifyingCompletionItem(
                    GetDefaultBuilder(defaultTrackingSpanInSubjectBuffer),
                    completionService,
                    workspace);
            }

            return new Model(
                disconnectedBufferGraph,
                updatedTotalItems,
                updatedTotalItems,
                updatedSelectedItem,
                isHardSelection,
                isUnique,
                useSuggestionCompletionMode,
                updatedBuilder,
                updatedDefaultBuilder,
                triggerInfo,
                GetDefaultTrackingSpanEnd(defaultTrackingSpanInSubjectBuffer, disconnectedBufferGraph),
                completionService.DismissIfEmpty);
        }
Beispiel #44
0
        public static Model CreateModel(
            DisconnectedBufferGraph disconnectedBufferGraph,
            TextSpan defaultTrackingSpanInSubjectBuffer,
            IList<CompletionItem> totalItems,
            CompletionItem selectedItem,
            bool isHardSelection,
            bool isUnique,
            bool useSuggestionCompletionMode,
            CompletionItem builder,
            CompletionTriggerInfo triggerInfo,
            ICompletionService completionService,
            Workspace workspace)
        {
            var updatedTotalItems = totalItems;
            CompletionItem updatedSelectedItem = selectedItem;
            CompletionItem updatedBuilder = builder;
            CompletionItem updatedDefaultBuilder = GetDefaultBuilder(defaultTrackingSpanInSubjectBuffer);

            if (completionService != null && workspace != null && triggerInfo.TriggerReason != CompletionTriggerReason.Snippets)
            {
                // In order to add snippet expansion notes to completion item descriptions, update
                // all of the provided CompletionItems to DisplayCompletionItems 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 shorcuts.

                updatedTotalItems = new List<CompletionItem>();
                updatedSelectedItem = null;

                foreach (var item in totalItems)
                {
                    var updatedItem = new DescriptionModifyingCompletionItem(item, completionService, workspace);
                    updatedTotalItems.Add(updatedItem);

                    if (item == selectedItem)
                    {
                        updatedSelectedItem = updatedItem;
                    }
                }

                updatedBuilder = null;
                if (builder != null)
                {
                    updatedBuilder = new DescriptionModifyingCompletionItem(builder, completionService, workspace);
                }

                updatedDefaultBuilder = new DescriptionModifyingCompletionItem(
                    GetDefaultBuilder(defaultTrackingSpanInSubjectBuffer),
                    completionService,
                    workspace);
            }

            return new Model(
                disconnectedBufferGraph,
                updatedTotalItems,
                updatedTotalItems,
                updatedSelectedItem,
                isHardSelection,
                isUnique,
                useSuggestionCompletionMode,
                updatedBuilder,
                updatedDefaultBuilder,
                triggerInfo,
                GetDefaultTrackingSpanEnd(defaultTrackingSpanInSubjectBuffer, disconnectedBufferGraph),
                completionService.DismissIfEmpty);
        }
Beispiel #45
0
        private async Task <IEnumerable <CompletionItemGroup> > GetGroupsAsync(
            Document documentOpt,
            SourceText text,
            int position,
            CompletionTriggerInfo triggerInfo,
            IEnumerable <ICompletionProvider> completionProviders,
            OptionSet options,
            CancellationToken cancellationToken)
        {
            completionProviders = completionProviders ?? this.GetDefaultCompletionProviders();
            var completionProviderToIndex = GetCompletionProviderToIndex(completionProviders);

            IEnumerable <ICompletionProvider> triggeredProviders;

            switch (triggerInfo.TriggerReason)
            {
            case CompletionTriggerReason.TypeCharCommand:
                triggeredProviders = completionProviders.Where(p => p.IsTriggerCharacter(text, position - 1, options)).ToList();
                break;

            case CompletionTriggerReason.BackspaceOrDeleteCommand:
                triggeredProviders = this.TriggerOnBackspace(text, position, triggerInfo, options)
                        ? completionProviders
                        : SpecializedCollections.EmptyEnumerable <ICompletionProvider>();
                break;

            default:
                triggeredProviders = completionProviders;
                break;
            }

            // Now, ask all the triggered providers if they can provide a group.
            var providersAndGroups = new List <ProviderGroup>();

            foreach (var p in triggeredProviders)
            {
                var g = await GetGroupAsync(p, documentOpt, text, position, triggerInfo, cancellationToken).ConfigureAwait(false);

                if (g != null)
                {
                    providersAndGroups.Add(new ProviderGroup {
                        Provider = p, Group = g
                    });
                }
            }

            // See if there was a group provided that was exclusive and had items in it.  If so, then
            // that's all we'll return.
            var firstExclusiveGroup = providersAndGroups.FirstOrDefault(
                t => t.Group.IsExclusive && t.Group.Items.Any());

            if (firstExclusiveGroup != null)
            {
                return(SpecializedCollections.SingletonEnumerable(firstExclusiveGroup.Group));
            }
            else
            {
                // If no exclusive providers provided anything, then go through the remaining
                // triggered list and see if any provide items.
                var nonExclusiveGroups = providersAndGroups.Where(t => !t.Group.IsExclusive).ToList();

                // If we still don't have any items, then we're definitely done.
                if (!nonExclusiveGroups.Any(g => g.Group.Items.Any()))
                {
                    return(null);
                }

                // If we do have items, then ask all the other (non exclusive providers) if they
                // want to augment the items.
                var augmentTriggerInfo = triggerInfo.WithIsAugment(true);

                var usedProviders                = nonExclusiveGroups.Select(g => g.Provider);
                var nonUsedProviders             = completionProviders.Except(usedProviders);
                var nonUsedNonExclusiveProviders = new List <ProviderGroup>();
                foreach (var p in nonUsedProviders)
                {
                    var g = await GetGroupAsync(p, documentOpt, text, position, augmentTriggerInfo, cancellationToken).ConfigureAwait(false);

                    if (g != null && !g.IsExclusive)
                    {
                        nonUsedNonExclusiveProviders.Add(new ProviderGroup {
                            Provider = p, Group = g
                        });
                    }
                }

                var allGroups = nonExclusiveGroups.Concat(nonUsedNonExclusiveProviders).ToList();
                if (allGroups.Count == 0)
                {
                    return(null);
                }

                // Providers are ordered, but we processed them in our own order.  Ensure that the
                // groups are properly ordered based on the original providers.
                allGroups.Sort((p1, p2) => completionProviderToIndex[p1.Provider] - completionProviderToIndex[p2.Provider]);
                return(allGroups.Select(g => g.Group));
            }
        }