Beispiel #1
0
        /// <summary>
        /// The method performs a preliminarily filtering of commit availability.
        /// In case of a doubt, it should respond with true.
        /// We will be able to cancel later in
        /// <see cref="TryCommit(IAsyncCompletionSession, ITextBuffer, VSCompletionItem, char, CancellationToken)"/>
        /// based on <see cref="VSCompletionItem"/> item, e.g. based on <see cref="CompletionItemRules"/>.
        /// </summary>
        public bool ShouldCommitCompletion(
            IAsyncCompletionSession session,
            SnapshotPoint location,
            char typedChar,
            CancellationToken cancellationToken)
        {
            if (!PotentialCommitCharacters.Contains(typedChar))
            {
                return(false);
            }

            return(!(session.Properties.TryGetProperty(CompletionSource.ExcludedCommitCharacters, out ImmutableArray <char> excludedCommitCharacter) &&
                     excludedCommitCharacter.Contains(typedChar)));
        }
        public async Task <CompletionContext> GetCompletionContextAsync(IAsyncCompletionSession session, CompletionTrigger trigger, SnapshotPoint triggerLocation, SnapshotSpan applicableToSpan, CancellationToken token)
        {
            var items = ImmutableArray.CreateBuilder <CompletionItem>();

            items.AddRange(keywords);
            foreach (var item in this.document.GetCompletions(triggerLocation.Position))
            {
                items.Add(new CompletionItem(item, this, CompletionItemIcon));
            }

            var result = new CompletionContext(items.ToImmutable());

            return(await Task.FromResult(result));
        }
Beispiel #3
0
        Task <object> ICompletionDocumentationProvider.GetDocumentationAsync(IAsyncCompletionSession session, CompletionItem item, CancellationToken token)
        {
            if (!item.Properties.TryGetProperty <BaseInfo> (typeof(BaseInfo), out var info) || info == null)
            {
                return(Task.FromResult <object> (null));
            }

            if (!session.Properties.TryGetProperty <MSBuildCompletionSessionContext> (typeof(MSBuildCompletionSessionContext), out var context))
            {
                return(Task.FromResult <object> (null));
            }

            return(DisplayElementFactory.GetInfoTooltipElement(context.doc, info, context.rr, token));
        }
Beispiel #4
0
        async Task <List <CompletionItem> > GetPackageNameCompletions(IAsyncCompletionSession session, MSBuildRootDocument doc, string searchQuery, CancellationToken token)
        {
            var tfm = doc.GetTargetFrameworkNuGetSearchParameter();

            session.Properties.AddProperty(typeof(NuGetSearchUpdater), new NuGetSearchUpdater(this, session, tfm));

            if (string.IsNullOrEmpty(searchQuery))
            {
                return(null);
            }

            var results = await provider.PackageSearchManager.SearchPackageNames(searchQuery.ToLower(), tfm).ToTask(token);

            return(CreateNuGetItemsFromSearchResults(results));
        }
