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

            _disconnectedBufferGraph = disconnectedBufferGraph;
            this.TotalItems = totalItems;
            this.FilteredItems = filteredItems;
            this.SelectedItem = selectedItem;
            this.IsHardSelection = isHardSelection;
            this.IsUnique = isUnique;
            this.UseSuggestionCompletionMode = useSuggestionCompletionMode;
            this.Builder = builder;
            this.DefaultBuilder = defaultBuilder;
            this.TriggerInfo = triggerInfo;
            this.CommitTrackingSpanEndPoint = commitSpanEndPoint;
            this.DismissIfEmpty = dismissIfEmpty;
        }
Пример #2
0
        private Model(
            DisconnectedBufferGraph disconnectedBufferGraph,
            IList<CompletionItem> totalItems,
            IList<CompletionItem> filteredItems,
            CompletionItem selectedItem,
            ImmutableArray<CompletionItemFilter> completionItemFilters,
            ImmutableDictionary<CompletionItemFilter, bool> filterState,
            IReadOnlyDictionary<CompletionItem, string> completionItemToFilterText,
            bool isHardSelection,
            bool isUnique,
            bool useSuggestionCompletionMode,
            CompletionItem builder,
            CompletionItem defaultBuilder,
            CompletionTriggerInfo triggerInfo,
            ITrackingPoint commitSpanEndPoint,
            bool dismissIfEmpty)
        {
            Contract.ThrowIfFalse(totalItems.Count != 0, "Must have at least one item.");

            _disconnectedBufferGraph = disconnectedBufferGraph;
            this.TotalItems = totalItems;
            this.FilteredItems = filteredItems;
            this.FilterState = filterState;
            this.SelectedItem = selectedItem;
            this.CompletionItemFilters = completionItemFilters;
            this.CompletionItemToFilterText = completionItemToFilterText;
            this.IsHardSelection = isHardSelection;
            this.IsUnique = isUnique;
            this.UseSuggestionCompletionMode = useSuggestionCompletionMode;
            this.Builder = builder;
            this.DefaultBuilder = defaultBuilder;
            this.TriggerInfo = triggerInfo;
            this.CommitTrackingSpanEndPoint = commitSpanEndPoint;
            this.DismissIfEmpty = dismissIfEmpty;
        }
Пример #3
0
        private PatternMatch? GetMatch(
            CompletionItem item, string filterText,
            bool includeMatchSpans, CultureInfo culture)
        {
            // If the item has a dot in it (i.e. for something like enum completion), then attempt
            // to match what the user wrote against the last portion of the name.  That way if they
            // write "Bl" and we have "Blub" and "Color.Black", we'll consider hte latter to be a
            // better match as they'll both be prefix matches, and the latter will have a higher
            // priority.

            var lastDotIndex = item.FilterText.LastIndexOf('.');
            if (lastDotIndex >= 0)
            {
                var textAfterLastDot = item.FilterText.Substring(lastDotIndex + 1);
                var match = GetMatchWorker(textAfterLastDot, filterText, includeMatchSpans, culture);
                if (match != null)
                {
                    return match;
                }
            }

            // Didn't have a dot, or the user text didn't match the portion after the dot.
            // Just do a normal check against the entire completion item.
            return GetMatchWorker(item.FilterText, filterText, includeMatchSpans, culture);
        }
        public override async Task<CompletionChange> GetChangeAsync(Document document, CompletionItem item, char? commitKey = default(char?), CancellationToken cancellationToken = default(CancellationToken))
        {
            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
            var newDocument = await DetermineNewDocumentAsync(item, text, cancellationToken).ConfigureAwait(false);

            var newText = await newDocument.GetTextAsync(cancellationToken).ConfigureAwait(false);
            var newRoot = await newDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            int? newPosition = null;

            // Attempt to find the inserted node and move the caret appropriately
            if (newRoot != null)
            {
                var caretTarget = newRoot.GetAnnotatedNodesAndTokens(_annotation).FirstOrNullable();
                if (caretTarget != null)
                {
                    var targetPosition = GetTargetCaretPosition(caretTarget.Value.AsNode());

                    // Something weird happened and we failed to get a valid position.
                    // Bail on moving the caret.
                    if (targetPosition > 0 && targetPosition <= newText.Length)
                    {
                        newPosition = targetPosition;
                    }
                }
            }

            var changes = await newDocument.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(false);
            return CompletionChange.Create(ImmutableArray.CreateRange(changes), newPosition, includesCommitCharacter: true);
        }
 public override bool? IsCommitCharacter(CompletionItem completionItem, char ch, string textTypedSoFar)
 {
     // TODO(cyrusn): We could just allow the standard list of completion characters.
     // However, i'd like to see what the experience is like really filtering down to the set
     // of things that is allowable.
     return ch == ' ' || ch == '(' || ch == '{' || ch == '[';
 }
        private async Task<Document> DetermineNewDocumentAsync(CompletionItem completionItem, SourceText sourceText, CancellationToken cancellationToken)
        {
            // The span we're going to replace
            var line = sourceText.Lines[MemberInsertionCompletionItem.GetLine(completionItem)];
            //var line = textSnapshot.GetLineFromLineNumber(MemberInsertionCompletionItem.GetLine(completionItem));

            //var sourceText = textSnapshot.AsText();
            var document = sourceText.GetOpenDocumentInCurrentContextWithChanges();
            Contract.ThrowIfNull(document);

            // Annotate the line we care about so we can find it after adding usings
            var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
            var token = GetToken(completionItem, tree, cancellationToken);
            var annotatedRoot = tree.GetRoot(cancellationToken).ReplaceToken(token, token.WithAdditionalAnnotations(_otherAnnotation));
            document = document.WithSyntaxRoot(annotatedRoot);

            var memberContainingDocument = await GenerateMemberAndUsingsAsync(document, completionItem, line, cancellationToken).ConfigureAwait(false);

            var insertionRoot = await PrepareTreeForMemberInsertionAsync(memberContainingDocument, cancellationToken).ConfigureAwait(false);
            var insertionText = await GenerateInsertionTextAsync(memberContainingDocument, cancellationToken).ConfigureAwait(false);

            var destinationSpan = ComputeDestinationSpan(insertionRoot, insertionText);

            var finalText = insertionRoot.GetText(sourceText.Encoding).Replace(destinationSpan, insertionText.Trim());

            document = document.WithText(finalText);
            var newRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            var declaration = GetSyntax(newRoot.FindToken(destinationSpan.End));

            document = document.WithSyntaxRoot(newRoot.ReplaceNode(declaration, declaration.WithAdditionalAnnotations(_annotation)));
            return Formatter.FormatAsync(document, _annotation, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken);
        }
