示例#1
0
 protected abstract Task<IEnumerable<CompletionItem>> GetItemsWorkerAsync(Document document, int position, TextSpan span, CompletionTrigger trigger, CancellationToken cancellationToken);
        public async Task <Mono.Debugging.Client.CompletionData> GetExpressionCompletionData(string exp, Mono.Debugging.Client.StackFrame frame, CancellationToken token)
        {
            var location = frame.SourceLocation;
            var document = DocumentContext.AnalysisDocument;

            if (document == null)
            {
                return(null);
            }
            var solution         = DocumentContext.RoslynWorkspace.CurrentSolution;
            var originalSnapshot = Editor.TextView.TextBuffer.CurrentSnapshot;
            var text             = originalSnapshot.GetText(new Span(0, originalSnapshot.Length));
            var insertOffset     = GetAdjustedContextPoint(originalSnapshot.GetLineFromLineNumber(location.EndLine - 1).Start.Position + location.EndColumn - 1, document);

            text = text.Insert(insertOffset, ";" + exp + ";");
            insertOffset++;            //advance for 1 which represents `;` before expression
            var textBuffer = PlatformCatalog.Instance.TextBufferFactoryService.CreateTextBuffer(text, Editor.TextView.TextBuffer.ContentType);
            var snapshot   = textBuffer.CurrentSnapshot;

            try {
                //Workaround Mono bug: https://github.com/mono/mono/issues/8700
                snapshot.AsText();
            } catch (Exception) {
            }

            // Fork the solution using this new primary buffer for the document and all of its linked documents.
            var forkedSolution = solution.WithDocumentText(document.Id, snapshot.AsText(), PreservationMode.PreserveIdentity);

            foreach (var link in document.GetLinkedDocumentIds())
            {
                forkedSolution = forkedSolution.WithDocumentText(link, snapshot.AsText(), PreservationMode.PreserveIdentity);
            }

            // Put it into a new workspace, and open it and its related documents
            // with the projection buffer as the text.
            var forkedWorkspace = new DebuggerIntelliSenseWorkspace(forkedSolution);

            forkedWorkspace.OpenDocument(document.Id, textBuffer.AsTextContainer());
            foreach (var link in document.GetLinkedDocumentIds())
            {
                forkedWorkspace.OpenDocument(link, textBuffer.AsTextContainer());
            }
            var cs                = forkedWorkspace.Services.GetLanguageServices(LanguageNames.CSharp).GetService <CompletionService> ();
            var trigger           = new CompletionTrigger(CompletionTriggerKind.Invoke, '\0');
            var roslynCompletions = await cs.GetCompletionsAsync(forkedWorkspace.CurrentSolution.GetDocument(document.Id), insertOffset + exp.Length, trigger, cancellationToken : token).ConfigureAwait(false);

            if (roslynCompletions == null)
            {
                return(null);
            }
            var result = new Mono.Debugging.Client.CompletionData();

            foreach (var roslynCompletion in roslynCompletions.Items)
            {
                if (roslynCompletion.Tags.Contains(WellKnownTags.Snippet))
                {
                    continue;
                }
                result.Items.Add(new Mono.Debugging.Client.CompletionItem(roslynCompletion.DisplayText, RoslynTagsToDebuggerFlags(roslynCompletion.Tags)));
            }
            result.ExpressionLength = roslynCompletions.Span.Length;
            return(result);
        }
示例#3
0
            /// <summary>
            /// Returns true if the completion item should be "soft" selected, or false if it should be "hard"
            /// selected.
            /// </summary>
            private static bool ShouldSoftSelectItem(CompletionItem item, string filterText, CompletionTrigger trigger)
            {
                // If all that has been typed is puntuation, then don't hard select anything.
                // It's possible the user is just typing language punctuation and selecting
                // anything in the list will interfere.  We only allow this if the filter text
                // exactly matches something in the list already.
                if (filterText.Length > 0 && IsAllPunctuation(filterText) && filterText != item.DisplayText)
                {
                    return(true);
                }

                // If the user hasn't actually typed anything, then don't hard select any item.
                // The only exception to this is if the completion provider has requested the
                // item be preselected.
                if (filterText.Length == 0)
                {
                    // Item didn't want to be hard selected with no filter text.
                    // So definitely soft select it.
                    if (item.Rules.SelectionBehavior != CompletionItemSelectionBehavior.HardSelection)
                    {
                        return(true);
                    }

                    // Item did not ask to be preselected.  So definitely soft select it.
                    if (item.Rules.MatchPriority == MatchPriority.Default)
                    {
                        return(true);
                    }
                }

                // The user typed something, or the item asked to be preselected.  In
                // either case, don't soft select this.
                Debug.Assert(filterText.Length > 0 || item.Rules.MatchPriority != MatchPriority.Default);
                return(false);
            }
 Task <CompletionContext> IAsyncCompletionSource.GetCompletionContextAsync(IAsyncCompletionSession session, CompletionTrigger trigger, SnapshotPoint triggerLocation, SnapshotSpan applicableToSpan, CancellationToken token) =>
 GetCompletionContextAsync(session, trigger, triggerLocation, applicableToSpan, token);
