├── art
├── options.png
├── before-after.png
└── focus-solution-explorer.png
├── src
├── Resources
│ └── Icon.png
├── Properties
│ └── AssemblyInfo.cs
├── source.extension.cs
├── Commands
│ ├── SolutionExplorerFocus.cs
│ ├── DeleteIISExpressLogsFolder.cs
│ ├── DeleteIISExpressTraceLogFilesFolder.cs
│ ├── DeleteDotVsFolder.cs
│ ├── DeleteTestResultsFolder.cs
│ ├── DeleteBinFolder.cs
│ ├── CloseOpenDocuments.cs
│ ├── CollapseFolders.cs
│ └── DeleteBase.cs
├── source.extension.vsixmanifest
├── VSPackage.cs
├── Options.cs
└── CloseAllTabs.csproj
├── .gitignore
├── .github
├── ISSUE_TEMPLATE.md
└── CONTRIBUTING.md
├── .gitattributes
├── LICENSE
├── appveyor.yml
├── CHANGELOG.md
├── CloseAllTabs.sln
└── README.md
/art/options.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/madskristensen/CloseAllTabs/master/art/options.png
--------------------------------------------------------------------------------
/art/before-after.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/madskristensen/CloseAllTabs/master/art/before-after.png
--------------------------------------------------------------------------------
/src/Resources/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/madskristensen/CloseAllTabs/master/src/Resources/Icon.png
--------------------------------------------------------------------------------
/art/focus-solution-explorer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/madskristensen/CloseAllTabs/master/art/focus-solution-explorer.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | packages
2 |
3 | # User files
4 | *.suo
5 | *.user
6 | *.sln.docstates
7 | .vs/
8 |
9 | # Build results
10 | [Dd]ebug/
11 | [Rr]elease/
12 | x64/
13 | [Bb]in/
14 | [Oo]bj/
15 |
16 | # MSTest test Results
17 | [Tt]est[Rr]esult*/
18 | [Bb]uild[Ll]og.*
19 |
20 | # NCrunch
21 | *.ncrunchsolution
22 | *.ncrunchproject
23 | _NCrunch_WebCompiler
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### Installed product versions
2 | - Visual Studio: [example 2015 Professional]
3 | - This extension: [example 1.1.21]
4 |
5 | ### Description
6 | Replace this text with a short description
7 |
8 | ### Steps to recreate
9 | 1. Replace this
10 | 2. text with
11 | 3. the steps
12 | 4. to recreate
13 |
14 | ### Current behavior
15 | Explain what it's doing and why it's wrong
16 |
17 | ### Expected behavior
18 | Explain what it should be doing after it's fixed.
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2016 Mads Kristensen
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
--------------------------------------------------------------------------------
/src/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 | using CloseAllTabs;
4 |
5 | [assembly: AssemblyTitle(Vsix.Name)]
6 | [assembly: AssemblyDescription(Vsix.Description)]
7 | [assembly: AssemblyConfiguration("")]
8 | [assembly: AssemblyCompany(Vsix.Author)]
9 | [assembly: AssemblyProduct(Vsix.Name)]
10 | [assembly: AssemblyCopyright(Vsix.Author)]
11 | [assembly: AssemblyTrademark("")]
12 | [assembly: AssemblyCulture("")]
13 |
14 | [assembly: ComVisible(false)]
15 |
16 | [assembly: AssemblyVersion(Vsix.Version)]
17 | [assembly: AssemblyFileVersion(Vsix.Version)]
18 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | image: Visual Studio 2019
2 |
3 | install:
4 | - ps: (new-object Net.WebClient).DownloadString("https://raw.github.com/madskristensen/ExtensionScripts/master/AppVeyor/vsix.ps1") | iex
5 |
6 | before_build:
7 | - ps: Vsix-IncrementVsixVersion | Vsix-UpdateBuildVersion
8 | - ps: Vsix-TokenReplacement src\source.extension.cs 'Version = "([0-9\\.]+)"' 'Version = "{version}"'
9 |
10 | build_script:
11 | - nuget restore -Verbosity quiet
12 | - msbuild /p:configuration=Release /p:DeployExtension=false /p:ZipPackageCompressionLevel=normal /v:m
13 |
14 | after_test:
15 | - ps: Vsix-PushArtifacts | Vsix-PublishToGallery
16 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Road map
2 |
3 | - [ ] Status bar indicator of the cleanup
4 |
5 | Features that have a checkmark are complete and available for
6 | download in the
7 | [CI build](http://vsixgallery.com/extension/55640f47-34bc-436b-8820-e7f64fbb31fc/).
8 |
9 | # Change log
10 |
11 | These are the changes to each version that has been released
12 | on the official Visual Studio extension gallery.
13 |
14 | ## 1.4
15 |
16 | - [x] Focus Solution Explorer on close
17 |
18 | ## 1.3
19 |
20 | - [x] Option to collapse projects
21 | - [x] Keep pinned tabs open
22 |
23 | ## 1.2
24 |
25 | - [x] Delete bin and obj folders on close
26 |
27 | ## 1.0
28 |
29 | - [x] Close open documents
30 | - [x] Collapse Solution Explorer
31 | - [x] Set focus on Solution Explorer
32 | - [x] Options to collapse solution folders
33 | - [x] Options page
--------------------------------------------------------------------------------
/src/source.extension.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------------
2 | //
3 | // This file was generated by VSIX Synchronizer
4 | //
5 | // ------------------------------------------------------------------------------
6 | namespace CloseAllTabs
7 | {
8 | internal sealed partial class Vsix
9 | {
10 | public const string Id = "55640f47-34bc-436b-8820-e7f64fbb31fc";
11 | public const string Name = "Clean Solution";
12 | public const string Description = @"Cleans up the solution for the next time you open it. Closes open documents and collapses folders automatically when a solution is being closed. ";
13 | public const string Language = "en-US";
14 | public const string Version = "1.4.22";
15 | public const string Author = "Mads Kristensen";
16 | public const string Tags = "tabs, cleanup, collapse";
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Commands/SolutionExplorerFocus.cs:
--------------------------------------------------------------------------------
1 | using EnvDTE;
2 | using EnvDTE80;
3 |
4 | namespace CloseAllTabs
5 | {
6 | public class SolutionExplorerFocus
7 | {
8 | private DTE2 _dte;
9 | private Options _options;
10 |
11 | private SolutionExplorerFocus(DTE2 dte, Options options)
12 | {
13 | _dte = dte;
14 | _options = options;
15 |
16 | Microsoft.VisualStudio.Shell.Events.SolutionEvents.OnBeforeCloseSolution += (s, e) => Execute();
17 | }
18 |
19 | public static SolutionExplorerFocus Instance { get; private set; }
20 |
21 | public static void Initialize(DTE2 dte, Options options)
22 | {
23 | Instance = new SolutionExplorerFocus(dte, options);
24 | }
25 |
26 | private void Execute()
27 | {
28 | if (!_options.FocusSolutionExplorer)
29 | return;
30 |
31 | Window solExp = _dte.Windows.Item(Constants.vsWindowKindSolutionExplorer);
32 |
33 | if (solExp != null)
34 | {
35 | solExp.Activate();
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Commands/DeleteIISExpressLogsFolder.cs:
--------------------------------------------------------------------------------
1 | using EnvDTE80;
2 | using System;
3 |
4 | namespace CloseAllTabs
5 | {
6 | public class DeleteIISExpressLogsFolder : DeleteBase
7 | {
8 | private DeleteIISExpressLogsFolder(DTE2 dte, Options options)
9 | {
10 | _dte = dte;
11 | _options = options;
12 |
13 | Microsoft.VisualStudio.Shell.Events.SolutionEvents.OnBeforeCloseSolution += (s, e) => Execute();
14 | }
15 |
16 | public static DeleteIISExpressLogsFolder Instance { get; private set; }
17 |
18 | public static void Initialize(DTE2 dte, Options options)
19 | {
20 | Instance = new DeleteIISExpressLogsFolder(dte, options);
21 | }
22 |
23 | private void Execute()
24 | {
25 | if (!_options.DeleteIISExpressLogsFolder)
26 | return;
27 |
28 | try
29 | {
30 | string root = GetIISExpressLogsFolder();
31 | DeleteFiles(root);
32 | }
33 | catch (Exception ex)
34 | {
35 | System.Diagnostics.Debug.Write(ex);
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Commands/DeleteIISExpressTraceLogFilesFolder.cs:
--------------------------------------------------------------------------------
1 | using EnvDTE80;
2 | using System;
3 |
4 | namespace CloseAllTabs
5 | {
6 | public class DeleteIISExpressTraceLogFilesFolder : DeleteBase
7 | {
8 | private DeleteIISExpressTraceLogFilesFolder(DTE2 dte, Options options)
9 | {
10 | _dte = dte;
11 | _options = options;
12 |
13 | Microsoft.VisualStudio.Shell.Events.SolutionEvents.OnBeforeCloseSolution += (s, e) => Execute();
14 | }
15 |
16 | public static DeleteIISExpressTraceLogFilesFolder Instance { get; private set; }
17 |
18 | public static void Initialize(DTE2 dte, Options options)
19 | {
20 | Instance = new DeleteIISExpressTraceLogFilesFolder(dte, options);
21 | }
22 |
23 | private void Execute()
24 | {
25 | if (!_options.DeleteIISExpressTraceLogFilesFolder)
26 | return;
27 |
28 | try
29 | {
30 | string root = GetIISExpressTraceLogFilesFolder();
31 | DeleteFiles(root);
32 | }
33 | catch (Exception ex)
34 | {
35 | System.Diagnostics.Debug.Write(ex);
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Commands/DeleteDotVsFolder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Runtime.InteropServices;
6 | using EnvDTE;
7 | using EnvDTE80;
8 |
9 | namespace CloseAllTabs
10 | {
11 | public class DeleteDotVsFolder : DeleteBase
12 | {
13 | private DeleteDotVsFolder(DTE2 dte, Options options)
14 | {
15 | _dte = dte;
16 | _options = options;
17 |
18 | Microsoft.VisualStudio.Shell.Events.SolutionEvents.OnBeforeCloseSolution += (s, e) => Execute();
19 | }
20 |
21 | public static DeleteDotVsFolder Instance { get; private set; }
22 |
23 | public static void Initialize(DTE2 dte, Options options)
24 | {
25 | Instance = new DeleteDotVsFolder(dte, options);
26 | }
27 |
28 | private void Execute()
29 | {
30 | if (!_options.DeleteDotVsFolder)
31 | return;
32 |
33 | try
34 | {
35 | string root = GetSolutionRootFolder(_dte.Solution);
36 | string dotVs = Path.Combine(root, ".vs");
37 | DeleteFiles(dotVs);
38 | }
39 | catch (Exception ex)
40 | {
41 | System.Diagnostics.Debug.Write(ex);
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Commands/DeleteTestResultsFolder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Runtime.InteropServices;
6 | using EnvDTE;
7 | using EnvDTE80;
8 |
9 | namespace CloseAllTabs
10 | {
11 | public class DeleteTestResultsFolder : DeleteBase
12 | {
13 | private DeleteTestResultsFolder(DTE2 dte, Options options)
14 | {
15 | _dte = dte;
16 | _options = options;
17 |
18 | Microsoft.VisualStudio.Shell.Events.SolutionEvents.OnBeforeCloseSolution += (s, e) => Execute();
19 | }
20 |
21 | public static DeleteTestResultsFolder Instance { get; private set; }
22 |
23 | public static void Initialize(DTE2 dte, Options options)
24 | {
25 | Instance = new DeleteTestResultsFolder(dte, options);
26 | }
27 |
28 | private void Execute()
29 | {
30 | if (!_options.DeleteTestResultsFolder)
31 | return;
32 |
33 | try
34 | {
35 | string root = GetSolutionRootFolder(_dte.Solution);
36 | string testResults = Path.Combine(root, "TestResults");
37 | DeleteFiles(testResults);
38 | }
39 | catch (Exception ex)
40 | {
41 | System.Diagnostics.Debug.Write(ex);
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Commands/DeleteBinFolder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using EnvDTE80;
4 | using Microsoft.VisualStudio.Shell.Events;
5 |
6 | namespace CloseAllTabs
7 | {
8 | public class DeleteBinFolder : DeleteBase
9 | {
10 | private DeleteBinFolder(DTE2 dte, Options options)
11 | {
12 | _dte = dte;
13 | _options = options;
14 |
15 | Microsoft.VisualStudio.Shell.Events.SolutionEvents.OnBeforeCloseSolution += (s, e) => Execute();
16 | }
17 |
18 | public static DeleteBinFolder Instance { get; private set; }
19 |
20 | public static void Initialize(DTE2 dte, Options options)
21 | {
22 | Instance = new DeleteBinFolder(dte, options);
23 | }
24 |
25 | private void Execute()
26 | {
27 | if (!_options.DeleteBinFolder)
28 | return;
29 |
30 | try
31 | {
32 | foreach (EnvDTE.Project project in GetAllProjects())
33 | {
34 | string root = GetProjectRootFolder(project);
35 |
36 | if (root == null)
37 | return;
38 |
39 | string bin = Path.Combine(root, "bin");
40 | string obj = Path.Combine(root, "obj");
41 |
42 | DeleteFiles(bin, obj);
43 | }
44 | }
45 | catch (Exception ex)
46 | {
47 | System.Diagnostics.Debug.Write(ex);
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/CloseAllTabs.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.28118.3006
5 | # Visual Studio 15
6 | VisualStudioVersion = 15.0.26430.6
7 | MinimumVisualStudioVersion = 10.0.40219.1
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{89718BC0-D84C-4E60-8112-B6091B483B4B}"
9 | ProjectSection(SolutionItems) = preProject
10 | appveyor.yml = appveyor.yml
11 | CHANGELOG.md = CHANGELOG.md
12 | README.md = README.md
13 | EndProjectSection
14 | EndProject
15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloseAllTabs", "src\CloseAllTabs.csproj", "{F986A3C0-DF30-408D-87B2-A7FFEDD534CE}"
16 | EndProject
17 | Global
18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
19 | Debug|Any CPU = Debug|Any CPU
20 | Release|Any CPU = Release|Any CPU
21 | EndGlobalSection
22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
23 | {F986A3C0-DF30-408D-87B2-A7FFEDD534CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24 | {F986A3C0-DF30-408D-87B2-A7FFEDD534CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
25 | {F986A3C0-DF30-408D-87B2-A7FFEDD534CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
26 | {F986A3C0-DF30-408D-87B2-A7FFEDD534CE}.Release|Any CPU.Build.0 = Release|Any CPU
27 | EndGlobalSection
28 | GlobalSection(SolutionProperties) = preSolution
29 | HideSolutionNode = FALSE
30 | EndGlobalSection
31 | GlobalSection(ExtensibilityGlobals) = postSolution
32 | SolutionGuid = {904EC3A2-D77A-46F9-B34F-DFBE23B3E08F}
33 | EndGlobalSection
34 | EndGlobal
35 |
--------------------------------------------------------------------------------
/src/source.extension.vsixmanifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Clean Solution
6 | Cleans up the solution for the next time you open it. Closes open documents and collapses folders automatically when a solution is being closed.
7 | https://github.com/madskristensen/CloseAllTabs
8 | Resources\LICENSE
9 | https://github.com/madskristensen/CloseAllTabs/blob/master/CHANGELOG.md
10 | Resources\Icon.png
11 | Resources\Icon.png
12 | tabs, cleanup, collapse
13 |
14 |
15 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/VSPackage.cs:
--------------------------------------------------------------------------------
1 | using EnvDTE;
2 | using EnvDTE80;
3 | using Microsoft.VisualStudio.Shell;
4 | using Microsoft.VisualStudio.Shell.Interop;
5 | using System;
6 | using System.Runtime.InteropServices;
7 | using System.Threading;
8 | using task = System.Threading.Tasks.Task;
9 |
10 | namespace CloseAllTabs
11 | {
12 | [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]
13 | [InstalledProductRegistration(Vsix.Name, Vsix.Description, Vsix.Version)]
14 | [ProvideAutoLoad(UIContextGuids.SolutionHasSingleProject, PackageAutoLoadFlags.BackgroundLoad)]
15 | [ProvideAutoLoad(UIContextGuids.SolutionHasMultipleProjects, PackageAutoLoadFlags.BackgroundLoad)]
16 | [ProvideOptionPage(typeof(Options), "Environment", Vsix.Name, 101, 102, true, new string[] { }, ProvidesLocalizedCategoryName = false)]
17 | [Guid(Vsix.Id)]
18 | public sealed class CleanOnClosePackage : AsyncPackage
19 | {
20 | protected override async task InitializeAsync(CancellationToken cancellationToken, IProgress progress)
21 | {
22 | await JoinableTaskFactory.SwitchToMainThreadAsync();
23 | var dte = await GetServiceAsync(typeof(DTE)) as DTE2;
24 |
25 | var options = (Options)GetDialogPage(typeof(Options));
26 |
27 | CloseOpenDocuments.Initialize(this, dte, options);
28 | CollapseFolders.Initialize(dte, options);
29 | SolutionExplorerFocus.Initialize(dte, options);
30 | DeleteBinFolder.Initialize(dte, options);
31 | DeleteTestResultsFolder.Initialize(dte, options);
32 | DeleteDotVsFolder.Initialize(dte, options);
33 | DeleteIISExpressLogsFolder.Initialize(dte, options);
34 | DeleteIISExpressTraceLogFilesFolder.Initialize(dte, options);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Commands/CloseOpenDocuments.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using EnvDTE;
3 | using EnvDTE80;
4 | using Microsoft.VisualStudio;
5 | using Microsoft.VisualStudio.Shell;
6 | using Microsoft.VisualStudio.Shell.Interop;
7 |
8 | namespace CloseAllTabs
9 | {
10 | public class CloseOpenDocuments
11 | {
12 | private readonly IServiceProvider _serviceProvider;
13 | private DTE2 _dte;
14 | private Options _options;
15 |
16 | private CloseOpenDocuments(IServiceProvider serviceProvider, DTE2 dte, Options options)
17 | {
18 | _serviceProvider = serviceProvider;
19 | _dte = dte;
20 | _options = options;
21 | }
22 |
23 | public static CloseOpenDocuments Instance { get; private set; }
24 |
25 | public static void Initialize(Package serviceProvider, DTE2 dte, Options options)
26 | {
27 | ThreadHelper.ThrowIfNotOnUIThread();
28 |
29 | Instance = new CloseOpenDocuments(serviceProvider, dte, options);
30 | Microsoft.VisualStudio.Shell.Events.SolutionEvents.OnBeforeCloseSolution += (s, e) => Instance.Execute();
31 | }
32 |
33 | private void Execute()
34 | {
35 | if (!_options.CloseDocuments)
36 | return;
37 |
38 | foreach (Document document in _dte.Documents)
39 | {
40 | string filePath = document.FullName;
41 |
42 | // Don't close pinned files
43 | if (VsShellUtilities.IsDocumentOpen(_serviceProvider, filePath, VSConstants.LOGVIEWID_Primary, out IVsUIHierarchy hierarchy, out uint itemId, out IVsWindowFrame frame))
44 | {
45 | ErrorHandler.ThrowOnFailure(frame.GetProperty((int)__VSFPROPID5.VSFPROPID_IsPinned, out object propVal));
46 |
47 | if (bool.TryParse(propVal.ToString(), out bool isPinned) && !isPinned)
48 | {
49 | document.Close(vsSaveChanges.vsSaveChangesPrompt);
50 | }
51 | }
52 | else
53 | {
54 | document.Close(vsSaveChanges.vsSaveChangesPrompt);
55 | }
56 | }
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Commands/CollapseFolders.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using EnvDTE;
3 | using EnvDTE80;
4 |
5 | namespace CloseAllTabs
6 | {
7 | public class CollapseFolders
8 | {
9 | private DTE2 _dte;
10 | private Options _options;
11 |
12 | private CollapseFolders(DTE2 dte, Options options)
13 | {
14 | _dte = dte;
15 | _options = options;
16 |
17 | Microsoft.VisualStudio.Shell.Events.SolutionEvents.OnBeforeCloseSolution += (s, e) => Execute();
18 | }
19 |
20 | public static CollapseFolders Instance { get; private set; }
21 |
22 | public static void Initialize(DTE2 dte, Options options)
23 | {
24 | Instance = new CollapseFolders(dte, options);
25 | }
26 |
27 | private void Execute()
28 | {
29 | if (!_options.CollapseOn)
30 | return;
31 |
32 | UIHierarchyItems hierarchy = _dte.ToolWindows.SolutionExplorer.UIHierarchyItems;
33 |
34 | try
35 | {
36 | _dte.SuppressUI = true;
37 | CollapseHierarchy(hierarchy);
38 | }
39 | finally
40 | {
41 | _dte.SuppressUI = false;
42 | }
43 | }
44 |
45 | private void CollapseHierarchy(UIHierarchyItems hierarchy)
46 | {
47 | foreach (UIHierarchyItem item in hierarchy.Cast().Where(item => item.UIHierarchyItems.Count > 0))
48 | {
49 | CollapseHierarchy(item.UIHierarchyItems);
50 |
51 | if (ShouldCollapse(item))
52 | item.UIHierarchyItems.Expanded = false;
53 | }
54 | }
55 |
56 | private bool ShouldCollapse(UIHierarchyItem item)
57 | {
58 | if (!item.UIHierarchyItems.Expanded)
59 | return false;
60 |
61 | // Always collapse files and folders
62 | if (!(item.Object is Project project))
63 | return true;
64 |
65 | // Collapse solution folders if enabled in settings
66 | if (project.Kind == ProjectKinds.vsProjectKindSolutionFolder && _options.CollapseSolutionFolders)
67 | return true;
68 |
69 | // Collapse projects if enabled in settings
70 | if (project.Kind != ProjectKinds.vsProjectKindSolutionFolder && _options.CollapseProjects)
71 | return true;
72 |
73 | return false;
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/Options.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.Shell;
2 | using System.ComponentModel;
3 |
4 | namespace CloseAllTabs
5 | {
6 | public class Options : DialogPage
7 | {
8 | // General
9 | [Category("General")]
10 | [DisplayName("Close documents")]
11 | [Description("Close all open documents on close unless they are pinned")]
12 | [DefaultValue(true)]
13 | public bool CloseDocuments { get; set; } = true;
14 |
15 | [Category("General")]
16 | [DisplayName("Delete bin and obj folder")]
17 | [Description("Deletes the bin and obj folders on close unless they are under source control")]
18 | [DefaultValue(false)]
19 | public bool DeleteBinFolder { get; set; }
20 |
21 | [Category("General")]
22 | [DisplayName("Delete TestResults folder")]
23 | [Description("Deletes the TestResults folders on close unless they are under source control")]
24 | [DefaultValue(false)]
25 | public bool DeleteTestResultsFolder { get; set; }
26 |
27 | [Category("General")]
28 | [DisplayName("Delete .vs folder")]
29 | [Description("Deletes the .vs folders on close unless they are under source control")]
30 | [DefaultValue(false)]
31 | public bool DeleteDotVsFolder { get; set; }
32 |
33 | // IIS Express
34 | [Category("IIS Express")]
35 | [DisplayName("Delete Logs folder")]
36 | [Description("Deletes the Logs folders of IIS Express")]
37 | [DefaultValue(false)]
38 | public bool DeleteIISExpressLogsFolder { get; set; }
39 |
40 | [Category("IIS Express")]
41 | [DisplayName("Delete TraceLogFiles folder")]
42 | [Description("Deletes the TraceLogFiles folders of IIS Express")]
43 | [DefaultValue(false)]
44 | public bool DeleteIISExpressTraceLogFilesFolder { get; set; }
45 |
46 | // Solution Explorer
47 | [Category("Solution Explorer")]
48 | [DisplayName("Collapse files and folders")]
49 | [Description("Collapse nodes in Solution Explorer on close")]
50 | [DefaultValue(true)]
51 | public bool CollapseOn { get; set; } = true;
52 |
53 | [Category("Solution Explorer")]
54 | [DisplayName("Collapse solution folders")]
55 | [Description("Collapse solution folders when collapsing")]
56 | [DefaultValue(true)]
57 | public bool CollapseSolutionFolders { get; set; } = true;
58 |
59 | [Category("Solution Explorer")]
60 | [DisplayName("Collapse projects")]
61 | [Description("Collapse all projects in a solution on close")]
62 | [DefaultValue(false)]
63 | public bool CollapseProjects { get; set; }
64 |
65 | [Category("Solution Explorer")]
66 | [DisplayName("Visible on open")]
67 | [Description("Makes sure Solution Explorer is visible when a solution is opened")]
68 | [DefaultValue(false)]
69 | public bool FocusSolutionExplorer { get; set; }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Clean Solution
2 |
3 | [](https://ci.appveyor.com/project/madskristensen/closealltabs)
4 |
5 | Download this extension from the [VS Gallery](https://visualstudiogallery.msdn.microsoft.com/97ffc3c6-f250-499a-b86b-833b3e55751e)
6 | or get the [CI build](http://vsixgallery.com/extension/55640f47-34bc-436b-8820-e7f64fbb31fc/).
7 |
8 | ---------------------------------------
9 |
10 | Cleans up the solution for the next time you open it.
11 | Closes open documents and collapses folders automatically when
12 | a solution is being closed.
13 |
14 | See the [change log](CHANGELOG.md) for changes and road map.
15 |
16 | ## Features
17 | When Visual Studio closes or the current solution is being manually closed,
18 | this extension will perform clean up.
19 |
20 | - Closes all open documents
21 | - Collapses nodes in Solution Explorer
22 | - Activates Solution Explorer
23 | - Delete *bin* and *obj* folders
24 | - Super fast - you won't even notice it
25 |
26 | ### Close open documents
27 | All open documents will be closed when the solution closes. This makes
28 | solution load faster for the next time you open it.
29 |
30 | ### Collapse nodes in Solution Explorer
31 | Projects and solutions can quickly become noisy to look at when folders
32 | and nested files are expanded in Solution Explorer.
33 |
34 | This extension automatically collapses all expanded nodes except for
35 | project nodes.
36 |
37 | 
38 |
39 | Be default, solution folders are collapsed as well, but that can be
40 | changed in the options.
41 |
42 | ### Activates Solution Explorer
43 | Ensures that Solution Explorer is the active tool window when you open
44 | a solution.
45 |
46 | This is useful if you're tool window layout docks Solution Explorer
47 | with other tool windows in the same location.
48 |
49 | 
50 |
51 | ### Delete *bin* and *obj* folders
52 | This options will delete *bin* and *obj* folders from all projects in
53 | the solution on close.
54 |
55 | **Note** that if any file under *bin* and *obj* is under source control,
56 | the folders won't be deleted.
57 |
58 | The *bin* and *obj* folders are usually safe to delete since they
59 | are automatically generated when the solution/project is being build by
60 | Visual Studio/MSBuild.
61 |
62 | This feature is off by default, but can easily be enabled in the
63 | settings.
64 |
65 | ### Settings
66 | Disable the individual features easily from the **Tools -> Options**
67 | dialog.
68 |
69 | 
70 |
71 | ## Contribute
72 | Check out the [contribution guidelines](.github/CONTRIBUTING.md)
73 | if you want to contribute to this project.
74 |
75 | For cloning and building this project yourself, make sure
76 | to install the
77 | [Extensibility Tools 2015](https://visualstudiogallery.msdn.microsoft.com/ab39a092-1343-46e2-b0f1-6a3f91155aa6)
78 | extension for Visual Studio which enables some features
79 | used by this project.
80 |
81 | ## License
82 | [Apache 2.0](LICENSE)
83 |
--------------------------------------------------------------------------------
/src/Commands/DeleteBase.cs:
--------------------------------------------------------------------------------
1 | using EnvDTE;
2 | using EnvDTE80;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Runtime.InteropServices;
8 | namespace CloseAllTabs
9 | {
10 | public class DeleteBase
11 | {
12 | protected DTE2 _dte;
13 | protected Options _options;
14 |
15 | protected void DeleteFiles(params string[] folders)
16 | {
17 | IEnumerable existingFolders = folders.Where(f => Directory.Exists(f));
18 |
19 | foreach (string folder in existingFolders)
20 | {
21 | IEnumerable files = Directory.EnumerateFiles(folder, "*.*", SearchOption.AllDirectories);
22 |
23 | if (!files.Any(f => f.EndsWith(".refresh") || _dte.SourceControl.IsItemUnderSCC(f)))
24 | {
25 | try
26 | {
27 | Directory.Delete(folder, true);
28 | }
29 | catch (Exception ex)
30 | {
31 | System.Diagnostics.Debug.Write(ex);
32 | }
33 | }
34 | }
35 | }
36 |
37 | protected IEnumerable GetAllProjects()
38 | {
39 | return _dte.Solution.Projects
40 | .Cast()
41 | .SelectMany(GetChildProjects)
42 | .Union(_dte.Solution.Projects.Cast())
43 | .Where(p => { try { return !string.IsNullOrEmpty(p.FullName); } catch { return false; } });
44 | }
45 |
46 | private static IEnumerable GetChildProjects(Project parent)
47 | {
48 | try
49 | {
50 | if (parent.Kind != ProjectKinds.vsProjectKindSolutionFolder && parent.Collection == null) // Unloaded
51 | return Enumerable.Empty();
52 |
53 | if (!string.IsNullOrEmpty(parent.FullName))
54 | return new[] { parent };
55 | }
56 | catch (COMException)
57 | {
58 | return Enumerable.Empty();
59 | }
60 |
61 | return parent.ProjectItems
62 | .Cast()
63 | .Where(p => p.SubProject != null)
64 | .SelectMany(p => GetChildProjects(p.SubProject));
65 | }
66 |
67 | public static string GetSolutionRootFolder(Solution solution)
68 | {
69 | if (!string.IsNullOrEmpty(solution.FullName))
70 | return File.Exists(solution.FullName) ? Path.GetDirectoryName(solution.FullName) : null;
71 |
72 | return null;
73 | }
74 |
75 | public static string GetProjectRootFolder(Project project)
76 | {
77 | if (string.IsNullOrEmpty(project.FullName))
78 | return null;
79 |
80 | string fullPath;
81 |
82 | try
83 | {
84 | fullPath = project.Properties.Item("FullPath").Value as string;
85 | }
86 | catch (ArgumentException)
87 | {
88 | try
89 | {
90 | // MFC projects don't have FullPath, and there seems to be no way to query existence
91 | fullPath = project.Properties.Item("ProjectDirectory").Value as string;
92 | }
93 | catch (ArgumentException)
94 | {
95 | // Installer projects have a ProjectPath.
96 | fullPath = project.Properties.Item("ProjectPath").Value as string;
97 | }
98 | }
99 |
100 | if (string.IsNullOrEmpty(fullPath))
101 | return File.Exists(project.FullName) ? Path.GetDirectoryName(project.FullName) : null;
102 |
103 | if (Directory.Exists(fullPath))
104 | return fullPath;
105 |
106 | if (File.Exists(fullPath))
107 | return Path.GetDirectoryName(fullPath);
108 |
109 | return null;
110 | }
111 |
112 | public static string GetIISExpressLogsFolder()
113 | {
114 | string fullPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "IISExpress", "Logs");
115 | return Directory.Exists(fullPath) ? fullPath : null;
116 | }
117 |
118 | public static string GetIISExpressTraceLogFilesFolder()
119 | {
120 | string fullPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "IISExpress", "TraceLogFiles");
121 | return Directory.Exists(fullPath) ? fullPath : null;
122 | }
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/src/CloseAllTabs.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(VisualStudioVersion)
5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
6 | true
7 |
8 |
9 |
10 |
11 | 14.0
12 |
13 |
14 |
15 |
16 |
17 | Program
18 | $(DevEnvDir)\devenv.exe
19 | /rootsuffix Exp
20 |
21 |
22 |
23 | Debug
24 | AnyCPU
25 | 2.0
26 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
27 | {F986A3C0-DF30-408D-87B2-A7FFEDD534CE}
28 | Library
29 | Properties
30 | CloseAllTabs
31 | CloseAllTabs
32 | v4.6
33 | true
34 | true
35 | true
36 | true
37 | true
38 | false
39 |
40 |
41 | true
42 | full
43 | false
44 | bin\Debug\
45 | DEBUG;TRACE
46 | prompt
47 | 4
48 |
49 |
50 | pdbonly
51 | true
52 | bin\Release\
53 | TRACE
54 | prompt
55 | 4
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | Component
69 |
70 |
71 |
72 | True
73 | True
74 | source.extension.vsixmanifest
75 |
76 |
77 |
78 |
79 |
80 | Resources\LICENSE
81 | true
82 |
83 |
84 | Designer
85 | VsixManifestGenerator
86 | source.extension.cs
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | 15.0.1
100 |
101 |
102 | 17.0.2120-preview2
103 | runtime; build; native; contentfiles; analyzers; buildtransitive
104 | all
105 |
106 |
107 |
108 |
109 | true
110 |
111 |
112 |
113 |
114 |
121 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Looking to contribute something? **Here's how you can help.**
4 |
5 | Please take a moment to review this document in order to make the contribution
6 | process easy and effective for everyone involved.
7 |
8 | Following these guidelines helps to communicate that you respect the time of
9 | the developers managing and developing this open source project. In return,
10 | they should reciprocate that respect in addressing your issue or assessing
11 | patches and features.
12 |
13 |
14 | ## Using the issue tracker
15 |
16 | The issue tracker is the preferred channel for [bug reports](#bug-reports),
17 | [features requests](#feature-requests) and
18 | [submitting pull requests](#pull-requests), but please respect the
19 | following restrictions:
20 |
21 | * Please **do not** use the issue tracker for personal support requests. Stack
22 | Overflow is a better place to get help.
23 |
24 | * Please **do not** derail or troll issues. Keep the discussion on topic and
25 | respect the opinions of others.
26 |
27 | * Please **do not** open issues or pull requests which *belongs to* third party
28 | components.
29 |
30 |
31 | ## Bug reports
32 |
33 | A bug is a _demonstrable problem_ that is caused by the code in the repository.
34 | Good bug reports are extremely helpful, so thanks!
35 |
36 | Guidelines for bug reports:
37 |
38 | 1. **Use the GitHub issue search** — check if the issue has already been
39 | reported.
40 |
41 | 2. **Check if the issue has been fixed** — try to reproduce it using the
42 | latest `master` or development branch in the repository.
43 |
44 | 3. **Isolate the problem** — ideally create an
45 | [SSCCE](http://www.sscce.org/) and a live example.
46 | Uploading the project on cloud storage (OneDrive, DropBox, et el.)
47 | or creating a sample GitHub repository is also helpful.
48 |
49 |
50 | A good bug report shouldn't leave others needing to chase you up for more
51 | information. Please try to be as detailed as possible in your report. What is
52 | your environment? What steps will reproduce the issue? What browser(s) and OS
53 | experience the problem? Do other browsers show the bug differently? What
54 | would you expect to be the outcome? All these details will help people to fix
55 | any potential bugs.
56 |
57 | Example:
58 |
59 | > Short and descriptive example bug report title
60 | >
61 | > A summary of the issue and the Visual Studio, browser, OS environments
62 | > in which it occurs. If suitable, include the steps required to reproduce the bug.
63 | >
64 | > 1. This is the first step
65 | > 2. This is the second step
66 | > 3. Further steps, etc.
67 | >
68 | > `` - a link to the project/file uploaded on cloud storage or other publicly accessible medium.
69 | >
70 | > Any other information you want to share that is relevant to the issue being
71 | > reported. This might include the lines of code that you have identified as
72 | > causing the bug, and potential solutions (and your opinions on their
73 | > merits).
74 |
75 |
76 | ## Feature requests
77 |
78 | Feature requests are welcome. But take a moment to find out whether your idea
79 | fits with the scope and aims of the project. It's up to *you* to make a strong
80 | case to convince the project's developers of the merits of this feature. Please
81 | provide as much detail and context as possible.
82 |
83 |
84 | ## Pull requests
85 |
86 | Good pull requests, patches, improvements and new features are a fantastic
87 | help. They should remain focused in scope and avoid containing unrelated
88 | commits.
89 |
90 | **Please ask first** before embarking on any significant pull request (e.g.
91 | implementing features, refactoring code, porting to a different language),
92 | otherwise you risk spending a lot of time working on something that the
93 | project's developers might not want to merge into the project.
94 |
95 | Please adhere to the [coding guidelines](#code-guidelines) used throughout the
96 | project (indentation, accurate comments, etc.) and any other requirements
97 | (such as test coverage).
98 |
99 | Adhering to the following process is the best way to get your work
100 | included in the project:
101 |
102 | 1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork,
103 | and configure the remotes:
104 |
105 | ```bash
106 | # Clone your fork of the repo into the current directory
107 | git clone https://github.com//.git
108 | # Navigate to the newly cloned directory
109 | cd
110 | # Assign the original repo to a remote called "upstream"
111 | git remote add upstream https://github.com/madskristensen/.git
112 | ```
113 |
114 | 2. If you cloned a while ago, get the latest changes from upstream:
115 |
116 | ```bash
117 | git checkout master
118 | git pull upstream master
119 | ```
120 |
121 | 3. Create a new topic branch (off the main project development branch) to
122 | contain your feature, change, or fix:
123 |
124 | ```bash
125 | git checkout -b
126 | ```
127 |
128 | 4. Commit your changes in logical chunks. Please adhere to these [git commit
129 | message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
130 | or your code is unlikely be merged into the main project. Use Git's
131 | [interactive rebase](https://help.github.com/articles/interactive-rebase)
132 | feature to tidy up your commits before making them public. Also, prepend name of the feature
133 | to the commit message. For instance: "SCSS: Fixes compiler results for IFileListener.\nFixes `#123`"
134 |
135 | 5. Locally merge (or rebase) the upstream development branch into your topic branch:
136 |
137 | ```bash
138 | git pull [--rebase] upstream master
139 | ```
140 |
141 | 6. Push your topic branch up to your fork:
142 |
143 | ```bash
144 | git push origin
145 | ```
146 |
147 | 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/)
148 | with a clear title and description against the `master` branch.
149 |
150 |
151 | ## Code guidelines
152 |
153 | - Always use proper indentation.
154 | - In Visual Studio under `Tools > Options > Text Editor > C# > Advanced`, make sure
155 | `Place 'System' directives first when sorting usings` option is enabled (checked).
156 | - Before committing, organize usings for each updated C# source file. Either you can
157 | right-click editor and select `Organize Usings > Remove and sort` OR use extension
158 | like [BatchFormat](http://visualstudiogallery.msdn.microsoft.com/a7f75c34-82b4-4357-9c66-c18e32b9393e).
159 | - Before committing, run Code Analysis in `Debug` configuration and follow the guidelines
160 | to fix CA issues. Code Analysis commits can be made separately.
161 |
--------------------------------------------------------------------------------