public void SimpleTest(string expected)
        {
            var model = new WorkspaceEdit()
            {
                Changes = new Dictionary <Uri, IEnumerable <TextEdit> >()
                {
                    {
                        new Uri("file:///abc/123/d.cs"), new [] {
                            new TextEdit()
                            {
                                NewText = "new text",
                                Range   = new Range(new Position(1, 1), new Position(2, 2))
                            },
                            new TextEdit()
                            {
                                NewText = "new text2",
                                Range   = new Range(new Position(3, 3), new Position(4, 4))
                            }
                        }
                    }
                }
            };
            var result = Fixture.SerializeObject(model);

            result.Should().Be(expected);

            var deresult = JsonConvert.DeserializeObject <WorkspaceEdit>(expected);

            deresult.ShouldBeEquivalentTo(model);
        }
Beispiel #2
0
        public void SimpleTest(string expected)
        {
            var model = new WorkspaceEdit {
                Changes = new Dictionary <DocumentUri, IEnumerable <TextEdit> > {
                    {
                        new Uri("file:///abc/123/d.cs"), new[] {
                            new TextEdit {
                                NewText = "new text",
                                Range   = new Range(new Position(1, 1), new Position(2, 2))
                            },
                            new TextEdit {
                                NewText = "new text2",
                                Range   = new Range(new Position(3, 3), new Position(4, 4))
                            }
                        }
                    }
                }
            };
            var result = Fixture.SerializeObject(model);

            result.Should().Be(expected);

            var deresult = new LspSerializer(ClientVersion.Lsp3).DeserializeObject <WorkspaceEdit>(expected);

            deresult.Should().BeEquivalentTo(model, x => x.UsingStructuralRecordEquality());
        }
Beispiel #3
0
        public WorkspaceEdit Rename(JToken arg)
        {
            this.traceSource.TraceEvent(TraceEventType.Information, 0, $"Received: {arg}");
            var    renameParams  = arg.ToObject <RenameParams>();
            string fullText      = File.ReadAllText(renameParams.TextDocument.Uri.LocalPath);
            string wordToReplace = GetWordAtPosition(fullText, renameParams.Position);

            Range[] placesToReplace = GetWordRangesInText(fullText, wordToReplace);

            var result = new WorkspaceEdit
            {
                DocumentChanges = new TextDocumentEdit[]
                {
                    new TextDocumentEdit
                    {
                        TextDocument = new OptionalVersionedTextDocumentIdentifier
                        {
                            Uri     = renameParams.TextDocument.Uri,
                            Version = ++version
                        },
                        Edits = placesToReplace.Select(range =>
                                                       new TextEdit
                        {
                            NewText = renameParams.NewName,
                            Range   = range
                        }).ToArray()
                    }
                }
            };

            this.traceSource.TraceEvent(TraceEventType.Information, 0, $"Sent: {JToken.FromObject(result)}");
            return(result);
        }
        private bool TryGetDocumentChanges(WorkspaceEdit workspaceEdit, out TextDocumentEdit[] documentChanges)
        {
            documentChanges = null;

            if (workspaceEdit.DocumentChanges?.Value is TextDocumentEdit[] documentEdits)
            {
                documentChanges = documentEdits;
                return true;
            }

            if (workspaceEdit.DocumentChanges?.Value is SumType<TextDocumentEdit, CreateFile, RenameFile, DeleteFile>[] sumTypeArray)
            {
                var documentEditList = new List<TextDocumentEdit>();
                foreach (var sumType in sumTypeArray)
                {
                    if (sumType.Value is TextDocumentEdit textDocumentEdit)
                    {
                        documentEditList.Add(textDocumentEdit);
                    }
                }

                if (documentEditList.Count > 0)
                {
                    documentChanges = documentEditList.ToArray();
                    return true;
                }
            }

            return false;
        }
