Skip to content

Reopen documents after paket commands #84 #170

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Paket.VisualStudio/Paket.VisualStudio.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
<Compile Include="Restore\PaketRestorer.cs" />
<Compile Include="Restore\RestoringProject.cs" />
<Compile Include="Restore\WaitDialogRestorer.cs" />
<Compile Include="SolutionExplorer\SolutionEventsProxy.cs" />
<Compile Include="Utils\Config.cs" />
<Compile Include="Utils\DisposableHelpers.cs" />
<Compile Include="EditorExtensions\CommandTargetBase.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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);
}


Expand Down Expand Up @@ -189,6 +193,9 @@ private void RunCommandOnPackageAndReloadAllDependendProjects(string helpTopic,
.ToArray();

SolutionExplorerExtensions.SaveSolution();

solutionEventsProxy.TrackOpenedDocuments();

foreach (var projectGuid in projectGuids)
SolutionExplorerExtensions.UnloadProject(projectGuid);

Expand Down Expand Up @@ -232,6 +239,8 @@ private void RunCommandAndReloadAllProjects(string helpTopic, Action<SolutionInf
project.Save();
}

solutionEventsProxy.TrackOpenedDocuments();

foreach (var projectGuid in projectGuids)
SolutionExplorerExtensions.UnloadProject(projectGuid);

Expand Down
80 changes: 80 additions & 0 deletions src/Paket.VisualStudio/SolutionExplorer/SolutionEventsProxy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using EnvDTE80;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;
using Paket.VisualStudio.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;

namespace Paket.VisualStudio.SolutionExplorer
{
internal class SolutionEventsProxy
{
internal SolutionEventsProxy(IServiceProvider serviceProvider)
{
solution = serviceProvider.GetService(typeof(SVsSolution)) as IVsSolution;

solutionEventsProxy = new _SolutionEventsProxy();
solution.AdviseSolutionEvents(solutionEventsProxy, out handle);

solutionEventsProxy.ProjectOpened.Subscribe(isOpened =>
{
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<string> openedDocuments;

private _SolutionEventsProxy solutionEventsProxy { get; }

/// <summary>
/// Track opened documents in projects, if they are in solution folders
/// they will not be unloaded, so we can ignore them
/// </summary>
internal void TrackOpenedDocuments()
{
openedDocuments = DteHelper.DTE.Documents
.Cast<EnvDTE.Document>()
.Where(d => d.ProjectItem?.ContainingProject?.Kind != ProjectKinds.vsProjectKindSolutionFolder)
.Select(d => d.FullName).ToList();
}

class _SolutionEventsProxy : IVsSolutionEvents3
{
public ISubject<bool> ProjectOpened { get; private set; }

public _SolutionEventsProxy()
{
this.ProjectOpened = new Subject<bool>();
}

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; }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,27 @@ public static void UnloadProject(Guid projectGuid)
ErrorHandler.ThrowOnFailure(hr);
}

public static IEnumerable<string> OpenFiles(IEnumerable<string> filesname)
{
return DteUtils.DTE.Solution.Projects
.OfType<Project>()
.SelectMany(GetProjects)
.SelectMany(p =>
{
var projectPath = Path.GetDirectoryName(GetProjectFullName(p));
var items = p.ProjectItems?.Cast<ProjectItem>();
return items?.Select(item => new Tuple<ProjectItem, string>(item, Path.Combine(projectPath, item.Name)))
?? Enumerable.Empty<Tuple<ProjectItem, string>>();
})
.Where(item => item != null && item.Item1 != null && filesname.Contains(item.Item2))
.Select(item => new Tuple<string, Window>(item.Item2, item.Item1.Open()))
.Select(item =>
{
item.Item2.Visible = true;
return item.Item1;
});
}

public static void ReloadProject(Guid projectGuid)
{
if (projectGuid == Guid.Empty)
Expand Down Expand Up @@ -117,6 +138,12 @@ public static List<Guid> 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<Project> GetAllProjects()
{
return DteUtils.DTE.Solution.Projects
Expand Down