示例#5
0
 public override bool ShouldTriggerCompletion(SourceText text, int position, CompletionTrigger trigger, Microsoft.CodeAnalysis.Options.OptionSet options)
 {
     return(trigger.Character == ' ');
 }
 private static CompletionTrigger GetCompletionTrigger(char?triggerChar)
 {
     return(triggerChar != null
         ? CompletionTrigger.CreateInsertionTrigger(triggerChar.Value)
         : CompletionTrigger.Invoke);
 }
示例#7
0
        async Task <ICompletionDataList> InternalHandleCodeCompletion(CodeCompletionContext completionContext, CompletionTriggerInfo triggerInfo, int triggerWordLength, CancellationToken token, bool forceSymbolCompletion = false)
        {
            var analysisDocument = DocumentContext.AnalysisDocument;

            if (analysisDocument == null)
            {
                return(EmptyCompletionDataList);
            }


            var        cs = DocumentContext.RoslynWorkspace.Services.GetLanguageServices(LanguageNames.CSharp).GetService <CompletionService> ();
            SourceText sourceText;

            if (!analysisDocument.TryGetText(out sourceText))
            {
                return(EmptyCompletionDataList);
            }

            CompletionTriggerKind kind;

            switch (triggerInfo.CompletionTriggerReason)
            {
            case CompletionTriggerReason.CharTyped:
                kind = CompletionTriggerKind.Insertion;
                break;

            case CompletionTriggerReason.CompletionCommand:
                kind = CompletionTriggerKind.InvokeAndCommitIfUnique;
                break;

            case CompletionTriggerReason.BackspaceOrDeleteCommand:
                kind = CompletionTriggerKind.Deletion;
                break;

            case CompletionTriggerReason.RetriggerCommand:
                kind = CompletionTriggerKind.InvokeAndCommitIfUnique;
                break;

            default:
                kind = CompletionTriggerKind.Insertion;
                break;
            }
            var triggerSnapshot = Editor.GetPlatformTextBuffer().CurrentSnapshot;
            var trigger         = new CompletionTrigger(kind, triggerInfo.TriggerCharacter.HasValue ? triggerInfo.TriggerCharacter.Value : '\0');

            if (triggerInfo.CompletionTriggerReason == CompletionTriggerReason.CharTyped)
            {
                if (!cs.ShouldTriggerCompletion(sourceText, completionContext.TriggerOffset, trigger, null))
                {
                    return(EmptyCompletionDataList);
                }
            }

            Counters.ProcessCodeCompletion.Trace("C#: Getting completions");
            var customOptions = DocumentContext.RoslynWorkspace.Options
                                .WithChangedOption(CompletionOptions.TriggerOnDeletion, LanguageNames.CSharp, true)
                                .WithChangedOption(CompletionOptions.HideAdvancedMembers, LanguageNames.CSharp, IdeApp.Preferences.CompletionOptionsHideAdvancedMembers);

            var completionList = await Task.Run(() => cs.GetCompletionsAsync(analysisDocument, Editor.CaretOffset, trigger, options: customOptions, cancellationToken: token)).ConfigureAwait(false);

            Counters.ProcessCodeCompletion.Trace("C#: Got completions");

            if (completionList == null)
            {
                return(EmptyCompletionDataList);
            }

            var result = new CompletionDataList();

            result.TriggerWordLength = triggerWordLength;
            CSharpCompletionData defaultCompletionData = null;
            bool first = true, addProtocolCompletion = false;

            foreach (var item in completionList.Items)
            {
                if (string.IsNullOrEmpty(item.DisplayText))
                {
                    continue;
                }
                var data = new CSharpCompletionData(analysisDocument, triggerSnapshot, cs, item);
                if (first)
                {
                    first = false;
                    addProtocolCompletion = data.Provider is OverrideCompletionProvider;
                }
                result.Add(data);
                if (item.Rules.MatchPriority > 0)
                {
                    if (defaultCompletionData == null || defaultCompletionData.Rules.MatchPriority < item.Rules.MatchPriority)
                    {
                        defaultCompletionData = data;
                    }
                }
            }

            result.AutoCompleteUniqueMatch = (triggerInfo.CompletionTriggerReason == CompletionTriggerReason.CompletionCommand);

            var partialDoc = analysisDocument.WithFrozenPartialSemantics(token);
            var semanticModel = await partialDoc.GetSemanticModelAsync(token).ConfigureAwait(false);

            var syntaxContext = CSharpSyntaxContext.CreateContext(DocumentContext.RoslynWorkspace, semanticModel, completionContext.TriggerOffset, token);

            if (addProtocolCompletion)
            {
                var provider = new ProtocolMemberCompletionProvider();

                var protocolMemberContext = new CompletionContext(provider, analysisDocument, completionContext.TriggerOffset, new TextSpan(completionContext.TriggerOffset, completionContext.TriggerWordLength), trigger, customOptions, token);

                await provider.ProvideCompletionsAsync(protocolMemberContext);

                foreach (var item in protocolMemberContext.Items)
                {
                    if (string.IsNullOrEmpty(item.DisplayText))
                    {
                        continue;
                    }
                    var data = new CSharpCompletionData(analysisDocument, triggerSnapshot, cs, item);
                    result.Add(data);
                }
            }

            if (forceSymbolCompletion || IdeApp.Preferences.AddImportedItemsToCompletionList)
            {
                Counters.ProcessCodeCompletion.Trace("C#: Adding import completion data");
                AddImportCompletionData(syntaxContext, result, semanticModel, completionContext.TriggerOffset, token);
                Counters.ProcessCodeCompletion.Trace("C#: Added import completion data");
            }
            if (defaultCompletionData != null)
            {
                result.DefaultCompletionString = defaultCompletionData.DisplayText;
            }

            if (completionList.SuggestionModeItem != null)
            {
                if (completionList.Items.Contains(completionList.SuggestionModeItem))
                {
                    result.DefaultCompletionString = completionList.SuggestionModeItem.DisplayText;
                }
                // if a suggestion mode item is present autoselection is disabled
                // for example in the lambda case the suggestion mode item is '<lambda expression>' which is not part of the completion item list but taggs the completion list as auto select == false.
                result.AutoSelect = false;
            }
            if (triggerInfo.TriggerCharacter == '_' && triggerWordLength == 1)
            {
                result.AutoSelect = false;
            }

            return(result);
        }