Beispiel #5
0
        private static RazorCodeAction CreateFQNCodeAction(
            RazorCodeActionContext context,
            Diagnostic fqnDiagnostic,
            RazorCodeAction codeAction,
            string fullyQualifiedName)
        {
            var codeDocumentIdentifier = new VersionedTextDocumentIdentifier()
            {
                Uri = context.Request.TextDocument.Uri
            };

            var fqnTextEdit = new TextEdit()
            {
                NewText = fullyQualifiedName,
                Range   = fqnDiagnostic.Range
            };

            var fqnWorkspaceEditDocumentChange = new WorkspaceEditDocumentChange(new TextDocumentEdit()
            {
                TextDocument = codeDocumentIdentifier,
                Edits        = new[] { fqnTextEdit },
            });

            var fqnWorkspaceEdit = new WorkspaceEdit()
            {
                DocumentChanges = new[] { fqnWorkspaceEditDocumentChange }
            };

            return(new RazorCodeAction()
            {
                Title = codeAction.Title,
                Edit = fqnWorkspaceEdit
            });
        }
        public async Task Rename(FilePath fileName, DocumentLocation location, string newName)
        {
            try {
                using (var monitor = LanguageClientProgressMonitors.GetSearchProgressMonitorForRename()) {
                    WorkspaceEdit edit = await session.Rename(
                        fileName,
                        location.CreatePosition(),
                        newName,
                        monitor.CancellationToken);

                    if (edit?.Changes == null)
                    {
                        monitor.ReportNothingToRename();
                    }
                    else
                    {
                        WorkspaceEditHandler.ApplyChanges(edit);
                    }
                }
            } catch (OperationCanceledException) {
                LanguageClientLoggingService.Log("Rename was canceled.");
            } catch (Exception ex) {
                LanguageClientLoggingService.LogError("Rename error.", ex);
            }
        }
 public static void ApplyChanges(WorkspaceEdit edit)
 {
     foreach (KeyValuePair <string, TextEdit[]> item in edit.Changes)
     {
         ApplyChanges(item.Key, item.Value);
     }
 }
     public override Task <CodeAction> ResolveAsync(CSharpCodeActionParams csharpParams, CodeAction codeAction, CancellationToken cancellationToken)
     {
         codeAction = codeAction with {
             Edit = new WorkspaceEdit()
         };
         return(Task.FromResult(codeAction));
     }
 }
        public void ReservedWord()
        {
            result = new WorkspaceEdit();
            string text = "method";

            Run(f, 16, 17, text);
            Assert.IsNull(result);
        }
        private static LSPDocumentMappingProvider GetDocumentMappingProvider(WorkspaceEdit expectedEdit)
        {
            var documentMappingProvider = new Mock <LSPDocumentMappingProvider>(MockBehavior.Strict);

            documentMappingProvider.Setup(d => d.RemapWorkspaceEditAsync(It.IsAny <WorkspaceEdit>(), It.IsAny <CancellationToken>())).
            Returns(Task.FromResult(expectedEdit));

            return(documentMappingProvider.Object);
        }
