コード例 #1
0
            private void Add(
                string displayText,
                string suffix,
                string description,
                bool standard,
                bool isDefault
                )
            {
                using var _1 = PooledStringBuilder.GetInstance(out var descriptionBuilder);
                using var _2 = ArrayBuilder <string> .GetInstance(out var examples);

                AddExamples(examples, standard, displayText);

                descriptionBuilder.AppendLine(
                    examples.Count == 1 ? FeaturesResources.Example : FeaturesResources.Examples
                    );
                foreach (var example in examples)
                {
                    descriptionBuilder.AppendLine(example);
                }

                descriptionBuilder.AppendLine();
                descriptionBuilder.Append(description);

                _items.Add(
                    new DateAndTimeItem(
                        displayText,
                        suffix,
                        descriptionBuilder.ToString(),
                        CompletionChange.Create(new TextChange(_replacementSpan, displayText)),
                        isDefault
                        )
                    );
            }
コード例 #2
0
            public void AddIfMissing(
                string displayText, string suffix, string description,
                RegexNode parentOpt, int?positionOffset = null, string insertionText = null)
            {
                var replacementStart = parentOpt != null
                    ? parentOpt.GetSpan().Start
                    : Position;

                var replacementSpan = TextSpan.FromBounds(replacementStart, Position);
                var newPosition     = replacementStart + positionOffset;

                insertionText ??= displayText;
                var escapedInsertionText = _language.EscapeText(insertionText, StringToken);

                if (escapedInsertionText != insertionText)
                {
                    newPosition += escapedInsertionText.Length - insertionText.Length;
                }

                AddIfMissing(new RegexItem(
                                 displayText, suffix, description,
                                 CompletionChange.Create(
                                     new TextChange(replacementSpan, escapedInsertionText),
                                     newPosition)));
            }
コード例 #3
0
        private static async Task <CompletionChange> GetConversionChangeAsync(
            Document document, CompletionItem item, CancellationToken cancellationToken)
        {
            var position = SymbolCompletionItem.GetContextPosition(item);
            var text     = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var(dotToken, _) = GetDotAndExpressionStart(root, position, cancellationToken);

            var questionToken = dotToken.GetPreviousToken().Kind() == SyntaxKind.QuestionToken
                ? dotToken.GetPreviousToken()
                : (SyntaxToken?)null;

            var expression = (ExpressionSyntax)dotToken.GetRequiredParent();

            expression = expression.GetRootConditionalAccessExpression() ?? expression;

            var replacement = questionToken != null
                ? $"(({item.DisplayText}){text.ToString(TextSpan.FromBounds(expression.SpanStart, questionToken.Value.FullSpan.Start))}){questionToken.Value}"
                : $"(({item.DisplayText}){text.ToString(TextSpan.FromBounds(expression.SpanStart, dotToken.SpanStart))})";

            // If we're at `x.$$.y` then we only want to replace up through the first dot.
            var tokenOnLeft    = root.FindTokenOnLeftOfPosition(position, includeSkipped: true);
            var fullTextChange = new TextChange(
                TextSpan.FromBounds(
                    expression.SpanStart,
                    tokenOnLeft.Kind() == SyntaxKind.DotDotToken ? tokenOnLeft.SpanStart + 1 : tokenOnLeft.Span.End),
                replacement);

            var newPosition = expression.SpanStart + replacement.Length;

            return(CompletionChange.Create(fullTextChange, newPosition));
        }
コード例 #4
0
        public override Task <CompletionChange> GetChangeAsync(
            Document document, CompletionItem item, char?commitKey, CancellationToken cancellationToken)
        {
            int?spanStart  = null;
            int?spanLength = null;

            if (item.Properties.TryGetValue("GodotSpan.Start", out string spanStartStr))
            {
                if (int.TryParse(spanStartStr, out int startResult))
                {
                    spanStart = startResult;
                }

                if (item.Properties.TryGetValue("GodotSpan.Length", out string spanLengthStr))
                {
                    if (int.TryParse(spanLengthStr, out int lengthResult))
                    {
                        spanLength = lengthResult;
                    }
                }
            }

            var span = spanStart.HasValue && spanLength.HasValue ?
                       new TextSpan(spanStart.Value, spanLength.Value) :
                       item.Span;

            return(Task.FromResult(CompletionChange.Create(new TextChange(span, item.DisplayText))));
        }
