Skip to content

Commit

Permalink
Merge pull request #751 from DustinCampbell/fix-code-actions-that-add…
Browse files Browse the repository at this point in the history
…-files

Fix code actions that add files to the workspace
  • Loading branch information
DustinCampbell authored Feb 5, 2017
2 parents bb26548 + bce09b6 commit 7af625e
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.Extensions.Logging;
using OmniSharp.Mef;
using OmniSharp.Models.V2;
using OmniSharp.Models;
using OmniSharp.Roslyn.CSharp.Extensions;
using OmniSharp.Services;

using RunCodeActionRequest = OmniSharp.Models.V2.RunCodeActionRequest;
using RunCodeActionResponse = OmniSharp.Models.V2.RunCodeActionResponse;

namespace OmniSharp.Roslyn.CSharp.Services.Refactoring.V2
{
[OmniSharpHandler(OmnisharpEndpoints.V2.RunCodeAction, LanguageNames.CSharp)]
Expand All @@ -31,38 +34,136 @@ public RunCodeActionService(OmniSharpWorkspace workspace, [ImportMany] IEnumerab

public async Task<RunCodeActionResponse> Handle(RunCodeActionRequest request)
{
var response = new RunCodeActionResponse();

var actions = await CodeActionHelper.GetActions(_workspace, _codeActionProviders, _logger, request);
var action = actions.FirstOrDefault(a => a.GetIdentifier().Equals(request.Identifier));
if (action == null)
{
return new RunCodeActionResponse();
}

_logger.LogInformation("Applying " + action);
_logger.LogInformation($"Applying code action: {action.Title}");

var operations = await action.GetOperationsAsync(CancellationToken.None);

var solution = _workspace.CurrentSolution;
var changes = Enumerable.Empty<OmniSharp.Models.ModifiedFileResponse>();
var directoryName = Path.GetDirectoryName(request.FileName);
var changes = new List<ModifiedFileResponse>();
var directory = Path.GetDirectoryName(request.FileName);

foreach (var o in operations)
{
var applyChangesOperation = o as ApplyChangesOperation;
if (applyChangesOperation != null)
{
changes = changes.Concat(await FileChanges.GetFileChangesAsync(applyChangesOperation.ChangedSolution, solution, directoryName, request.WantsTextChanges));
var fileChanges = await GetFileChangesAsync(applyChangesOperation.ChangedSolution, solution, directory, request.WantsTextChanges);

changes.AddRange(fileChanges);
solution = applyChangesOperation.ChangedSolution;
}
}

if (request.ApplyTextChanges)
{
// Will this fail if FileChanges.GetFileChangesAsync(...) added files to the workspace?
_workspace.TryApplyChanges(solution);
}

response.Changes = changes;
return response;
return new RunCodeActionResponse
{
Changes = changes
};
}

private async Task<IEnumerable<ModifiedFileResponse>> GetFileChangesAsync(Solution newSolution, Solution oldSolution, string directory, bool wantTextChanges)
{
var filePathToResponseMap = new Dictionary<string, ModifiedFileResponse>();
var solutionChanges = newSolution.GetChanges(oldSolution);

foreach (var projectChange in solutionChanges.GetProjectChanges())
{
// Handle added documents
foreach (var documentId in projectChange.GetAddedDocuments())
{
var newDocument = newSolution.GetDocument(documentId);
var text = await newDocument.GetTextAsync();

var newFilePath = newDocument.FilePath == null || !Path.IsPathRooted(newDocument.FilePath)
? Path.Combine(directory, newDocument.Name)
: newDocument.FilePath;

var modifiedFileResponse = new ModifiedFileResponse(newFilePath)
{
Changes = new[] {
new LinePositionSpanTextChange
{
NewText = text.ToString()
}
}
};

filePathToResponseMap[newFilePath] = modifiedFileResponse;

// We must add new files to the workspace to ensure that they're present when the host editor
// tries to modify them. This is a strange interaction because the workspace could be left
// in an incomplete state if the host editor doesn't apply changes to the new file, but it's
// what we've got today.
if (_workspace.GetDocument(newFilePath) == null)
{
var fileInfo = new FileInfo(newFilePath);
if (!fileInfo.Exists)
{
fileInfo.CreateText().Dispose();
}
else
{
// The file already exists on disk? Ensure that it's zero-length. If so, we can still use it.
if (fileInfo.Length > 0)
{
_logger.LogError($"File already exists on disk: '{newFilePath}'");
break;
}
}

_workspace.AddDocument(projectChange.ProjectId, newFilePath, newDocument.SourceCodeKind);
}
else
{
// The file already exists in the workspace? We're in a bad state.
_logger.LogError($"File already exists in workspace: '{newFilePath}'");
}
}

// Handle changed documents
foreach (var documentId in projectChange.GetChangedDocuments())
{
var newDocument = newSolution.GetDocument(documentId);
var filePath = newDocument.FilePath;

ModifiedFileResponse modifiedFileResponse;
if (!filePathToResponseMap.TryGetValue(filePath, out modifiedFileResponse))
{
modifiedFileResponse = new ModifiedFileResponse(filePath);
filePathToResponseMap[filePath] = modifiedFileResponse;
}

if (wantTextChanges)
{
var originalDocument = oldSolution.GetDocument(documentId);
var textChanges = await newDocument.GetTextChangesAsync(originalDocument);
var linePositionSpanTextChanges = await LinePositionSpanTextChange.Convert(originalDocument, textChanges);

modifiedFileResponse.Changes = modifiedFileResponse.Changes != null
? modifiedFileResponse.Changes.Union(linePositionSpanTextChanges)
: linePositionSpanTextChanges;
}
else
{
var text = await newDocument.GetTextAsync();
modifiedFileResponse.Buffer = text.ToString();
}
}
}

return filePathToResponseMap.Values;
}
}
}
76 changes: 0 additions & 76 deletions src/OmniSharp.Roslyn.CSharp/Workers/Refactoring/FileChanges.cs

This file was deleted.

1 change: 0 additions & 1 deletion src/OmniSharp.Roslyn/OmniSharpWorkspace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ namespace OmniSharp
[Export, Shared]
public class OmniSharpWorkspace : Workspace
{
private HashSet<DocumentId> _activeDocuments = new HashSet<DocumentId>();
public bool Initialized { get; set; }
public BufferManager BufferManager { get; private set; }

Expand Down

0 comments on commit 7af625e

Please sign in to comment.