示例#8
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()));
        }
示例#9
0
        void ICommandHandler <TypeCharCommandArgs> .ExecuteCommand(TypeCharCommandArgs args, Action nextHandler)
        {
            AssertIsForeground();

            // When a character is typed it is *always* sent through to the editor.  This way the
            // editor always represents what would have been typed had completion not been involved
            // at this point.  That means that if we decide to commit, then undo'ing the commit will
            // return you to the code that you would have typed if completion was not up.
            //
            // The steps we follow for commit are as follows:
            //
            //      1) send the commit character through to the buffer.
            //      2) open a transaction.
            //          2a) roll back the text to before the text was sent through
            //          2b) commit the item.
            //          2c) send the commit character through again.*
            //          2d) commit the transaction.
            //
            // 2c is very important.  it makes sure that post our commit all our normal features
            // run depending on what got typed.  For example if the commit character was (
            // then brace completion may run.  If it was ; then formatting may run.  But, importantly
            // this code doesn't need to know anything about that.  Furthermore, because that code
            // runs within this transaction, then the user can always undo and get to what the code
            // would have been if completion was not involved.
            //
            // 2c*: note sending the commit character through to the buffer again can be controlled
            // by the completion item.  For example, completion items that want to totally handle
            // what gets output into the buffer can ask for this not to happen.  An example of this
            // is override completion.  If the user types "override Method(" then we'll want to
            // spit out the entire method and *not* also spit out "(" again.

            // In order to support 2a (rolling back), we capture hte state of the buffer before
            // we send the character through.  We then just apply the edits in reverse order to
            // roll us back.
            var initialTextSnapshot = this.SubjectBuffer.CurrentSnapshot;

            var initialCaretPosition = GetCaretPointInViewBuffer();

            // Note: while we're doing this, we don't want to hear about buffer changes (since we
            // know they're going to happen).  So we disconnect and reconnect to the event
            // afterwards.  That way we can hear about changes to the buffer that don't happen
            // through us.

            // Automatic Brace Completion may also move the caret, so unsubscribe from that too
            this.TextView.TextBuffer.PostChanged -= OnTextViewBufferPostChanged;
            this.TextView.Caret.PositionChanged  -= OnCaretPositionChanged;

            // In Venus/Razor, the user might be typing on the buffer's seam. This means that,
            // depending on the character typed, the character may not go into our buffer.
            var isOnSeam = IsOnSeam();

            try
            {
                nextHandler();
            }
            finally
            {
                this.TextView.TextBuffer.PostChanged += OnTextViewBufferPostChanged;
                this.TextView.Caret.PositionChanged  += OnCaretPositionChanged;
            }

            // We only want to process typechar if it is a normal typechar and no one else is
            // involved.  i.e. if there was a typechar, but someone processed it and moved the caret
            // somewhere else then we don't want completion.  Also, if a character was typed but
            // something intercepted and placed different text into the editor, then we don't want
            // to proceed.
            if (this.TextView.TypeCharWasHandledStrangely(this.SubjectBuffer, args.TypedChar))
            {
                if (sessionOpt != null)
                {
                    // If we're on a seam (razor) with a computation, and the user types a character
                    // that goes into the other side of the seam, the character may be a commit character.
                    // If it's a commit character, just commit without trying to check caret position,
                    // since the caret is no longer in our buffer.
                    if (isOnSeam)
                    {
                        var model = this.WaitForModel();
                        if (this.CommitIfCommitCharacter(args.TypedChar, model, initialTextSnapshot, nextHandler))
                        {
                            return;
                        }
                    }

                    if (_autoBraceCompletionChars.Contains(args.TypedChar) &&
                        this.SubjectBuffer.GetFeatureOnOffOption(InternalFeatureOnOffOptions.AutomaticPairCompletion))
                    {
                        var model = this.WaitForModel();
                        if (this.CommitIfCommitCharacter(args.TypedChar, model, initialTextSnapshot, nextHandler))
                        {
                            // I don't think there is any better way than this. if typed char is one of auto brace completion char,
                            // we don't do multiple buffer change check
                            return;
                        }
                    }

                    // If we were computing anything, we stop.  We only want to process a typechar
                    // if it was a normal character.
                    this.DismissSessionIfActive();
                }

                return;
            }

            var completionService = this.GetCompletionService();

            if (completionService == null)
            {
                return;
            }

            var options = GetOptions();

            Contract.ThrowIfNull(options);

            var isTextuallyTriggered       = IsTextualTriggerCharacter(completionService, args.TypedChar, options);
            var isPotentialFilterCharacter = IsPotentialFilterCharacter(args);
            var trigger = CompletionTrigger.CreateInsertionTrigger(args.TypedChar);

            if (sessionOpt == null)
            {
                // No computation at all.  If this is not a trigger character, we just ignore it and
                // stay in this state.  Otherwise, if it's a trigger character, start up a new
                // computation and start computing the model in the background.
                if (isTextuallyTriggered)
                {
                    // First create the session that represents that we now have a potential
                    // completion list.  Then tell it to start computing.
                    StartNewModelComputation(completionService, trigger, filterItems: true, dismissIfEmptyAllowed: true);
                    return;
                }
                else
                {
                    // No need to do anything.  Just stay in the state where we have no session.
                    return;
                }
            }
            else
            {
                sessionOpt.UpdateModelTrackingSpan(initialCaretPosition);

                // If the session is up, it may be in one of many states.  It may know nothing
                // (because it is currently computing the list of completions).  Or it may have a
                // list of completions that it has filtered.

                // If the user types something which is absolutely known to be a filter character
                // then we can just proceed without blocking.
                if (isPotentialFilterCharacter)
                {
                    if (isTextuallyTriggered)
                    {
                        // The character typed was something like "a".  It can both filter a list if
                        // we have computed one, or it can trigger a new list.  Ask the computation
                        // to compute again. If nothing has been computed, then it will try to
                        // compute again, otherwise it will just ignore this request.
                        sessionOpt.ComputeModel(completionService, trigger, _roles, options);
                    }

                    // Now filter whatever result we have.
                    sessionOpt.FilterModel(
                        CompletionFilterReason.TypeChar,
                        recheckCaretPosition: false,
                        dismissIfEmptyAllowed: true,
                        filterState: null);
                }
                else
                {
                    // It wasn't a trigger or filter character. At this point, we make our
                    // determination on what to do based on what has actually been computed and
                    // what's being typed. This means waiting on the session and will effectively
                    // block the user.

                    var model = WaitForModel();

                    // What they type may end up filtering, committing, or else will dismiss.
                    //
                    // For example, we may filter in cases like this: "Color."
                    //
                    // "Color" will have already filtered the list down to some things like
                    // "Color", "Color.Red", "Color.Blue", etc.  When we process the 'dot', we
                    // actually want to filter some more.  But we can't know that ahead of time until
                    // we have computed the list of completions.
                    if (this.IsFilterCharacter(args.TypedChar, model))
                    {
                        // Known to be a filter character for the currently selected item.  So just
                        // filter the session.
                        sessionOpt.FilterModel(CompletionFilterReason.TypeChar,
                                               recheckCaretPosition: false,
                                               dismissIfEmptyAllowed: true,
                                               filterState: null);
                        return;
                    }

                    // It wasn't a filter character.  We'll either commit what's selected, or we'll
                    // dismiss the completion list.  First, ensure that what was typed is in the
                    // buffer.

                    // Now, commit if it was a commit character.
                    this.CommitIfCommitCharacter(args.TypedChar, model, initialTextSnapshot, nextHandler);

                    // At this point we don't want a session anymore (either because we committed, or
                    // because we got a character we don't know how to handle).  Unilaterally dismiss
                    // the session.
                    DismissSessionIfActive();

                    // The character may commit/dismiss and then trigger completion again. So check
                    // for that here.
                    if (isTextuallyTriggered)
                    {
                        StartNewModelComputation(
                            completionService, trigger, filterItems: true, dismissIfEmptyAllowed: true);
                        return;
                    }
                }
            }
        }
 public override bool ShouldTriggerCompletion(SourceText text, int caretPosition, CompletionTrigger trigger, OptionSet options) =>
 ShouldTriggerCompletion();
        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));
        }