Beispiel #11
0
        public override async Task <CommandOrCodeActionContainer> Handle(CodeActionParams request, CancellationToken cancellationToken)
        {
            var omnisharpRequest = new GetCodeActionsRequest
            {
                FileName  = Helpers.FromUri(request.TextDocument.Uri),
                Column    = request.Range.Start.Character,
                Line      = request.Range.Start.Line,
                Selection = Helpers.FromRange(request.Range),
            };

            var omnisharpResponse = await _getActionsHandler.Handle(omnisharpRequest);

            var codeActions = new List <CodeAction>();

            foreach (var ca in omnisharpResponse.CodeActions)
            {
                CodeActionKind kind;
                if (ca.Identifier.StartsWith("using "))
                {
                    kind = CodeActionKind.QuickFix;
                }
                else if (ca.Identifier.StartsWith("Inline "))
                {
                    kind = CodeActionKind.RefactorInline;
                }
                else if (ca.Identifier.StartsWith("Extract "))
                {
                    kind = CodeActionKind.RefactorExtract;
                }
                else if (ca.Identifier.StartsWith("Change "))
                {
                    kind = CodeActionKind.QuickFix;
                }
                else
                {
                    kind = CodeActionKind.Refactor;
                }

                codeActions.Add(
                    new CodeAction
                {
                    Title       = ca.Name,
                    Kind        = kind,
                    Diagnostics = new Container <Diagnostic>(),
                    Edit        = new WorkspaceEdit(),
                    Command     = Command.Create("omnisharp/executeCodeAction")
                                  .WithArguments(new CommandData()
                    {
                        Uri        = request.TextDocument.Uri,
                        Identifier = ca.Identifier,
                        Name       = ca.Name,
                        Range      = request.Range,
                    })
                                  with {
                        Title = ca.Name
                    }
                });
Beispiel #12
0
        public void DocumentChangesTest(string expected)
        {
            var model = new WorkspaceEdit()
            {
                DocumentChanges = new Container <TextDocumentEdit>(
                    new TextDocumentEdit()
                {
                    TextDocument = new VersionedTextDocumentIdentifier()
                    {
                        Version = 1,
                        Uri     = new Uri("file:///abc/123/d.cs"),
                    },
                    Edits = new[] {
                        new TextEdit()
                        {
                            NewText = "new text",
                            Range   = new Range(new Position(1, 1), new Position(2, 2))
                        },
                        new TextEdit()
                        {
                            NewText = "new text2",
                            Range   = new Range(new Position(3, 3), new Position(4, 4))
                        }
                    }
                },
                    new TextDocumentEdit()
                {
                    TextDocument = new VersionedTextDocumentIdentifier()
                    {
                        Version = 1,
                        Uri     = new Uri("file:///abc/123/b.cs"),
                    },
                    Edits = new[] {
                        new TextEdit()
                        {
                            NewText = "new text2",
                            Range   = new Range(new Position(1, 1), new Position(2, 2))
                        },
                        new TextEdit()
                        {
                            NewText = "new text3",
                            Range   = new Range(new Position(3, 3), new Position(4, 4))
                        }
                    }
                }
                    )
            };
            var result = Fixture.SerializeObject(model);

            result.Should().Be(expected);

            var deresult = new Serializer(ClientVersion.Lsp3).DeserializeObject <WorkspaceEdit>(expected);

            deresult.Should().BeEquivalentTo(model);
        }
Beispiel #13
0
        public void Run(string testfile, int lineInEditor, int colInEditor, string newText = "newText")
        {
            Client.TextDocument.DidOpen(testfile, "dfy");
            RenameParams p = new RenameParams()
            {
                NewName      = newText,
                Position     = new Position(lineInEditor - 1, colInEditor - 1),
                TextDocument = new TextDocumentIdentifier(new Uri(testfile))
            };
            var response = Client.SendRequest <WorkspaceEdit>("textDocument/rename", p, CancellationSource.Token);

            result = response.Result;
        }
Beispiel #14
0
        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);
        }
Beispiel #15
0
        public bool ApplyEdit(string transaction_name, Dictionary <string, LspTypes.TextEdit[]> changes)
        {
            WorkspaceEdit edit = new WorkspaceEdit()
            {
                Changes = changes
            };
            ApplyWorkspaceEditParams parameter = new ApplyWorkspaceEditParams
            {
                Label = transaction_name,
                Edit  = edit
            };

            _ = rpc.InvokeAsync <ApplyWorkspaceEditResponse>(Methods.WorkspaceApplyEditName, parameter);
            return(true);
        }
        public async Task HandleRequestAsync_CSharpProjection_RemapsWorkspaceEdit()
        {
            // Arrange
            var called          = false;
            var expectedEdit    = new WorkspaceEdit();
            var documentManager = new TestDocumentManager();

            documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>());

            var requestInvoker = GetRequestInvoker <RenameParams, WorkspaceEdit>(
                new WorkspaceEdit(),
                (method, serverContentType, renameParams, ct) =>
            {
                Assert.Equal(Methods.TextDocumentRenameName, method);
                Assert.Equal(RazorLSPConstants.CSharpContentTypeName, serverContentType);
                called = true;
            });

            var projectionProvider = GetProjectionProvider(new ProjectionResult()
            {
                LanguageKind = RazorLanguageKind.CSharp
            });
            var documentMappingProvider = GetDocumentMappingProvider(expectedEdit);

            var renameHandler = new RenameHandler(requestInvoker, documentManager, projectionProvider, documentMappingProvider);
            var renameRequest = new RenameParams()
            {
                Position     = new Position(0, 1),
                NewName      = "NewName",
                TextDocument = new TextDocumentIdentifier()
                {
                    Uri = Uri
                },
            };

            // Act
            var result = await renameHandler.HandleRequestAsync(renameRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false);

            // Assert
            Assert.True(called);
            Assert.Equal(expectedEdit, result);

            // Actual remapping behavior is tested in LSPDocumentMappingProvider tests.
        }
        public WorkspaceEdit GetRenameChanges(string newName, Uri uri, int line, int col)
        {
            var symbolAtCursor = _manager.GetSymbolByPosition(uri, line, col);

            if (symbolAtCursor == null)
            {
                SetError(Resources.LoggingMessages.rename_no_symbol + $" L{line}:C{col}");
                return(null);
            }

            VerifyNewName(newName);

            if (Outcome.Error)
            {
                return(null);
            }

            Dictionary <Uri, List <TextEdit> > changes = new Dictionary <Uri, List <TextEdit> >();

            foreach (var symbol in symbolAtCursor.GetAllOccurrences())
            {
                var textEdit = new TextEdit
                {
                    NewText = newName,
                    Range   = new Range
                    {
                        Start = new Position(symbol.Line - 1, symbol.Column - 1),
                        End   = new Position(symbol.Line - 1, symbol.IdentifierEndColumn - 1)
                    }
                };
                var editsForAffectedFile = GetOrCreate(changes, symbol);
                editsForAffectedFile.Add(textEdit);
            }

            var changesAsEnumerable = ConvertDict(changes);

            var result = new WorkspaceEdit
            {
                Changes = changesAsEnumerable
            };

            return(result);
        }
        public async override Task<WorkspaceEdit> RemapWorkspaceEditAsync(WorkspaceEdit workspaceEdit, CancellationToken cancellationToken)
        {
            if (TryGetDocumentChanges(workspaceEdit, out var documentChanges))
            {
                // The LSP spec says, we should prefer `DocumentChanges` property over `Changes` if available.
                var remappedEdits = await RemapVersionedDocumentEditsAsync(documentChanges, cancellationToken).ConfigureAwait(false);
                return new WorkspaceEdit()
                {
                    DocumentChanges = remappedEdits
                };
            }
            else if (workspaceEdit?.Changes != null)
            {
                var remappedEdits = await RemapDocumentEditsAsync(workspaceEdit.Changes, cancellationToken).ConfigureAwait(false);
                return new WorkspaceEdit()
                {
                    Changes = remappedEdits
                };
            }

            return workspaceEdit;
        }
