Beispiel #1
0
                static async Task <LSP.TextEdit> GenerateTextEdit(
                    Document document,
                    CompletionItem item,
                    CompletionService completionService,
                    SourceText?documentText,
                    TextSpan?defaultSpan,
                    LSP.Range?defaultRange,
                    CancellationToken cancellationToken)
                {
                    Contract.ThrowIfNull(documentText);
                    Contract.ThrowIfNull(defaultSpan);
                    Contract.ThrowIfNull(defaultRange);

                    var completionChange = await completionService.GetChangeAsync(
                        document, item, cancellationToken : cancellationToken).ConfigureAwait(false);

                    var completionChangeSpan = completionChange.TextChange.Span;

                    var textEdit = new LSP.TextEdit()
                    {
                        NewText = completionChange.TextChange.NewText ?? "",
                        Range   = completionChangeSpan == defaultSpan.Value
                            ? defaultRange
                            : ProtocolConversions.TextSpanToRange(completionChangeSpan, documentText),
                    };

                    return(textEdit);
                }
Beispiel #2
0
                static async Task AddTextEdit(
                    Document document,
                    CompletionItem item,
                    LSP.CompletionItem lspItem,
                    CompletionService completionService,
                    SourceText documentText,
                    TextSpan defaultSpan,
                    bool itemDefaultsSupported,
                    CancellationToken cancellationToken)
                {
                    var completionChange = await completionService.GetChangeAsync(
                        document, item, cancellationToken : cancellationToken).ConfigureAwait(false);

                    var completionChangeSpan = completionChange.TextChange.Span;
                    var newText = completionChange.TextChange.NewText ?? "";

                    if (itemDefaultsSupported && completionChangeSpan == defaultSpan)
                    {
                        // The span is the same as the default, we just need to store the new text as
                        // the insert text so the client can create the text edit from it and the default range.
                        lspItem.InsertText = newText;
                    }
                    else
                    {
                        var textEdit = new LSP.TextEdit()
                        {
                            NewText = newText,
                            Range   = ProtocolConversions.TextSpanToRange(completionChangeSpan, documentText),
                        };
                        lspItem.TextEdit = textEdit;
                    }
                }
