From 5b250f676b4b2c0a4cb44f75d2c1767125589c46 Mon Sep 17 00:00:00 2001 From: Tom Meschter Date: Mon, 15 Oct 2018 15:53:50 -0700 Subject: [PATCH] Implement new interfaces for adding files Implement a new interface to allow csproj/msvbprj to add files. The existing `ICSharpProjecSite.OnSourceFileAdded` and `IVbCompilerProject.AddFile` had to go back to the hierarchy to check if the file had any `` metadata on it, effectively requiring that these methods only be called on the main thread. However, this metadata is readily available to csproj/msvbprj; the new `IProjectSiteEx.AddFilEx` method allow it to be passed in. This should make it possible to call this method on a background thread. Also, the language service supports batching up project changes before pushing them to the workspace, but does not currently expose a way for csproj/msvbprj to tell it when a batch of changes is starting or ending. The `StartBatch` and `EndBatch` methods on `IProjectSiteEx` fill this need. --- .../ProjectSystem/Interop/IProjectSiteEx.cs | 18 ++++++++++ .../Legacy/AbstractLegacyProject.cs | 25 +++++++++++++ .../AbstractLegacyProject_IProjectSiteEx.cs | 36 +++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 src/VisualStudio/Core/Def/Implementation/ProjectSystem/Interop/IProjectSiteEx.cs create mode 100644 src/VisualStudio/Core/Def/Implementation/ProjectSystem/Legacy/AbstractLegacyProject_IProjectSiteEx.cs diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/Interop/IProjectSiteEx.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/Interop/IProjectSiteEx.cs new file mode 100644 index 0000000000000..29be54c3319eb --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/Interop/IProjectSiteEx.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Runtime.InteropServices; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Interop +{ + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("38B39ADD-D4D6-47E1-B996-7ED16D0295A5")] + internal interface IProjectSiteEx + { + void StartBatch(); + void EndBatch(); + + void AddFileEx([MarshalAs(UnmanagedType.LPWStr)] string filePath, [MarshalAs(UnmanagedType.LPWStr)] string linkMetadata); + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/Legacy/AbstractLegacyProject.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/Legacy/AbstractLegacyProject.cs index 4357a46d36ef2..641ff097b4811 100644 --- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/Legacy/AbstractLegacyProject.cs +++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/Legacy/AbstractLegacyProject.cs @@ -31,6 +31,8 @@ internal abstract partial class AbstractLegacyProject : ForegroundThreadAffiniti protected IProjectCodeModel ProjectCodeModel { get; set; } protected VisualStudioWorkspace Workspace { get; } + private static readonly char[] PathSeparatorCharacters = { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }; + #region Mutable fields that should only be used from the UI thread private readonly VsENCRebuildableProjectImpl _editAndContinueProject; @@ -133,6 +135,29 @@ protected void AddFile( VisualStudioProject.AddSourceFile(filename, sourceCodeKind, folders); } + protected void AddFile( + string filename, + string linkMetadata, + SourceCodeKind sourceCodeKind) + { + // We have tests that assert that XOML files should not get added; this was similar + // behavior to how ASP.NET projects would add .aspx files even though we ultimately ignored + // them. XOML support is planned to go away for Dev16, but for now leave the logic there. + if (filename.EndsWith(".xoml")) + { + return; + } + + var folders = ImmutableArray.Empty; + if (!string.IsNullOrEmpty(linkMetadata)) + { + var linkFolderPath = Path.GetDirectoryName(linkMetadata); + folders = linkFolderPath.Split(PathSeparatorCharacters).ToImmutableArray(); + } + + VisualStudioProject.AddSourceFile(filename, sourceCodeKind, folders); + } + protected void RemoveFile(string filename) { AssertIsForeground(); diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/Legacy/AbstractLegacyProject_IProjectSiteEx.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/Legacy/AbstractLegacyProject_IProjectSiteEx.cs new file mode 100644 index 0000000000000..75d6ffed5b15c --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/Legacy/AbstractLegacyProject_IProjectSiteEx.cs @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis; +using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Interop; +using Roslyn.Utilities; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Legacy +{ + internal abstract partial class AbstractLegacyProject : IProjectSiteEx + { + private readonly Stack _batchScopes = new Stack(); + + public void StartBatch() + { + _batchScopes.Push(VisualStudioProject.CreateBatchScope()); + } + + public void EndBatch() + { + Contract.ThrowIfFalse(_batchScopes.Count > 0); + var scope = _batchScopes.Pop(); + scope.Dispose(); + } + + public void AddFileEx([MarshalAs(UnmanagedType.LPWStr)] string filePath, [MarshalAs(UnmanagedType.LPWStr)] string linkMetadata) + { + // TODO: uncomment when fixing https://github.com/dotnet/roslyn/issues/5325 + //var sourceCodeKind = extension.Equals(".csx", StringComparison.OrdinalIgnoreCase) + // ? SourceCodeKind.Script + // : SourceCodeKind.Regular; + AddFile(filePath, linkMetadata, SourceCodeKind.Regular); + } + } +}