Beispiel #19
0
        private WorkspaceEdit?MapWorkspaceEdit(WorkspaceEdit workspaceEdit, bool mapRanges, RazorCodeDocument codeDocument)
        {
            if (TryGetDocumentChanges(workspaceEdit, out var documentChanges))
            {
                // The LSP spec says, we should prefer `DocumentChanges` property over `Changes` if available.
                var remappedEdits = MapDocumentChanges(documentChanges, mapRanges, codeDocument);
                return(new WorkspaceEdit()
                {
                    DocumentChanges = remappedEdits
                });
            }
            else if (workspaceEdit.Changes != null)
            {
                var remappedEdits = MapChanges(workspaceEdit.Changes, mapRanges, codeDocument);
                return(new WorkspaceEdit()
                {
                    Changes = remappedEdits
                });
            }

            return(workspaceEdit);
        }
Beispiel #20
0
        public async Task <WorkspaceEdit> Handle(RenameParams request, CancellationToken cancellationToken)
        {
            _router.Window.LogMessage(new LogMessageParams()
            {
                Type    = MessageType.Log,
                Message = "Proto file completion list request at line: " + (request.Position.Line + 1),
            });

            _threadManager.AssertBackgroundThread();

            var document = await Task.Factory.StartNew(
                () =>
            {
                _snapshotManager.TryResolveDocument(request.TextDocument.Uri.AbsolutePath, out var doc);
                return(doc);
            },
                CancellationToken.None,
                TaskCreationOptions.None,
                _threadManager.ForegroundScheduler);

            var syntaxTree = await document.GetSyntaxTreeAsync();

            var documentChanges = new List <TextEdit>();

            var owner = syntaxTree.Root.GetNodeAt((int)request.Position.Line, (int)request.Position.Character);


            if (owner is InputNode || owner is OutputNode || (owner is NameNode && owner.Parent is MessageNode))
            {
                var nameQuery = owner.Content;

                // We need to find all other Input, Output and Message nodes to rename them.
                var inputNodes = syntaxTree.Root.GetDescendentNodes <InputNode>();
                for (var i = 0; i < inputNodes.Count; i++)
                {
                    var inputNode = inputNodes[i];
                    if (inputNode.Content == nameQuery)
                    {
                        var textEdit = new TextEdit()
                        {
                            Range = new Range(
                                new Position(inputNode.StartLine, inputNode.StartCol),
                                new Position(inputNode.EndLine, inputNode.EndCol)),
                            NewText = request.NewName,
                        };
                        documentChanges.Add(textEdit);
                    }
                }

                var outputNodes = syntaxTree.Root.GetDescendentNodes <OutputNode>();
                for (var i = 0; i < outputNodes.Count; i++)
                {
                    var outputNode = outputNodes[i];
                    if (outputNode.Content == nameQuery)
                    {
                        var textEdit = new TextEdit()
                        {
                            Range = new Range(
                                new Position(outputNode.StartLine, outputNode.StartCol),
                                new Position(outputNode.EndLine, outputNode.EndCol)),
                            NewText = request.NewName,
                        };
                        documentChanges.Add(textEdit);
                    }
                }

                for (var i = 0; i < syntaxTree.Root.Messages.Count; i++)
                {
                    var message = syntaxTree.Root.Messages[i];
                    if (message.Name == nameQuery)
                    {
                        var textEdit = new TextEdit()
                        {
                            Range = new Range(
                                new Position(message.NameNode.StartLine, message.NameNode.StartCol),
                                new Position(message.NameNode.EndLine, message.NameNode.EndCol)),
                            NewText = request.NewName,
                        };
                        documentChanges.Add(textEdit);
                    }
                }
            }

            var workspaceEdit = new WorkspaceEdit();

            if (documentChanges.Count > 0)
            {
                workspaceEdit.Changes = new Dictionary <Uri, IEnumerable <TextEdit> >()
                {
                    [request.TextDocument.Uri] = documentChanges,
                };
            }

            return(workspaceEdit);
        }