Beispiel #3
0
        public async System.Threading.Tasks.Task <object[]> TextDocumentFormattingName(JToken arg)
        {
            if (trace)
            {
                System.Console.Error.WriteLine("<-- TextDocumentFormatting");
                System.Console.Error.WriteLine(arg.ToString());
            }
            var request  = arg.ToObject <DocumentFormattingParams>();
            var document = CheckDoc(request.TextDocument.Uri);
            var new_list = new List <Microsoft.VisualStudio.LanguageServer.Protocol.TextEdit>();
            var changes  = LanguageServer.Module.Reformat(document);
            int count    = 0;

            foreach (var delta in changes)
            {
                var new_edit = new Microsoft.VisualStudio.LanguageServer.Protocol.TextEdit();
                new_edit.Range = new Microsoft.VisualStudio.LanguageServer.Protocol.Range();
                var lcs = LanguageServer.Module.GetLineColumn(delta.range.Start.Value, document);
                var lce = LanguageServer.Module.GetLineColumn(delta.range.End.Value, document);
                new_edit.Range.Start = new Position(lcs.Item1, lcs.Item2);
                new_edit.Range.End   = new Position(lce.Item1, lce.Item2);
                new_edit.NewText     = delta.NewText;
                new_list.Add(new_edit);
                count++;
            }
            return(new_list.ToArray());
        }
        public async System.Threading.Tasks.Task <WorkspaceEdit> TextDocumentRenameName(JToken arg)
        {
            if (trace)
            {
                System.Console.Error.WriteLine("<-- TextDocumentRename");
                System.Console.Error.WriteLine(arg.ToString());
            }
            RenameParams request   = arg.ToObject <RenameParams>();
            Document     document  = CheckDoc(request.TextDocument.Uri);
            Position     position  = request.Position;
            int          line      = position.Line;
            int          character = position.Character;
            int          index     = LanguageServer.Module.GetIndex(line, character, document);

            if (trace)
            {
                System.Console.Error.WriteLine("position index = " + index);
                (int, int)back = LanguageServer.Module.GetLineColumn(index, document);
                System.Console.Error.WriteLine("back to l,c = " + back.Item1 + "," + back.Item2);
            }
            string new_name = request.NewName;
            Dictionary <string, LanguageServer.TextEdit[]> changes = LanguageServer.Module.Rename(index, new_name, document);
            WorkspaceEdit edit  = new WorkspaceEdit();
            int           count = 0;
            Dictionary <string, Microsoft.VisualStudio.LanguageServer.Protocol.TextEdit[]> edit_changes_array = new Dictionary <string, Microsoft.VisualStudio.LanguageServer.Protocol.TextEdit[]>();

            foreach (KeyValuePair <string, LanguageServer.TextEdit[]> pair in changes)
            {
                string doc = pair.Key;
                Uri    uri = new Uri(doc);
                LanguageServer.TextEdit[] val = pair.Value;
                List <Microsoft.VisualStudio.LanguageServer.Protocol.TextEdit> new_list = new List <Microsoft.VisualStudio.LanguageServer.Protocol.TextEdit>();
                foreach (LanguageServer.TextEdit v in val)
                {
                    Microsoft.VisualStudio.LanguageServer.Protocol.TextEdit new_edit = new Microsoft.VisualStudio.LanguageServer.Protocol.TextEdit
                    {
                        Range = new Microsoft.VisualStudio.LanguageServer.Protocol.Range()
                    };
                    (int, int)lcs        = LanguageServer.Module.GetLineColumn(v.range.Start.Value, document);
                    (int, int)lce        = LanguageServer.Module.GetLineColumn(v.range.End.Value, document);
                    new_edit.Range.Start = new Position(lcs.Item1, lcs.Item2);
                    new_edit.Range.End   = new Position(lce.Item1, lce.Item2);
                    new_edit.NewText     = v.NewText;
                    new_list.Add(new_edit);
                    count++;
                }
                edit_changes_array.Add(uri.ToString(), new_list.ToArray());
            }
            edit.Changes = edit_changes_array;
            return(edit);
        }
        // Internal for testing
        internal static async Task <LSP.TextEdit> GenerateTextEditAsync(
            Document document,
            CompletionService completionService,
            CompletionItem selectedItem,
            bool snippetsSupported,
            CancellationToken cancellationToken
            )
        {
            var documentText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var completionChange = await completionService
                                   .GetChangeAsync(document, selectedItem, cancellationToken : cancellationToken)
                                   .ConfigureAwait(false);

            var completionChangeSpan = completionChange.TextChange.Span;
            var newText = completionChange.TextChange.NewText;

            Contract.ThrowIfNull(newText);

            // If snippets are supported, that means we can move the caret (represented by $0) to
            // a new location.
            if (snippetsSupported)
            {
                var caretPosition = completionChange.NewPosition;
                if (caretPosition.HasValue)
                {
                    // caretPosition is the absolute position of the caret in the document.
                    // We want the position relative to the start of the snippet.
                    var relativeCaretPosition = caretPosition.Value - completionChangeSpan.Start;

                    // The caret could technically be placed outside the bounds of the text
                    // being inserted. This situation is currently unsupported in LSP, so in
                    // these cases we won't move the caret.
                    if (relativeCaretPosition >= 0 && relativeCaretPosition <= newText.Length)
                    {
                        newText = newText.Insert(relativeCaretPosition, "$0");
                    }
                }
            }

            var textEdit = new LSP.TextEdit()
            {
                NewText = newText,
                Range   = ProtocolConversions.TextSpanToRange(completionChangeSpan, documentText),
            };

            return(textEdit);
        }