示例#12
0
 public CompletionStartData InitializeCompletion(CompletionTrigger trigger, SnapshotPoint triggerLocation, CancellationToken token)
 {
     return(CompletionStartData.DoesNotParticipateInCompletion);
 }
示例#13
0
 Task <CompletionContext> IAsyncCompletionSource.GetCompletionContextAsync(IAsyncCompletionSession session, CompletionTrigger trigger, SnapshotPoint triggerLocation, SnapshotSpan applicableToSpan, CancellationToken token)
 {
     throw new NotImplementedException("This item source is not meant to be registered. It is used only to provide a tooltip.");
 }
示例#14
0
        public override bool ShouldTriggerCompletion(SourceText text, int caretPosition, CompletionTrigger trigger, OptionSet options)
        {
            foreach (var language in GetLanguageProviders(text => text.GetOpenDocumentInCurrentContextWithChanges(), text))
            {
                var completionProvider = (language as IEmbeddedLanguageFeatures)?.CompletionProvider;
                if (completionProvider != null)
                {
                    if (completionProvider.ShouldTriggerCompletion(
                            text, caretPosition, trigger, options))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
        protected override async Task <IEnumerable <CompletionItem> > GetItemsWorkerAsync(
            Document document, int position,
            CompletionTrigger trigger, CancellationToken cancellationToken)
        {
            try
            {
                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 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 (IsAttributeNameContext(token, position, out var elementName, out var existingAttributes))
                {
                    return(GetAttributeItems(elementName, existingAttributes));
                }

                var wasTriggeredAfterSpace = trigger.Kind == CompletionTriggerKind.Insertion && trigger.Character == ' ';
                if (wasTriggeredAfterSpace)
                {
                    // Nothing below this point should triggered by a space character
                    // (only attribute names should be triggered by <SPACE>)
                    return(null);
                }

                if (IsAttributeValueContext(token, out elementName, out var attributeName))
                {
                    return(GetAttributeValueItems(declaredSymbol, elementName, attributeName));
                }

                if (trigger.Kind == CompletionTriggerKind.Insertion && trigger.Character != '<')
                {
                    // With the use of IsTriggerAfterSpaceOrStartOfWordCharacter, the code below is much
                    // too aggressive at suggesting tags, so exit early before degrading the experience
                    return(null);
                }

                var items = new List <CompletionItem>();

                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)))
                {
                    // The user is typing inside an XmlElement
                    if (token.Parent.Parent.Kind() == SyntaxKind.XmlElement ||
                        token.Parent.Parent.IsParentKind(SyntaxKind.XmlElement))
                    {
                        // Avoid including language keywords when following < or <text, since these cases should only be
                        // attempting to complete the XML name (which for language keywords is 'see'). While the parser
                        // treats the 'name' in '< name' as an XML name, we don't treat it like that here so the completion
                        // experience is consistent for '< ' and '< n'.
                        var xmlNameOnly = token.IsKind(SyntaxKind.LessThanToken) ||
                                          (token.Parent.IsKind(SyntaxKind.XmlName) && !token.HasLeadingTrivia);
                        var includeKeywords = !xmlNameOnly;

                        items.AddRange(GetNestedItems(declaredSymbol, includeKeywords));
                    }

                    if (token.Parent.Parent is XmlElementSyntax xmlElement)
                    {
                        AddXmlElementItems(items, xmlElement.StartTag);
                    }

                    if (token.Parent.IsParentKind(SyntaxKind.XmlEmptyElement) &&
                        token.Parent.Parent.Parent is XmlElementSyntax nestedXmlElement)
                    {
                        AddXmlElementItems(items, nestedXmlElement.StartTag);
                    }

                    if (token.Parent.Parent is DocumentationCommentTriviaSyntax ||
                        (token.Parent.Parent.IsKind(SyntaxKind.XmlEmptyElement) && token.Parent.Parent.Parent is DocumentationCommentTriviaSyntax))
                    {
                        items.AddRange(GetTopLevelItems(declaredSymbol, parentTrivia));
                    }
                }

                if (token.Parent is XmlElementStartTagSyntax startTag &&
                    token == startTag.GreaterThanToken)
                {
                    AddXmlElementItems(items, startTag);
                }

                items.AddRange(GetAlwaysVisibleItems());
                return(items);
            }
            catch (Exception e) when(FatalError.ReportWithoutCrashUnlessCanceled(e))
            {
                return(SpecializedCollections.EmptyEnumerable <CompletionItem>());
            }
        }
