private async Task CheckResultsAsync(Document document, int position, bool isBuilder) { var triggerInfos = new List <CompletionTrigger>(); triggerInfos.Add(CompletionTrigger.CreateInsertionTrigger('a')); triggerInfos.Add(CompletionTrigger.Invoke); triggerInfos.Add(CompletionTrigger.CreateDeletionTrigger('z')); var service = GetCompletionService(document.Project); var provider = Assert.Single(service.GetTestAccessor().GetAllProviders(ImmutableHashSet <string> .Empty)); foreach (var triggerInfo in triggerInfos) { var completionList = await service.GetTestAccessor().GetContextAsync( provider, document, position, triggerInfo, options: CompletionOptions.Default, cancellationToken: CancellationToken.None); if (isBuilder) { Assert.NotNull(completionList); Assert.True(completionList.SuggestionModeItem != null, "Expecting a suggestion mode, but none was present"); } else { if (completionList != null) { Assert.True(completionList.SuggestionModeItem == null, "group.Builder == " + (completionList.SuggestionModeItem != null ? completionList.SuggestionModeItem.DisplayText : "null")); } } } }
private async Task CheckResultsAsync(Document document, int position, bool isBuilder) { var triggerInfos = new List <CompletionTrigger>(); triggerInfos.Add(CompletionTrigger.CreateInsertionTrigger('a')); triggerInfos.Add(CompletionTrigger.Invoke); triggerInfos.Add(CompletionTrigger.CreateDeletionTrigger('z')); var service = GetCompletionService(document.Project.Solution.Workspace); foreach (var triggerInfo in triggerInfos) { var completionList = await service.GetTestAccessor().GetContextAsync( service.GetTestAccessor().ExclusiveProviders?[0], document, position, triggerInfo, options: null, cancellationToken: CancellationToken.None); if (isBuilder) { Assert.NotNull(completionList); Assert.True(completionList.SuggestionModeItem != null, "Expecting a suggestion mode, but none was present"); } else { if (completionList != null) { Assert.True(completionList.SuggestionModeItem == null, "group.Builder == " + (completionList.SuggestionModeItem != null ? completionList.SuggestionModeItem.DisplayText : "null")); } } } }
bool TryStartSession(char c, bool isDelete) { if (HasSession) return false; var info = CompletionInfo.Create(textView.TextSnapshot); if (info == null) return false; int pos = textView.Caret.Position.BufferPosition.Position; var completionTrigger = isDelete ? CompletionTrigger.CreateDeletionTrigger(c) : CompletionTrigger.CreateInsertionTrigger(c); if (!info.Value.CompletionService.ShouldTriggerCompletion(info.Value.SourceText, pos, completionTrigger)) return false; StartSession(info, completionTrigger); return HasSession; }
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; } else { // backspace deletedChar = viewBufferCaretPoint > 0 ? textView.TextBuffer.CurrentSnapshot[viewBufferCaretPoint - 1] : default; } 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.GetDocumentWithFrozenPartialSemantics(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); } } }
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, filterItems: false, dismissIfEmptyAllowed: true); } 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.StopModelComputation(); return; } else if (model != null) { // If we were triggered on backspace/delete, and we're still deleting, // then we don't want to filter out items (i.e. we still want all items). // However, we do still want to run the code to figure out what the best // item is to select from all those items. FilterToSomeOrAllItems( filterItems: model.Trigger.Kind != CompletionTriggerKind.Deletion, dismissIfEmptyAllowed: true, filterReason: CompletionFilterReason.BackspaceOrDelete); } } }