diff --git a/src/Paket.VisualStudio/Paket.VisualStudio.csproj b/src/Paket.VisualStudio/Paket.VisualStudio.csproj index 8ef70b7cb..4c05505e0 100644 --- a/src/Paket.VisualStudio/Paket.VisualStudio.csproj +++ b/src/Paket.VisualStudio/Paket.VisualStudio.csproj @@ -107,6 +107,7 @@ + diff --git a/src/Paket.VisualStudio/SolutionExplorer/PaketMenuCommandService.cs b/src/Paket.VisualStudio/SolutionExplorer/PaketMenuCommandService.cs index 08ec92d4d..f6315ea7a 100644 --- a/src/Paket.VisualStudio/SolutionExplorer/PaketMenuCommandService.cs +++ b/src/Paket.VisualStudio/SolutionExplorer/PaketMenuCommandService.cs @@ -6,6 +6,8 @@ using Paket.VisualStudio.Utils; using System.Threading.Tasks; using System.Threading; +using Microsoft.VisualStudio.Shell.Interop; +using System.Collections.Generic; namespace Paket.VisualStudio.SolutionExplorer { @@ -30,12 +32,14 @@ internal class PaketMenuCommandService private readonly IServiceProvider serviceProvider; private readonly OleMenuCommandService menuCommandService; private readonly ActiveGraphNodeTracker tracker; + private readonly SolutionEventsProxy solutionEventsProxy; public PaketMenuCommandService(IServiceProvider serviceProvider, OleMenuCommandService menuCommandService, ActiveGraphNodeTracker tracker) { this.serviceProvider = serviceProvider; this.menuCommandService = menuCommandService; this.tracker = tracker; + this.solutionEventsProxy = new SolutionEventsProxy(serviceProvider); } @@ -189,6 +193,9 @@ private void RunCommandOnPackageAndReloadAllDependendProjects(string helpTopic, .ToArray(); SolutionExplorerExtensions.SaveSolution(); + + solutionEventsProxy.TrackOpenedDocuments(); + foreach (var projectGuid in projectGuids) SolutionExplorerExtensions.UnloadProject(projectGuid); @@ -232,6 +239,8 @@ private void RunCommandAndReloadAllProjects(string helpTopic, Action + { + if (openedDocuments == null || !openedDocuments.Any()) return; + + SolutionExplorerExtensions.OpenFiles(this.openedDocuments) + .ToList() + .ForEach(file => this.openedDocuments.Remove(file)); + }); + } + + private uint handle; + private IVsSolution solution; + private List openedDocuments; + + private _SolutionEventsProxy solutionEventsProxy { get; } + + /// + /// Track opened documents in projects, if they are in solution folders + /// they will not be unloaded, so we can ignore them + /// + internal void TrackOpenedDocuments() + { + openedDocuments = DteHelper.DTE.Documents + .Cast() + .Where(d => d.ProjectItem?.ContainingProject?.Kind != ProjectKinds.vsProjectKindSolutionFolder) + .Select(d => d.FullName).ToList(); + } + + class _SolutionEventsProxy : IVsSolutionEvents3 + { + public ISubject ProjectOpened { get; private set; } + + public _SolutionEventsProxy() + { + this.ProjectOpened = new Subject(); + } + + public int OnAfterOpenProject(IVsHierarchy pHierarchy, int fAdded) + { + this.ProjectOpened.OnNext(true); + return VSConstants.S_OK; + } + public int OnQueryCloseProject(IVsHierarchy pHierarchy, int fRemoving, ref int pfCancel) { return VSConstants.S_OK; } + public int OnBeforeCloseProject(IVsHierarchy pHierarchy, int fRemoved) { return VSConstants.S_OK; } + public int OnAfterLoadProject(IVsHierarchy pStubHierarchy, IVsHierarchy pRealHierarchy) { return VSConstants.S_OK; } + public int OnQueryUnloadProject(IVsHierarchy pRealHierarchy, ref int pfCancel) { return VSConstants.S_OK; } + public int OnBeforeUnloadProject(IVsHierarchy pRealHierarchy, IVsHierarchy pStubHierarchy) { return VSConstants.S_OK; } + public int OnAfterOpenSolution(object pUnkReserved, int fNewSolution) { return VSConstants.S_OK; } + public int OnQueryCloseSolution(object pUnkReserved, ref int pfCancel) { return VSConstants.S_OK; } + public int OnBeforeCloseSolution(object pUnkReserved) { return VSConstants.S_OK; } + public int OnAfterCloseSolution(object pUnkReserved) { return VSConstants.S_OK; } + public int OnAfterMergeSolution(object pUnkReserved) { return VSConstants.S_OK; } + public int OnBeforeOpeningChildren(IVsHierarchy pHierarchy) { return VSConstants.S_OK; } + public int OnAfterOpeningChildren(IVsHierarchy pHierarchy) { return VSConstants.S_OK; } + public int OnBeforeClosingChildren(IVsHierarchy pHierarchy) { return VSConstants.S_OK; } + public int OnAfterClosingChildren(IVsHierarchy pHierarchy) { return VSConstants.S_OK; } + } + } +} diff --git a/src/Paket.VisualStudio/SolutionExplorer/SolutionExplorerExtensions.cs b/src/Paket.VisualStudio/SolutionExplorer/SolutionExplorerExtensions.cs index dbf11ae3c..17533ecf2 100644 --- a/src/Paket.VisualStudio/SolutionExplorer/SolutionExplorerExtensions.cs +++ b/src/Paket.VisualStudio/SolutionExplorer/SolutionExplorerExtensions.cs @@ -84,6 +84,27 @@ public static void UnloadProject(Guid projectGuid) ErrorHandler.ThrowOnFailure(hr); } + public static IEnumerable OpenFiles(IEnumerable filesname) + { + return DteUtils.DTE.Solution.Projects + .OfType() + .SelectMany(GetProjects) + .SelectMany(p => + { + var projectPath = Path.GetDirectoryName(GetProjectFullName(p)); + var items = p.ProjectItems?.Cast(); + return items?.Select(item => new Tuple(item, Path.Combine(projectPath, item.Name))) + ?? Enumerable.Empty>(); + }) + .Where(item => item != null && item.Item1 != null && filesname.Contains(item.Item2)) + .Select(item => new Tuple(item.Item2, item.Item1.Open())) + .Select(item => + { + item.Item2.Visible = true; + return item.Item1; + }); + } + public static void ReloadProject(Guid projectGuid) { if (projectGuid == Guid.Empty) @@ -117,6 +138,12 @@ public static List GetAllProjectGuids() return projectGuids; } + private static string GetProjectFullName(Project project) + { + var solutionFolder = Path.GetDirectoryName(DteUtils.DTE.Solution.FullName); + return Path.Combine(solutionFolder, project.UniqueName); + } + public static IEnumerable GetAllProjects() { return DteUtils.DTE.Solution.Projects