Beispiel #6
0
        public async Task TestCodeActionResolveHandlerAsync()
        {
            var initialMarkup =
                @"class A
{
    void M()
    {
        {|caret:|}int i = 1;
    }
}";

            using var testLspServer = CreateTestLspServer(initialMarkup, out var locations);

            var unresolvedCodeAction = CodeActionsTests.CreateCodeAction(
                title: CSharpAnalyzersResources.Use_implicit_type,
                kind: CodeActionKind.Refactor,
                children: Array.Empty <LSP.VSCodeAction>(),
                data: CreateCodeActionResolveData(
                    CSharpAnalyzersResources.Use_implicit_type,
                    locations["caret"].Single()
                    ),
                priority: PriorityLevel.Low,
                groupName: "Roslyn1",
                applicableRange: new LSP.Range
            {
                Start = new Position {
                    Line = 4, Character = 8
                },
                End = new Position {
                    Line = 4, Character = 11
                }
            },
                diagnostics: null
                );

            // Expected text after edit:
            //     class A
            //     {
            //         void M()
            //         {
            //             var i = 1;
            //         }
            //     }
            var expectedTextEdits = new LSP.TextEdit[]
            {
                GenerateTextEdit(
                    "var",
                    new LSP.Range {
                    Start = new Position(4, 8), End = new Position(4, 11)
                }
                    )
            };

            var expectedResolvedAction = CodeActionsTests.CreateCodeAction(
                title: CSharpAnalyzersResources.Use_implicit_type,
                kind: CodeActionKind.Refactor,
                children: Array.Empty <LSP.VSCodeAction>(),
                data: CreateCodeActionResolveData(
                    CSharpAnalyzersResources.Use_implicit_type,
                    locations["caret"].Single()
                    ),
                priority: PriorityLevel.Low,
                groupName: "Roslyn1",
                diagnostics: null,
                applicableRange: new LSP.Range
            {
                Start = new Position {
                    Line = 4, Character = 8
                },
                End = new Position {
                    Line = 4, Character = 11
                }
            },
                edit: GenerateWorkspaceEdit(locations, expectedTextEdits)
                );

            var actualResolvedAction = await RunGetCodeActionResolveAsync(
                testLspServer,
                unresolvedCodeAction
                );

            AssertJsonEquals(expectedResolvedAction, actualResolvedAction);
        }
Beispiel #7
0
        public async Task TestCodeActionResolveHandlerAsync_NestedAction()
        {
            var initialMarkup =
                @"class A
{
    void M()
    {
        int {|caret:|}i = 1;
    }
}";

            using var testLspServer = CreateTestLspServer(initialMarkup, out var locations);

            var unresolvedCodeAction = CodeActionsTests.CreateCodeAction(
                title: string.Format(FeaturesResources.Introduce_constant_for_0, "1"),
                kind: CodeActionKind.Refactor,
                children: Array.Empty <LSP.VSCodeAction>(),
                data: CreateCodeActionResolveData(
                    FeaturesResources.Introduce_constant
                    + "|"
                    + string.Format(FeaturesResources.Introduce_constant_for_0, "1"),
                    locations["caret"].Single()
                    ),
                priority: PriorityLevel.Normal,
                groupName: "Roslyn2",
                applicableRange: new LSP.Range
            {
                Start = new Position {
                    Line = 4, Character = 8
                },
                End = new Position {
                    Line = 4, Character = 11
                }
            },
                diagnostics: null
                );

            // Expected text after edits:
            //     class A
            //     {
            //         private const int V = 1;
            //
            //         void M()
            //         {
            //             int i = V;
            //         }
            //     }
            var expectedTextEdits = new LSP.TextEdit[]
            {
                GenerateTextEdit(
                    @"private const int V = 1;

",
                    new LSP.Range {
                    Start = new Position(2, 4), End = new Position(2, 4)
                }
                    ),
                GenerateTextEdit(
                    "V",
                    new LSP.Range {
                    Start = new Position(4, 16), End = new Position(4, 17)
                }
                    )
            };

            var expectedResolvedAction = CodeActionsTests.CreateCodeAction(
                title: string.Format(FeaturesResources.Introduce_constant_for_0, "1"),
                kind: CodeActionKind.Refactor,
                children: Array.Empty <LSP.VSCodeAction>(),
                data: CreateCodeActionResolveData(
                    FeaturesResources.Introduce_constant
                    + "|"
                    + string.Format(FeaturesResources.Introduce_constant_for_0, "1"),
                    locations["caret"].Single()
                    ),
                priority: PriorityLevel.Normal,
                groupName: "Roslyn2",
                applicableRange: new LSP.Range
            {
                Start = new Position {
                    Line = 4, Character = 8
                },
                End = new Position {
                    Line = 4, Character = 11
                }
            },
                diagnostics: null,
                edit: GenerateWorkspaceEdit(locations, expectedTextEdits)
                );

            var actualResolvedAction = await RunGetCodeActionResolveAsync(
                testLspServer,
                unresolvedCodeAction
                );

            AssertJsonEquals(expectedResolvedAction, actualResolvedAction);
        }