Beispiel #21
0
 public void ResetResults()
 {
     result = null;
 }
Beispiel #22
0
        public override async Task <WorkspaceEdit?> HandleRequestAsync(RenameParams request, RequestContext context, CancellationToken cancellationToken)
        {
            WorkspaceEdit?workspaceEdit = null;
            var           document      = SolutionProvider.GetDocument(request.TextDocument, context.ClientName);

            if (document != null)
            {
                var oldSolution   = document.Project.Solution;
                var renameService = document.Project.LanguageServices.GetRequiredService <IEditorInlineRenameService>();
                var position      = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

                var renameInfo = await renameService.GetRenameInfoAsync(document, position, cancellationToken).ConfigureAwait(false);

                if (!renameInfo.CanRename)
                {
                    return(workspaceEdit);
                }

                var renameLocationSet = await renameInfo.FindRenameLocationsAsync(oldSolution.Workspace.Options, cancellationToken).ConfigureAwait(false);

                var renameReplacementInfo = await renameLocationSet.GetReplacementsAsync(request.NewName, oldSolution.Workspace.Options, cancellationToken).ConfigureAwait(false);

                var renamedSolution = renameReplacementInfo.NewSolution;
                var solutionChanges = renamedSolution.GetChanges(oldSolution);

                // Linked files can correspond to multiple roslyn documents each with changes.  Merge the changes in the linked files so that all linked documents have the same text.
                // Then we can just take the text changes from the first document to avoid returning duplicate edits.
                renamedSolution = await renamedSolution.WithMergedLinkedFileChangesAsync(oldSolution, solutionChanges, cancellationToken : cancellationToken).ConfigureAwait(false);

                solutionChanges = renamedSolution.GetChanges(oldSolution);
                var changedDocuments = solutionChanges
                                       .GetProjectChanges()
                                       .SelectMany(p => p.GetChangedDocuments(onlyGetDocumentsWithTextChanges: true))
                                       .GroupBy(docId => renamedSolution.GetRequiredDocument(docId).FilePath, StringComparer.OrdinalIgnoreCase).Select(group => group.First());

                using var _ = ArrayBuilder <TextDocumentEdit> .GetInstance(out var documentEdits);

                foreach (var docId in changedDocuments)
                {
                    var oldDoc = oldSolution.GetRequiredDocument(docId);
                    var newDoc = renamedSolution.GetRequiredDocument(docId);

                    var textChanges = await newDoc.GetTextChangesAsync(oldDoc, cancellationToken).ConfigureAwait(false);

                    var oldText = await oldDoc.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    var textDocumentEdit = new TextDocumentEdit
                    {
                        TextDocument = new VersionedTextDocumentIdentifier {
                            Uri = newDoc.GetURI()
                        },
                        Edits = textChanges.Select(tc => ProtocolConversions.TextChangeToTextEdit(tc, oldText)).ToArray()
                    };
                    documentEdits.Add(textDocumentEdit);
                }

                workspaceEdit = new WorkspaceEdit {
                    DocumentChanges = documentEdits.ToArray()
                };
            }

            return(workspaceEdit);
        }