示例#16
0
 public sealed override bool ShouldTriggerCompletion(SourceText text, int caretPosition, CompletionTrigger trigger, OptionSet options)
 => ShouldTriggerCompletionImpl(text, caretPosition, trigger);
 public override bool ShouldTriggerCompletion(SourceText text, int caretPosition, CompletionTrigger trigger, OptionSet options)
 {
     return(trigger.Kind switch
     {
         CompletionTriggerKind.Invoke => true,
         CompletionTriggerKind.InvokeAndCommitIfUnique => true,
         CompletionTriggerKind.Insertion => trigger.Character == '"',
         _ => false,
     });
示例#18
0
 internal sealed override bool ShouldTriggerCompletion(HostLanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CompletionOptions options)
 => ShouldTriggerCompletionImpl(text, caretPosition, trigger);
示例#19
0
        public override bool ShouldTriggerCompletion(SourceText text, int caretPosition, CompletionTrigger trigger, OptionSet options)
        {
            if (trigger.Kind == CompletionTriggerKind.Invoke ||
                trigger.Kind == CompletionTriggerKind.InvokeAndCommitIfUnique)
            {
                return(true);
            }

            if (trigger.Kind == CompletionTriggerKind.Insertion)
            {
                return(IsTriggerCharacter(trigger.Character));
            }

            return(false);
        }
示例#20
0
 protected abstract bool ShouldTriggerCompletionImpl(SourceText text, int caretPosition, CompletionTrigger trigger);
示例#21
0
        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));
        }
        private void ExecuteBackspaceOrDelete(ITextView textView, Action nextHandler, bool isDelete)
        {
            AssertIsForeground();

            char?deletedChar;
            var  subjectBufferCaretPoint = GetCaretPointInSubjectBuffer();
            var  viewBufferCaretPoint    = GetCaretPointInViewBuffer();

            if (isDelete)
            {
                deletedChar = viewBufferCaretPoint.Position >= 0 && viewBufferCaretPoint.Position < textView.TextBuffer.CurrentSnapshot.Length
                    ? textView.TextBuffer.CurrentSnapshot[viewBufferCaretPoint.Position]
                    : default(char?);
            }
            else
            {
                // backspace
                deletedChar = viewBufferCaretPoint > 0
                    ? textView.TextBuffer.CurrentSnapshot[viewBufferCaretPoint - 1]
                    : default(char?);
            }

            if (sessionOpt == null)
            {
                // No computation. Disconnect from caret position changes, send the backspace through,
                // and start a computation.
                this.TextView.TextBuffer.PostChanged -= OnTextViewBufferPostChanged;
                this.TextView.Caret.PositionChanged  -= OnCaretPositionChanged;
                try
                {
                    nextHandler();
                }
                finally
                {
                    this.TextView.TextBuffer.PostChanged += OnTextViewBufferPostChanged;
                    this.TextView.Caret.PositionChanged  += OnCaretPositionChanged;
                }

                var trigger           = CompletionTrigger.CreateDeletionTrigger(deletedChar.GetValueOrDefault());
                var completionService = this.GetCompletionService();

                if (completionService != null)
                {
                    this.StartNewModelComputation(completionService, trigger);
                }

                return;
            }
            else
            {
                var textBeforeDeletion     = SubjectBuffer.AsTextContainer().CurrentText;
                var documentBeforeDeletion = textBeforeDeletion.GetDocumentWithFrozenPartialSemanticsAsync(CancellationToken.None)
                                             .WaitAndGetResult(CancellationToken.None);

                this.TextView.TextBuffer.PostChanged -= OnTextViewBufferPostChanged;
                this.TextView.Caret.PositionChanged  -= OnCaretPositionChanged;
                try
                {
                    nextHandler();
                }
                finally
                {
                    this.TextView.TextBuffer.PostChanged += OnTextViewBufferPostChanged;
                    this.TextView.Caret.PositionChanged  += OnCaretPositionChanged;
                }

                var model = sessionOpt.Computation.InitialUnfilteredModel;

                if ((model == null && CaretHasLeftDefaultTrackingSpan(subjectBufferCaretPoint, documentBeforeDeletion)) ||
                    (model != null && this.IsCaretOutsideAllItemBounds(model, this.GetCaretPointInViewBuffer())) ||
                    (model != null && model.OriginalList.Rules.DismissIfLastCharacterDeleted && AllFilterTextsEmpty(model, GetCaretPointInViewBuffer())))
                {
                    // If the caret moved out of bounds of our items, then we want to dismiss the list.
                    this.DismissSessionIfActive();
                    return;
                }
                else if (model != null)
                {
                    sessionOpt.FilterModel(CompletionFilterReason.Deletion, filterState: null);
                }
            }
        }