Пример #7
0
 private CompletionList(TextSpan defaultSpan, ImmutableArray<CompletionItem> items, CompletionRules rules, CompletionItem suggestionModeItem)
 {
     this.DefaultSpan = defaultSpan;
     this.Items = items.IsDefault ? ImmutableArray<CompletionItem>.Empty : items;
     this.Rules = rules ?? CompletionRules.Default;
     this.SuggestionModeItem = suggestionModeItem;
 }
        private bool IsCaretOutsideItemBounds(
            Model model,
            SnapshotPoint caretPoint,
            CompletionItem item,
            Dictionary<TextSpan, string> textSpanToText,
            Dictionary<TextSpan, ViewTextSpan> textSpanToViewSpan)
        {
            // Easy first check.  See if the caret point is before the start of the item.
            if (!textSpanToViewSpan.TryGetValue(item.Span, out var filterSpanInViewBuffer))
            {
                filterSpanInViewBuffer = model.GetViewBufferSpan(item.Span);
                textSpanToViewSpan[item.Span] = filterSpanInViewBuffer;
            }

            if (caretPoint < filterSpanInViewBuffer.TextSpan.Start)
            {
                return true;
            }

            var textSnapshot = caretPoint.Snapshot;

            var currentText = model.GetCurrentTextInSnapshot(item.Span, textSnapshot, textSpanToText);
            var currentTextSpan = new TextSpan(filterSpanInViewBuffer.TextSpan.Start, currentText.Length);

            return !currentTextSpan.IntersectsWith(caretPoint);
        }
Пример #9
0
 protected virtual Task<CompletionDescription> GetDescriptionWorkerAsync(
     Document document, CompletionItem item, CancellationToken cancellationToken)
 {
     return CommonCompletionItem.HasDescription(item)
         ? Task.FromResult(CommonCompletionItem.GetDescription(item))
         : Task.FromResult(CompletionDescription.Empty);
 }
Пример #10
0
        private async Task<ImmutableArray<TaggedText>> TryAddSnippetInvocationPart(
            Document document, CompletionItem item, 
            ImmutableArray<TaggedText> parts, CancellationToken cancellationToken)
        {
            var languageServices = document.Project.LanguageServices;
            var snippetService = languageServices.GetService<ISnippetInfoService>();
            if (snippetService != null)
            {
                var change = await GetTextChangeAsync(document, item, ch: '\t', cancellationToken: cancellationToken).ConfigureAwait(false) ??
                    new TextChange(item.Span, item.DisplayText);
                var insertionText = change.NewText;

                if (snippetService != null && snippetService.SnippetShortcutExists_NonBlocking(insertionText))
                {
                    var note = string.Format(FeaturesResources.Note_colon_Tab_twice_to_insert_the_0_snippet, insertionText);

                    if (parts.Any())
                    {
                        parts = parts.Add(new TaggedText(TextTags.LineBreak, Environment.NewLine));
                    }

                    parts = parts.Add(new TaggedText(TextTags.Text, note));
                }
            }

            return parts;
        }
