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); }
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()); }
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; }
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); }
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 } });
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); }
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; }
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); }
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; }
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); }
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); }
public void ResetResults() { result = null; }
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); }
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); } }
public override Task <WorkspaceEdit> RemapWorkspaceEditAsync(WorkspaceEdit workspaceEdit, CancellationToken cancellationToken) => throw new NotImplementedException();
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);
/// <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)); }