示例#23
0
 CompletionStartData IAsyncCompletionSource.InitializeCompletion(CompletionTrigger trigger, SnapshotPoint triggerLocation, CancellationToken token) => InitializeCompletion(trigger, triggerLocation, token);
        public override bool ShouldTriggerCompletion(SourceText text, int caretPosition, CompletionTrigger trigger, OptionSet options)
        {
            if (Options == null)
            {
                // Package not loaded yet (e.g. no solution opened)
                return(false);
            }

            bool shouldTrigger = triggerCompletions.Any(c => c.ShouldTriggerCompletion(text, caretPosition, trigger, Options));

            return(shouldTrigger || base.ShouldTriggerCompletion(text, caretPosition, trigger, options));
        }
示例#25
0
 private async Task <CompletionList> GetCompletionListAsync(CompletionService completionService, CompletionTrigger trigger, CancellationToken cancellationToken)
 {
     return(_documentOpt != null
         ? await completionService.GetCompletionsAsync(_documentOpt, _subjectBufferCaretPosition, trigger, _roles, _options, cancellationToken).ConfigureAwait(false)
         : null);
 }
示例#26
0
 protected abstract Task <CompletionItem> GetSuggestionModeItemAsync(Document document, int position, TextSpan span, CompletionTrigger triggerInfo, CancellationToken cancellationToken);