Пример #11
0
        public void SetCompletionItems(
            IList<CompletionItem> completionItems,
            CompletionItem selectedItem,
            CompletionItem suggestionModeItem,
            bool suggestionMode,
            bool isSoftSelected,
            ImmutableArray<CompletionItemFilter> completionItemFilters,
            string filterText)
        {
            this.AssertIsForeground();

            // Initialize the completion map to a reasonable default initial size (+1 for the builder)
            CompletionItemMap = CompletionItemMap ?? new Dictionary<CompletionItem, VSCompletion>(completionItems.Count + 1);
            FilterText = filterText;
            SuggestionModeItem = suggestionModeItem;

            this.SetupFilters(completionItemFilters);

            CreateCompletionListBuilder(selectedItem, suggestionModeItem, suggestionMode);
            CreateNormalCompletionListItems(completionItems);

            var selectedCompletionItem = GetVSCompletion(selectedItem);
            VsCompletionSet.SelectionStatus = new CompletionSelectionStatus(
                selectedCompletionItem, 
                isSelected: !isSoftSelected, isUnique: selectedCompletionItem != null);
        }
        public override TextChange GetTextChange(CompletionItem selectedItem, char? ch = null, string textTypedSoFar = null)
        {
            var displayText = selectedItem.DisplayText;

            if (ch != null)
            {
                // If user types a space, do not complete the " =" (space and equals) at the end of a named parameter. The
                // typed space character will be passed through to the editor, and they can then type the '='.
                if (ch == ' ' && displayText.EndsWith(SpaceEqualsString, StringComparison.Ordinal))
                {
                    return new TextChange(selectedItem.FilterSpan, displayText.Remove(displayText.Length - SpaceEqualsString.Length));
                }

                // If the user types '=', do not complete the '=' at the end of the named parameter because the typed '=' 
                // will be passed through to the editor.
                if (ch == '=' && displayText.EndsWith(EqualsString, StringComparison.Ordinal))
                {
                    return new TextChange(selectedItem.FilterSpan, displayText.Remove(displayText.Length - EqualsString.Length));
                }

                // If the user types ':', do not complete the ':' at the end of the named parameter because the typed ':' 
                // will be passed through to the editor.
                if (ch == ':' && displayText.EndsWith(ColonString, StringComparison.Ordinal))
                {
                    return new TextChange(selectedItem.FilterSpan, displayText.Remove(displayText.Length - ColonString.Length));
                }
            }

            return new TextChange(selectedItem.FilterSpan, displayText);
        }
Пример #13
0
 public AvalonEditCompletionData(CompletionItem item)
 {
     _item = item;
     Text = item.DisplayText;
     Content = item.DisplayText;
     // Image = item.Glyph;
 }
Пример #14
0
 /// <summary>
 /// Creates a new <see cref="CompletionList"/> instance.
 /// </summary>
 /// <param name="defaultSpan">The span of the syntax element at the caret position when the <see cref="CompletionList"/> was created.</param>
 /// <param name="items">The completion items to present to the user.</param>
 /// <param name="rules">The rules used to control behavior of the completion list shown to the user during typing.</param>
 /// <param name="suggestionModeItem">An optional <see cref="CompletionItem"/> that appears selected in the list presented to the user during suggestion mode.</param>
 /// <returns></returns>
 public static CompletionList Create(
     TextSpan defaultSpan,
     ImmutableArray<CompletionItem> items,
     CompletionRules rules = null,
     CompletionItem suggestionModeItem = null)
 {
     return Create(defaultSpan, items, rules, suggestionModeItem, isExclusive: false);
 }
Пример #15
0
 /// <summary>
 /// Creates a new <see cref="CompletionList"/> instance.
 /// </summary>
 /// <param name="defaultSpan">The span of the syntax element at the caret position when the <see cref="CompletionList"/> was created.</param>
 /// <param name="items">The completion items to present to the user.</param>
 /// <param name="rules">The rules used to control behavior of the completion list shown to the user during typing.</param>
 /// <param name="suggestionModeItem">An optional <see cref="CompletionItem"/> that appears selected in the list presented to the user during suggestion mode.</param>
 /// <returns></returns>
 public static CompletionList Create(
     TextSpan defaultSpan,
     ImmutableArray<CompletionItem> items,
     CompletionRules rules = null,
     CompletionItem suggestionModeItem = null)
 {
     return new CompletionList(defaultSpan, FixItemSpans(items, defaultSpan), rules, suggestionModeItem);
 }
 void ICompletionSet.SetCompletionItems(
     IList<CompletionItem> completionItems, CompletionItem selectedItem, 
     CompletionItem suggestionModeItem, bool suggestionMode, bool isSoftSelected, ImmutableArray<CompletionItemFilter> completionItemFilters, string filterText)
 {
     _roslynCompletionSet.SetCompletionItems(
         completionItems, selectedItem, suggestionModeItem, suggestionMode,
         isSoftSelected, completionItemFilters, filterText);
 }
            public override TextChange? GetTextChange(CompletionItem selectedItem, char? ch = default(char?), string textTypedSoFar = null)
            {
                if (ch.HasValue && ch.Value == '(')
                {
                    return new TextChange(selectedItem.FilterSpan, ((SymbolCompletionItem)selectedItem).Symbols[0].Name);
                }

                return new TextChange(selectedItem.FilterSpan, selectedItem.DisplayText);
            }
        public override bool? IsFilterCharacter(CompletionItem completionItem, char ch, string textTypedSoFar)
        {
            if (ch == '!' || ch == '-' || ch == '[')
            {
                return true;
            }

            return base.IsFilterCharacter(completionItem, ch, textTypedSoFar);
        }
        /// <summary>
        /// Internal for testing purposes only.
        /// </summary>
        internal static async Task<TextChange> GetTextChangeAsync(
            CompletionService service, Document document, CompletionItem item,
            char? commitKey = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            var change = await service.GetChangeAsync(document, item, commitKey, cancellationToken).ConfigureAwait(false);

            // normally the items that produce multiple changes are not expecting to trigger the behaviors that rely on looking at the text
            return change.TextChange;
        }
