diff options
author | Lluis Sanchez <llsan@microsoft.com> | 2019-06-04 15:01:31 +0300 |
---|---|---|
committer | Lluis Sanchez <llsan@microsoft.com> | 2019-06-04 15:01:31 +0300 |
commit | 046482870c9040954dd3b9296d719e26c1216eec (patch) | |
tree | 0f81ceaf655fd2021ee3adf24a7b7a89e776f619 /main | |
parent | 2adc4c688539386a99182246487a90983bd81d84 (diff) |
Fix mime type assignment issues in FileModel
The MimeType property was not properly set in some cases, such as when
creating a new file, or when saving a file with a new name and extension.
FileModel now ensures that the MimeType property is always up to date,
and TextBufferFileModel now updates the content type of the buffer
when creating a new document or when saving a document.
Fixes VSTS# 825629 - No error message shows up in TypeScript files
Diffstat (limited to 'main')
7 files changed, 149 insertions, 17 deletions
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/DocumentModel.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/DocumentModel.cs index 18e0b74522..e05ed9f1c2 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/DocumentModel.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/DocumentModel.cs @@ -103,14 +103,20 @@ namespace MonoDevelop.Ide.Gui.Documents public void CreateNew () { + InitializeNew (); + ModelRepresentation.CreateNew (); + } + + protected void InitializeNew () + { if (IsLoaded) throw new InvalidOperationException ("Model already loaded"); if (Data.IsLinked) throw new InvalidOperationException ("Model already linked"); isNew = true; - ModelRepresentation.CreateNew (); } + public bool IsNew { get { CheckInitialized (); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/FileDocumentController.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/FileDocumentController.cs index fc2801d171..2ecfd021c1 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/FileDocumentController.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/FileDocumentController.cs @@ -110,7 +110,7 @@ namespace MonoDevelop.Ide.Gui.Documents if (!typeof (FileModel).IsAssignableFrom (FileModelType)) throw new InvalidOperationException ("Invalid file model type: " + FileModelType); var fileModel = (FileModel)Activator.CreateInstance (FileModelType); - fileModel.CreateNew (); + fileModel.CreateNew (fileDescriptor.FilePath, fileDescriptor.MimeType); await fileModel.SetContent (fileDescriptor.Content); if (fileDescriptor.Encoding != null && fileModel is TextFileModel textFileModel) textFileModel.Encoding = fileDescriptor.Encoding; diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/FileModel.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/FileModel.cs index 2d0b324dc6..b2c3ed6f24 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/FileModel.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/FileModel.cs @@ -41,9 +41,9 @@ namespace MonoDevelop.Ide.Gui.Documents { } - public string MimeType { get; set; } + public string MimeType => IsLoaded ? GetRepresentation<FileModelRepresentation> ().MimeType : null; - public FilePath FilePath => Id != null ? (FilePath)Id : FilePath.Null; + public FilePath FilePath => Id != null ? (FilePath) Id : (IsLoaded ? GetRepresentation<FileModelRepresentation> ().FilePath : FilePath.Null); public bool CanWrite { get { @@ -57,6 +57,14 @@ namespace MonoDevelop.Ide.Gui.Documents } } + public void CreateNew (string fileName, string mimeType) + { + InitializeNew (); + var rep = GetRepresentation<FileModelRepresentation> (); + rep.InitUnsaved (fileName, mimeType); + rep.CreateNew (); + } + public Task LinkToFile (FilePath filePath) { if (FilePath != filePath) @@ -70,10 +78,10 @@ namespace MonoDevelop.Ide.Gui.Documents await UnlinkFromId (); } - public Task SaveAs (FilePath filePath) + public async Task SaveAs (FilePath filePath) { - LinkToFile (filePath); - return Save (); + await LinkToFile (filePath); + await Save (); } /// <summary> @@ -99,9 +107,20 @@ namespace MonoDevelop.Ide.Gui.Documents protected abstract class FileModelRepresentation : ModelRepresentation { - public FilePath FilePath => Id != null ? (FilePath)Id : FilePath.Null; + FilePath unsavedFilePath; + + public FilePath FilePath => Id != null ? (FilePath)Id : unsavedFilePath; public string MimeType { get; set; } + internal void InitUnsaved (FilePath filePath, string mimeType) + { + unsavedFilePath = filePath; + if (mimeType != null) + MimeType = mimeType; + else if (!filePath.IsNullOrEmpty) + MimeType = Runtime.PeekService<DesktopService> ()?.GetMimeTypeForUri (filePath); + } + public async Task SetContent (Stream content) { try { @@ -128,6 +147,11 @@ namespace MonoDevelop.Ide.Gui.Documents } else throw new InvalidOperationException ($"Can't copy data from model of type {other.GetType ()} into a model of type {GetType ()}"); } + + protected override async Task OnIdChanged () + { + MimeType = (await Runtime.GetService<DesktopService> ()).GetMimeTypeForUri (FilePath); + } } class InternalFileModelRepresentation : FileModelRepresentation diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/ModelRepresentation.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/ModelRepresentation.cs index bdbde45d4c..8ca0506274 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/ModelRepresentation.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/ModelRepresentation.cs @@ -68,6 +68,7 @@ namespace MonoDevelop.Ide.Gui.Documents { try { await WaitHandle.WaitAsync (); + await CheckIdChange (); if (IsLoaded) return; if (DocumentModelData.IsLinked) @@ -96,6 +97,7 @@ namespace MonoDevelop.Ide.Gui.Documents { try { await WaitHandle.WaitAsync (); + await CheckIdChange (); await OnLoad (); IsLoaded = true; HasUnsavedChanges = false; @@ -108,6 +110,7 @@ namespace MonoDevelop.Ide.Gui.Documents { try { await WaitHandle.WaitAsync (); + await CheckIdChange (); await OnSave (); HasUnsavedChanges = false; } finally { @@ -138,6 +141,25 @@ namespace MonoDevelop.Ide.Gui.Documents protected abstract void OnCreateNew (); + /// <summary> + /// Invoked just before a load or save operation when the Id of a model has changed + /// </summary> + protected virtual Task OnIdChanged () + { + return Task.CompletedTask; + } + + object id; + + Task CheckIdChange () + { + if (id != Id) { + id = Id; + return OnIdChanged (); + } else + return Task.CompletedTask; + } + protected abstract Task OnLoad (); protected abstract Task OnSave (); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/TextBufferFileModel.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/TextBufferFileModel.cs index 5b3e7db3c6..59f3193212 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/TextBufferFileModel.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/TextBufferFileModel.cs @@ -66,8 +66,7 @@ namespace MonoDevelop.Ide.Gui.Documents protected override async Task OnLoad () { var text = await TextFileUtility.GetTextAsync (FilePath, CancellationToken.None); - MimeType = (await Runtime.GetService<DesktopService> ()).GetMimeTypeForUri (FilePath); - var contentType = (MimeType == null) ? PlatformCatalog.Instance.TextBufferFactoryService.InertContentType : GetContentTypeFromMimeType (FilePath, MimeType); + var contentType = GetContentTypeFromMimeType (); if (textDocument != null) { // Reloading try { @@ -115,6 +114,10 @@ namespace MonoDevelop.Ide.Gui.Documents protected override Task OnSave () { + var contentType = GetContentTypeFromMimeType (); + if (textDocument.TextBuffer.ContentType != contentType) + textDocument.TextBuffer.ChangeContentType (contentType, null); + // OnLoad is always called before anything else, so the document should be ready textDocument.SaveAs (FilePath, true); cleanReiteratedVersion = textDocument.TextBuffer.CurrentSnapshot.Version.ReiteratedVersionNumber; @@ -126,17 +129,18 @@ namespace MonoDevelop.Ide.Gui.Documents ITextDocument CreateTextDocument (string text) { - var contentType = (MimeType == null) - ? PlatformCatalog.Instance.TextBufferFactoryService.InertContentType - : GetContentTypeFromMimeType (FilePath, MimeType); + var contentType = GetContentTypeFromMimeType (); var buffer = PlatformCatalog.Instance.TextBufferFactoryService.CreateTextBuffer (text, contentType); var doc = PlatformCatalog.Instance.TextDocumentFactoryService.CreateTextDocument (buffer, FilePath.ToString () ?? ""); return doc; } - protected static IContentType GetContentTypeFromMimeType (string filePath, string mimeType) + IContentType GetContentTypeFromMimeType () { - return MimeTypeCatalog.Instance.GetContentTypeForMimeType (mimeType, filePath) + if (MimeType == null) + return PlatformCatalog.Instance.TextBufferFactoryService.InertContentType; + + return MimeTypeCatalog.Instance.GetContentTypeForMimeType (MimeType, FilePath) ?? PlatformCatalog.Instance.ContentTypeRegistryService.GetContentType ("text"); } diff --git a/main/tests/Ide.Tests/MonoDevelop.Ide.Gui.DocumentModels/FileModelTests.cs b/main/tests/Ide.Tests/MonoDevelop.Ide.Gui.DocumentModels/FileModelTests.cs index a6868183b9..a31145b40a 100644 --- a/main/tests/Ide.Tests/MonoDevelop.Ide.Gui.DocumentModels/FileModelTests.cs +++ b/main/tests/Ide.Tests/MonoDevelop.Ide.Gui.DocumentModels/FileModelTests.cs @@ -29,10 +29,12 @@ using NUnit.Framework; using System.IO; using System.Threading.Tasks; using MonoDevelop.Core; +using UnitTests; namespace MonoDevelop.Ide.Gui.DocumentModels { - public class FileModelTests: DocumentModelTestsBase + [RequireService(typeof(DesktopService))] + public class FileModelTests : DocumentModelTestsBase { string tempFile; @@ -154,7 +156,7 @@ namespace MonoDevelop.Ide.Gui.DocumentModels var file = CreateFileModel (); await file.LinkToFile (fileName); - Assert.AreEqual (fileName, file.FilePath.ToString()); + Assert.AreEqual (fileName, file.FilePath.ToString ()); Assert.IsFalse (file.IsNew); Assert.IsFalse (file.IsLoaded); Assert.IsFalse (file.HasUnsavedChanges); @@ -171,6 +173,20 @@ namespace MonoDevelop.Ide.Gui.DocumentModels } [Test] + public async Task UnsharedFileModelLoadSetsMimeType () + { + var dir = Util.CreateTmpDir ("UnsharedFileModelLoadSetsMimeType"); + var fileName = Path.Combine (dir, "Foo.cs"); + File.WriteAllText (fileName, "Foo"); + + var file = CreateFileModel (); + await file.LinkToFile (fileName); + Assert.AreEqual (null, file.MimeType); + await file.Load (); + Assert.AreEqual ("text/x-csharp", file.MimeType); + } + + [Test] public async Task UnsharedFileModelChangeEvents () { int changedCount = 0; @@ -259,5 +275,34 @@ namespace MonoDevelop.Ide.Gui.DocumentModels File.Delete (fileName); } } + + [Test] + public void CreateNewFile () + { + using (var model = CreateFileModel ()) { + model.CreateNew ("foo.cs", null); + Assert.AreEqual ("foo.cs", model.FilePath.ToString ()); + Assert.AreEqual ("text/x-csharp", model.MimeType); + } + using (var model = CreateFileModel ()) { + model.CreateNew (null, "text/x-csharp"); + Assert.AreEqual (FilePath.Null, model.FilePath); + Assert.AreEqual ("text/x-csharp", model.MimeType); + } + } + + [Test] + public async Task CreateNewFileRenameWhenSaving () + { + using (var model = CreateFileModel ()) { + model.CreateNew ("foo.cs", null); + + var dir = UnitTests.Util.CreateTmpDir ("CreateNewFileRenameWhenSaving"); + var file = Path.Combine (dir, "bar.txt"); + await model.SaveAs (file); + Assert.AreEqual ("text/plain", model.MimeType); + Assert.AreEqual (file, model.FilePath.ToString ()); + } + } } } diff --git a/main/tests/Ide.Tests/MonoDevelop.Ide.Gui.DocumentModels/TextBufferFileModelTests.cs b/main/tests/Ide.Tests/MonoDevelop.Ide.Gui.DocumentModels/TextBufferFileModelTests.cs index f5df67d105..f3805b8f47 100644 --- a/main/tests/Ide.Tests/MonoDevelop.Ide.Gui.DocumentModels/TextBufferFileModelTests.cs +++ b/main/tests/Ide.Tests/MonoDevelop.Ide.Gui.DocumentModels/TextBufferFileModelTests.cs @@ -24,7 +24,11 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; +using System.IO; +using System.Threading.Tasks; +using MonoDevelop.Core; using MonoDevelop.Ide.Gui.Documents; +using NUnit.Framework; namespace MonoDevelop.Ide.Gui.DocumentModels { @@ -34,5 +38,32 @@ namespace MonoDevelop.Ide.Gui.DocumentModels { return new TextBufferFileModel (); } + + [Test] + public void CreateNewTextBufferFile () + { + using (var model = new TextBufferFileModel ()) { + model.CreateNew ("foo.cs", null); + Assert.AreEqual ("CSharp", model.TextBuffer.ContentType.TypeName); + } + using (var model = new TextBufferFileModel ()) { + model.CreateNew (null, "text/x-csharp"); + Assert.AreEqual ("CSharp", model.TextBuffer.ContentType.TypeName); + } + } + + [Test] + public async Task CreateNewTextBufferFileRenameWhenSaving () + { + using (var model = new TextBufferFileModel ()) { + model.CreateNew ("foo.cs", null); + Assert.AreEqual ("CSharp", model.TextBuffer.ContentType.TypeName); + + var dir = UnitTests.Util.CreateTmpDir ("CreateNewFileRenameWhenSaving"); + var file = Path.Combine (dir, "bar.txt"); + await model.SaveAs (file); + Assert.AreEqual ("text", model.TextBuffer.ContentType.TypeName); + } + } } } |