コード例 #5
0
        public override async Task <CompletionChange> GetChangeAsync(Document document, CompletionItem item, char?commitKey, CancellationToken cancellationToken)
        {
            var change = (await GetTextChangeAsync(document, item, commitKey, cancellationToken).ConfigureAwait(false))
                         ?? new TextChange(item.Span, item.DisplayText);

            return(CompletionChange.Create(change));
        }
コード例 #6
0
        //=====================================================================

        /// <inheritdoc />
        public override async Task <CompletionChange> GetChangeAsync(Document document, CompletionItem item,
                                                                     char?commitChar, CancellationToken cancellationToken)
        {
            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            if (!item.Properties.TryGetValue(nameof(CommentsElement.TextBeforeCaret), out string replacementText))
            {
                replacementText = item.DisplayText;
            }

            var itemSpan        = item.Span;
            var replacementSpan = TextSpan.FromBounds(text[itemSpan.Start - 1] == '<' && replacementText.Length > 0 &&
                                                      replacementText[0] == '<' ? itemSpan.Start - 1 : itemSpan.Start, itemSpan.End);

            int newPosition = replacementSpan.Start + replacementText.Length;

            // Include the commit character?
            if (commitChar != null && !Char.IsWhiteSpace(commitChar.Value) &&
                commitChar.Value != replacementText[replacementText.Length - 1])
            {
                replacementText += commitChar.Value;
                newPosition++;
            }

            if (item.Properties.TryGetValue(nameof(CommentsElement.TextAfterCaret), out string afterCaretText))
            {
                replacementText += afterCaretText;
            }

            return(CompletionChange.Create(new TextChange(replacementSpan, replacementText), newPosition, true));
        }
コード例 #7
0
        private void ProvideEscapeCategoryCompletions(EmbeddedCompletionContext context)
        {
            foreach (var(name, (shortDesc, longDesc)) in RegexCharClass.EscapeCategories)
            {
                var displayText = name;

                // There are some internal escape categories the regex engine has (like _xmlI).
                // Just filter out here so we only show the main documented regex categories.
                // Note: we still include those in RegexCharClass.EscapeCategories because we
                // don't want to report an error on code that does use these since the .net
                // regex engine will allow them.
                if (displayText.StartsWith("_"))
                {
                    continue;
                }

                var description = longDesc.Length > 0
                    ? longDesc
                    : string.Format(Regex_unicode_general_category_0, name);

                context.AddIfMissing(new RegexItem(
                                         displayText, shortDesc, description,
                                         change: CompletionChange.Create(
                                             new TextChange(new TextSpan(context.Position, 0), name), newPosition: null)));
            }
        }
コード例 #8
0
        public override Task <CompletionChange> GetChangeAsync(Document document, CompletionItem item, char?commitKey, CancellationToken cancellationToken)
        {
            var insertText = item.DisplayText;
            var textChange = new TextChange(item.Span, insertText + " KEY");

            return(Task.FromResult(CompletionChange.Create(textChange)));
        }
コード例 #9
0
        public override async Task <CompletionChange> GetChangeAsync(Document document, CompletionItem item, char?commitChar = default(char?), CancellationToken cancellationToken = default(CancellationToken))
        {
            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var beforeCaretText = XmlDocCommentCompletionItem.GetBeforeCaretText(item);
            var afterCaretText  = XmlDocCommentCompletionItem.GetAfterCaretText(item);

            var itemSpan        = item.Span;
            var replacementSpan = TextSpan.FromBounds(text[itemSpan.Start - 1] == '<' && beforeCaretText[0] == '<' ? itemSpan.Start - 1 : itemSpan.Start, itemSpan.End);

            var replacementText = beforeCaretText;
            var newPosition     = replacementSpan.Start + beforeCaretText.Length;

            if (commitChar.HasValue && !char.IsWhiteSpace(commitChar.Value) && commitChar.Value != replacementText[replacementText.Length - 1])
            {
                // include the commit character
                replacementText += commitChar.Value;

                // The caret goes after whatever commit character we spit.
                newPosition++;
            }

            replacementText += afterCaretText;

            return(CompletionChange.Create(
                       new TextChange(replacementSpan, replacementText),
                       newPosition, includesCommitCharacter: true));
        }