Beispiel #23
0
        public void DocumentChangesTest(string expected)
        {
            var model = new WorkspaceEdit {
                DocumentChanges = new Container <WorkspaceEditDocumentChange>(
                    new TextDocumentEdit {
                    TextDocument = new OptionalVersionedTextDocumentIdentifier {
                        Version = 1,
                        Uri     = new Uri("file:///abc/123/d.cs"),
                    },
                    Edits = new[] {
                        new TextEdit {
                            NewText = "new text",
                            Range   = new Range(new Position(1, 1), new Position(2, 2))
                        },
                        new TextEdit {
                            NewText = "new text2",
                            Range   = new Range(new Position(3, 3), new Position(4, 4))
                        }
                    }
                },
                    new TextDocumentEdit {
                    TextDocument = new OptionalVersionedTextDocumentIdentifier {
                        Version = 1,
                        Uri     = new Uri("file:///abc/123/b.cs"),
                    },
                    Edits = new[] {
                        new TextEdit {
                            NewText = "new text2",
                            Range   = new Range(new Position(1, 1), new Position(2, 2))
                        },
                        new TextEdit {
                            NewText = "new text3",
                            Range   = new Range(new Position(3, 3), new Position(4, 4))
                        }
                    }
                },
                    new CreateFile {
                    Uri     = "file:///abc/123/b.cs",
                    Options = new CreateFileOptions {
                        IgnoreIfExists = true,
                        Overwrite      = true
                    }
                },
                    new RenameFile {
                    OldUri  = "file:///abc/123/b.cs",
                    NewUri  = "file:///abc/123/c.cs",
                    Options = new RenameFileOptions {
                        IgnoreIfExists = true,
                        Overwrite      = true
                    }
                },
                    new DeleteFile {
                    Uri     = "file:///abc/123/c.cs",
                    Options = new DeleteFileOptions {
                        IgnoreIfNotExists = true,
                        Recursive         = false
                    }
                }
                    )
            };
            var result = Fixture.SerializeObject(model);

            result.Should().Be(expected);

            var deresult = new LspSerializer(ClientVersion.Lsp3).DeserializeObject <WorkspaceEdit>(expected);

            deresult.Should().BeEquivalentTo(
                model, x => x
                .ComparingByMembers <WorkspaceEditDocumentChange>()
                );
        }
        public async override Task <CodeAction> ResolveAsync(
            CSharpCodeActionParams csharpParams,
            CodeAction codeAction,
            CancellationToken cancellationToken)
        {
            if (csharpParams is null)
            {
                throw new ArgumentNullException(nameof(csharpParams));
            }

            if (codeAction is null)
            {
                throw new ArgumentNullException(nameof(codeAction));
            }

            var resolvedCodeAction = await ResolveCodeActionWithServerAsync(csharpParams.RazorFileUri, codeAction, cancellationToken).ConfigureAwait(false);

            if (resolvedCodeAction.Edit?.DocumentChanges is null)
            {
                // Unable to resolve code action with server, return original code action
                return(codeAction);
            }

            if (resolvedCodeAction.Edit.DocumentChanges.Count() != 1)
            {
                // We don't yet support multi-document code actions, return original code action
                return(codeAction);
            }

            cancellationToken.ThrowIfCancellationRequested();

            var documentSnapshot = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() =>
            {
                _documentResolver.TryResolveDocument(csharpParams.RazorFileUri.GetAbsoluteOrUNCPath(), out var documentSnapshot);
                return(documentSnapshot);
            }, cancellationToken).ConfigureAwait(false);

            if (documentSnapshot is null)
            {
                return(codeAction);
            }

            var documentChanged = resolvedCodeAction.Edit.DocumentChanges.First();

            if (!documentChanged.IsTextDocumentEdit)
            {
                // Only Text Document Edit changes are supported currently, return original code action
                return(codeAction);
            }

            cancellationToken.ThrowIfCancellationRequested();

            var csharpTextEdits = documentChanged.TextDocumentEdit.Edits.ToArray();

            // Remaps the text edits from the generated C# to the razor file,
            // as well as applying appropriate formatting.
            var formattedEdits = await _razorFormattingService.ApplyFormattedEditsAsync(
                csharpParams.RazorFileUri,
                documentSnapshot,
                RazorLanguageKind.CSharp,
                csharpTextEdits,
                s_defaultFormattingOptions,
                cancellationToken,
                bypassValidationPasses : true);

            cancellationToken.ThrowIfCancellationRequested();

            var documentVersion = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() =>
            {
                _documentVersionCache.TryGetDocumentVersion(documentSnapshot, out var version);
                return(version);
            }, cancellationToken).ConfigureAwait(false);

            var codeDocumentIdentifier = new OptionalVersionedTextDocumentIdentifier()
            {
                Uri     = csharpParams.RazorFileUri,
                Version = documentVersion.Value
            };

            resolvedCodeAction = resolvedCodeAction with
            {
                Edit = new WorkspaceEdit()
                {
                    DocumentChanges = new[] {
                        new WorkspaceEditDocumentChange(
                            new TextDocumentEdit()
                        {
                            TextDocument = codeDocumentIdentifier,
                            Edits        = formattedEdits,
                        })
                    }
                }
            };

            return(resolvedCodeAction);
        }
    }