Beispiel #5
0
        public async Task <CompletionContext> GetCompletionContextAsync(IAsyncCompletionSession session, CompletionTrigger trigger, SnapshotPoint triggerLocation, SnapshotSpan applicableToSpan, CancellationToken token)
        {
            var document = applicableToSpan.Snapshot.GetOpenDocumentInCurrentContextWithChanges();

            Microsoft.CodeAnalysis.Completion.CompletionTrigger CreateTrigger()
            {
                switch (trigger.Reason)
                {
                case CompletionTriggerReason.Invoke:
                case CompletionTriggerReason.InvokeAndCommitIfUnique:
                    return(Microsoft.CodeAnalysis.Completion.CompletionTrigger.Invoke);

                case CompletionTriggerReason.Insertion:
                    return(Microsoft.CodeAnalysis.Completion.CompletionTrigger.CreateInsertionTrigger(trigger.Character));

                case CompletionTriggerReason.Backspace:
                case CompletionTriggerReason.Deletion:
                    return(Microsoft.CodeAnalysis.Completion.CompletionTrigger.CreateDeletionTrigger(trigger.Character));

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            var completions = await _completionService.GetCompletionsAsync(
                document,
                triggerLocation.Position,
                CreateTrigger(),
                document.Workspace.Options,
                cancellationToken : token);

            if (completions == null)
            {
                return(CompletionContext.Empty);
            }

            var items = completions.Items
                        .Select(x =>
            {
                var item = new CompletionItem(x.DisplayText, this, new ImageElement(x.Glyph.GetImageId()));
                item.Properties.AddProperty("Document", document);
                item.Properties.AddProperty("CompletionItem", x);
                return(item);
            })
                        .ToImmutableArray();

            return(new CompletionContext(items));
        }
        public Task <object> GetDescriptionAsync(IAsyncCompletionSession session, CompletionItem item, CancellationToken token)
        {
            if (item is null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            if (!item.Properties.TryGetProperty(DescriptionKey, out AggregateBoundAttributeDescription completionDescription))
            {
                return(Task.FromResult <object>(string.Empty));
            }

            var description = _descriptionFactory.CreateClassifiedDescription(completionDescription);

            return(Task.FromResult <object>(description));
        }
        public bool ShouldCommitCompletion(IAsyncCompletionSession session, SnapshotPoint location, char typedChar, CancellationToken token)
        {
            if (Array.IndexOf(allCommitChars, typedChar) < 0)
            {
                return(false);
            }

            // only handle sessions that XML completion participated in
            // although we aren't told what exact item we might be committing yet, the trigger tells us enough
            // about the kind of item to allow us to specialize the commit chars
            if (!session.Properties.TryGetProperty(typeof(XmlCompletionTrigger), out XmlCompletionTrigger kind))
            {
                return(false);
            }
            ;

            switch (kind)
            {
            case XmlCompletionTrigger.Element:
            case XmlCompletionTrigger.ElementWithBracket:
                // allow using / as a commit char for elements as self-closing elements, but special case disallowing it
                // in the cases where that could conflict with typing the / at the start of a closing tag
                if (typedChar == '/')
                {
                    var span = session.ApplicableToSpan.GetSpan(location.Snapshot);
                    if (span.Length == (kind == XmlCompletionTrigger.Element ? 0 : 1))
                    {
                        return(false);
                    }
                }
                return(Array.IndexOf(tagCommitChars, typedChar) > -1);

            case XmlCompletionTrigger.Attribute:
                return(Array.IndexOf(attributeCommitChars, typedChar) > -1);

            case XmlCompletionTrigger.AttributeValue:
                return(Array.IndexOf(attributeValueCommitChars, typedChar) > -1);

            case XmlCompletionTrigger.DocType:
                return(Array.IndexOf(tagCommitChars, typedChar) > -1);

            case XmlCompletionTrigger.Entity:
                return(Array.IndexOf(entityCommitChars, typedChar) > -1);
            }

            return(false);
        }
        public async Task <CompletionContext> GetCompletionContextAsync(
            IAsyncCompletionSession session,
            CompletionTrigger trigger,
            SnapshotPoint triggerLocation,
            SnapshotSpan applicableSpan,
            CancellationToken token)
        {
            _foregroundDispatcher.AssertBackgroundThread();

            try
            {
                var syntaxTree = await _parser.GetLatestSyntaxTreeAsync(triggerLocation.Snapshot, token);

                var location             = new SourceSpan(triggerLocation.Position, 0);
                var razorCompletionItems = _completionFactsService.GetCompletionItems(syntaxTree, location);

                var completionItems = new List <CompletionItem>();
                foreach (var razorCompletionItem in razorCompletionItems)
                {
                    if (razorCompletionItem.Kind != RazorCompletionItemKind.Directive)
                    {
                        // Don't support any other types of completion kinds other than directives.
                        continue;
                    }

                    var completionItem = new CompletionItem(
                        displayText: razorCompletionItem.DisplayText,
                        filterText: razorCompletionItem.DisplayText,
                        insertText: razorCompletionItem.InsertText,
                        source: this,
                        icon: DirectiveImageGlyph,
                        filters: DirectiveCompletionFilters,
                        suffix: string.Empty,
                        sortText: razorCompletionItem.DisplayText,
                        attributeIcons: ImmutableArray <ImageElement> .Empty);
                    completionItem.Properties.AddProperty(DescriptionKey, razorCompletionItem.Description);
                    completionItems.Add(completionItem);
                }
                var context = new CompletionContext(completionItems.ToImmutableArray());
                return(context);
            }
            catch (OperationCanceledException)
            {
                return(CompletionContext.Empty);
            }
        }
        internal Task <CompletionContext> GetCompletionContextAsync(IAsyncCompletionSession session, CompletionTrigger trigger, SnapshotPoint triggerLocation, SnapshotSpan applicableToSpan, CancellationToken token)
        {
            CompletionContext context;

            if (TextView.TryGetWordCompletionData(out var wordCompletionData))
            {
                var itemsRaw = wordCompletionData.WordCollection.Select(x => new CompletionItem(x, this)).ToArray();
                var items    = ImmutableArray.Create <CompletionItem>(itemsRaw);
                context = new CompletionContext(items);
            }
            else
            {
                context = CompletionContext.Empty;
            }

            return(Task.FromResult(context));
        }
        public async Task <object> GetDescriptionAsync(IAsyncCompletionSession session, CompletionItem item, CancellationToken token)
        {
            if (item.Properties.TryGetProperty(ResolvePropertyKey, out Func <Microsoft.VisualStudio.LanguageServer.Protocol.CompletionItem, Task <Microsoft.VisualStudio.LanguageServer.Protocol.CompletionItem> > resolver) &&
                resolver != null &&
                item.Properties.TryGetProperty(ProtocolItemKey, out Microsoft.VisualStudio.LanguageServer.Protocol.CompletionItem unresolvedItem))
            {
                var resolvedItem = await resolver(unresolvedItem);

                if (resolvedItem != null)
                {
                    unresolvedItem.TextEdit            = unresolvedItem.TextEdit ?? resolvedItem.TextEdit;
                    unresolvedItem.AdditionalTextEdits = unresolvedItem.AdditionalTextEdits ?? resolvedItem.AdditionalTextEdits;
                    return(resolvedItem?.Detail);
                }
            }

            return(null);
        }
        public CommitResult TryCommit(IAsyncCompletionSession session, ITextBuffer buffer, CompletionItem item, char typedChar, CancellationToken token)
        {
            if (!item.TryGetKind(out var kind))
            {
                return(CommitResult.Unhandled);
            }

            switch (kind)
            {
            case XmlCompletionItemKind.MultipleClosingTags:
            case XmlCompletionItemKind.ClosingTag:
                InsertClosingTags(session, buffer, item);
                return(CommitResult.Handled);
            }

            LoggingService.LogWarning($"XML commit manager did not handle unknown special completion kind {kind}");
            return(CommitResult.Unhandled);
        }
Beispiel #12
0
        public Task <ImmutableArray <VSCompletionItem> > SortCompletionListAsync(
            IAsyncCompletionSession session,
            AsyncCompletionSessionInitialDataSnapshot data,
            CancellationToken cancellationToken)
        {
            if (session.TextView.Properties.TryGetProperty(CompletionSource.TargetTypeFilterExperimentEnabled, out bool isExperimentEnabled) && isExperimentEnabled)
            {
                AsyncCompletionLogger.LogSessionHasExperimentEnabled();

                // This method is called exactly once, so use the opportunity to set a baseline for telemetry.
                if (data.InitialList.Any(i => i.Filters.Any(f => f.DisplayText == FeaturesResources.Target_type_matches)))
                {
                    AsyncCompletionLogger.LogSessionContainsTargetTypeFilter();
                }
            }

            return(Task.FromResult(data.InitialList.OrderBy(i => i.SortText).ToImmutableArray()));
        }
        protected override Task <CompletionContext> GetAttributeCompletionsAsync(
            IAsyncCompletionSession session,
            SnapshotPoint triggerLocation,
            List <XObject> nodePath,
            IAttributedXObject attributedObject,
            Dictionary <string, string> existingAtts,
            CancellationToken token)
        {
            if (nodePath.LastOrDefault() is XElement xel && xel.NameEquals("Hello", true))
            {
                var item = new CompletionItem("There", this)
                           .AddKind(XmlCompletionItemKind.Attribute);
                var items = ImmutableArray <CompletionItem> .Empty;
                items = items.Add(item);
                return(Task.FromResult(new CompletionContext(items)));
            }

            return(Task.FromResult(CompletionContext.Empty));
        }
Beispiel #14
0
        public CompletionContinuation HandleTypedChar(IAsyncCompletionSession session, VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem selectedItem, SnapshotPoint location, char typedChar, CancellationToken token)
        {
            if (this.serverCommitCharacters.Contains(typedChar))
            {
                return(CompletionContinuation.Commit);
            }

            if (selectedItem?.CommitCharacters.Contains(typedChar) == true)
            {
                return(CompletionContinuation.Commit);
            }

            if (this.ShouldContinue(typedChar))
            {
                return(CompletionContinuation.Continue);
            }

            return(CompletionContinuation.Dismiss);
        }
        public async Task <object> GetDescriptionAsync(IAsyncCompletionSession session, CompletionItem item, CancellationToken token)
        {
            if (item.Properties.TryGetProperty("knownmoniker", out string name))
            {
                try
                {
                    PropertyInfo property = typeof(KnownMonikers).GetProperty(name, BindingFlags.Static | BindingFlags.Public);
                    var          moniker  = (ImageMoniker)property.GetValue(null, null);

                    await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

                    var image = new CrispImage
                    {
                        Source = await moniker.ToBitmapSourceAsync(100),
                        Height = 100,
                        Width  = 100,
                    };

                    return(image);
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.Write(ex);
                }
            }
            else if (item.Properties.TryGetProperty("IsGlobal", out bool isGlobal) && isGlobal)
            {
                var img = GetFileName(item.DisplayText);

                if (!string.IsNullOrEmpty(img))
                {
                    await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

                    return(new Image
                    {
                        Source = new BitmapImage(new Uri(img)),
                        MaxHeight = 720 // VS minimum requirements is 1280x720
                    });
                }
            }

            return(null);
        }
Beispiel #16
0
        // this is primarily used to pass info from GetCompletionContextAsync to GetDocumentationAsync
        // but also reuses the values calculated for expression completion in GetCompletionContextAsync
        // if it's determined not be be expression completion but actually ends up
        // in GetElementCompletionsAsync or GetAttributeCompletionsAsync
        async Task <MSBuildCompletionSessionContext> GetSessionContext(IAsyncCompletionSession session, SnapshotPoint triggerLocation, CancellationToken token)
        {
            if (session.Properties.TryGetProperty <MSBuildCompletionSessionContext> (typeof(MSBuildCompletionSessionContext), out var context))
            {
                return(context);
            }
            var parser      = GetParser();
            var parseResult = await parser.GetOrParseAsync((ITextSnapshot2)triggerLocation.Snapshot, token);

            var doc   = parseResult.MSBuildDocument ?? MSBuildRootDocument.Empty;
            var spine = parser.GetSpineParser(triggerLocation);
            var rr    = MSBuildResolver.Resolve(GetSpineParser(triggerLocation), triggerLocation.Snapshot.GetTextSource(), doc, provider.FunctionTypeProvider);

            context = new MSBuildCompletionSessionContext {
                doc = doc, rr = rr, spine = spine
            };
            session.Properties.AddProperty(typeof(MSBuildCompletionSessionContext), context);
            return(context);
        }
Beispiel #17
0
        // this is primarily used to pass info from GetCompletionContextAsync to GetDocumentationAsync
        // but also reuses the values calculated for expression completion in GetCompletionContextAsync
        // if it's determined not be be expression completion but actually ends up
        // in GetElementCompletionsAsync or GetAttributeCompletionsAsync
        async Task <MSBuildCompletionSessionContext> GetSessionContext(IAsyncCompletionSession session, SnapshotPoint triggerLocation, CancellationToken token)
        {
            if (session.Properties.TryGetProperty <MSBuildCompletionSessionContext> (typeof(MSBuildCompletionSessionContext), out var context))
            {
                return(context);
            }

            MSBuildParseResult parseResult = parser.LastOutput ?? await parser.GetOrProcessAsync(triggerLocation.Snapshot, token);

            var doc   = parseResult.MSBuildDocument ?? MSBuildRootDocument.Empty;
            var spine = XmlParser.GetSpineParser(triggerLocation);
            // clone the spine because the resolver alters it
            var rr = MSBuildResolver.Resolve(spine.Clone(), triggerLocation.Snapshot.GetTextSource(), doc, provider.FunctionTypeProvider, token);

            context = new MSBuildCompletionSessionContext {
                doc = doc, rr = rr, spine = spine
            };
            session.Properties.AddProperty(typeof(MSBuildCompletionSessionContext), context);
            return(context);
        }
Beispiel #18
0
        public async Task <CompletionContext> GetCompletionContextAsync(IAsyncCompletionSession session, CompletionTrigger trigger, SnapshotPoint triggerLocation, SnapshotSpan applicableToSpan, CancellationToken token)
        {
            var text = triggerLocation.Snapshot.GetText(0, triggerLocation.Position);
            var data = await DebuggingService.GetCompletionDataAsync(DebuggingService.CurrentFrame, text, token);

            if (data == null)
            {
                return(new CompletionContext(ImmutableArray <CompletionItem> .Empty));
            }

            var builder = ImmutableArray.CreateBuilder <CompletionItem> (data.Items.Count);

            foreach (var item in data.Items)
            {
                var image = new ImageElement(ObjectValueTreeViewController.GetImageId(item.Flags));

                builder.Add(new CompletionItem(item.Name, this, image));
            }

            return(new CompletionContext(builder.MoveToImmutable()));
        }
Beispiel #19
0
        public async Task <CompletionContext> GetCompletionContextAsync(IAsyncCompletionSession session, CompletionTrigger trigger, SnapshotPoint triggerLocation, SnapshotSpan applicableToSpan, CancellationToken cancellationToken)
        {
            var completionContexts = await ComputeNonEmptyCompletionContextsAsync(triggerLocation, applicableToSpan, cancellationToken);

            if (completionContexts.Length == 0)
            {
                return(null);
            }

            var completionItems = new LinkedList <CompletionItem>();

            foreach (var context in completionContexts)
            {
                foreach (var item in context.Items)
                {
                    var completionItem = item.CreateVsCompletionItem(this);
                    completionItems.AddLast(completionItem);
                }
            }

            return(new CompletionContext(completionItems.ToImmutableArray()));
        }
Beispiel #20
0
        public async Task <object> GetDescriptionAsync(IAsyncCompletionSession session, VSCompletionItem item, CancellationToken cancellationToken)
        {
            if (!item.Properties.TryGetProperty(RoslynItem, out RoslynCompletionItem roslynItem) ||
                !session.Properties.TryGetProperty(TriggerSnapshot, out ITextSnapshot triggerSnapshot))
            {
                return(null);
            }

            var document = triggerSnapshot.GetOpenDocumentInCurrentContextWithChanges();

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

            var service = document.GetLanguageService <CompletionService>();

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

            var description = await service.GetDescriptionAsync(document, roslynItem, cancellationToken).ConfigureAwait(false);

            var elements = IntelliSense.Helpers.BuildClassifiedTextElements(description.TaggedParts).ToArray();

            if (elements.Length == 0)
            {
                return(new ClassifiedTextElement());
            }
            else if (elements.Length == 1)
            {
                return(elements[0]);
            }
            else
            {
                return(new ContainerElement(ContainerElementStyle.Stacked | ContainerElementStyle.VerticalPadding, elements));
            }
        }
Beispiel #21
0
        public async Task <CompletionContext> GetCompletionContextAsync(IAsyncCompletionSession session, CompletionTrigger trigger, SnapshotPoint triggerLocation, SnapshotSpan applicableToSpan, CancellationToken token)
        {
            // See whether we are in the key or value portion of the pair
            var lineStart              = triggerLocation.GetContainingLine().Start;
            var spanBeforeCaret        = new SnapshotSpan(lineStart, triggerLocation);
            var textBeforeCaret        = triggerLocation.Snapshot.GetText(spanBeforeCaret);
            var colonIndex             = textBeforeCaret.IndexOf(':');
            var colonExistsBeforeCaret = colonIndex != -1;

            // User is likely in the key portion of the pair
            if (!colonExistsBeforeCaret)
            {
                return(GetContextForKey());
            }

            // User is likely in the value portion of the pair. Try to provide extra items based on the key.
            var KeyExtractingRegex = new Regex(@"\W*(\w+)\W*:");
            var key           = KeyExtractingRegex.Match(textBeforeCaret);
            var candidateName = key.Success ? key.Groups.Count > 0 && key.Groups[1].Success ? key.Groups[1].Value : string.Empty : string.Empty;

            return(GetContextForValue(candidateName));
        }
Beispiel #22
0
        public override async Task <CompletionContext> GetCompletionContextAsync(IAsyncCompletionSession session, CompletionTrigger trigger, SnapshotPoint triggerLocation, SnapshotSpan applicableToSpan, CancellationToken token)
        {
            var context = await GetSessionContext(session, triggerLocation, token);

            var rr    = context.rr;
            var doc   = context.doc;
            var spine = context.spine;

            if (rr?.ElementSyntax != null)
            {
                var reason = ConvertReason(trigger.Reason, trigger.Character);
                if (reason.HasValue && IsPossibleExpressionCompletionContext(spine))
                {
                    string expression   = spine.GetIncompleteValue(triggerLocation.Snapshot);
                    var    triggerState = GetTriggerState(
                        expression,
                        reason.Value,
                        trigger.Character,
                        rr.IsCondition(),
                        out int triggerLength,
                        out ExpressionNode triggerExpression,
                        out var listKind,
                        out IReadOnlyList <ExpressionNode> comparandVariables
                        );
                    if (triggerState != TriggerState.None)
                    {
                        var info = rr.GetElementOrAttributeValueInfo(doc);
                        if (info != null && info.ValueKind != MSBuildValueKind.Nothing)
                        {
                            session.Properties.AddProperty(typeof(TriggerState), triggerState);
                            return(await GetExpressionCompletionsAsync(
                                       session, info, triggerState, listKind, triggerLength, triggerExpression, comparandVariables, rr, triggerLocation, doc, token));
                        }
                    }
                }
            }

            return(await base.GetCompletionContextAsync(session, trigger, triggerLocation, applicableToSpan, token));
        }
Beispiel #23
0
        public async Task <object> GetDescriptionAsync(IAsyncCompletionSession session, CompletionItem item, CancellationToken token)
        {
            var content = new ContainerElement(
                ContainerElementStyle.Wrapped,
                CompletionItemIcon,
                new ClassifiedTextElement(
                    new ClassifiedTextRun(PredefinedClassificationTypeNames.Keyword, "Hello!"),
                    new ClassifiedTextRun(PredefinedClassificationTypeNames.Identifier, " This is a sample item")));
            var lineInfo = new ClassifiedTextElement(
                new ClassifiedTextRun(
                    PredefinedClassificationTypeNames.Comment,
                    "You are on line " + ((int)(session.Properties["LineNumber"]) + 1).ToString()));
            var timeInfo = new ClassifiedTextElement(
                new ClassifiedTextRun(
                    PredefinedClassificationTypeNames.Identifier,
                    "and it is " + DateTime.Now.ToShortTimeString()));

            return(new ContainerElement(
                       ContainerElementStyle.Stacked,
                       content,
                       lineInfo,
                       timeInfo));
        }
Beispiel #24
0
        public Task <ImmutableArray <VSCompletionItem> > SortCompletionListAsync(
            IAsyncCompletionSession session,
            AsyncCompletionSessionInitialDataSnapshot data,
            CancellationToken cancellationToken)
        {
            var stopwatch   = SharedStopwatch.StartNew();
            var sessionData = CompletionSessionData.GetOrCreateSessionData(session);

            // This method is called exactly once, so use the opportunity to set a baseline for telemetry.
            if (sessionData.TargetTypeFilterExperimentEnabled)
            {
                AsyncCompletionLogger.LogSessionHasTargetTypeFilterEnabled();
                if (data.InitialList.Any(i => i.Filters.Any(f => f.DisplayText == FeaturesResources.Target_type_matches)))
                {
                    AsyncCompletionLogger.LogSessionContainsTargetTypeFilter();
                }
            }

            // Sort by default comparer of Roslyn CompletionItem
            var sortedItems = data.InitialList.OrderBy(CompletionItemData.GetOrAddDummyRoslynItem).ToImmutableArray();

            AsyncCompletionLogger.LogItemManagerSortTicksDataPoint((int)stopwatch.Elapsed.TotalMilliseconds);
            return(Task.FromResult(sortedItems));
        }
        public CommitResult TryCommit(IAsyncCompletionSession session, ITextBuffer buffer, CompletionItem item, char typedChar, CancellationToken token)
        {
            if (!item.Properties.TryGetProperty <MSBuildSpecialCommitKind> (typeof(MSBuildSpecialCommitKind), out var kind))
            {
                return(CommitResult.Unhandled);
            }

            switch (kind)
            {
            case MSBuildSpecialCommitKind.NewGuid:
                InsertGuid(session, buffer);
                return(CommitResult.Handled);

            case MSBuildSpecialCommitKind.ItemReference:
            case MSBuildSpecialCommitKind.PropertyReference:
                Insert(session, buffer, item.InsertText);
                RetriggerCompletion(session.TextView);
                //TODO: insert trailing )
                return(CommitResult.Handled);
            }

            LoggingService.LogError($"MSBuild commit manager did not handle unknown special completion kind {kind}");
            return(CommitResult.Unhandled);
        }
Beispiel #26
0
        Task <object> ICompletionDocumentationProvider.GetDocumentationAsync(
            IAsyncCompletionSession session, CompletionItem item,
            CancellationToken token)
        {
            if (!session.Properties.TryGetProperty <MSBuildCompletionSessionContext> (typeof(MSBuildCompletionSessionContext), out var context))
            {
                return(Task.FromResult <object> (null));
            }

            // note that the value is a tuple despite the key
            if (item.Properties.TryGetProperty <Tuple <string, FeedKind> > (typeof(Tuple <string, FeedKind>), out var packageSearchResult))
            {
                return(GetPackageDocumentationAsync(context.doc, packageSearchResult.Item1, packageSearchResult.Item2, token));
            }

            if (item.Properties.TryGetProperty <BaseInfo> (typeof(BaseInfo), out var info) && info != null)
            {
                return(provider.DisplayElementFactory.GetInfoTooltipElement(
                           session.TextView.TextBuffer, context.doc, info, context.rr, token
                           ));
            }

            return(Task.FromResult <object> (null));
        }
Beispiel #27
0
        async Task <CompletionContext> GetExpressionCompletionsAsync(
            IAsyncCompletionSession session,
            ValueInfo info, TriggerState triggerState, ListKind listKind,
            int triggerLength, ExpressionNode triggerExpression,
            IReadOnlyList <ExpressionNode> comparandVariables,
            MSBuildResolveResult rr, SnapshotPoint triggerLocation,
            MSBuildRootDocument doc, CancellationToken token)
        {
            var kind = info.InferValueKindIfUnknown();

            if (!ValidateListPermitted(listKind, kind))
            {
                return(CompletionContext.Empty);
            }

            bool allowExpressions = kind.AllowExpressions();

            kind = kind.GetScalarType();

            if (kind == MSBuildValueKind.Data || kind == MSBuildValueKind.Nothing)
            {
                return(CompletionContext.Empty);
            }

            bool isValue = triggerState == TriggerState.Value;

            var items = new List <CompletionItem> ();

            if (comparandVariables != null && isValue)
            {
                foreach (var ci in ExpressionCompletion.GetComparandCompletions(doc, comparandVariables))
                {
                    items.Add(CreateCompletionItem(ci, XmlCompletionItemKind.AttributeValue));
                }
            }

            if (isValue)
            {
                switch (kind)
                {
                case MSBuildValueKind.NuGetID:
                    if (triggerExpression is ExpressionText t)
                    {
                        var packageNameItems = await GetPackageNameCompletions(session, doc, t.Value, token);

                        if (packageNameItems != null)
                        {
                            items.AddRange(packageNameItems);
                        }
                    }
                    break;

                case MSBuildValueKind.NuGetVersion: {
                    var packageVersionItems = await GetPackageVersionCompletions(doc, rr, token);

                    if (packageVersionItems != null)
                    {
                        items.AddRange(packageVersionItems);
                    }
                    break;
                }

                case MSBuildValueKind.Sdk:
                case MSBuildValueKind.SdkWithVersion: {
                    var sdkItems = await GetSdkCompletions(doc, token);

                    if (sdkItems != null)
                    {
                        items.AddRange(sdkItems);
                    }
                    break;
                }

                case MSBuildValueKind.Guid:
                    items.Add(CreateSpecialItem("New GUID", "Inserts a new GUID", KnownImages.Add, MSBuildSpecialCommitKind.NewGuid));
                    break;

                case MSBuildValueKind.Lcid:
                    items.AddRange(GetLcidCompletions());
                    break;
                }
            }

            //TODO: better metadata support
            IEnumerable <BaseInfo> cinfos;

            if (info.CustomType != null && info.CustomType.Values.Count > 0 && isValue)
            {
                cinfos = info.CustomType.Values;
            }
            else
            {
                //FIXME: can we avoid awaiting this unless we actually need to resolve a function? need to propagate async downwards
                await provider.FunctionTypeProvider.EnsureInitialized(token);

                cinfos = ExpressionCompletion.GetCompletionInfos(rr, triggerState, kind, triggerExpression, triggerLength, doc, provider.FunctionTypeProvider);
            }

            if (cinfos != null)
            {
                foreach (var ci in cinfos)
                {
                    items.Add(CreateCompletionItem(ci, XmlCompletionItemKind.AttributeValue));
                }
            }

            if ((allowExpressions && isValue) || triggerState == TriggerState.BareFunctionArgumentValue)
            {
                items.Add(CreateSpecialItem("$(", "Property reference", KnownImages.MSBuildProperty, MSBuildSpecialCommitKind.PropertyReference));
            }

            if (allowExpressions && isValue)
            {
                items.Add(CreateSpecialItem("@(", "Item reference", KnownImages.MSBuildItem, MSBuildSpecialCommitKind.ItemReference));
                if (IsMetadataAllowed(triggerExpression, rr))
                {
                    items.Add(CreateSpecialItem("%(", "Metadata reference", KnownImages.MSBuildItem, MSBuildSpecialCommitKind.MetadataReference));
                }
            }

            if (items.Count > 0)
            {
                return(CreateCompletionContext(items));
            }

            return(CompletionContext.Empty);
        }
Beispiel #28
0
        private FilteredCompletionModel UpdateCompletionList(
            IAsyncCompletionSession session,
            AsyncCompletionSessionDataSnapshot data,
            CancellationToken cancellationToken)
        {
            if (!session.Properties.TryGetProperty(CompletionSource.HasSuggestionItemOptions, out bool hasSuggestedItemOptions))
            {
                // This is the scenario when the session is created out of Roslyn, in some other provider, e.g. in Debugger.
                // For now, the default hasSuggestedItemOptions is false.
                hasSuggestedItemOptions = false;
            }

            hasSuggestedItemOptions |= data.DisplaySuggestionItem;

            var filterText = session.ApplicableToSpan.GetText(data.Snapshot);
            var reason     = data.Trigger.Reason;

            if (!session.Properties.TryGetProperty(CompletionSource.InitialTriggerKind, out CompletionTriggerKind initialRoslynTriggerKind))
            {
                initialRoslynTriggerKind = CompletionTriggerKind.Invoke;
            }

            // Check if the user is typing a number. If so, only proceed if it's a number
            // directly after a <dot>. That's because it is actually reasonable for completion
            // to be brought up after a <dot> and for the user to want to filter completion
            // items based on a number that exists in the name of the item. However, when
            // we are not after a dot (i.e. we're being brought up after <space> is typed)
            // then we don't want to filter things. Consider the user writing:
            //
            //      dim i =<space>
            //
            // We'll bring up the completion list here (as VB has completion on <space>).
            // If the user then types '3', we don't want to match against Int32.
            if (filterText.Length > 0 && char.IsNumber(filterText[0]))
            {
                if (!IsAfterDot(data.Snapshot, session.ApplicableToSpan))
                {
                    // Dismiss the session.
                    return(null);
                }
            }

            // We need to filter if a non-empty strict subset of filters are selected
            var selectedFilters = data.SelectedFilters.Where(f => f.IsSelected).Select(f => f.Filter).ToImmutableArray();
            var needToFilter    = selectedFilters.Length > 0 && selectedFilters.Length < data.SelectedFilters.Length;
            var filterReason    = Helpers.GetFilterReason(data.Trigger);

            // If the session was created/maintained out of Roslyn, e.g. in debugger; no properties are set and we should use data.Snapshot.
            // However, we prefer using the original snapshot in some projection scenarios.
            if (!session.Properties.TryGetProperty(CompletionSource.TriggerSnapshot, out ITextSnapshot snapshotForDocument))
            {
                snapshotForDocument = data.Snapshot;
            }

            var document          = snapshotForDocument.TextBuffer.AsTextContainer().GetOpenDocumentInCurrentContext();
            var completionService = document?.GetLanguageService <CompletionService>();
            var completionRules   = completionService?.GetRules() ?? CompletionRules.Default;
            var completionHelper  = document != null?CompletionHelper.GetHelper(document) : _defaultCompletionHelper;

            var initialListOfItemsToBeIncluded = new List <ExtendedFilterResult>();

            foreach (var item in data.InitialSortedList)
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (needToFilter && ShouldBeFilteredOutOfCompletionList(item, selectedFilters))
                {
                    continue;
                }

                if (!item.Properties.TryGetProperty(CompletionSource.RoslynItem, out RoslynCompletionItem roslynItem))
                {
                    roslynItem = RoslynCompletionItem.Create(
                        displayText: item.DisplayText,
                        filterText: item.FilterText,
                        sortText: item.SortText,
                        displayTextSuffix: item.Suffix);
                }

                if (MatchesFilterText(completionHelper, roslynItem, filterText, initialRoslynTriggerKind, filterReason, _recentItemsManager.RecentItems))
                {
                    initialListOfItemsToBeIncluded.Add(new ExtendedFilterResult(item, new FilterResult(roslynItem, filterText, matchedFilterText: true)));
                }
                else
                {
                    // The item didn't match the filter text.  We'll still keep it in the list
                    // if one of two things is true:
                    //
                    //  1. The user has only typed a single character.  In this case they might
                    //     have just typed the character to get completion.  Filtering out items
                    //     here is not desirable.
                    //
                    //  2. They brough up completion with ctrl-j or through deletion.  In these
                    //     cases we just always keep all the items in the list.
                    if (initialRoslynTriggerKind == CompletionTriggerKind.Deletion ||
                        initialRoslynTriggerKind == CompletionTriggerKind.Invoke ||
                        filterText.Length <= 1)
                    {
                        initialListOfItemsToBeIncluded.Add(new ExtendedFilterResult(item, new FilterResult(roslynItem, filterText, matchedFilterText: false)));
                    }
                }
            }

            if (data.Trigger.Reason == CompletionTriggerReason.Backspace &&
                completionRules.DismissIfLastCharacterDeleted &&
                session.ApplicableToSpan.GetText(data.Snapshot).Length == 0)
            {
                // Dismiss the session
                return(null);
            }

            if (initialListOfItemsToBeIncluded.Count == 0)
            {
                return(HandleAllItemsFilteredOut(reason, data.SelectedFilters, completionRules));
            }

            var options = document?.Project.Solution.Options;
            var highlightMatchingPortions = options?.GetOption(CompletionOptions.HighlightMatchingPortionsOfCompletionListItems, document.Project.Language) ?? true;
            var showCompletionItemFilters = options?.GetOption(CompletionOptions.ShowCompletionItemFilters, document.Project.Language) ?? true;

            var updatedFilters = showCompletionItemFilters
                ? GetUpdatedFilters(initialListOfItemsToBeIncluded, data.SelectedFilters)
                : ImmutableArray <CompletionFilterWithState> .Empty;

            var highlightedList = GetHighlightedList(initialListOfItemsToBeIncluded, filterText, completionHelper, highlightMatchingPortions).ToImmutableArray();

            // If this was deletion, then we control the entire behavior of deletion ourselves.
            if (initialRoslynTriggerKind == CompletionTriggerKind.Deletion)
            {
                return(HandleDeletionTrigger(data.Trigger.Reason, initialListOfItemsToBeIncluded, filterText, updatedFilters, highlightedList));
            }

            Func <ImmutableArray <RoslynCompletionItem>, string, ImmutableArray <RoslynCompletionItem> > filterMethod;

            if (completionService == null)
            {
                filterMethod = (items, text) => CompletionService.FilterItems(completionHelper, items, text);
            }
            else
            {
                filterMethod = (items, text) => completionService.FilterItems(document, items, text);
            }

            return(HandleNormalFiltering(
                       filterMethod,
                       filterText,
                       updatedFilters,
                       initialRoslynTriggerKind,
                       filterReason,
                       data.Trigger.Character,
                       initialListOfItemsToBeIncluded,
                       highlightedList,
                       completionHelper,
                       hasSuggestedItemOptions));
        }
        public CommitResult TryCommit(IAsyncCompletionSession session, ITextBuffer buffer, CompletionItem item, char typedChar, CancellationToken token)
        {
            if (item.Properties.TryGetProperty(ReplAsyncCompletionSource.ProtocolItemKey, out Microsoft.VisualStudio.LanguageServer.Protocol.CompletionItem completionItem) &&
                item.Properties.TryGetProperty(ReplAsyncCompletionSource.TriggerPointKey, out SnapshotPoint triggerLocation))
            {
                // Tab and Enter characters should also commit.
                if (typedChar != '\t' && typedChar != '\n')
                {
                    bool isCommitCharacter = false;

                    if (completionItem.CommitCharacters != null && completionItem.CommitCharacters.Length != 0)
                    {
                        // If there are commit characters set for the particular completion item, then it should take precedence.
                        foreach (var completionItemCommitCharacter in completionItem.CommitCharacters)
                        {
                            if (completionItemCommitCharacter.Length > 0 && completionItemCommitCharacter[0] == typedChar)
                            {
                                isCommitCharacter = true;
                                break;
                            }
                        }

                        if (!isCommitCharacter)
                        {
                            return(new CommitResult(isHandled: false, behavior: CommitBehavior.CancelCommit));
                        }
                    }

                    // TODO: Review if this should be removed if server passes in CommitTriggers for each CompletionItem.  This is in place to unblock VC headless VS demo for build 2019
                    if (!isCommitCharacter && this.typicalDimissChars.Contains(typedChar))
                    {
                        // If we got here it means the completion item has not specificed commit characters and we want to dismiss the commit and the intellisense session because it's a dismiss character.
                        return(CommitResult.Handled);
                    }
                }

                if (completionItem.TextEdit != null || completionItem.AdditionalTextEdits != null)
                {
                    // Completion text edits are computed when the completion session is first triggered. The lines typed
                    // after the completion session was started need to be deleted to revert the document to its original state.
                    var caretPositionAtBuffer = session.TextView.GetCaretPointAtSubjectBuffer(buffer);
                    if (caretPositionAtBuffer.HasValue)
                    {
                        var deleteTextLength = caretPositionAtBuffer.Value.Position - triggerLocation.Position;
                        if (deleteTextLength > 0)
                        {
                            var deleteSpan = new Span(triggerLocation.Position, deleteTextLength);
                            buffer.Delete(deleteSpan);
                        }

                        if (completionItem.TextEdit != null)
                        {
                            LspEditorUtilities.ApplyTextEdit(completionItem.TextEdit, triggerLocation.Snapshot, buffer);
                        }
                        else if (completionItem.InsertText != null)
                        {
                            buffer.Replace(session.ApplicableToSpan.GetSpan(buffer.CurrentSnapshot), completionItem.InsertText);
                        }

                        if (completionItem.AdditionalTextEdits != null)
                        {
                            LspEditorUtilities.ApplyTextEdits(completionItem.AdditionalTextEdits, triggerLocation.Snapshot, buffer);
                        }

                        return(CommitResult.Handled);
                    }
                }
            }

            return(CommitResult.Unhandled);
        }
 public bool ShouldCommitCompletion(IAsyncCompletionSession session, SnapshotPoint location, char typedChar, CancellationToken token)
 {
     return(true);
 }