示例#27
0
 internal Task <CompletionList> GetCompletionListAsync(
     CompletionService service,
     Document document, int position, CompletionTrigger triggerInfo, OptionSet options = null)
 {
     return(service.GetCompletionsAsync(document, position, triggerInfo, options: options));
 }
 protected override ImmutableArray <CompletionProvider> GetProviders(ImmutableHashSet <string> roles, CompletionTrigger trigger)
 {
     return(TestProviders);
 }
        protected override async Task <CompletionItem> GetSuggestionModeItemAsync(
            Document document, int position, TextSpan itemSpan, CompletionTrigger trigger, CancellationToken cancellationToken = default)
        {
            if (trigger.Kind != CompletionTriggerKind.Snippets)
            {
                var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

                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(CreateSuggestionModeItem(CSharpFeaturesResources.lambda_expression, CSharpFeaturesResources.Autoselect_disabled_due_to_potential_lambda_declaration));
                }
                else if (IsAnonymousObjectCreation(token))
                {
                    return(CreateSuggestionModeItem(CSharpFeaturesResources.member_name, CSharpFeaturesResources.Autoselect_disabled_due_to_possible_explicitly_named_anonymous_type_member_creation));
                }
                else if (IsPotentialPatternVariableDeclaration(tree.FindTokenOnLeftOfPosition(position, cancellationToken)))
                {
                    return(CreateSuggestionModeItem(CSharpFeaturesResources.pattern_variable, CSharpFeaturesResources.Autoselect_disabled_due_to_potential_pattern_variable_declaration));
                }
                else if (token.IsPreProcessorExpressionContext())
                {
                    return(CreateEmptySuggestionModeItem());
                }
                else if (token.IsKindOrHasMatchingText(SyntaxKind.FromKeyword) || token.IsKindOrHasMatchingText(SyntaxKind.JoinKeyword))
                {
                    return(CreateSuggestionModeItem(CSharpFeaturesResources.range_variable, CSharpFeaturesResources.Autoselect_disabled_due_to_potential_range_variable_declaration));
                }
                else if (tree.IsNamespaceDeclarationNameContext(position, cancellationToken))
                {
                    return(CreateSuggestionModeItem(CSharpFeaturesResources.namespace_name, CSharpFeaturesResources.Autoselect_disabled_due_to_namespace_declaration));
                }
                else if (tree.IsPartialTypeDeclarationNameContext(position, cancellationToken, out var typeDeclaration))
                {
                    switch (typeDeclaration.Keyword.Kind())
                    {
                    case SyntaxKind.ClassKeyword:
                        return(CreateSuggestionModeItem(CSharpFeaturesResources.class_name, CSharpFeaturesResources.Autoselect_disabled_due_to_type_declaration));

                    case SyntaxKind.StructKeyword:
                        return(CreateSuggestionModeItem(CSharpFeaturesResources.struct_name, CSharpFeaturesResources.Autoselect_disabled_due_to_type_declaration));

                    case SyntaxKind.InterfaceKeyword:
                        return(CreateSuggestionModeItem(CSharpFeaturesResources.interface_name, CSharpFeaturesResources.Autoselect_disabled_due_to_type_declaration));
                    }
                }
                else if (tree.IsPossibleDeconstructionDesignation(position, cancellationToken))
                {
                    return(CreateSuggestionModeItem(CSharpFeaturesResources.designation_name,
                                                    CSharpFeaturesResources.Autoselect_disabled_due_to_possible_deconstruction_declaration));
                }
            }

            return(null);
        }
示例#30
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));
        }
 protected abstract Task<CompletionItem> GetSuggestionModeItemAsync(Document document, int position, TextSpan span, CompletionTrigger triggerInfo, CancellationToken cancellationToken);
示例#32
0
        public Task <CompletionContext> GetCompletionContextAsync(IAsyncCompletionSession session, CompletionTrigger trigger, SnapshotPoint triggerLocation, SnapshotSpan applicableToSpan, CancellationToken token)
        {
            if (_parser.TryGetCompletionList(triggerLocation, _attributeName, out IEnumerable <CompletionItem> completions))
            {
                return(Task.FromResult(new CompletionContext(completions.ToImmutableArray())));
            }

            return(Task.FromResult(CompletionContext.Empty));
        }