Beispiel #25
0
 public override Task <WorkspaceEdit> RemapWorkspaceEditAsync(WorkspaceEdit workspaceEdit, CancellationToken cancellationToken) => throw new NotImplementedException();
Beispiel #26
0
        public async override Task <CodeAction?> ResolveAsync(
            CSharpCodeActionParams csharpParams,
            CodeAction codeAction,
            CancellationToken cancellationToken)
        {
            if (csharpParams is null)
            {
                throw new ArgumentNullException(nameof(csharpParams));
            }

            if (codeAction is null)
            {
                throw new ArgumentNullException(nameof(codeAction));
            }

            cancellationToken.ThrowIfCancellationRequested();

            var resolvedCodeAction = await ResolveCodeActionWithServerAsync(csharpParams.RazorFileUri, codeAction, cancellationToken).ConfigureAwait(false);

            if (resolvedCodeAction?.Edit?.DocumentChanges is null)
            {
                // Unable to resolve code action with server, return original code action
                return(codeAction);
            }

            if (resolvedCodeAction.Edit.DocumentChanges.Count() != 1)
            {
                // We don't yet support multi-document code actions, return original code action
                Debug.Fail($"Encountered an unsupported multi-document code action edit with ${codeAction.Title}.");
                return(codeAction);
            }

            var documentChanged = resolvedCodeAction.Edit.DocumentChanges.First();

            if (!documentChanged.IsTextDocumentEdit)
            {
                // Only Text Document Edit changes are supported currently, return original code action
                return(codeAction);
            }

            var textEdit = documentChanged.TextDocumentEdit !.Edits.FirstOrDefault();

            if (textEdit is null)
            {
                // No text edit available
                return(codeAction);
            }

            var documentInfo = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync <(DocumentSnapshot, int)?>(() =>
            {
                if (_documentResolver.TryResolveDocument(csharpParams.RazorFileUri.ToUri().GetAbsoluteOrUNCPath(), out var documentSnapshot))
                {
                    if (_documentVersionCache.TryGetDocumentVersion(documentSnapshot, out var version))
                    {
                        return(documentSnapshot, version.Value);
                    }
                }

                return(null);
            }, cancellationToken).ConfigureAwait(false);

            if (documentInfo is null)
            {
                return(codeAction);
            }

            var(documentSnapshot, documentVersion) = documentInfo.Value;

            var codeDocument = await documentSnapshot.GetGeneratedOutputAsync().ConfigureAwait(false);

            if (codeDocument.IsUnsupported())
            {
                return(codeAction);
            }

            if (!_documentMappingService.TryMapFromProjectedDocumentRange(codeDocument, textEdit.Range, MappingBehavior.Inclusive, out var originalRange))
            {
                // Text edit failed to map
                return(codeAction);
            }

            textEdit = textEdit with {
                Range = originalRange
            };

            var codeDocumentIdentifier = new OptionalVersionedTextDocumentIdentifier()
            {
                Uri     = csharpParams.RazorFileUri,
                Version = documentVersion
            };

            resolvedCodeAction = resolvedCodeAction with
            {
                Edit = new WorkspaceEdit()
                {
                    DocumentChanges = new[] {
                        new WorkspaceEditDocumentChange(
                            new TextDocumentEdit()
                        {
                            TextDocument = codeDocumentIdentifier,
                            Edits        = new[] { textEdit },
                        })
                    }
                },
            };

            return(resolvedCodeAction);
        }
    }
 public abstract Task <WorkspaceEdit> RemapWorkspaceEditAsync(WorkspaceEdit workspaceEdit, CancellationToken cancellationToken);