コード例 #10
0
        public override async Task <CompletionChange> GetChangeAsync(Document document, CompletionItem item, char?commitKey = null, CancellationToken cancellationToken = default)
        {
            // IsComplexTextEdit is true when we want to add async to the container.
            if (!item.IsComplexTextEdit)
            {
                return(await base.GetChangeAsync(document, item, commitKey, cancellationToken).ConfigureAwait(false));
            }

            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var declaration = root.FindToken(item.Span.Start).GetAncestor(node => node.IsAsyncSupportingFunctionSyntax());

            if (declaration is null)
            {
                // We already check that in ProvideCompletionsAsync above.
                Debug.Assert(false, "Expected non-null value for declaration.");
                return(await base.GetChangeAsync(document, item, commitKey, cancellationToken).ConfigureAwait(false));
            }

            using var _ = ArrayBuilder <TextChange> .GetInstance(out var builder);

            builder.Add(new TextChange(new TextSpan(GetSpanStart(declaration), 0), "async "));
            builder.Add(new TextChange(item.Span, item.DisplayText));

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var newText = text.WithChanges(builder);

            return(CompletionChange.Create(CodeAnalysis.Completion.Utilities.Collapse(newText, builder.ToImmutableArray())));
        }
コード例 #11
0
        public static async Task <CompletionChange> GetChangeAsync(Document document, CompletionItem item, CancellationToken cancellationToken)
        {
            var insertText = item.DisplayText;

            int?newPosition = null;

            if (item.Properties.TryGetValue(CompletionItemProperties.NewPositionOffset, out string positionOffsetString) &&
                int.TryParse(positionOffsetString, out int positionOffset) &&
                positionOffset != 0)
            {
                int originalNewPosition = item.Span.End + insertText.Length;
                newPosition = originalNewPosition + positionOffset;
            }

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

            // Create TextChange with added using
            if (item.Properties.TryGetValue(CompletionItemProperties.NamespaceToImport, out string nsName))
            {
                int position       = item.Span.End;
                var sourceTextTask = document.GetTextAsync(cancellationToken).ConfigureAwait(false);
                var docWithUsing   = await _namespaceResolver.AddNamespaceImportAsync(nsName, document, position, cancellationToken).ConfigureAwait(false);

                var usingChange = await docWithUsing.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(false);

                var changes    = usingChange.Union(new[] { textChange }).ToList();
                var sourceText = await sourceTextTask;
                sourceText = sourceText.WithChanges(changes);

                textChange = Collapse(sourceText, changes);
            }

            return(CompletionChange.Create(textChange, newPosition));
        }
コード例 #12
0
        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));
        }
コード例 #13
0
        public sealed override async Task <CompletionChange> GetChangeAsync(Document document, CompletionItem item, char?commitKey = null, CancellationToken cancellationToken = default)
        {
            // IsComplexTextEdit is true when we want to add async to the container.
            if (!item.IsComplexTextEdit)
            {
                return(await base.GetChangeAsync(document, item, commitKey, cancellationToken).ConfigureAwait(false));
            }

            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var declaration = GetAsyncSupportingDeclaration(root.FindToken(item.Span.Start));

            if (declaration is null)
            {
                // IsComplexTextEdit should only be true when GetAsyncSupportingDeclaration returns non-null.
                // This is ensured by the ShouldMakeContainerAsync overrides.
                Debug.Assert(false, "Expected non-null value for declaration.");
                return(await base.GetChangeAsync(document, item, commitKey, cancellationToken).ConfigureAwait(false));
            }

            var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>();
            var syntaxKinds = document.GetRequiredLanguageService <ISyntaxKindsService>();

            using var _ = ArrayBuilder <TextChange> .GetInstance(out var builder);

            builder.Add(new TextChange(new TextSpan(GetSpanStart(declaration), 0), syntaxFacts.GetText(syntaxKinds.AsyncKeyword) + " "));
            builder.Add(new TextChange(item.Span, item.DisplayText));

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var newText = text.WithChanges(builder);

            return(CompletionChange.Create(Utilities.Collapse(newText, builder.ToImmutableArray())));
        }
コード例 #14
0
 public RegexItem(
     string displayText, string inlineDescription, string fullDescription, CompletionChange change)
 {
     DisplayText       = displayText;
     InlineDescription = inlineDescription;
     FullDescription   = fullDescription;
     Change            = change;
 }