Пример #20
0
        public void AddItem(CompletionItem item)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            _itemsBuilder.Add(item);
        }
            private CompletionItem GetCompletionItem(CompletionItem item)
            {
                if (item is DescriptionModifyingCompletionItem)
                {
                    return ((DescriptionModifyingCompletionItem)item).CompletionItem;
                }

                return item;
            }
Пример #22
0
        internal static bool IsFilterCharacter(CompletionItem item, char ch, string textTypedSoFar)
        {
            // If the user types something that matches what is in the completion list, then just
            // count it as a filter character.

            // For example, if they type "Program " and "Program Files" is in the list, the <space>
            // should be counted as a filter character and not a commit character.
            return item.DisplayText.StartsWith(textTypedSoFar, StringComparison.OrdinalIgnoreCase);
        }
        public override TextChange GetTextChange(CompletionItem selectedItem, char? ch = null, string textTypedSoFar = null)
        {
            var symbolItem = (SymbolCompletionItem)selectedItem;
            var insertionText = ch == null
                ? symbolItem.InsertionText
                : GetInsertionText(symbolItem, ch.Value);

            return new TextChange(selectedItem.FilterSpan, insertionText);
        }
Пример #24
0
        public SimplePresentationItem(CompletionItem item, CompletionService completionService, bool isSuggestionModeItem = false)
        {
            Debug.Assert(item != null);
            Debug.Assert(completionService != null);

            this.Item = item;
            this.CompletionService = completionService;
            this.IsSuggestionModeItem = isSuggestionModeItem;
        }
        public void PresentItems(
            ITrackingSpan triggerSpan,
            IList<CompletionItem> completionItems,
            CompletionItem selectedItem,
            CompletionItem presetBuilder,
            bool suggestionMode,
            bool isSoftSelected)
        {
            AssertIsForeground();

            // check if this update is still relevant
            if (_textView.IsClosed || _isDismissed)
            {
                return;
            }

            _completionSet.SetTrackingSpan(triggerSpan);

            _ignoreSelectionStatusChangedEvent = true;
            try
            {
                _completionSet.SetCompletionItems(completionItems, selectedItem, presetBuilder, suggestionMode, isSoftSelected);
            }
            finally
            {
                _ignoreSelectionStatusChangedEvent = false;
            }

            if (_editorSessionOpt == null)
            {
                // We're tracking the caret.  Don't have the editor do it. 
                // Map the span instead of a point to avoid affinity problems.
                _editorSessionOpt = _completionBroker.CreateCompletionSession(
                    _textView,
                    triggerSpan.GetStartTrackingPoint(PointTrackingMode.Negative),
                    trackCaret: false);

                var debugTextView = _textView as IDebuggerTextView;
                if (debugTextView != null && !debugTextView.IsImmediateWindow)
                {
                    debugTextView.HACK_StartCompletionSession(_editorSessionOpt);
                }

                _editorSessionOpt.Dismissed += (s, e) => OnEditorSessionDismissed();

                // So here's the deal.  We cannot create the editor session and give it the right
                // items (even though we know what they are).  Instead, the session will call
                // back into the ICompletionSourceProvider (which is us) to get those values. It
                // will pass itself along with the calls back into ICompletionSourceProvider.
                // So, in order to make that connection work, we add properties to the session
                // so that we can call back into ourselves, get the items and add it to the
                // session.
                _editorSessionOpt.Properties.AddProperty(Key, this);
                _editorSessionOpt.Start();
            }
        }
Пример #26
0
        private CompletionProvider GetCompletionProvider(CompletionItem item)
        {
            var completionService = this.GetCompletionService() as CompletionServiceWithProviders;
            if (completionService != null)
            {
                return completionService.GetProvider(item);
            }

            return null;
        }
        public override bool IsCommitCharacter(CompletionItem completionItem, char ch, string textTypedSoFar)
        {
            if ((ch == '"' || ch == ' ')
                && completionItem.DisplayText.Contains(ch))
            {
                return false;
            }

            return CompletionUtilities.IsCommitCharacter(completionItem, ch, textTypedSoFar) || ch == '>' || ch == '\t';
        }
        protected override bool SendEnterThroughToEditorCore(CompletionItem completionItem, string textTypedSoFar, OptionSet options)
        {
            // If the text doesn't match, no reason to even check the options
            if (completionItem.DisplayText != textTypedSoFar)
            {
                return false;
            }

            return options.GetOption(CSharpCompletionOptions.AddNewLineOnEnterAfterFullyTypedWord);
        }
        public static DeclarationModifiers GetModifiers(CompletionItem item)
        {
            if (item.Properties.TryGetValue("Modifiers", out var text) &&
                DeclarationModifiers.TryParse(text, out var modifiers))
            {
                return modifiers;
            }

            return default(DeclarationModifiers);
        }
        public static int GetTokenSpanEnd(CompletionItem item)
        {
            if (item.Properties.TryGetValue("TokenSpanEnd", out var text)
                && int.TryParse(text, out var number))
            {
                return number;
            }

            return 0;
        }
Пример #31
0
        public override Task <CompletionDescription> GetDescriptionAsync(Document document, CompletionItem item, CancellationToken cancellationToken)
        {
            if (!item.Properties.TryGetValue(DescriptionKey, out var description))
            {
                return(SpecializedTasks.Default <CompletionDescription>());
            }

            return(Task.FromResult(CompletionDescription.Create(
                                       ImmutableArray.Create(new TaggedText(TextTags.Text, description)))));
        }