Beispiel #28
0
        /// <nodoc />
        public Result <WorkspaceEdit, ResponseError> GetWorkspaceEdits(RenameParams renameParameters, CancellationToken token)
        {
            if (!TryFindNode(renameParameters.ToTextDocumentPosition(), out var node))
            {
                return(s_emptyResult);
            }

            // The logic for IsNodeEligibleForRenameand the checking for the import statement
            // was ported directly from the typescript version. Whe the import statement
            // isn't inside the IsNodeEligibleForRename function isn't clear. Perhaps
            // it is used elsewhere in TypeScript.

            // Do a pre-check to see if this node is even remotely eiligible for rename
            // This is purely based on syntax kind.
            if (!IsNodeEligibleForRename(node))
            {
                return(s_emptyResult);
            }

            // Make sure we aren't trying to rename attempts to rename
            // the "default" keyword from the import statement.
            // TODO: This was ported from the type-script repositiory. I'm not sure I completely understand this.
            var symbol = TypeChecker.GetSymbolAtLocation(node);

            if (symbol != null &&
                symbol.Declarations?.Count > 0 &&
                node.Kind == SyntaxKind.Identifier &&
                node.Cast <IIdentifier>().OriginalKeywordKind == SyntaxKind.DefaultKeyword &&
                (symbol.Parent.Flags & SymbolFlags.Module) != SymbolFlags.Namespace)
            {
                return(s_emptyResult);
            }

            // Call the find all references provider and get all the locations.
            var findReferencesResult = m_findReferencesProvider.GetReferencesAtPosition(renameParameters.ToTextDocumentPosition(), token);

            if (!findReferencesResult.IsSuccess)
            {
                return(Result <WorkspaceEdit, ResponseError> .Error(findReferencesResult.ErrorValue));
            }

            // Next, we need to create a list per document URI (so a dictionary of Document URI to Ranges)
            // to create the workspace edits.
            var rangesByUri = new MultiValueDictionary <string, LanguageServerProtocolRange>();

            foreach (var location in findReferencesResult.SuccessValue)
            {
                rangesByUri.Add(location.Uri, location.Range);
            }

            // If the change is referenced in a lot of places that would cause performance issue
            // as all the files being touched would be opened by the IDE
            int fileReferenceCount = rangesByUri.Count;

            if (fileReferenceCount > ReferenceThreshold)
            {
                string message = string.Format(BuildXL.Ide.LanguageServer.Strings.RenameWarningMessage, fileReferenceCount);

                var actions = new MessageActionItem[] {
                    new MessageActionItem()
                    {
                        Title = BuildXL.Ide.LanguageServer.Strings.ContinueActionTitle
                    },
                    new MessageActionItem()
                    {
                        Title = BuildXL.Ide.LanguageServer.Strings.CancelActionTitle
                    }
                };

                var response = RpcExtensions.ShowMessageRequestAsync(this.JsonRpc, MessageType.Warning, message, actions).GetAwaiter().GetResult();

                if (response == null || response.Title.Equals(BuildXL.Ide.LanguageServer.Strings.CancelActionTitle, System.StringComparison.OrdinalIgnoreCase))
                {
                    return(Result <WorkspaceEdit, ResponseError> .Success(null));
                }
            }

            // Now, create the result which is a URI to an Array of text edits.
            var changes = new Dictionary <string, TextEdit[]>();

            foreach (var uriToRangePair in rangesByUri)
            {
                var edits = new List <TextEdit>();
                foreach (var locationRange in uriToRangePair.Value)
                {
                    edits.Add(new TextEdit
                    {
                        NewText = renameParameters.NewName,
                        Range   = locationRange,
                    });
                }

                changes[uriToRangePair.Key] = edits.ToArray();
            }

            var result = new WorkspaceEdit
            {
                Changes = changes,
            };

            return(Result <WorkspaceEdit, ResponseError> .Success(result));
        }