コード例 #15
0
        public override Task <CompletionChange> GetChangeAsync(Document document, CompletionItem item, char?commitKey, CancellationToken cancellationToken)
        {
            // These values have always been added by us.
            var startString  = item.Properties[StartKey];
            var lengthString = item.Properties[LengthKey];
            var newText      = item.Properties[NewTextKey];

            return(Task.FromResult(CompletionChange.Create(new TextChange(new TextSpan(int.Parse(startString), int.Parse(lengthString)), newText))));
        }
        public override async Task <CompletionChange> GetChangeAsync(Document document, CompletionItem item, char?commitKey, CancellationToken cancellationToken)
        {
            var tree = await document.GetSyntaxTreeAsync();

            var node = GetCurrentLiteral(tree, item.Span.Start);

            // insert the insertion text property
            return(CompletionChange.Create(ImmutableArray <TextChange> .Empty.Add(new TextChange(node.Span, item.Properties[InsertionTextKey]))));
        }
コード例 #17
0
 public DateAndTimeItem(
     string displayText, string inlineDescription, string fullDescription, CompletionChange change, bool isDefault)
 {
     DisplayText       = displayText;
     InlineDescription = inlineDescription;
     FullDescription   = fullDescription;
     Change            = change;
     IsDefault         = isDefault;
 }
コード例 #18
0
        public override Task <CompletionChange> GetChangeAsync(Document document, CompletionItem item, char?commitKey, CancellationToken cancellationToken)
        {
            if (item.Properties.TryGetValue("Start", out var start) &&
                int.TryParse(start, out var s) &&
                item.Properties.TryGetValue("Length", out var length) &&
                int.TryParse(length, out var l))
            {
                return(Task.FromResult(CompletionChange.Create(new TextChange(new TextSpan(s, l), item.SortText))));
            }

            return(base.GetChangeAsync(document, item, commitKey, cancellationToken));
        }
コード例 #19
0
        public override async Task <CompletionChange> GetChangeAsync(Document document, CompletionItem item, char?commitKey, CancellationToken cancellationToken)
        {
            string insertText;

            if (!item.Properties.TryGetValue(CompletionItemProperties.InsertText, out insertText))
            {
                insertText = item.DisplayText;
            }

            // Add using for required symbol.
            // Any better place to put this?
            if (TryGetSymbolMapping(item, out ISymbol symbol) && IsCommitContext())
            {
                if (symbol.IsStaticImportable())
                {
                    if (Options.StaticSuggestionsAsCodeFixes)
                    {
                        var ns = symbol.GetNamespace();

                        var fullname = symbol.ToDisplayString();
                        insertText = fullname               //change insertText so that it includes Class name and import namespace if necessary
                                     .Replace(ns + ".", "") //remove namespace from the fully qualified name
                        ;
                        //remove (list of params)
                        var index_of_parenthesis = insertText.IndexOf('(');
                        if (index_of_parenthesis > -1)
                        {
                            insertText = insertText.Remove(index_of_parenthesis);
                        }

                        //we may still need to import namespace for the class, so we check for that here
                        var syntaxTree = await document.GetSyntaxTreeAsync().ConfigureAwait(false);

                        var importedNamespaces = syntaxTree.GetImportedNamespaces();
                        if (!importedNamespaces.Contains(ns))
                        {
                            _namespaceResolver.AddNamespaceOrStatic(ns, true);
                        }
                    }
                    else
                    {
                        _namespaceResolver.AddNamespaceOrStatic(symbol.ContainingType.ToDisplayString(), false);
                    }
                }
                else
                {
                    _namespaceResolver.AddNamespaceOrStatic(symbol.GetNamespace(), true);
                }
            }

            return(CompletionChange.Create(new TextChange(item.Span, insertText)));
        }
