diff --git a/src/OmniSharp.Cake/CakeProjectSystem.cs b/src/OmniSharp.Cake/CakeProjectSystem.cs index 4f7ccbcf00..a3fcc629f7 100644 --- a/src/OmniSharp.Cake/CakeProjectSystem.cs +++ b/src/OmniSharp.Cake/CakeProjectSystem.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Scripting; +using Microsoft.CodeAnalysis.Text; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using OmniSharp.Cake.Services; @@ -126,7 +127,7 @@ private void AddCakeFile(string cakeFilePath) // add Cake project to workspace _workspace.AddProject(project); var documentId = DocumentId.CreateNewId(project.Id); - var loader = new CakeTextLoader(cakeFilePath, _scriptService); + var loader = TextLoader.From(TextAndVersion.Create(SourceText.From(cakeScript.Source), VersionStamp.Create(DateTime.UtcNow))); var documentInfo = DocumentInfo.Create( documentId, cakeFilePath, diff --git a/src/OmniSharp.Cake/CakeTextLoader.cs b/src/OmniSharp.Cake/CakeTextLoader.cs deleted file mode 100644 index ed48ab64e6..0000000000 --- a/src/OmniSharp.Cake/CakeTextLoader.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using Cake.Scripting.Abstractions.Models; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Text; -using OmniSharp.Cake.Services; - -namespace OmniSharp.Cake -{ - internal class CakeTextLoader : TextLoader - { - private readonly string _filePath; - private readonly ICakeScriptService _scriptService; - - public CakeTextLoader(string filePath, ICakeScriptService generationService) - { - if (filePath == null) - { - throw new ArgumentNullException(nameof(filePath)); - } - - if (!Path.IsPathRooted(filePath)) - { - throw new ArgumentException("Expected an absolute file path", nameof(filePath)); - } - - _filePath = filePath; - _scriptService = generationService ?? throw new ArgumentNullException(nameof(generationService)); - } - - public override Task LoadTextAndVersionAsync(Workspace workspace, DocumentId documentId, CancellationToken cancellationToken) - { - var prevLastWriteTime = File.GetLastWriteTimeUtc(_filePath); - - var script = _scriptService.Generate(new FileChange - { - FileName = _filePath, - FromDisk = true - }); - var version = VersionStamp.Create(prevLastWriteTime); - var text = SourceText.From(script.Source); - var textAndVersion = TextAndVersion.Create(text, version, _filePath); - - var newLastWriteTime = File.GetLastWriteTimeUtc(_filePath); - if (!newLastWriteTime.Equals(prevLastWriteTime)) - { - throw new IOException($"File was externally modified: {_filePath}"); - } - - return Task.FromResult(textAndVersion); - } - } -} diff --git a/src/OmniSharp.Cake/Services/RequestHandlers/Buffer/UpdateBufferHandler.cs b/src/OmniSharp.Cake/Services/RequestHandlers/Buffer/UpdateBufferHandler.cs index b25c2c20cd..cc2cbb7afc 100644 --- a/src/OmniSharp.Cake/Services/RequestHandlers/Buffer/UpdateBufferHandler.cs +++ b/src/OmniSharp.Cake/Services/RequestHandlers/Buffer/UpdateBufferHandler.cs @@ -46,6 +46,8 @@ public async Task Handle(UpdateBufferRequest request) NewText = change.NewText }); } + + fileChange.FromDisk = false; } else { diff --git a/src/OmniSharp.MSBuild/ProjectManager.cs b/src/OmniSharp.MSBuild/ProjectManager.cs index a58c491fb5..011adda8af 100644 --- a/src/OmniSharp.MSBuild/ProjectManager.cs +++ b/src/OmniSharp.MSBuild/ProjectManager.cs @@ -602,7 +602,7 @@ private void OnDirectoryFileChanged(string path, FileChangeType changeType) { // Use the buffer manager to add the new file to the appropriate projects // Hosts that don't pass the FileChangeType may wind up updating the buffer twice - _workspace.BufferManager.UpdateBufferAsync(new UpdateBufferRequest() { FileName = path, FromDisk = true }).Wait(); + _workspace.BufferManager.UpdateBufferAsync(new UpdateBufferRequest() { FileName = path, FromDisk = true }, isCreate: changeType == FileChangeType.Create).Wait(); } } } diff --git a/src/OmniSharp.Roslyn/BufferManager.cs b/src/OmniSharp.Roslyn/BufferManager.cs index 3989b35307..19d5d1a0a4 100644 --- a/src/OmniSharp.Roslyn/BufferManager.cs +++ b/src/OmniSharp.Roslyn/BufferManager.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; +using Microsoft.Extensions.Logging; using OmniSharp.FileWatching; using OmniSharp.Models; using OmniSharp.Models.ChangeBuffer; @@ -20,14 +21,14 @@ public class BufferManager private readonly ISet _transientDocumentIds = new HashSet(); private readonly object _lock = new object(); private readonly IFileSystemWatcher _fileSystemWatcher; - private readonly Action _onFileChanged; + private readonly ILogger _logger; - public BufferManager(OmniSharpWorkspace workspace, IFileSystemWatcher fileSystemWatcher) + public BufferManager(OmniSharpWorkspace workspace, ILoggerFactory loggerFactory, IFileSystemWatcher fileSystemWatcher) { _workspace = workspace; _workspace.WorkspaceChanged += OnWorkspaceChanged; _fileSystemWatcher = fileSystemWatcher; - _onFileChanged = OnFileChanged; + _logger = loggerFactory.CreateLogger(); } public bool IsTransientDocument(DocumentId documentId) @@ -38,7 +39,7 @@ public bool IsTransientDocument(DocumentId documentId) } } - public async Task UpdateBufferAsync(Request request) + public async Task UpdateBufferAsync(Request request, bool isCreate = false) { var buffer = request.Buffer; var changes = request.Changes; @@ -46,6 +47,7 @@ public async Task UpdateBufferAsync(Request request) if (request is UpdateBufferRequest updateRequest && updateRequest.FromDisk) { buffer = File.ReadAllText(updateRequest.FileName); + _logger.LogDebug("Read file contents:\n{0}", buffer); } if (request.FileName == null || (buffer == null && changes == null)) @@ -64,7 +66,20 @@ public async Task UpdateBufferAsync(Request request) foreach (var documentId in documentIds) { - solution = solution.WithDocumentText(documentId, sourceText); + var document = solution.GetDocument(documentId); + + // This can happen when the client sends a create request for a file that we created on the server, + // such as RunCodeAction. Unfortunately, previous attempts to have this fully controlled by the vscode + // client (such that it sent both create event and then updated existing text) wasn't successful: + // vscode seems to always trigger an update buffer event before triggering the create event. + if (isCreate && string.IsNullOrEmpty(buffer) && (await document.GetTextAsync()).Length > 0) + { + _logger.LogDebug("File was created with content in workspace, ignoring disk update"); + continue; + } + + solution = document.WithText(sourceText).Project.Solution; + _logger.LogDebug("Updating file {0} with new text:\n{1}", request.FileName, sourceText); } } else @@ -100,6 +115,8 @@ public async Task UpdateBufferAsync(Request request) } } + _logger.LogDebug("Updating file {0} with new text:\n{1}", document.FilePath, sourceText); + solution = solution.WithDocumentText(documentId, sourceText); } } @@ -108,6 +125,7 @@ public async Task UpdateBufferAsync(Request request) } else if (buffer != null) { + _logger.LogDebug("Adding transient file for {0}\n{1}", request.FileName, buffer); TryAddTransientDocument(request.FileName, buffer); } } diff --git a/src/OmniSharp.Roslyn/OmniSharpWorkspace.cs b/src/OmniSharp.Roslyn/OmniSharpWorkspace.cs index 90a0de8c1d..e178359fc7 100644 --- a/src/OmniSharp.Roslyn/OmniSharpWorkspace.cs +++ b/src/OmniSharp.Roslyn/OmniSharpWorkspace.cs @@ -52,7 +52,7 @@ public bool Initialized public OmniSharpWorkspace(HostServicesAggregator aggregator, ILoggerFactory loggerFactory, IFileSystemWatcher fileSystemWatcher) : base(aggregator.CreateHostServices(), "Custom") { - BufferManager = new BufferManager(this, fileSystemWatcher); + BufferManager = new BufferManager(this, loggerFactory, fileSystemWatcher); _logger = loggerFactory.CreateLogger(); fileSystemWatcher.WatchDirectories(OnDirectoryRemoved); } diff --git a/test-assets/test-projects/CakeProject/tools/packages.config b/test-assets/test-projects/CakeProject/tools/packages.config index d86ba709fc..7a82ca0a18 100644 --- a/test-assets/test-projects/CakeProject/tools/packages.config +++ b/test-assets/test-projects/CakeProject/tools/packages.config @@ -1,4 +1,4 @@ - - \ No newline at end of file + +