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); }
/// <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);
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); }
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); }
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())); }
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)); }
public CompletionStartData InitializeCompletion(CompletionTrigger trigger, SnapshotPoint triggerLocation, CancellationToken token) { return(CompletionStartData.DoesNotParticipateInCompletion); }
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."); }
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>()); } }
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, });
internal sealed override bool ShouldTriggerCompletion(HostLanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CompletionOptions options) => ShouldTriggerCompletionImpl(text, caretPosition, trigger);
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); }
protected abstract bool ShouldTriggerCompletionImpl(SourceText text, int caretPosition, CompletionTrigger trigger);
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); } } }
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)); }
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); }
protected abstract Task <CompletionItem> GetSuggestionModeItemAsync(Document document, int position, TextSpan span, CompletionTrigger triggerInfo, CancellationToken cancellationToken);
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); }
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);
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)); }