コード例 #20
0
            public override Task <CompletionChange> GetChangeAsync(
                Document document,
                CodeAnalysis.Completion.CompletionItem item,
                char?commitCharacter = null,
                CancellationToken cancellationToken = default)
            {
                var textChange = new TextChange(span: new TextSpan(start: 77, length: 9), newText: @"public override void M()
    {
        throw new System.NotImplementedException();
    }");

                return(Task.FromResult(CompletionChange.Create(textChange, newPosition: 0)));
            }
コード例 #21
0
        public override async Task <CompletionChange> GetChangeAsync(Document doc, CompletionItem item, char?commitKey = default(char?), CancellationToken cancellationToken = default(CancellationToken))
        {
            (string beforeText, string afterText, string newMethod) = await GetInsertText(item.Properties);

            TextChange change;

            if (newMethod != null)
            {
                change = new TextChange(new TextSpan(item.Span.Start, item.Span.Length), item.Properties [MethodNameKey] + ";");
                var semanticModel = await doc.GetSemanticModelAsync(cancellationToken);

                if (!doc.IsOpen() || await doc.IsForkedDocumentWithSyntaxChangesAsync(cancellationToken))
                {
                    return(CompletionChange.Create(change));
                }

                await Runtime.RunInMainThread(delegate {
                    var document = IdeApp.Workbench.ActiveDocument;
                    var editor   = document.Editor;
                    if (editor.EditMode != EditMode.Edit)
                    {
                        return;
                    }
                    var parsedDocument  = document.ParsedDocument;
                    var declaringType   = semanticModel.GetEnclosingSymbolMD <INamedTypeSymbol> (item.Span.Start, default(CancellationToken));
                    var insertionPoints = InsertionPointService.GetInsertionPoints(
                        document.Editor,
                        semanticModel,
                        declaringType,
                        editor.CaretOffset
                        );
                    var options = new InsertionModeOptions(
                        GettextCatalog.GetString("Create new method"),
                        insertionPoints,
                        point => {
                        if (!point.Success)
                        {
                            return;
                        }
                        point.InsertionPoint.Insert(document.Editor, document, newMethod);
                    }
                        );
                    editor.StartInsertionMode(options);
                });

                return(CompletionChange.Create(change));
            }
            change = new TextChange(new TextSpan(item.Span.Start, item.Span.Length), beforeText + afterText);

            return(CompletionChange.Create(change, item.Span.Start + beforeText.Length));
        }
コード例 #22
0
        public override Task <CompletionChange> GetChangeAsync(Document document, CompletionItem item, char?commitKey, CancellationToken cancellationToken)
        {
            // These values have always been added by us.
            var startString  = item.Properties[StartKey];
            var lengthString = item.Properties[LengthKey];
            var newText      = item.Properties[NewTextKey];

            // This value is optionally added in some cases and may not always be there.
            item.Properties.TryGetValue(NewPositionKey, out var newPositionString);

            return(Task.FromResult(CompletionChange.Create(
                                       new TextChange(new TextSpan(int.Parse(startString), int.Parse(lengthString)), newText),
                                       newPositionString == null ? default(int?) : int.Parse(newPositionString))));
        }
コード例 #23
0
        public override async Task <CompletionChange> GetChangeAsync(Document document, CompletionItem item, char?commitKey, CancellationToken cancellationToken)
        {
            // custom completion logic
            var model = await document.GetSemanticModelAsync();

            var tree         = model.SyntaxTree;
            var root         = tree.GetRoot();
            var memberAccess = tree.GetRoot().GetCurrentMemberAccess(item.Span.Start);

            if (!item.Properties.TryGetValue(CurrentSnipperProperty, out var currentSnippet))
            {
                return(CompletionChange.Create(ImmutableArray <TextChange> .Empty));
            }

            if (memberAccess != null)
            {
                var      snip         = snippets.FirstOrDefault(s => s.GetType().ToString() == currentSnippet);
                var      newRoot      = snip.ChangeTree(document, model, memberAccess, commitKey);
                string   expectedText = null;
                TextSpan nodeSpan     = default(TextSpan);
                if (snip is IWorkspaceUpdatingSnippet wsnip)
                {
                    ll = async(workspace, solution) => {
                        var doc = solution.GetDocument(document.Id);
                        if ((await doc.GetTextAsync()).ToString() == expectedText)
                        {
                            wsnip.Update(doc, (await doc.GetSyntaxRootAsync()).FindNode(nodeSpan) as ExpressionSyntax, commitKey);
                        }
                    };
                }

                //if (newRoot == null) newRoot = root.ReplaceNode(memberAccess, memberAccess.Expression);
                if (newRoot == null)
                {
                    newRoot = root.ReplaceNode(memberAccess, memberAccess.WithName(SyntaxFactory.IdentifierName(item.DisplayText)));
                }
                // format tree
                var newTree = tree.WithRootAndOptions(Formatter.Format(newRoot, Formatter.Annotation, document.Project.Solution.Workspace), tree.Options);
                // return changes done in the new tree
                var changes = newTree.GetChanges(tree).Select(c => TrimWhitespaceChnage(c, tree.GetText())).Select(c => MoveToNode(c, tree.GetText(), memberAccess.Expression.Span)).ToArray();
                ImmutableArray <TextChange> finalChanges = ImmutableArray.Create(MergeChanges(changes, tree.GetText()));
                expectedText = tree.GetText().WithChanges(finalChanges).ToString();
                nodeSpan     = MoveSpan(memberAccess.Expression.Span, finalChanges);
                return(CompletionChange.Create(finalChanges, includesCommitCharacter: false));
            }
            return(await base.GetChangeAsync(document, item, commitKey, cancellationToken));
        }
コード例 #24
0
        // Точка расширения для замены подставляемого при completion текста
        public override Task <CompletionChange> GetChangeAsync(
            Document document, CompletionItem item, char?commitKey, CancellationToken cancellationToken)
        {
            // Если это свойство DTO-класса, то экранируем его квадратными скобками (escaping)
            if (item.Tags.Contains(WellKnownTags.Property))
            {
                string[] splitted = item.DisplayText.Split('.');
                string   newText  = splitted.Length > 1
                                        ? $"[{splitted[0]}].[{splitted[1]}]"
                                        : $"[{splitted[0]}]";

                return(Task.FromResult(
                           CompletionChange.Create(new TextChange(item.Span, newText))));
            }

            return(base.GetChangeAsync(document, item, commitKey, cancellationToken));
        }
        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));
        }
        public override Task <CompletionChange> GetChangeAsync(Document document, CompletionItem item, char?commitKey, CancellationToken cancellationToken)
        {
            string insertText;

            if (!item.Properties.TryGetValue(CompletionItemProperties.InsertText, out insertText))
            {
                insertText = item.DisplayText;
            }
            var change = Task.FromResult(CompletionChange.Create(new TextChange(item.Span, insertText)));

            // Add using for required symbol.
            // Any better place to put this?
            if (TryGetSymbolMapping(item, out ISymbol symbol) && IsCommitContext())
            {
                _namespaceResolver.AddNamespace(symbol.GetNamespace());
            }

            return(change);
        }
