├── .gitignore
├── IntegrationTests.testsettings
├── LICENSE
├── README.md
├── RemoveTrailingWhitespaces.sln
├── RemoveTrailingWhitespaces
├── GlobalSuppressions.cs
├── Guids.cs
├── Key.snk
├── LICENSE.txt
├── PkcCmdIDList.cs
├── Properties
│ └── AssemblyInfo.cs
├── RemoveTrailingWhitespaces.csproj
├── RemoveTrailingWhitespaces.vsct
├── RemoveTrailingWhitespacesPackage.cs
├── RemoveTrailingWhitespaces_IntegrationTests
│ ├── IntegrationTest Library
│ │ ├── DialogboxPurger.cs
│ │ ├── NativeMethods.cs
│ │ └── Utils.cs
│ ├── Key.snk
│ ├── PackageTest.cs
│ ├── RemoveTrailingWhitespaces_IntegrationTests.csproj
│ └── SignOff-Tests
│ │ ├── CPPProjectTests.cs
│ │ ├── CSharpProjectTests.cs
│ │ ├── SolutionTests.cs
│ │ └── VBProjectTests.cs
├── RemoveTrailingWhitespaces_UnitTests
│ ├── Key.snk
│ ├── PackageTest.cs
│ └── RemoveTrailingWhitespaces_UnitTests.csproj
├── Resources.Designer.cs
├── Resources.resx
├── Resources
│ ├── menuicon.png
│ ├── packageicon.png
│ └── preview.png
├── VSPackage.resx
├── app.config
└── source.extension.vsixmanifest
└── UnitTests.testsettings
/.gitignore:
--------------------------------------------------------------------------------
1 | #Visual Studio files
2 | *.[Oo]bj
3 | *.user
4 | *.aps
5 | *.pch
6 | *.vspscc
7 | *.vssscc
8 | *_i.c
9 | *_p.c
10 | *.ncb
11 | *.suo
12 | *.tlb
13 | *.tlh
14 | *.bak
15 | *.[Cc]ache
16 | *.ilk
17 | *.log
18 | *.lib
19 | *.sbr
20 | *.sdf
21 | *.opensdf
22 | *.unsuccessfulbuild
23 | ipch/
24 | [Oo]bj/
25 | [Bb]in
26 | [Dd]ebug*/
27 | [Rr]elease*/
28 | Ankh.NoLoad
29 | .vs/
30 | #NuGet
31 | packages/
32 |
--------------------------------------------------------------------------------
/IntegrationTests.testsettings:
--------------------------------------------------------------------------------
1 |
2 |
7 | This test run configuration uses the VS IDE host type in the test run.
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Sergey Semushin
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RemoveTrailingWhitespaces
2 | Visual Studio extension. Trailing whitespace removal tool. Removes either manually or on file save.
3 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28307.539
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A688CC3C-273D-4418-ABD7-5047BF9B32C2}"
7 | ProjectSection(SolutionItems) = preProject
8 | IntegrationTests.testsettings = IntegrationTests.testsettings
9 | UnitTests.testsettings = UnitTests.testsettings
10 | EndProjectSection
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemoveTrailingWhitespaces", "RemoveTrailingWhitespaces\RemoveTrailingWhitespaces.csproj", "{33B06D46-74C6-4F60-BB43-B3FDB8BDCEB0}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {33B06D46-74C6-4F60-BB43-B3FDB8BDCEB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {33B06D46-74C6-4F60-BB43-B3FDB8BDCEB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {33B06D46-74C6-4F60-BB43-B3FDB8BDCEB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {33B06D46-74C6-4F60-BB43-B3FDB8BDCEB0}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {2596E577-D090-421F-B128-6D2DB3A369B2}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/GlobalSuppressions.cs:
--------------------------------------------------------------------------------
1 | // This file is used by Code Analysis to maintain SuppressMessage
2 | // attributes that are applied to this project. Project-level
3 | // suppressions either have no target or are given a specific target
4 | // and scoped to a namespace, type, member, etc.
5 | //
6 | // To add a suppression to this file, right-click the message in the
7 | // Error List, point to "Suppress Message(s)", and click "In Project
8 | // Suppression File". You do not need to add suppressions to this
9 | // file manually.
10 |
11 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1017:MarkAssembliesWithComVisible")]
12 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/Guids.cs:
--------------------------------------------------------------------------------
1 | // Guids.cs
2 | // MUST match guids.h
3 | using System;
4 |
5 | namespace Predelnik.RemoveTrailingWhitespaces
6 | {
7 | static class GuidList
8 | {
9 | public const string guidRemoveTrailingWhitespacesPkgString = "70f718a3-a985-44e9-9e00-4c767c708ace";
10 | public const string guidRemoveTrailingWhitespacesCmdSetString = "9880ef45-cb7d-4531-bccf-d228fccbb119";
11 |
12 | public static readonly Guid guidRemoveTrailingWhitespacesCmdSet = new Guid(guidRemoveTrailingWhitespacesCmdSetString);
13 | };
14 | }
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/Key.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Predelnik/RemoveTrailingWhitespaces/934f165bc70de78c66832c4957b65768b8736cb0/RemoveTrailingWhitespaces/Key.snk
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Sergey Semushin
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/PkcCmdIDList.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Predelnik.RemoveTrailingWhitespaces
8 | {
9 | static class PkgCmdIDList
10 | {
11 | public const uint cmdIdRemoveTrailingWhitespaces = 0x1010;
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using System.Resources;
4 | using System.Runtime.CompilerServices;
5 | using System.Runtime.InteropServices;
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | [assembly: AssemblyTitle("RemoveTrailingWhitespaces")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("Predelnik")]
14 | [assembly: AssemblyProduct("RemoveTrailingWhitespaces")]
15 | [assembly: AssemblyCopyright("")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 | [assembly: ComVisible(false)]
19 | [assembly: CLSCompliant(false)]
20 | [assembly: NeutralResourcesLanguage("en-US")]
21 |
22 | // Version information for an assembly consists of the following four values:
23 | //
24 | // Major Version
25 | // Minor Version
26 | // Build Number
27 | // Revision
28 | //
29 | // You can specify all the values or you can default the Revision and Build Numbers
30 | // by using the '*' as shown below:
31 |
32 | [assembly: AssemblyVersion("1.0.0.0")]
33 | [assembly: AssemblyFileVersion("1.0.0.0")]
34 |
35 | [assembly: InternalsVisibleTo("RemoveTrailingWhitespaces_IntegrationTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010025f2f501a5b7d0e729d71d613472ae5dacbf8ef9316ee2ed91bec9b6edc254fc19d4a35e9b15138dc11786a83be77f98de3612b527c83de9781f6c9103cffd361bad95e79656694d05e64d51d710a7288229d0d8f5b3606c138c5ead16001989fadc0e936625d608a0cd5cd86912ac7236b5c12b3b56f41c68977643ee0238bc")]
36 | [assembly: InternalsVisibleTo("RemoveTrailingWhitespaces_UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010025f2f501a5b7d0e729d71d613472ae5dacbf8ef9316ee2ed91bec9b6edc254fc19d4a35e9b15138dc11786a83be77f98de3612b527c83de9781f6c9103cffd361bad95e79656694d05e64d51d710a7288229d0d8f5b3606c138c5ead16001989fadc0e936625d608a0cd5cd86912ac7236b5c12b3b56f41c68977643ee0238bc")]
37 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/RemoveTrailingWhitespaces.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 15.0
5 | 12.0
6 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
7 |
8 |
9 |
10 |
11 | 12.0
12 | publish\
13 | true
14 | Disk
15 | false
16 | Foreground
17 | 7
18 | Days
19 | false
20 | false
21 | true
22 | 0
23 | 1.0.0.%2a
24 | false
25 | false
26 | true
27 |
28 |
29 |
30 |
31 |
32 |
33 | Debug
34 | AnyCPU
35 | 2.0
36 | {33B06D46-74C6-4F60-BB43-B3FDB8BDCEB0}
37 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
38 | Library
39 | Properties
40 | Predelnik.RemoveTrailingWhitespaces
41 | RemoveTrailingWhitespaces
42 | True
43 | Key.snk
44 | v4.8
45 |
46 |
47 | true
48 | full
49 | false
50 | bin\Debug\
51 | DEBUG;TRACE
52 | prompt
53 | 4
54 | true
55 |
56 |
57 | pdbonly
58 | true
59 | bin\Release\
60 | TRACE
61 | prompt
62 | 4
63 | true
64 |
65 |
66 |
67 | True
68 |
69 |
70 | True
71 |
72 |
73 | True
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | {00020430-0000-0000-C000-000000000046}
109 | 2
110 | 0
111 | 0
112 | primary
113 | False
114 | False
115 |
116 |
117 |
118 |
119 |
120 |
121 | True
122 | True
123 | Resources.resx
124 |
125 |
126 |
127 | Component
128 |
129 |
130 |
131 |
132 |
133 | ResXFileCodeGenerator
134 | Resources.Designer.cs
135 | Designer
136 |
137 |
138 | true
139 | VSPackage
140 | Designer
141 |
142 |
143 |
144 |
145 |
146 | Designer
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 | Menus.ctmenu
155 | Designer
156 |
157 |
158 |
159 |
160 | Always
161 | true
162 |
163 |
164 | Always
165 | true
166 |
167 |
168 | true
169 |
170 |
171 |
172 |
173 | False
174 | .NET Framework 3.5 SP1
175 | false
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 | 17.0.487
184 |
185 |
186 | 17.0.491
187 |
188 |
189 |
190 | true
191 |
192 |
193 |
194 |
201 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/RemoveTrailingWhitespaces.vsct:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
28 |
29 |
36 |
37 |
38 |
42 |
43 |
46 |
47 |
48 |
49 |
50 |
52 |
53 |
60 |
61 |
62 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/RemoveTrailingWhitespacesPackage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Globalization;
4 | using System.Runtime.InteropServices;
5 | using System.ComponentModel.Design;
6 | using Microsoft.VisualStudio;
7 | using Microsoft.VisualStudio.Shell.Interop;
8 | using Microsoft.VisualStudio.Shell;
9 | using System.ComponentModel;
10 | using Microsoft.VisualStudio.Text;
11 | using Microsoft.VisualStudio.Text.Operations;
12 | using Microsoft.VisualStudio.ComponentModelHost;
13 | using Microsoft.VisualStudio.TextManager.Interop;
14 | using Microsoft.VisualStudio.Editor;
15 | using System.Linq;
16 | using EnvDTE;
17 | using System.Collections.Generic;
18 |
19 | using Task = System.Threading.Tasks.Task;
20 | using Microsoft;
21 |
22 | namespace Predelnik.RemoveTrailingWhitespaces
23 | {
24 | [CLSCompliant(false), ComVisible(true)]
25 | public class OptionsPage : DialogPage
26 | {
27 | private bool removeTrailingWhitespacesOnSave = true;
28 | [Category("All")]
29 | [DisplayName("Remove Trailing Whitespaces on Save")]
30 | public bool RemoveTrailingWhitespacesOnSave
31 | {
32 | get { return removeTrailingWhitespacesOnSave; }
33 | set { removeTrailingWhitespacesOnSave = value; }
34 | }
35 | };
36 |
37 | internal class RunningDocTableEvents : IVsRunningDocTableEvents3
38 | {
39 | readonly RemoveTrailingWhitespacesPackage _pkg;
40 |
41 | public RunningDocTableEvents(RemoveTrailingWhitespacesPackage pkg)
42 | {
43 | _pkg = pkg;
44 | }
45 |
46 | public int OnBeforeSave(uint docCookie)
47 | {
48 | if (_pkg.RemoveOnSave())
49 | {
50 | RunningDocumentInfo runningDocumentInfo = new RunningDocumentInfo(_pkg.rdt, docCookie);
51 | EnvDTE.Document document = _pkg.dte.Documents.OfType().SingleOrDefault(x => x.FullName == runningDocumentInfo.Moniker);
52 | if (document == null)
53 | return VSConstants.S_OK;
54 | if (document.Object("TextDocument") is TextDocument textDoc)
55 | _pkg.RemoveTrailingWhiteSpaces(textDoc);
56 | }
57 | return VSConstants.S_OK;
58 | }
59 |
60 | public int OnAfterAttributeChange(uint docCookie, uint grfAttribs) { return VSConstants.S_OK; }
61 | public int OnAfterAttributeChangeEx(uint docCookie, uint grfAttribs, IVsHierarchy pHierOld,
62 | uint itemidOld, string pszMkDocumentOld, IVsHierarchy pHierNew,
63 | uint itemidNew, string pszMkDocumentNew)
64 | {
65 | return VSConstants.S_OK;
66 | }
67 |
68 | public int OnAfterDocumentWindowHide(uint docCookie, IVsWindowFrame pFrame) { return VSConstants.S_OK; }
69 | public int OnAfterFirstDocumentLock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining)
70 | {
71 | return VSConstants.S_OK;
72 | }
73 |
74 | public int OnAfterSave(uint docCookie) { return VSConstants.S_OK; }
75 | public int OnBeforeDocumentWindowShow(uint docCookie, int fFirstShow, IVsWindowFrame pFrame) { return VSConstants.S_OK; }
76 |
77 | public int OnBeforeLastDocumentUnlock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining)
78 | {
79 | return VSConstants.S_OK;
80 | }
81 | }
82 |
83 | ///
84 | /// This is the class that implements the package exposed by this assembly.
85 | ///
86 | /// The minimum requirement for a class to be considered a valid package for Visual Studio
87 | /// is to implement the IVsPackage interface and register itself with the shell.
88 | /// This package uses the helper classes defined inside the Managed Package Framework (MPF)
89 | /// to do it: it derives from the Package class that provides the implementation of the
90 | /// IVsPackage interface and uses the registration attributes defined in the framework to
91 | /// register itself and its components with the shell.
92 | ///
93 | // This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is
94 | // a package.
95 | [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]
96 | // This attribute is used to register the information needed to show this package
97 | // in the Help/About dialog of Visual Studio.
98 | [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
99 | [Guid(GuidList.guidRemoveTrailingWhitespacesPkgString)]
100 | [ProvideOptionPage(typeof(OptionsPage), "Remove Trailing Whitespaces", "Options", 1000, 1001, true)]
101 | [ProvideMenuResource("Menus.ctmenu", 1)]
102 | [ProvideAutoLoad("{f1536ef8-92ec-443c-9ed7-fdadf150da82}", PackageAutoLoadFlags.BackgroundLoad)]
103 | public sealed class RemoveTrailingWhitespacesPackage : AsyncPackage
104 | {
105 | ///
106 | /// Default constructor of the package.
107 | /// Inside this method you can place any initialization code that does not require
108 | /// any Visual Studio service because at this point the package object is created but
109 | /// not sited yet inside Visual Studio environment. The place to do all the other
110 | /// initialization is the Initialize method.
111 | ///
112 |
113 | public RemoveTrailingWhitespacesPackage()
114 | {
115 | Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering constructor for: {0}", this.ToString()));
116 | }
117 |
118 | /////////////////////////////////////////////////////////////////////////////
119 | // Overridden Package Implementation
120 | #region Package Members
121 | public DTE dte;
122 | public IVsRunningDocumentTable rdt;
123 | public IFindService findService;
124 | private uint rdtCookie;
125 | public IComponentModel componentModel;
126 |
127 | ///
128 | /// Initialization of the package; this method is called right after the package is sited, so this is the place
129 | /// where you can put all the initialization code that rely on services provided by VisualStudio.
130 | ///
131 | protected override async Task InitializeAsync(System.Threading.CancellationToken cancellationToken, IProgress progress)
132 | {
133 | dte = await GetServiceAsync(typeof(EnvDTE.DTE)) as EnvDTE.DTE;
134 | Assumes.Present(dte);
135 | rdt = await GetServiceAsync(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable;
136 | Assumes.Present(rdt);
137 | componentModel = GetGlobalService(typeof(SComponentModel)) as IComponentModel;
138 | await this.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
139 | InitializePackage();
140 | }
141 |
142 | private void InitializePackage ()
143 | {
144 | rdt.AdviseRunningDocTableEvents(new RunningDocTableEvents(this), out rdtCookie);
145 | if (GetService(typeof(IMenuCommandService)) is OleMenuCommandService mcs)
146 | {
147 | // Create the command for the menu item.
148 | CommandID menuCommandID = new CommandID(
149 | GuidList.guidRemoveTrailingWhitespacesCmdSet, (int)PkgCmdIDList.cmdIdRemoveTrailingWhitespaces);
150 | OleMenuCommand menuItem = new OleMenuCommand(OnRemoveTrailingWhitespacesPressed, menuCommandID);
151 | menuItem.BeforeQueryStatus += OnBeforeQueryStatus;
152 | mcs.AddCommand(menuItem);
153 | }
154 | }
155 |
156 | private void OnBeforeQueryStatus(object sender, EventArgs e)
157 | {
158 | var cmd = (OleMenuCommand)sender;
159 |
160 | cmd.Visible = IsNeededForActiveDocument();
161 | cmd.Enabled = cmd.Visible;
162 | }
163 |
164 | private bool IsNeededForActiveDocument()
165 | {
166 | var doc = dte.ActiveDocument;
167 | if (doc == null)
168 | {
169 | return false;
170 | }
171 |
172 | if (doc.ReadOnly)
173 | {
174 | return false;
175 | }
176 |
177 | if (!(doc.Object("TextDocument") is TextDocument))
178 | {
179 | return false;
180 | }
181 |
182 | return true;
183 | }
184 |
185 | private void OnRemoveTrailingWhitespacesPressed(object sender, EventArgs e)
186 | {
187 | if (dte.ActiveDocument == null) return;
188 | if (!(dte.ActiveDocument.Object() is TextDocument textDocument)) return;
189 | RemoveTrailingWhiteSpaces(textDocument);
190 | }
191 |
192 | private IFinder GetFinder(string findWhat, string replacement, ITextBuffer textBuffer)
193 | {
194 | var findService = componentModel.GetService ();
195 | var finderFactory = findService.CreateFinderFactory(findWhat, replacement, FindOptions.UseRegularExpressions);
196 | return finderFactory.Create(textBuffer.CurrentSnapshot);
197 | }
198 |
199 | internal static ITextBuffer GettextBufferAt(TextDocument textDocument, IComponentModel componentModel, IServiceProvider serviceProvider)
200 | {
201 | ThreadHelper.ThrowIfNotOnUIThread();
202 | IVsWindowFrame windowFrame;
203 | if (VsShellUtilities.IsDocumentOpen(
204 | serviceProvider,
205 | textDocument.Parent.FullName,
206 | Guid.Empty,
207 | out var _,
208 | out var _,
209 | out windowFrame))
210 | {
211 | IVsTextView view = VsShellUtilities.GetTextView(windowFrame);
212 | IVsTextLines lines;
213 | if (view.GetBuffer(out lines) == 0)
214 | {
215 | var buffer = lines as IVsTextBuffer;
216 | if (buffer != null)
217 | {
218 | var editorAdapterFactoryService = componentModel.GetService();
219 | return editorAdapterFactoryService.GetDataBuffer(buffer);
220 | }
221 | }
222 | }
223 |
224 | return null;
225 | }
226 | private static void ReplaceAll(ITextBuffer textBuffer, IEnumerable replacements)
227 | {
228 | if (replacements.Any())
229 | {
230 | using (var edit = textBuffer.CreateEdit())
231 | {
232 | foreach (var match in replacements)
233 | {
234 | edit.Replace(match.Match, match.Replace);
235 | }
236 |
237 | edit.Apply();
238 | }
239 | }
240 | }
241 |
242 | public void RemoveTrailingWhiteSpaces(TextDocument textDocument)
243 | {
244 | var textBuffer = GettextBufferAt(textDocument, componentModel, this);
245 | ReplaceAll(textBuffer, GetFinder("[^\\S\\r\\n]+(?=\\r?$)", "", textBuffer).FindForReplaceAll());
246 | }
247 |
248 | public bool RemoveOnSave()
249 | {
250 | var props = dte.get_Properties("Remove Trailing Whitespaces", "Options");
251 | return (bool)props.Item("RemoveTrailingWhitespacesOnSave").Value;
252 | }
253 |
254 |
255 | #endregion
256 |
257 | }
258 | }
259 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/RemoveTrailingWhitespaces_IntegrationTests/IntegrationTest Library/DialogboxPurger.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace Microsoft.VsSDK.IntegrationTestLibrary
3 | {
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 | using System.Runtime.InteropServices;
8 | using System.Threading;
9 | using Microsoft.VisualStudio.Shell.Interop;
10 | using Microsoft.VisualStudio.Shell;
11 |
12 | ///
13 | /// This class is responsible to close dialog boxes that pop up during different VS Calls
14 | ///
15 | internal class DialogBoxPurger : IDisposable
16 | {
17 | ///
18 | /// The default number of milliseconds to wait for the threads to signal to terminate.
19 | ///
20 | private const int DefaultMillisecondsToWait = 3500;
21 |
22 | ///
23 | /// Object used for synchronization between thread calls.
24 | ///
25 | internal static volatile object Mutex = new object();
26 |
27 | ///
28 | /// The IVsUIShell. This cannot be queried on the working thread from the service provider. Must be done in the main thread.!!
29 | ///
30 | private IVsUIShell uiShell;
31 |
32 | ///
33 | /// The button to "press" on the dialog.
34 | ///
35 | private int buttonAction;
36 |
37 | ///
38 | /// Thread signales to the calling thread that it is done.
39 | ///
40 | private bool exitThread = false;
41 |
42 | ///
43 | /// Calling thread signales to this thread to die.
44 | ///
45 | private AutoResetEvent threadDone = new AutoResetEvent(false);
46 |
47 | ///
48 | /// The queued thread started.
49 | ///
50 | private AutoResetEvent threadStarted = new AutoResetEvent(false);
51 |
52 | ///
53 | /// The result of the dialogbox closing for all the dialog boxes. That is if there are two of them and one fails this will be false.
54 | ///
55 | private bool dialogBoxCloseResult = false;
56 |
57 | ///
58 | /// The expected text to see on the dialog box. If set the thread will continue finding the dialog box with this text.
59 | ///
60 | private string expectedDialogBoxText = String.Empty;
61 |
62 | ///
63 | /// The number of the same dialog boxes to wait for.
64 | /// This is for scenarios when two dialog boxes with the same text are popping up.
65 | ///
66 | private int numberOfDialogsToWaitFor = 1;
67 |
68 | ///
69 | /// Has the object been disposed.
70 | ///
71 | private bool isDisposed;
72 |
73 | ///
74 | /// Overloaded ctor.
75 | ///
76 | /// The botton to "press" on the dialog box.
77 | /// The number of dialog boxes with the same message to wait for. This is the situation when the same action pops up two of the same dialog boxes
78 | /// The expected dialog box message to check for.
79 | internal DialogBoxPurger(int buttonAction, int numberOfDialogsToWaitFor, string expectedDialogMesssage)
80 | {
81 | this.buttonAction = buttonAction;
82 | this.numberOfDialogsToWaitFor = numberOfDialogsToWaitFor;
83 | this.expectedDialogBoxText = expectedDialogMesssage;
84 | }
85 |
86 | ///
87 | /// Overloaded ctor.
88 | ///
89 | /// The botton to "press" on the dialog box.
90 | /// The number of dialog boxes with the same message to wait for. This is the situation when the same action pops up two of the same dialog boxes
91 | internal DialogBoxPurger(int buttonAction, int numberOfDialogsToWaitFor)
92 | {
93 | this.buttonAction = buttonAction;
94 | this.numberOfDialogsToWaitFor = numberOfDialogsToWaitFor;
95 | }
96 |
97 | ///
98 | /// Overloaded ctor.
99 | ///
100 | /// The botton to "press" on the dialog box.
101 | /// The expected dialog box message to check for.
102 | internal DialogBoxPurger(int buttonAction, string expectedDialogMesssage)
103 | {
104 | this.buttonAction = buttonAction;
105 | this.expectedDialogBoxText = expectedDialogMesssage;
106 | }
107 |
108 | ///
109 | /// Overloaded ctor.
110 | ///
111 | /// The botton to "press" on the dialog box.
112 | internal DialogBoxPurger(int buttonAction)
113 | {
114 | this.buttonAction = buttonAction;
115 | }
116 |
117 | ///
118 | #region IDisposable Members
119 |
120 | void IDisposable.Dispose()
121 | {
122 | if (this.isDisposed)
123 | {
124 | return;
125 | }
126 |
127 | this.WaitForDialogThreadToTerminate();
128 |
129 | this.isDisposed = true;
130 | }
131 |
132 | ///
133 | /// Spawns a thread that will start listening to dialog boxes.
134 | ///
135 | internal void Start()
136 | {
137 | // We ask for the uishell here since we cannot do that on the therad that we will spawn.
138 | IVsUIShell uiShell = Package.GetGlobalService(typeof(SVsUIShell)) as IVsUIShell;
139 |
140 | if (uiShell == null)
141 | {
142 | throw new InvalidOperationException("Could not get the uiShell from the serviceProvider");
143 | }
144 |
145 | this.uiShell = uiShell;
146 |
147 | System.Threading.Thread thread = new System.Threading.Thread(new ThreadStart(this.HandleDialogBoxes));
148 | thread.Start();
149 |
150 | // We should never deadlock here, hence do not use the lock. Wait to be sure that the thread started.
151 | this.threadStarted.WaitOne(3500, false);
152 | }
153 |
154 | ///
155 | /// Waits for the dialog box close thread to terminate. If the thread does not signal back within millisecondsToWait that it is shutting down,
156 | /// then it will tell to the thread to do it.
157 | ///
158 | internal bool WaitForDialogThreadToTerminate()
159 | {
160 | return this.WaitForDialogThreadToTerminate(DefaultMillisecondsToWait);
161 | }
162 |
163 | ///
164 | /// Waits for the dialog box close thread to terminate. If the thread does not signal back within millisecondsToWait that it is shutting down,
165 | /// then it will tell to the thread to do it.
166 | ///
167 | /// The number milliseconds to wait for until the dialog purger thread is signaled to terminate. This is just for safe precaution that we do not hang.
168 | /// The result of the dialog boxes closing
169 | internal bool WaitForDialogThreadToTerminate(int numberOfMillisecondsToWait)
170 | {
171 | bool signaled = false;
172 |
173 | // We give millisecondsToWait sec to bring up and close the dialog box.
174 | signaled = this.threadDone.WaitOne(numberOfMillisecondsToWait, false);
175 |
176 | // Kill the thread since a timeout occured.
177 | if (!signaled)
178 | {
179 | lock (Mutex)
180 | {
181 | // Set the exit thread to true. Next time the thread will kill itselfes if it sees
182 | this.exitThread = true;
183 | }
184 |
185 | // Wait for the thread to finish. We should never deadlock here.
186 | this.threadDone.WaitOne();
187 | }
188 |
189 | return this.dialogBoxCloseResult;
190 | }
191 |
192 | ///
193 | /// This is the thread method.
194 | ///
195 | private void HandleDialogBoxes()
196 | {
197 | // No synchronization numberOfDialogsToWaitFor since it is readonly
198 | IntPtr[] hwnds = new IntPtr[this.numberOfDialogsToWaitFor];
199 | bool[] dialogBoxCloseResults = new bool[this.numberOfDialogsToWaitFor];
200 |
201 | try
202 | {
203 | // Signal that we started
204 | lock (Mutex)
205 | {
206 | this.threadStarted.Set();
207 | }
208 |
209 | // The loop will be exited either if a message is send by the caller thread or if we found the dialog. If a message box text is specified the loop will not exit until the dialog is found.
210 | bool stayInLoop = true;
211 | int dialogBoxesToWaitFor = 1;
212 |
213 | while (stayInLoop)
214 | {
215 | int hwndIndex = dialogBoxesToWaitFor - 1;
216 |
217 | // We need to lock since the caller might set context to null.
218 | lock (Mutex)
219 | {
220 | if (this.exitThread)
221 | {
222 | break;
223 | }
224 |
225 | // We protect the shell too from reentrency.
226 | this.uiShell.GetDialogOwnerHwnd(out hwnds[hwndIndex]);
227 |
228 | }
229 |
230 | if (hwnds[hwndIndex] != IntPtr.Zero)
231 | {
232 | StringBuilder windowClassName = new StringBuilder(256);
233 | NativeMethods.GetClassName(hwnds[hwndIndex], windowClassName, windowClassName.Capacity);
234 |
235 | // The #32770 is the class name of a messagebox dialog.
236 | if (windowClassName.ToString().Contains("#32770"))
237 | {
238 | IntPtr unmanagedMemoryLocation = IntPtr.Zero;
239 | string dialogBoxText = String.Empty;
240 | try
241 | {
242 | unmanagedMemoryLocation = Marshal.AllocHGlobal(10 * 1024);
243 | NativeMethods.EnumChildWindows(hwnds[hwndIndex], new NativeMethods.CallBack(FindMessageBoxString), unmanagedMemoryLocation);
244 | dialogBoxText = Marshal.PtrToStringUni(unmanagedMemoryLocation);
245 | }
246 | finally
247 | {
248 | if (unmanagedMemoryLocation != IntPtr.Zero)
249 | {
250 | Marshal.FreeHGlobal(unmanagedMemoryLocation);
251 | }
252 | }
253 |
254 | lock (Mutex)
255 | {
256 |
257 | // Since this is running on the main thread be sure that we close the dialog.
258 | bool dialogCloseResult = false;
259 | if (this.buttonAction != 0)
260 | {
261 | dialogCloseResult = NativeMethods.EndDialog(hwnds[hwndIndex], this.buttonAction);
262 | }
263 |
264 | // Check if we have found the right dialog box.
265 | if (String.IsNullOrEmpty(this.expectedDialogBoxText) || (!String.IsNullOrEmpty(dialogBoxText) && String.Compare(this.expectedDialogBoxText, dialogBoxText.Trim(), StringComparison.OrdinalIgnoreCase) == 0))
266 | {
267 | dialogBoxCloseResults[hwndIndex] = dialogCloseResult;
268 | if (dialogBoxesToWaitFor++ >= this.numberOfDialogsToWaitFor)
269 | {
270 | stayInLoop = false;
271 | }
272 | }
273 | }
274 | }
275 | }
276 | }
277 | }
278 | finally
279 | {
280 | //Let the main thread run a possible close command.
281 | System.Threading.Thread.Sleep(2000);
282 |
283 | foreach (IntPtr hwnd in hwnds)
284 | {
285 | // At this point the dialog should be closed, if not attempt to close it.
286 | if (hwnd != IntPtr.Zero)
287 | {
288 | NativeMethods.SendMessage(hwnd, NativeMethods.WM_CLOSE, 0, new IntPtr(0));
289 | }
290 | }
291 |
292 | lock (Mutex)
293 | {
294 | // Be optimistic.
295 | this.dialogBoxCloseResult = true;
296 |
297 | for (int i = 0; i < dialogBoxCloseResults.Length; i++)
298 | {
299 | if (!dialogBoxCloseResults[i])
300 | {
301 | this.dialogBoxCloseResult = false;
302 | break;
303 | }
304 | }
305 |
306 | this.threadDone.Set();
307 | }
308 | }
309 | }
310 |
311 | ///
312 | /// Finds a messagebox string on a messagebox.
313 | ///
314 | /// The windows handle of the dialog
315 | /// A pointer to the memorylocation the string will be written to
316 | /// True if found.
317 | private static bool FindMessageBoxString(IntPtr hwnd, IntPtr unmanagedMemoryLocation)
318 | {
319 | StringBuilder sb = new StringBuilder(512);
320 | NativeMethods.GetClassName(hwnd, sb, sb.Capacity);
321 |
322 | if (sb.ToString().ToLower().Contains("static"))
323 | {
324 | StringBuilder windowText = new StringBuilder(2048);
325 | NativeMethods.GetWindowText(hwnd, windowText, windowText.Capacity);
326 |
327 | if (windowText.Length > 0)
328 | {
329 | IntPtr stringAsPtr = IntPtr.Zero;
330 | try
331 | {
332 | stringAsPtr = Marshal.StringToHGlobalAnsi(windowText.ToString());
333 | char[] stringAsArray = windowText.ToString().ToCharArray();
334 |
335 | // Since unicode characters are copied check if we are out of the allocated length.
336 | // If not add the end terminating zero.
337 | if ((2 * stringAsArray.Length) + 1 < 2048)
338 | {
339 | Marshal.Copy(stringAsArray, 0, unmanagedMemoryLocation, stringAsArray.Length);
340 | Marshal.WriteInt32(unmanagedMemoryLocation, 2 * stringAsArray.Length, 0);
341 | }
342 | }
343 | finally
344 | {
345 | if (stringAsPtr != IntPtr.Zero)
346 | {
347 | Marshal.FreeHGlobal(stringAsPtr);
348 | }
349 | }
350 | return false;
351 | }
352 | }
353 |
354 | return true;
355 | }
356 |
357 | #endregion
358 | }
359 | }
360 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/RemoveTrailingWhitespaces_IntegrationTests/IntegrationTest Library/NativeMethods.cs:
--------------------------------------------------------------------------------
1 | /***************************************************************************
2 |
3 | Copyright (c) Microsoft Corporation. All rights reserved.
4 | This code is licensed under the Visual Studio SDK license terms.
5 | THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
6 | ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
7 | IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
8 | PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
9 |
10 | ***************************************************************************/
11 |
12 | namespace Microsoft.VsSDK.IntegrationTestLibrary
13 | {
14 | using System;
15 | using System.Collections.Generic;
16 | using System.Text;
17 | using System.Runtime.InteropServices;
18 | using System.Threading;
19 | using Microsoft.VisualStudio.Shell.Interop;
20 |
21 | ///
22 | /// Defines pinvoked utility methods and internal VS Constants
23 | ///
24 | internal static class NativeMethods
25 | {
26 | internal delegate bool CallBack(IntPtr hwnd, IntPtr lParam);
27 |
28 | // Declare two overloaded SendMessage functions
29 | [DllImport("user32.dll")]
30 | internal static extern UInt32 SendMessage(IntPtr hWnd, UInt32 Msg,
31 | UInt32 wParam, IntPtr lParam);
32 |
33 | [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
34 | internal static extern bool PeekMessage([In, Out] ref Microsoft.VisualStudio.OLE.Interop.MSG msg, HandleRef hwnd, int msgMin, int msgMax, int remove);
35 |
36 | [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
37 | internal static extern bool TranslateMessage([In, Out] ref Microsoft.VisualStudio.OLE.Interop.MSG msg);
38 |
39 | [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
40 | internal static extern int DispatchMessage([In] ref Microsoft.VisualStudio.OLE.Interop.MSG msg);
41 |
42 | [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
43 | internal static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool attach);
44 |
45 | [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
46 | internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
47 |
48 | [DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
49 | internal static extern uint GetCurrentThreadId();
50 |
51 | [DllImport("user32")]
52 | internal static extern int EnumChildWindows(IntPtr hwnd, CallBack x, IntPtr y);
53 |
54 | [DllImport("user32")]
55 | internal static extern bool IsWindowVisible(IntPtr hDlg);
56 |
57 | [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
58 | internal static extern IntPtr SetFocus(IntPtr hWnd);
59 |
60 | [DllImport("user32")]
61 | internal static extern int GetClassName(IntPtr hWnd,
62 | StringBuilder className,
63 | int stringLength);
64 | [DllImport("user32")]
65 | internal static extern int GetWindowText(IntPtr hWnd, StringBuilder className, int stringLength);
66 |
67 |
68 | [DllImport("user32")]
69 | internal static extern bool EndDialog(IntPtr hDlg, int result);
70 |
71 | [DllImport("Kernel32")]
72 | internal static extern long GetLastError();
73 |
74 | internal const int QS_KEY = 0x0001,
75 | QS_MOUSEMOVE = 0x0002,
76 | QS_MOUSEBUTTON = 0x0004,
77 | QS_POSTMESSAGE = 0x0008,
78 | QS_TIMER = 0x0010,
79 | QS_PAINT = 0x0020,
80 | QS_SENDMESSAGE = 0x0040,
81 | QS_HOTKEY = 0x0080,
82 | QS_ALLPOSTMESSAGE = 0x0100,
83 | QS_MOUSE = QS_MOUSEMOVE | QS_MOUSEBUTTON,
84 | QS_INPUT = QS_MOUSE | QS_KEY,
85 | QS_ALLEVENTS = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY,
86 | QS_ALLINPUT = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE;
87 |
88 | internal const int Facility_Win32 = 7;
89 |
90 | internal const int WM_CLOSE = 0x0010;
91 |
92 | internal const int
93 | S_FALSE = 0x00000001,
94 | S_OK = 0x00000000,
95 |
96 | IDOK = 1,
97 | IDCANCEL = 2,
98 | IDABORT = 3,
99 | IDRETRY = 4,
100 | IDIGNORE = 5,
101 | IDYES = 6,
102 | IDNO = 7,
103 | IDCLOSE = 8,
104 | IDHELP = 9,
105 | IDTRYAGAIN = 10,
106 | IDCONTINUE = 11;
107 |
108 | internal static long HResultFromWin32(long error)
109 | {
110 | if (error <= 0)
111 | {
112 | return error;
113 | }
114 |
115 | return ((error & 0x0000FFFF) | (Facility_Win32 << 16) | 0x80000000);
116 | }
117 |
118 | ///
119 | /// Please use this "approved" method to compare file names.
120 | ///
121 | public static bool IsSamePath(string file1, string file2)
122 | {
123 | if (file1 == null || file1.Length == 0)
124 | {
125 | return (file2 == null || file2.Length == 0);
126 | }
127 |
128 | Uri uri1 = null;
129 | Uri uri2 = null;
130 |
131 | try
132 | {
133 | if (!Uri.TryCreate(file1, UriKind.Absolute, out uri1) || !Uri.TryCreate(file2, UriKind.Absolute, out uri2))
134 | {
135 | return false;
136 | }
137 |
138 | if (uri1 != null && uri1.IsFile && uri2 != null && uri2.IsFile)
139 | {
140 | return 0 == String.Compare(uri1.LocalPath, uri2.LocalPath, StringComparison.OrdinalIgnoreCase);
141 | }
142 |
143 | return file1 == file2;
144 | }
145 | catch (UriFormatException e)
146 | {
147 | System.Diagnostics.Trace.WriteLine("Exception " + e.Message);
148 | }
149 |
150 | return false;
151 | }
152 |
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/RemoveTrailingWhitespaces_IntegrationTests/IntegrationTest Library/Utils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text;
4 | using System.Reflection;
5 | using System.Diagnostics;
6 | using System.Collections;
7 | using System.Collections.Generic;
8 | using System.ComponentModel.Design;
9 | using System.Runtime.InteropServices;
10 | using Microsoft.VisualStudio.Shell.Interop;
11 | using Microsoft.VisualStudio.Shell;
12 | using EnvDTE;
13 | using EnvDTE80;
14 | using Microsoft.Win32;
15 | using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
16 | using Microsoft.VisualStudio.TestTools.UnitTesting;
17 | using Microsoft.VSSDK.Tools.VsIdeTesting;
18 | using Microsoft.VisualStudio;
19 |
20 | namespace Microsoft.VsSDK.IntegrationTestLibrary
21 | {
22 | ///
23 | ///
24 | public class TestUtils
25 | {
26 |
27 | #region Methods: Handling embedded resources
28 | ///
29 | /// Gets the embedded file identified by the resource name, and converts the
30 | /// file into a string.
31 | ///
32 | /// In VS, is DefaultNamespace.FileName?
33 | ///
34 | public static string GetEmbeddedStringResource(Assembly assembly, string resourceName)
35 | {
36 | string result = null;
37 |
38 | // Use the .NET procedure for loading a file embedded in the assembly
39 | Stream stream = assembly.GetManifestResourceStream(resourceName);
40 | if (stream != null)
41 | {
42 | // Convert bytes to string
43 | byte[] fileContentsAsBytes = new byte[stream.Length];
44 | stream.Read(fileContentsAsBytes, 0, (int)stream.Length);
45 | result = Encoding.Default.GetString(fileContentsAsBytes);
46 | }
47 | else
48 | {
49 | // Embedded resource not found - list available resources
50 | Debug.WriteLine("Unable to find the embedded resource file '" + resourceName + "'.");
51 | Debug.WriteLine(" Available resources:");
52 | foreach (string aResourceName in assembly.GetManifestResourceNames())
53 | {
54 | Debug.WriteLine(" " + aResourceName);
55 | }
56 | }
57 |
58 | return result;
59 | }
60 | ///
61 | ///
62 | ///
63 | ///
64 | ///
65 | ///
66 | ///
67 | public static void WriteEmbeddedResourceToFile(Assembly assembly, string embeddedResourceName, string fileName)
68 | {
69 | // Get file contents
70 | string fileContents = GetEmbeddedStringResource(assembly, embeddedResourceName);
71 | if (fileContents == null)
72 | throw new ApplicationException("Failed to get embedded resource '" + embeddedResourceName + "' from assembly '" + assembly.FullName);
73 |
74 | // Write to file
75 | StreamWriter sw = new StreamWriter(fileName);
76 | sw.Write(fileContents);
77 | sw.Close();
78 | }
79 |
80 | ///
81 | /// Writes an embedded resource to a file.
82 | ///
83 | /// The name of the assembly that the embedded resource is defined.
84 | /// The name of the embedded resource.
85 | /// The file to write the embedded resource's content.
86 | public static void WriteEmbeddedResourceToBinaryFile(Assembly assembly, string embeddedResourceName, string fileName)
87 | {
88 | // Get file contents
89 | Stream stream = assembly.GetManifestResourceStream(embeddedResourceName);
90 | if (stream == null)
91 | throw new InvalidOperationException("Failed to get embedded resource '" + embeddedResourceName + "' from assembly '" + assembly.FullName);
92 |
93 | // Write to file
94 | BinaryWriter sw = null;
95 | FileStream fs = null;
96 | try
97 | {
98 | byte[] fileContentsAsBytes = new byte[stream.Length];
99 | stream.Read(fileContentsAsBytes, 0, (int)stream.Length);
100 |
101 | FileMode mode = FileMode.CreateNew;
102 | if (File.Exists(fileName))
103 | {
104 | mode = FileMode.Truncate;
105 | }
106 |
107 | fs = new FileStream(fileName, mode);
108 |
109 | sw = new BinaryWriter(fs);
110 | sw.Write(fileContentsAsBytes);
111 | }
112 | finally
113 | {
114 | if (fs != null)
115 | {
116 | fs.Close();
117 | }
118 | if (sw != null)
119 | {
120 | sw.Close();
121 | }
122 | }
123 | }
124 |
125 | #endregion
126 |
127 | #region Methods: Handling temporary files and directories
128 | ///
129 | /// Returns the first available file name on the form
130 | /// [baseFileName]i.[extension]
131 | /// where [i] starts at 1 and increases until there is an available file name
132 | /// in the given directory. Also creates an empty file with that name to mark
133 | /// that file as occupied.
134 | ///
135 | /// Directory that the file should live in.
136 | ///
137 | /// may be null, in which case the .[extension] part
138 | /// is not added.
139 | /// Full file name.
140 | public static string GetNewFileName(string directory, string baseFileName, string extension)
141 | {
142 | // Get the new file name
143 | string fileName = GetNewFileOrDirectoryNameWithoutCreatingAnything(directory, baseFileName, extension);
144 |
145 | // Create an empty file to mark it as taken
146 | StreamWriter sw = new StreamWriter(fileName);
147 |
148 | sw.Write("");
149 | sw.Close();
150 | return fileName;
151 | }
152 | ///
153 | /// Returns the first available directory name on the form
154 | /// [baseDirectoryName]i
155 | /// where [i] starts at 1 and increases until there is an available directory name
156 | /// in the given directory. Also creates the directory to mark it as occupied.
157 | ///
158 | /// Directory that the file should live in.
159 | ///
160 | /// Full directory name.
161 | public static string GetNewDirectoryName(string directory, string baseDirectoryName)
162 | {
163 | // Get the new file name
164 | string directoryName = GetNewFileOrDirectoryNameWithoutCreatingAnything(directory, baseDirectoryName, null);
165 |
166 | // Create an empty directory to make it as occupied
167 | Directory.CreateDirectory(directoryName);
168 |
169 | return directoryName;
170 | }
171 |
172 | ///
173 | ///
174 | ///
175 | ///
176 | ///
177 | ///
178 | ///
179 | private static string GetNewFileOrDirectoryNameWithoutCreatingAnything(string directory, string baseFileName, string extension)
180 | {
181 | // - get a file name that we can use
182 | string fileName;
183 | int i = 1;
184 |
185 | string fullFileName = null;
186 | while (true)
187 | {
188 | // construct next file name
189 | fileName = baseFileName + i;
190 | if (extension != null)
191 | fileName += '.' + extension;
192 |
193 | // check if that file exists in the directory
194 | fullFileName = Path.Combine(directory, fileName);
195 |
196 | if (!File.Exists(fullFileName) && !Directory.Exists(fullFileName))
197 | break;
198 | else
199 | i++;
200 | }
201 |
202 | return fullFileName;
203 | }
204 | #endregion
205 |
206 | #region Methods: Handling solutions
207 | ///
208 | /// Closes the currently open solution (if any), and creates a new solution with the given name.
209 | ///
210 | /// Name of new solution.
211 | public void CreateEmptySolution(string directory, string solutionName)
212 | {
213 | CloseCurrentSolution(__VSSLNSAVEOPTIONS.SLNSAVEOPT_NoSave);
214 |
215 | string solutionDirectory = GetNewDirectoryName(directory, solutionName);
216 |
217 | // Create and force save solution
218 | IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution));
219 | solutionService.CreateSolution(solutionDirectory, solutionName, (uint)__VSCREATESOLUTIONFLAGS.CSF_SILENT);
220 | solutionService.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_ForceSave, null, 0);
221 | DTE dte = VsIdeTestHostContext.Dte;
222 | Assert.AreEqual(solutionName + ".sln", Path.GetFileName(dte.Solution.FileName), "Newly created solution has wrong Filename");
223 | }
224 |
225 | public void CloseCurrentSolution(__VSSLNSAVEOPTIONS saveoptions)
226 | {
227 | // Get solution service
228 | IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution));
229 |
230 | // Close already open solution
231 | solutionService.CloseSolutionElement((uint)saveoptions, null, 0);
232 | }
233 |
234 | public void ForceSaveSolution()
235 | {
236 | // Get solution service
237 | IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution));
238 |
239 | // Force-save the solution
240 | solutionService.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_ForceSave, null, 0);
241 | }
242 |
243 | ///
244 | /// Get current number of open project in solution
245 | ///
246 | ///
247 | public int ProjectCount()
248 | {
249 | // Get solution service
250 | IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution));
251 | object projectCount;
252 | solutionService.GetProperty((int)__VSPROPID.VSPROPID_ProjectCount, out projectCount);
253 | return (int)projectCount;
254 | }
255 | #endregion
256 |
257 | #region Methods: Handling projects
258 | ///
259 | /// Creates a project.
260 | ///
261 | /// Name of new project.
262 | /// Name of project template to use
263 | /// language
264 | /// New project.
265 | public void CreateProjectFromTemplate(string projectName, string templateName, string language, bool exclusive)
266 | {
267 | DTE dte = (DTE)VsIdeTestHostContext.ServiceProvider.GetService(typeof(DTE));
268 |
269 | Solution2 sol = dte.Solution as Solution2;
270 | string projectTemplate = sol.GetProjectTemplate(templateName, language);
271 |
272 | // - project name and directory
273 | string solutionDirectory = Directory.GetParent(dte.Solution.FullName).FullName;
274 | string projectDirectory = GetNewDirectoryName(solutionDirectory, projectName);
275 |
276 | dte.Solution.AddFromTemplate(projectTemplate, projectDirectory, projectName, false);
277 | }
278 | #endregion
279 |
280 | #region Methods: Handling project items
281 | ///
282 | /// Create a new item in the project
283 | ///
284 | /// the parent collection for the new item
285 | ///
286 | ///
287 | ///
288 | ///
289 | public ProjectItem AddNewItemFromVsTemplate(ProjectItems parent, string templateName, string language, string name)
290 | {
291 | if (parent == null)
292 | throw new ArgumentException("project");
293 | if (name == null)
294 | throw new ArgumentException("name");
295 |
296 | DTE dte = (DTE)VsIdeTestHostContext.ServiceProvider.GetService(typeof(DTE));
297 |
298 | Solution2 sol = dte.Solution as Solution2;
299 |
300 | string filename = sol.GetProjectItemTemplate(templateName, language);
301 |
302 | parent.AddFromTemplate(filename, name);
303 |
304 | return parent.Item(name);
305 | }
306 |
307 | ///
308 | /// Save an open document.
309 | ///
310 | /// for filebased documents this is the full path to the document
311 | public void SaveDocument(string documentMoniker)
312 | {
313 | // Get document cookie and hierarchy for the file
314 | IVsRunningDocumentTable runningDocumentTableService = (IVsRunningDocumentTable)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsRunningDocumentTable));
315 | uint docCookie;
316 | IntPtr docData;
317 | IVsHierarchy hierarchy;
318 | uint itemId;
319 | runningDocumentTableService.FindAndLockDocument(
320 | (uint)Microsoft.VisualStudio.Shell.Interop._VSRDTFLAGS.RDT_NoLock,
321 | documentMoniker,
322 | out hierarchy,
323 | out itemId,
324 | out docData,
325 | out docCookie);
326 |
327 | // Save the document
328 | IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution));
329 | solutionService.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_ForceSave, hierarchy, docCookie);
330 | }
331 |
332 | public void CloseInEditorWithoutSaving(string fullFileName)
333 | {
334 | // Get the RDT service
335 | IVsRunningDocumentTable runningDocumentTableService = (IVsRunningDocumentTable)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsRunningDocumentTable));
336 | Assert.IsNotNull(runningDocumentTableService, "Failed to get the Running Document Table Service");
337 |
338 | // Get our document cookie and hierarchy for the file
339 | uint docCookie;
340 | IntPtr docData;
341 | IVsHierarchy hierarchy;
342 | uint itemId;
343 | runningDocumentTableService.FindAndLockDocument(
344 | (uint)Microsoft.VisualStudio.Shell.Interop._VSRDTFLAGS.RDT_NoLock,
345 | fullFileName,
346 | out hierarchy,
347 | out itemId,
348 | out docData,
349 | out docCookie);
350 |
351 | // Get the SolutionService
352 | IVsSolution solutionService = VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution)) as IVsSolution;
353 | Assert.IsNotNull(solutionService, "Failed to get IVsSolution service");
354 |
355 | // Close the document
356 | solutionService.CloseSolutionElement(
357 | (uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_NoSave,
358 | hierarchy,
359 | docCookie);
360 | }
361 | #endregion
362 |
363 | #region Methods: Handling Toolwindows
364 | public bool CanFindToolwindow(Guid persistenceGuid)
365 | {
366 | IVsUIShell uiShellService = VsIdeTestHostContext.ServiceProvider.GetService(typeof(SVsUIShell)) as IVsUIShell;
367 | Assert.IsNotNull(uiShellService);
368 | IVsWindowFrame windowFrame;
369 | int hr = uiShellService.FindToolWindow((uint)__VSFINDTOOLWIN.FTW_fFindFirst, ref persistenceGuid, out windowFrame);
370 | Assert.IsTrue(hr == VSConstants.S_OK);
371 |
372 | return (windowFrame != null);
373 | }
374 | #endregion
375 |
376 | #region Methods: Loading packages
377 | public IVsPackage LoadPackage(Guid packageGuid)
378 | {
379 | IVsShell shellService = (IVsShell)VsIdeTestHostContext.ServiceProvider.GetService(typeof(SVsShell));
380 | IVsPackage package;
381 | shellService.LoadPackage(ref packageGuid, out package);
382 | Assert.IsNotNull(package, "Failed to load package");
383 | return package;
384 | }
385 | #endregion
386 |
387 | ///
388 | /// Executes a Command (menu item) in the given context
389 | ///
390 | public void ExecuteCommand(CommandID cmd)
391 | {
392 | object Customin = null;
393 | object Customout = null;
394 | string guidString = cmd.Guid.ToString("B").ToUpper();
395 | int cmdId = cmd.ID;
396 | DTE dte = VsIdeTestHostContext.Dte;
397 | dte.Commands.Raise(guidString, cmdId, ref Customin, ref Customout);
398 | }
399 |
400 | }
401 | }
402 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/RemoveTrailingWhitespaces_IntegrationTests/Key.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Predelnik/RemoveTrailingWhitespaces/934f165bc70de78c66832c4957b65768b8736cb0/RemoveTrailingWhitespaces/RemoveTrailingWhitespaces_IntegrationTests/Key.snk
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/RemoveTrailingWhitespaces_IntegrationTests/PackageTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 | using Microsoft.VSSDK.Tools.VsIdeTesting;
7 | using Microsoft.VisualStudio.Shell.Interop;
8 | using Microsoft.VisualStudio.Shell;
9 | using EnvDTE;
10 |
11 | namespace RemoveTrailingWhitespaces_IntegrationTests
12 | {
13 | ///
14 | /// Integration test for package validation
15 | ///
16 | [TestClass]
17 | public class PackageTest
18 | {
19 | private delegate void ThreadInvoker();
20 |
21 | private TestContext testContextInstance;
22 |
23 | ///
24 | ///Gets or sets the test context which provides
25 | ///information about and functionality for the current test run.
26 | ///
27 | public TestContext TestContext
28 | {
29 | get
30 | {
31 | return testContextInstance;
32 | }
33 | set
34 | {
35 | testContextInstance = value;
36 | }
37 | }
38 |
39 | [TestMethod]
40 | [HostType("VS IDE")]
41 | public void PackageLoadTest()
42 | {
43 | UIThreadInvoker.Invoke((ThreadInvoker)delegate()
44 | {
45 |
46 | //Get the Shell Service
47 | IVsShell shellService = VsIdeTestHostContext.ServiceProvider.GetService(typeof(SVsShell)) as IVsShell;
48 | Assert.IsNotNull(shellService);
49 |
50 | //Validate package load
51 | IVsPackage package;
52 | Guid packageGuid = new Guid(Predelnik.RemoveTrailingWhitespaces.GuidList.guidRemoveTrailingWhitespacesPkgString);
53 | Assert.IsTrue(0 == shellService.LoadPackage(ref packageGuid, out package));
54 | Assert.IsNotNull(package, "Package failed to load");
55 |
56 | });
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/RemoveTrailingWhitespaces_IntegrationTests/RemoveTrailingWhitespaces_IntegrationTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 2.0
7 | {C96EE774-20BF-48A2-AE59-09A0F2709808}
8 | Library
9 | Properties
10 | RemoveTrailingWhitespaces_IntegrationTests
11 | RemoveTrailingWhitespaces_IntegrationTests
12 | v4.6
13 | 512
14 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
15 |
16 |
17 |
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 | Key.snk
36 |
37 |
38 | true
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | true
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | {33B06D46-74C6-4F60-BB43-B3FDB8BDCEB0}
77 | RemoveTrailingWhitespaces
78 |
79 |
80 |
81 |
88 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/RemoveTrailingWhitespaces_IntegrationTests/SignOff-Tests/CPPProjectTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Collections.Generic;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 | using Microsoft.VsSDK.IntegrationTestLibrary;
6 | using Microsoft.VSSDK.Tools.VsIdeTesting;
7 | using EnvDTE;
8 | using System.IO;
9 |
10 | namespace RemoveTrailingWhitespaces_IntegrationTests.IntegrationTests
11 | {
12 | [TestClass]
13 | public class CPPProjectTests
14 | {
15 | #region fields
16 | private delegate void ThreadInvoker();
17 | private TestContext _testContext;
18 | #endregion
19 |
20 | #region properties
21 | ///
22 | ///Gets or sets the test context which provides
23 | ///information about and functionality for the current test run.
24 | ///
25 | public TestContext TestContext
26 | {
27 | get { return _testContext; }
28 | set { _testContext = value; }
29 | }
30 | #endregion
31 |
32 | #region ctors
33 | public CPPProjectTests()
34 | {
35 | }
36 | #endregion
37 |
38 | #region Additional test attributes
39 | //
40 | // You can use the following additional attributes as you write your tests:
41 | //
42 | // Use ClassInitialize to run code before running the first test in the class
43 | // [ClassInitialize()]
44 | // public static void MyClassInitialize(TestContext testContext) { }
45 | //
46 | // Use ClassCleanup to run code after all tests in a class have run
47 | // [ClassCleanup()]
48 | // public static void MyClassCleanup() { }
49 | //
50 | // Use TestInitialize to run code before running each test
51 | // [TestInitialize()]
52 | // public void MyTestInitialize() { }
53 | //
54 | // Use TestCleanup to run code after each test has run
55 | // [TestCleanup()]
56 | // public void MyTestCleanup() { }
57 | //
58 | #endregion
59 |
60 | [HostType("VS IDE")]
61 | [TestMethod]
62 | public void CPPWinformsApplication()
63 | {
64 | UIThreadInvoker.Invoke((ThreadInvoker)delegate()
65 | {
66 | //Solution and project creation parameters
67 | string solutionName = "CPPWinApp";
68 | string projectName = "CPPWinApp";
69 |
70 | //Template parameters
71 | string projectType = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}";
72 | string projectTemplateName = Path.Combine("vcNet", "mc++appwiz.vsz");
73 |
74 | string itemTemplateName = "newc++file.cpp";
75 | string newFileName = "Test.cpp";
76 |
77 | DTE dte = (DTE)VsIdeTestHostContext.ServiceProvider.GetService(typeof(DTE));
78 |
79 | TestUtils testUtils = new TestUtils();
80 |
81 | testUtils.CreateEmptySolution(TestContext.TestDir, solutionName);
82 | Assert.AreEqual(0, testUtils.ProjectCount());
83 |
84 | //Add new CPP Windows application project to existing solution
85 | string solutionDirectory = Directory.GetParent(dte.Solution.FullName).FullName;
86 | string projectDirectory = TestUtils.GetNewDirectoryName(solutionDirectory, projectName);
87 | string projectTemplatePath = Path.Combine(dte.Solution.get_TemplatePath(projectType), projectTemplateName);
88 | Assert.IsTrue(File.Exists(projectTemplatePath), string.Format("Could not find template file: {0}", projectTemplatePath));
89 | dte.Solution.AddFromTemplate(projectTemplatePath, projectDirectory, projectName, false);
90 |
91 | //Verify that the new project has been added to the solution
92 | Assert.AreEqual(1, testUtils.ProjectCount());
93 |
94 | //Get the project
95 | Project project = dte.Solution.Item(1);
96 | Assert.IsNotNull(project);
97 | Assert.IsTrue(string.Compare(project.Name, projectName, StringComparison.InvariantCultureIgnoreCase) == 0);
98 |
99 | //Verify Adding new code file to project
100 | string newItemTemplatePath = Path.Combine(dte.Solution.ProjectItemsTemplatePath(projectType), itemTemplateName);
101 | Assert.IsTrue(File.Exists(newItemTemplatePath));
102 | ProjectItem item = project.ProjectItems.AddFromTemplate(newItemTemplatePath, newFileName);
103 | Assert.IsNotNull(item);
104 |
105 | });
106 | }
107 |
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/RemoveTrailingWhitespaces_IntegrationTests/SignOff-Tests/CSharpProjectTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Collections.Generic;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 | using Microsoft.VsSDK.IntegrationTestLibrary;
6 | using Microsoft.VSSDK.Tools.VsIdeTesting;
7 |
8 | namespace RemoveTrailingWhitespaces_IntegrationTests.IntegrationTests
9 | {
10 | [TestClass]
11 | public class CSharpProjectTests
12 | {
13 | #region fields
14 | private delegate void ThreadInvoker();
15 | private TestContext _testContext;
16 | #endregion
17 |
18 | #region properties
19 | ///
20 | ///Gets or sets the test context which provides
21 | ///information about and functionality for the current test run.
22 | ///
23 | public TestContext TestContext
24 | {
25 | get { return _testContext; }
26 | set { _testContext = value; }
27 | }
28 | #endregion
29 |
30 | #region ctors
31 | public CSharpProjectTests()
32 | {
33 | }
34 | #endregion
35 |
36 | #region Additional test attributes
37 | //
38 | // You can use the following additional attributes as you write your tests:
39 | //
40 | // Use ClassInitialize to run code before running the first test in the class
41 | // [ClassInitialize()]
42 | // public static void MyClassInitialize(TestContext testContext) { }
43 | //
44 | // Use ClassCleanup to run code after all tests in a class have run
45 | // [ClassCleanup()]
46 | // public static void MyClassCleanup() { }
47 | //
48 | // Use TestInitialize to run code before running each test
49 | // [TestInitialize()]
50 | // public void MyTestInitialize() { }
51 | //
52 | // Use TestCleanup to run code after each test has run
53 | // [TestCleanup()]
54 | // public void MyTestCleanup() { }
55 | //
56 | #endregion
57 |
58 | [TestMethod]
59 | [HostType("VS IDE")]
60 | public void WinformsApplication()
61 | {
62 | UIThreadInvoker.Invoke((ThreadInvoker)delegate()
63 | {
64 | TestUtils testUtils = new TestUtils();
65 |
66 | testUtils.CreateEmptySolution(TestContext.TestDir, "CSWinApp");
67 | Assert.AreEqual(0, testUtils.ProjectCount());
68 |
69 | //Create Winforms application project
70 | //TestUtils.CreateProjectFromTemplate("MyWindowsApp", "Windows Application", "CSharp", false);
71 | //Assert.AreEqual(1, TestUtils.ProjectCount());
72 |
73 | //TODO Verify that we can debug launch the application
74 |
75 | //TODO Set Break point and verify that will hit
76 |
77 | //TODO Verify Adding new project item to project
78 |
79 | });
80 | }
81 |
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/RemoveTrailingWhitespaces_IntegrationTests/SignOff-Tests/SolutionTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Collections.Generic;
4 | using Microsoft.VisualStudio.Shell.Interop;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 | using Microsoft.VSSDK.Tools.VsIdeTesting;
7 | using EnvDTE;
8 | using System.IO;
9 | using Microsoft.VsSDK.IntegrationTestLibrary;
10 |
11 |
12 | namespace RemoveTrailingWhitespaces_IntegrationTests.IntegrationTests
13 | {
14 | [TestClass]
15 | public class SolutionTests
16 | {
17 | #region fields
18 | private delegate void ThreadInvoker();
19 | private TestContext _testContext;
20 | #endregion
21 |
22 | #region properties
23 | ///
24 | ///Gets or sets the test context which provides
25 | ///information about and functionality for the current test run.
26 | ///
27 | public TestContext TestContext
28 | {
29 | get { return _testContext; }
30 | set { _testContext = value; }
31 | }
32 | #endregion
33 |
34 |
35 | #region ctors
36 | public SolutionTests()
37 | {
38 | }
39 |
40 | #endregion
41 |
42 | [TestMethod]
43 | [HostType("VS IDE")]
44 | public void CreateEmptySolution()
45 | {
46 | UIThreadInvoker.Invoke((ThreadInvoker)delegate()
47 | {
48 | TestUtils testUtils = new TestUtils();
49 | testUtils.CloseCurrentSolution(__VSSLNSAVEOPTIONS.SLNSAVEOPT_NoSave);
50 | testUtils.CreateEmptySolution(TestContext.TestDir, "EmptySolution");
51 | });
52 | }
53 |
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/RemoveTrailingWhitespaces_IntegrationTests/SignOff-Tests/VBProjectTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Collections.Generic;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 | using Microsoft.VsSDK.IntegrationTestLibrary;
6 | using Microsoft.VSSDK.Tools.VsIdeTesting;
7 | using EnvDTE;
8 |
9 | namespace RemoveTrailingWhitespaces_IntegrationTests.IntegrationTests
10 | {
11 | [TestClass]
12 | public class VisualBasicProjectTests
13 | {
14 | #region fields
15 | private delegate void ThreadInvoker();
16 | private TestContext _testContext;
17 | #endregion
18 |
19 | #region properties
20 | ///
21 | ///Gets or sets the test context which provides
22 | ///information about and functionality for the current test run.
23 | ///
24 | public TestContext TestContext
25 | {
26 | get { return _testContext; }
27 | set { _testContext = value; }
28 | }
29 | #endregion
30 |
31 | #region ctors
32 | public VisualBasicProjectTests()
33 | {
34 | }
35 | #endregion
36 |
37 | #region Additional test attributes
38 | //
39 | // You can use the following additional attributes as you write your tests:
40 | //
41 | // Use ClassInitialize to run code before running the first test in the class
42 | // [ClassInitialize()]
43 | // public static void MyClassInitialize(TestContext testContext) { }
44 | //
45 | // Use ClassCleanup to run code after all tests in a class have run
46 | // [ClassCleanup()]
47 | // public static void MyClassCleanup() { }
48 | //
49 | // Use TestInitialize to run code before running each test
50 | // [TestInitialize()]
51 | // public void MyTestInitialize() { }
52 | //
53 | // Use TestCleanup to run code after each test has run
54 | // [TestCleanup()]
55 | // public void MyTestCleanup() { }
56 | //
57 | #endregion
58 |
59 | [HostType("VS IDE")]
60 | [TestMethod]
61 | public void VBWinformsApplication()
62 | {
63 | UIThreadInvoker.Invoke((ThreadInvoker)delegate()
64 | {
65 | //Solution and project creation parameters
66 | string solutionName = "VBWinApp";
67 | string projectName = "VBWinApp";
68 |
69 | //Template parameters
70 | string language = "VisualBasic";
71 | string projectTemplateName = "WindowsApplication.Zip";
72 | string itemTemplateName = "CodeFile.zip";
73 | string newFileName = "Test.vb";
74 |
75 | DTE dte = (DTE)VsIdeTestHostContext.ServiceProvider.GetService(typeof(DTE));
76 |
77 | TestUtils testUtils = new TestUtils();
78 |
79 | testUtils.CreateEmptySolution(TestContext.TestDir, solutionName);
80 | Assert.AreEqual(0, testUtils.ProjectCount());
81 |
82 | //Add new Windows application project to existing solution
83 | testUtils.CreateProjectFromTemplate(projectName, projectTemplateName, language, false);
84 |
85 | //Verify that the new project has been added to the solution
86 | Assert.AreEqual(1, testUtils.ProjectCount());
87 |
88 | //Get the project
89 | Project project = dte.Solution.Item(1);
90 | Assert.IsNotNull(project);
91 | Assert.IsTrue(string.Compare(project.Name, projectName, StringComparison.InvariantCultureIgnoreCase) == 0);
92 |
93 | //Verify Adding new code file to project
94 | ProjectItem newCodeFileItem = testUtils.AddNewItemFromVsTemplate(project.ProjectItems, itemTemplateName, language, newFileName);
95 | Assert.IsNotNull(newCodeFileItem, "Could not create new project item");
96 |
97 | });
98 | }
99 |
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/RemoveTrailingWhitespaces_UnitTests/Key.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Predelnik/RemoveTrailingWhitespaces/934f165bc70de78c66832c4957b65768b8736cb0/RemoveTrailingWhitespaces/RemoveTrailingWhitespaces_UnitTests/Key.snk
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/RemoveTrailingWhitespaces_UnitTests/PackageTest.cs:
--------------------------------------------------------------------------------
1 | /***************************************************************************
2 |
3 | Copyright (c) Microsoft Corporation. All rights reserved.
4 | This code is licensed under the Visual Studio SDK license terms.
5 | THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
6 | ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
7 | IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
8 | PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
9 |
10 | ***************************************************************************/
11 |
12 | using System;
13 | using System.Collections;
14 | using System.Text;
15 | using System.Reflection;
16 | using Microsoft.VsSDK.UnitTestLibrary;
17 | using Microsoft.VisualStudio.Shell.Interop;
18 | using Microsoft.VisualStudio.TestTools.UnitTesting;
19 | using Predelnik.RemoveTrailingWhitespaces;
20 |
21 | namespace RemoveTrailingWhitespaces_UnitTests
22 | {
23 | [TestClass()]
24 | public class PackageTest
25 | {
26 | [TestMethod()]
27 | public void CreateInstance()
28 | {
29 | RemoveTrailingWhitespacesPackage package = new RemoveTrailingWhitespacesPackage();
30 | }
31 |
32 | [TestMethod()]
33 | public void IsIVsPackage()
34 | {
35 | RemoveTrailingWhitespacesPackage package = new RemoveTrailingWhitespacesPackage();
36 | Assert.IsNotNull(package as IVsPackage, "The object does not implement IVsPackage");
37 | }
38 |
39 | [TestMethod()]
40 | public void SetSite()
41 | {
42 | // Create the package
43 | IVsPackage package = new RemoveTrailingWhitespacesPackage() as IVsPackage;
44 | Assert.IsNotNull(package, "The object does not implement IVsPackage");
45 |
46 | // Create a basic service provider
47 | OleServiceProvider serviceProvider = OleServiceProvider.CreateOleServiceProviderWithBasicServices();
48 |
49 | // Site the package
50 | Assert.AreEqual(0, package.SetSite(serviceProvider), "SetSite did not return S_OK");
51 |
52 | // Unsite the package
53 | Assert.AreEqual(0, package.SetSite(null), "SetSite(null) did not return S_OK");
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/RemoveTrailingWhitespaces_UnitTests/RemoveTrailingWhitespaces_UnitTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 2.0
7 | {81EA4FD4-B565-4F47-A7CF-7D4580B0186A}
8 | Library
9 | Properties
10 | RemoveTrailingWhitespaces_UnitTests
11 | RemoveTrailingWhitespaces_UnitTests
12 | v4.6
13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 | Key.snk
35 |
36 |
37 | true
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | true
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | {33B06D46-74C6-4F60-BB43-B3FDB8BDCEB0}
73 | RemoveTrailingWhitespaces
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Predelnik.RemoveTrailingWhitespaces {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Predelnik.RemoveTrailingWhitespaces.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 | text/microsoft-resx
119 |
120 |
121 | 2.0
122 |
123 |
124 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
125 |
126 |
127 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
128 |
129 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/Resources/menuicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Predelnik/RemoveTrailingWhitespaces/934f165bc70de78c66832c4957b65768b8736cb0/RemoveTrailingWhitespaces/Resources/menuicon.png
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/Resources/packageicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Predelnik/RemoveTrailingWhitespaces/934f165bc70de78c66832c4957b65768b8736cb0/RemoveTrailingWhitespaces/Resources/packageicon.png
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/Resources/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Predelnik/RemoveTrailingWhitespaces/934f165bc70de78c66832c4957b65768b8736cb0/RemoveTrailingWhitespaces/Resources/preview.png
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/VSPackage.resx:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 | text/microsoft-resx
120 |
121 |
122 | 2.0
123 |
124 |
125 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
126 |
127 |
128 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
129 |
130 |
131 |
132 | RemoveTrailingWhitespaces
133 |
134 |
135 | Trailing whitespace removal tool. Removes either manually or on file save.
136 |
137 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/RemoveTrailingWhitespaces/source.extension.vsixmanifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | RemoveTrailingWhitespaces
6 | Trailing whitespace removal tool. Removes either manually or on file save.
7 | LICENSE.txt
8 | Resources\packageicon.png
9 | Resources\preview.png
10 | Formatting, Trailing Whitespaces, Utility
11 |
12 |
13 |
16 |
17 | amd64
18 |
19 |
20 | amd64
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/UnitTests.testsettings:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 | This test run configuration is used for running the unit tests
9 |
10 |
--------------------------------------------------------------------------------