Пример #32
0
 public CommitResult TryCommit(IAsyncCompletionSession session, ITextBuffer buffer, CompletionItem item, char typedChar, CancellationToken token)
 {
     return(typedChar.Equals(' ') ? CommitResult.Handled : CommitResult.Unhandled);
 }
Пример #33
0
 /// <summary>
 /// Returns true if the completion item should be "soft" selected, or false if it should be "hard"
 /// selected.
 /// </summary>
 public virtual bool ShouldSoftSelectItem(CompletionItem item, string filterText, CompletionTrigger trigger)
 {
     return(filterText.Length == 0 && !item.Rules.Preselect);
 }
Пример #34
0
        public IReadOnlyList <TextSpan> GetHighlightedSpans(CompletionItem completionItem, string filterText)
        {
            var match = GetMatch(completionItem, filterText, includeMatchSpans: true);

            return(match?.MatchedSpans);
        }
Пример #35
0
 private static void AssertRazorCompletionItem(DirectiveDescriptor directive, CompletionItem item, IAsyncCompletionSource source) =>
 AssertRazorCompletionItem(directive.Directive, directive, item, source);
Пример #36
0
 public virtual TextChange GetTextChange(CompletionItem selectedItem, char?ch = null, string textTypedSoFar = null)
 {
     return(new TextChange(selectedItem.FilterSpan, selectedItem.DisplayText));
 }
Пример #37
0
        public override async Task ProduceCompletionListAsync(CompletionListContext context)
        {
            try
            {
                var document          = context.Document;
                var position          = context.Position;
                var options           = context.Options;
                var cancellationToken = context.CancellationToken;

                var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

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

                var token = tree.FindTokenOnLeftOfPosition(position, cancellationToken);
                if (token.IsMandatoryNamedParameterPosition())
                {
                    return;
                }

                var typeInferenceService = document.GetLanguageService <ITypeInferenceService>();

                var span          = new TextSpan(position, 0);
                var semanticModel = await document.GetSemanticModelForSpanAsync(span, cancellationToken).ConfigureAwait(false);

                var type = typeInferenceService.InferType(semanticModel, position,
                                                          objectAsDefault: true,
                                                          cancellationToken: cancellationToken);

                // If we have a Nullable<T>, unwrap it.
                if (type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
                {
                    type = type.GetTypeArguments().FirstOrDefault();

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

                if (type.TypeKind != TypeKind.Enum)
                {
                    type = GetCompletionListType(type, semanticModel.GetEnclosingNamedType(position, cancellationToken), semanticModel.Compilation);
                    if (type == null)
                    {
                        return;
                    }
                }

                if (!type.IsEditorBrowsable(options.GetOption(CompletionOptions.HideAdvancedMembers, semanticModel.Language), semanticModel.Compilation))
                {
                    return;
                }

                // Does type have any aliases?
                ISymbol alias = await type.FindApplicableAlias(position, semanticModel, cancellationToken).ConfigureAwait(false);

                var displayService = document.GetLanguageService <ISymbolDisplayService>();
                var displayText    = alias != null
                    ? alias.Name
                    : displayService.ToMinimalDisplayString(semanticModel, position, type);

                var workspace = document.Project.Solution.Workspace;
                var text      = await semanticModel.SyntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false);

                var textChangeSpan = CompletionUtilities.GetTextChangeSpan(text, position);

                var item = new CompletionItem(
                    this,
                    displayText: displayText,
                    filterSpan: textChangeSpan,
                    descriptionFactory: CommonCompletionUtilities.CreateDescriptionFactory(workspace, semanticModel, position, alias ?? type),
                    glyph: (alias ?? type).GetGlyph(),
                    preselect: true,
                    rules: ItemRules.Instance);

                context.AddItem(item);
            }
            catch (Exception e) when(FatalError.ReportUnlessCanceled(e))
            {
                throw ExceptionUtilities.Unreachable;
            }
        }
Пример #38
0
 protected abstract bool IsGeneric(CompletionItem completionItem);
Пример #39
0
        public override async Task <CompletionChange> GetChangeAsync(Document document, CompletionItem item, char?commitKey = default(char?), CancellationToken cancellationToken = default(CancellationToken))
        {
            var projectIdGuid = item.Properties[ProjectGuidKey];
            var projectId     = ProjectId.CreateFromSerialized(new System.Guid(projectIdGuid));
            var project       = document.Project.Solution.GetProject(projectId);
            var assemblyName  = item.DisplayText;
            var publicKey     = await GetPublicKeyOfProjectAsync(project, cancellationToken).ConfigureAwait(false);

            if (!string.IsNullOrEmpty(publicKey))
            {
                assemblyName += $", PublicKey={ publicKey }";
            }

            var textChange = new TextChange(item.Span, assemblyName);

            return(CompletionChange.Create(textChange));
        }
 protected override Task <TextChange?> GetTextChangeAsync(CompletionItem selectedItem, char?ch, CancellationToken cancellationToken)
 {
     return(Task.FromResult <TextChange?>(new TextChange(
                                              selectedItem.Span,
                                              selectedItem.DisplayText)));
 }
        protected override async Task <TextChange?> GetTextChangeAsync(CompletionItem selectedItem, char?ch, CancellationToken cancellationToken)
        {
            (string beforeText, string afterText, string newMethod) = await GetInsertText(selectedItem.Properties);

            return(new TextChange(new TextSpan(selectedItem.Span.Start, selectedItem.Span.Length), beforeText + afterText));
        }
Пример #42
0
 protected bool IsArgumentName(CompletionItem item)
 {
     return(item.Tags.Contains(CompletionTags.ArgumentName));
 }
Пример #43
0
        private static void AssertRazorCompletionItem(string completionDisplayText, DirectiveDescriptor directive, CompletionItem item, IAsyncCompletionSource source)
        {
            Assert.Equal(item.DisplayText, completionDisplayText);
            Assert.Equal(item.FilterText, completionDisplayText);
            Assert.Equal(item.InsertText, directive.Directive);
            Assert.Same(item.Source, source);
            Assert.True(item.Properties.TryGetProperty <DirectiveCompletionDescription>(RazorDirectiveCompletionSource.DescriptionKey, out var actualDescription));
            Assert.Equal(directive.Description, actualDescription.Description);

            AssertRazorCompletionItemDefaults(item);
        }
Пример #44
0
 public abstract bool IsCommitCharacter(CompletionItem completionItem, char ch, string textTypedSoFar);
Пример #45
0
 public virtual bool IsFilterCharacter(CompletionItem completionItem, char ch, string textTypedSoFar)
 {
     return(false);
 }
Пример #46
0
        public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            // This provider is exported for all workspaces - so limit it to just our workspace & the debugger's intellisense workspace
            if (context.Document.Project.Solution.Workspace.Kind != WorkspaceKind.AnyCodeRoslynWorkspace &&
                context.Document.Project.Solution.Workspace.Kind != StringConstants.DebuggerIntellisenseWorkspaceKind)
            {
                return;
            }

            var lspClient = _roslynLspClientServiceFactory.ActiveLanguageServerClient;

            if (lspClient == null)
            {
                return;
            }

            var text = await context.Document.GetTextAsync(context.CancellationToken).ConfigureAwait(false);

            var completionParams = new LSP.CompletionParams
            {
                TextDocument = ProtocolConversions.DocumentToTextDocumentIdentifier(context.Document),
                Position     = ProtocolConversions.LinePositionToPosition(text.Lines.GetLinePosition(context.Position)),
                Context      = new LSP.CompletionContext {
                    TriggerCharacter = context.Trigger.Character.ToString(), TriggerKind = GetTriggerKind(context.Trigger)
                }
            };

            var completionObject = await lspClient.RequestAsync(LSP.Methods.TextDocumentCompletion.ToLSRequest(), completionParams, context.CancellationToken).ConfigureAwait(false);

            if (completionObject == null)
            {
                return;
            }

            var completionList = ((JToken)completionObject).ToObject <RoslynCompletionItem[]>();

            foreach (var item in completionList)
            {
                ImmutableArray <string> tags;
                if (item.Tags != null)
                {
                    tags = item.Tags.AsImmutable();
                }
                else
                {
                    var glyph = ProtocolConversions.CompletionItemKindToGlyph(item.Kind);
                    tags = GlyphTags.GetTags(glyph);
                }

                var properties = ImmutableDictionary.CreateBuilder <string, string>();
                if (!string.IsNullOrEmpty(item.Detail))
                {
                    // The display text is encoded as TaggedText | value
                    properties.Add("Description", $"Text|{item.Detail}");
                }

                properties.Add("InsertionText", item.InsertText);
                properties.Add("ResolveData", JToken.FromObject(item).ToString());
                var completionItem = CompletionItem.Create(item.Label, item.FilterText, item.SortText, properties: properties.ToImmutable(), tags: tags);
                context.AddItem(completionItem);
            }
        }