コード例 #27
0
        public override async Task <CompletionChange> GetChangeAsync(Document document, CompletionItem item, char?commitKey = null, CancellationToken cancellationToken = default)
        {
            // This retrieves the document without the text used to invoke completion
            // as well as the new cursor position after that has been removed.
            var(strippedDocument, position) = await GetDocumentWithoutInvokingTextAsync(document, SnippetCompletionItem.GetInvocationPosition(item), cancellationToken).ConfigureAwait(false);

            var service           = strippedDocument.GetRequiredLanguageService <ISnippetService>();
            var snippetIdentifier = SnippetCompletionItem.GetSnippetIdentifier(item);
            var snippetProvider   = service.GetSnippetProvider(snippetIdentifier);

            // This retrieves the generated Snippet
            var snippet = await snippetProvider.GetSnippetAsync(strippedDocument, position, cancellationToken).ConfigureAwait(false);

            var strippedText = await strippedDocument.GetTextAsync(cancellationToken).ConfigureAwait(false);

            // This introduces the text changes of the snippet into the document with the completion invoking text
            var allChangesText = strippedText.WithChanges(snippet.TextChanges);

            // This retrieves ALL text changes from the original document which includes the TextChanges from the snippet
            // as well as the clean up.
            var allChangesDocument = document.WithText(allChangesText);
            var allTextChanges     = await allChangesDocument.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(false);

            var change = Utilities.Collapse(allChangesText, allTextChanges.AsImmutable());

            // Converts the snippet to an LSP formatted snippet string.
            var lspSnippet = await RoslynLSPSnippetConverter.GenerateLSPSnippetAsync(allChangesDocument, snippet.CursorPosition, snippet.Placeholders, change, item.Span.Start, cancellationToken).ConfigureAwait(false);

            // If the TextChanges retrieved starts after the trigger point of the CompletionItem,
            // then we need to move the bounds backwards and encapsulate the trigger point.
            if (change.Span.Start > item.Span.Start)
            {
                var textSpan    = TextSpan.FromBounds(item.Span.Start, change.Span.End);
                var snippetText = change.NewText;
                Contract.ThrowIfNull(snippetText);
                change = new TextChange(textSpan, snippetText);
            }

            var props = ImmutableDictionary <string, string> .Empty
                        .Add(SnippetCompletionItem.LSPSnippetKey, lspSnippet);

            return(CompletionChange.Create(change, allTextChanges.AsImmutable(), properties: props, snippet.CursorPosition, includesCommitCharacter: true));
        }
コード例 #28
0
        public override async Task <CompletionChange> GetChangeAsync(Document doc, CompletionItem item, char?commitKey = default(char?), CancellationToken cancellationToken = default(CancellationToken))
        {
            TextChange change;

            if (item.Properties.ContainsKey("NewMethod"))
            {
                change = new TextChange(new TextSpan(item.Span.Start, item.Span.Length), item.Properties ["MethodName"] + ";");
                var document       = IdeApp.Workbench.ActiveDocument;
                var editor         = document.Editor;
                var parsedDocument = document.ParsedDocument;
                var semanticModel  = await doc.GetSemanticModelAsync(cancellationToken);

                var declaringType   = semanticModel.GetEnclosingSymbolMD <INamedTypeSymbol> (item.Span.Start, default(CancellationToken));
                var insertionPoints = InsertionPointService.GetInsertionPoints(
                    document.Editor,
                    parsedDocument,
                    declaringType,
                    editor.CaretOffset
                    );
                var options = new InsertionModeOptions(
                    GettextCatalog.GetString("Create new method"),
                    insertionPoints,
                    point => {
                    if (!point.Success)
                    {
                        return;
                    }
                    point.InsertionPoint.Insert(document.Editor, document, item.Properties ["NewMethod"]);
                }
                    );

                editor.StartInsertionMode(options);

                return(CompletionChange.Create(change));
            }
            var beforeText = item.Properties ["InsertBefore"];
            var afterText  = item.Properties ["InsertAfter"];

            change = new TextChange(new TextSpan(item.Span.Start, item.Span.Length), beforeText + afterText);

            return(CompletionChange.Create(change, item.Span.Start + beforeText.Length));
        }
        public override async Task <CompletionChange> GetChangeAsync(Document document, CompletionItem item,
                                                                     char?commitKey, CancellationToken cancellationToken)
        {
            if (await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false) is CompilationUnitSyntax
                rootNode)
            {
                if (rootNode.Usings.All(u => u.Name.GetText().ToString() != $"System.Reactive.Linq"))
                {
                    rootNode = rootNode.InsertNodesAfter(rootNode.Usings.Last(),
                                                         new[]
                    {
                        SyntaxFactory.UsingDirective(SyntaxFactory.ParseName($"System.Reactive.Linq"))
                        .NormalizeWhitespace().WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed)
                    });
                }

                if (rootNode.Usings.All(u => u.Name.GetText().ToString() != "RxMethodGenerator"))
                {
                    rootNode = rootNode.InsertNodesAfter(rootNode.Usings.Last(),
                                                         new[]
                    {
                        SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("RxMethodGenerator"))
                        .NormalizeWhitespace().WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed)
                    });
                }

                Document?newDocument = document.WithSyntaxRoot(rootNode);
                document.Project.Solution.Workspace.TryApplyChanges(newDocument.Project.Solution);
            }

            string   newText = $".{item.DisplayText}()";
            TextSpan newSpan = new TextSpan(item.Span.Start - 1, 1);

            TextChange textChange = new TextChange(newSpan, newText);

            return(await Task.FromResult(CompletionChange.Create(textChange)));
        }
コード例 #30
0
            private void Add(string displayText, string suffix, string description, bool standard)
            {
                using var _ = PooledStringBuilder.GetInstance(out var descriptionBuilder);

                // Single letter custom strings need a %, or else they're interpreted as a format
                // standard format string (and will throw a format exception).
                var formatString = !standard && displayText.Length == 1
                    ? "%" + displayText
                    : displayText;

                descriptionBuilder.AppendLine(@$ "{s_primaryCulture.Name}: {s_exampleDateTime.ToString(formatString)}");
                if (s_secondaryCulture != null)
                {
                    descriptionBuilder.AppendLine(@$ "{s_secondaryCulture.Name}: {s_exampleDateTime.ToString(formatString)}");
                }

                descriptionBuilder.AppendLine();
                descriptionBuilder.Append(description);

                _items.Add(new DateAndTimeItem(
                               displayText, suffix, descriptionBuilder.ToString(),
                               CompletionChange.Create(
                                   new TextChange(_replacementSpan, displayText))));
            }