Пример #47
0
 public abstract bool SendEnterThroughToEditor(CompletionItem completionItem, string textTypedSoFar);
Пример #48
0
 private void CommitOnNonTypeChar(
     CompletionItem item, Model model)
 {
     Commit(item, model, commitChar: null, initialTextSnapshot: null, nextHandler: null);
 }
Пример #49
0
        protected override async Task <CompletionDescription> GetDescriptionWorkerAsync(Document document, CompletionItem item, CancellationToken cancellationToken)
        {
            var lspClient = _roslynLspClientServiceFactory.ActiveLanguageServerClient;

            if (lspClient == null)
            {
                return(await base.GetDescriptionWorkerAsync(document, item, cancellationToken).ConfigureAwait(false));
            }

            if (!item.Properties.TryGetValue("ResolveData", out var serializedItem))
            {
                return(await base.GetDescriptionWorkerAsync(document, item, cancellationToken).ConfigureAwait(false));
            }

            var completionItem         = JToken.Parse(serializedItem).ToObject <RoslynCompletionItem>();
            var request                = new LspRequest <RoslynCompletionItem, RoslynCompletionItem>(LSP.Methods.TextDocumentCompletionResolveName);
            var resolvedCompletionItem = await lspClient.RequestAsync(request, completionItem, cancellationToken).ConfigureAwait(false);

            if (resolvedCompletionItem?.Description == null)
            {
                return(await base.GetDescriptionWorkerAsync(document, item, cancellationToken).ConfigureAwait(false));
            }

            var parts = resolvedCompletionItem.Description.Select(tt => tt.ToTaggedText()).AsImmutable();

            return(CompletionDescription.Create(parts));
        }
Пример #50
0
 public override bool SendEnterThroughToEditor(CompletionItem completionItem, string textTypedSoFar)
 {
     return(CompletionUtilities.SendEnterThroughToEditor(completionItem, textTypedSoFar));
 }
Пример #51
0
        protected static int GetRecentItemIndex(ImmutableArray <string> recentItems, CompletionItem item)
        {
            var index = recentItems.IndexOf(item.DisplayText);

            return(-index);
        }
Пример #52
0
 get => GetIcon(CompletionItem, MimeType);
Пример #53
0
 protected bool IsObjectCreationItem(CompletionItem item)
 {
     return(item.Tags.Contains(CompletionTags.ObjectCreation));
 }
Пример #54
0
        public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            if (!context.Options.GetOption(RegularExpressionsOptions.ProvideRegexCompletions, context.Document.Project.Language))
            {
                return;
            }

            if (context.Trigger.Kind != CompletionTriggerKind.Invoke &&
                context.Trigger.Kind != CompletionTriggerKind.InvokeAndCommitIfUnique &&
                context.Trigger.Kind != CompletionTriggerKind.Insertion)
            {
                return;
            }

            var position = context.Position;

            var(tree, stringToken) = await _language.TryGetTreeAndTokenAtPositionAsync(
                context.Document, position, context.CancellationToken).ConfigureAwait(false);

            if (tree == null ||
                position <= stringToken.SpanStart ||
                position >= stringToken.Span.End)
            {
                return;
            }

            var embeddedContext = new EmbeddedCompletionContext(this._language, context, tree, stringToken);

            ProvideCompletions(embeddedContext);

            if (embeddedContext.Items.Count == 0)
            {
                return;
            }

            foreach (var embeddedItem in embeddedContext.Items)
            {
                var change     = embeddedItem.Change;
                var textChange = change.TextChange;

                var properties = ImmutableDictionary.CreateBuilder <string, string>();
                properties.Add(StartKey, textChange.Span.Start.ToString());
                properties.Add(LengthKey, textChange.Span.Length.ToString());
                properties.Add(NewTextKey, textChange.NewText);
                properties.Add(DescriptionKey, embeddedItem.FullDescription);
                properties.Add(EmbeddedLanguageCompletionProvider.EmbeddedProviderName, this.Name);

                if (change.NewPosition != null)
                {
                    properties.Add(NewPositionKey, change.NewPosition.ToString());
                }

                // Keep everything sorted in the order we just produced the items in.
                var sortText = context.Items.Count.ToString("0000");
                context.AddItem(CompletionItem.Create(
                                    displayText: embeddedItem.DisplayText,
                                    inlineDescription: embeddedItem.InlineDescription,
                                    sortText: sortText,
                                    properties: properties.ToImmutable(),
                                    rules: s_rules));
            }

            context.IsExclusive = true;
        }
Пример #55
0
        private void Commit(
            CompletionItem item, Model model, char?commitChar,
            ITextSnapshot initialTextSnapshot, Action nextHandler)
        {
            AssertIsForeground();

            // We could only be called if we had a model at this point.
            Contract.ThrowIfNull(model);

            // Now that we've captured the model at this point, we can stop ourselves entirely.
            // This is also desirable as we may have reentrancy problems when we call into
            // custom commit completion providers.  I.e. if the custom provider moves the caret,
            // then we do not want to process that move as it may put us into an unexpected state.
            //
            // TODO(cyrusn): We still have a general reentrancy problem where calling into a custom
            // commit provider (or just calling into the editor) may cause something to call back
            // into us.  However, for now, we just hope that no such craziness will occur.
            this.DismissSessionIfActive();

            CompletionChange completionChange;

            using (var transaction = CaretPreservingEditTransaction.TryCreate(
                       EditorFeaturesResources.IntelliSense, TextView, _undoHistoryRegistry, _editorOperationsFactoryService))
            {
                if (transaction == null)
                {
                    // This text buffer has no undo history and has probably been unmapped.
                    // (Workflow unmaps its projections when losing focus (such as double clicking the completion list)).
                    // Bail on committing completion because we won't be able to find a Document to update either.

                    return;
                }

                // We want to merge with any of our other programmatic edits (e.g. automatic brace completion)
                transaction.MergePolicy = AutomaticCodeChangeMergePolicy.Instance;

                var provider = GetCompletionProvider(item) as ICustomCommitCompletionProvider;
                if (provider != null)
                {
                    provider.Commit(item, this.TextView, this.SubjectBuffer, model.TriggerSnapshot, commitChar);
                }
                else
                {
                    // Right before calling Commit, we may have passed the commitChar through to the
                    // editor.  That was so that undoing completion will get us back to the state we
                    // we would be in if completion had done nothing.  However, now that we're going
                    // to actually commit, we want to roll back to where we were before we pushed
                    // commit character into the buffer.  This has multiple benefits:
                    //
                    //   1) the buffer is in a state we expect it to be in.  i.e. we don't have to
                    //      worry about what might have happened (like brace-completion) when the
                    //      commit char was inserted.
                    //   2) after we commit the item, we'll pass the commit character again into the
                    //      buffer (unless the items asks us not to).  By doing this, we can make sure
                    //      that things like brace-completion or formatting trigger as we expect them
                    //      to.
                    var characterWasSentIntoBuffer = commitChar != null &&
                                                     initialTextSnapshot.Version.VersionNumber != this.SubjectBuffer.CurrentSnapshot.Version.VersionNumber;
                    if (characterWasSentIntoBuffer)
                    {
                        RollbackToBeforeTypeChar(initialTextSnapshot);
                    }

                    // Now, get the change the item wants to make.  Note that the change will be relative
                    // to the initial snapshot/document the item was triggered from.  We'll map that change
                    // forward, then apply it to our current snapshot.
                    var triggerDocument = model.TriggerDocument;
                    var triggerSnapshot = model.TriggerSnapshot;

                    var completionService = CompletionService.GetService(triggerDocument);
                    Contract.ThrowIfNull(completionService, nameof(completionService));

                    completionChange = completionService.GetChangeAsync(
                        triggerDocument, item, commitChar, CancellationToken.None).WaitAndGetResult(CancellationToken.None);
                    var textChange = completionChange.TextChange;

                    var triggerSnapshotSpan = new SnapshotSpan(triggerSnapshot, textChange.Span.ToSpan());
                    var mappedSpan          = triggerSnapshotSpan.TranslateTo(
                        this.SubjectBuffer.CurrentSnapshot, SpanTrackingMode.EdgeInclusive);

                    var adjustedNewText = AdjustForVirtualSpace(textChange);
                    var editOptions     = GetEditOptions(mappedSpan, adjustedNewText);

                    // Now actually make the text change to the document.
                    using (var textEdit = this.SubjectBuffer.CreateEdit(editOptions, reiteratedVersionNumber: null, editTag: null))
                    {
                        textEdit.Replace(mappedSpan.Span, adjustedNewText);
                        textEdit.Apply();
                    }

                    // If the completion change requested a new position for the caret to go,
                    // then set the caret to go directly to that point.
                    if (completionChange.NewPosition.HasValue)
                    {
                        SetCaretPosition(desiredCaretPosition: completionChange.NewPosition.Value);
                    }
                    else if (editOptions.ComputeMinimalChange)
                    {
                        // Or, If we're doing a minimal change, then the edit that we make to the
                        // buffer may not make the total text change that places the caret where we
                        // would expect it to go based on the requested change. In this case,
                        // determine where the item should go and set the care manually.

                        // Note: we only want to move the caret if the caret would have been moved
                        // by the edit.  i.e. if the caret was actually in the mapped span that
                        // we're replacing.
                        if (TextView.GetCaretPoint(this.SubjectBuffer) is SnapshotPoint caretPositionInBuffer &&
                            mappedSpan.IntersectsWith(caretPositionInBuffer))
                        {
                            SetCaretPosition(desiredCaretPosition: mappedSpan.Start.Position + adjustedNewText.Length);
                        }
                    }

                    // Now, pass along the commit character unless the completion item said not to
                    if (characterWasSentIntoBuffer && !completionChange.IncludesCommitCharacter)
                    {
                        nextHandler();
                    }

                    // If the insertion is long enough, the caret will scroll out of the visible area.
                    // Re-center the view.
                    this.TextView.Caret.EnsureVisible();
                }

                transaction.Complete();
            }

            // Let the completion rules know that this item was committed.
            this.MakeMostRecentItem(item.DisplayText);
        }
        protected override SyntaxToken GetToken(CompletionItem completionItem, SyntaxTree tree, CancellationToken cancellationToken)
        {
            var tokenSpanEnd = MemberInsertionCompletionItem.GetTokenSpanEnd(completionItem);

            return(tree.FindTokenOnLeftOfPosition(tokenSpanEnd, cancellationToken));
        }
Пример #57
0
 protected static bool IsEnumMemberItem(CompletionItem item)
 {
     return(item.Tags.Contains(CompletionTags.EnumMember));
 }
Пример #58
0
 public RoslynCompletionData(Microsoft.CodeAnalysis.Document document, ITextSnapshot triggerSnapshot, CompletionService completionService, CompletionItem completionItem)
 {
     this.doc               = document;
     this.triggerSnapshot   = triggerSnapshot;
     this.completionService = completionService;
     CompletionItem         = completionItem;
 }
Пример #59
0
 public override TextDocumentIdentifier?GetTextDocumentIdentifier(CompletionItem request) => null;
Пример #60
0
        protected int CompareMatches(PatternMatch match1, PatternMatch match2, CompletionItem item1, CompletionItem item2)
        {
            int diff;

            diff = PatternMatch.CompareType(match1, match2);
            if (diff != 0)
            {
                return(diff);
            }

            diff = PatternMatch.CompareCamelCase(match1, match2);
            if (diff != 0)
            {
                return(diff);
            }

            // argument names are not prefered
            if (IsArgumentName(item1) && !IsArgumentName(item2))
            {
                return(1);
            }
            else if (IsArgumentName(item2) && !IsArgumentName(item1))
            {
                return(-1);
            }

            // preselected items are prefered
            if (item1.Rules.Preselect && !item2.Rules.Preselect)
            {
                return(-1);
            }
            else if (item2.Rules.Preselect && !item1.Rules.Preselect)
            {
                return(1);
            }

            diff = PatternMatch.CompareCase(match1, match2);
            if (diff != 0)
            {
                return(diff);
            }

            diff = PatternMatch.ComparePunctuation(match1, match2);
            if (diff != 0)
            {
                return(diff);
            }

            return(0);
        }