Skip to content

Commit 9b973e7

Browse files
committed
Support VS 2022
1 parent 76b88f7 commit 9b973e7

14 files changed

+296
-40
lines changed

Shared/ITextReplacer.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using EnvDTE;
2+
3+
namespace Shared
4+
{
5+
public interface ITextReplacer
6+
{
7+
void Replace(string whatRegex, string with, Document document);
8+
}
9+
}

Shared/LICENSE

Lines changed: 0 additions & 20 deletions
This file was deleted.

Shared/SaveCommandPackage.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using EnvDTE;
88
using EnvDTE80;
99
using Microsoft.VisualStudio;
10+
using Microsoft.VisualStudio.ComponentModelHost;
1011
using Microsoft.VisualStudio.Shell;
1112
using System;
1213
using System.Diagnostics.CodeAnalysis;
@@ -44,11 +45,15 @@ namespace WhitespaceCleanerExtension
4445
[ProvideAutoLoad(VSConstants.UICONTEXT.SolutionExistsAndFullyLoaded_string, PackageAutoLoadFlags.BackgroundLoad)]
4546
public sealed class SaveCommandPackage : AsyncPackage
4647
{
48+
public static SaveCommandPackage Instance { get; private set; }
49+
4750
/// <summary>
4851
/// SaveCommandPackage GUID string.
4952
/// </summary>
5053
public const string PackageGuidString = "90ab0a97-fa71-411d-918e-28d82a7a9173";
5154

55+
public IComponentModel ComponentModel { get; private set; }
56+
5257
private SaveEventHandler _saveHandler;
5358

5459
/// <summary>
@@ -74,8 +79,20 @@ protected override async System.Threading.Tasks.Task InitializeAsync(Cancellatio
7479

7580
var dte = await GetServiceAsync(typeof(DTE)) as DTE2;
7681

82+
ComponentModel = GetGlobalService(typeof(SComponentModel)) as IComponentModel;
83+
84+
await JoinableTaskFactory.SwitchToMainThreadAsync();
85+
86+
#if VS2022
87+
var textReplacer = new WhitespaceCleanerExtension2022.TextReplacer();
88+
#else
89+
var textReplacer = new TextReplacer(dte);
90+
#endif
91+
7792
_saveHandler = new SaveEventHandler();
78-
_saveHandler.OnConnection(dte);
93+
_saveHandler.OnConnection(dte, textReplacer);
94+
95+
Instance = this;
7996
}
8097

8198
#endregion

Shared/SaveEventHandler.cs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using EnvDTE;
22
using EnvDTE80;
3+
using Microsoft.VisualStudio.Shell;
4+
using Shared;
35
using System;
46
using System.Globalization;
57

@@ -10,24 +12,30 @@ public sealed class SaveEventHandler
1012
private DTE2 _applicationObject;
1113
private DocumentEvents _documentEvents;
1214
private string _whitespaceRegex;
15+
private ITextReplacer _textReplacer;
1316
private bool _saved;
1417

15-
public void OnConnection(DTE2 application)
18+
public void OnConnection(DTE2 application, ITextReplacer textReplacer)
1619
{
20+
ThreadHelper.ThrowIfNotOnUIThread();
21+
1722
_applicationObject = application;
1823
_documentEvents = _applicationObject.Events.DocumentEvents;
1924
_whitespaceRegex = ":Zs+$";
2025
if (double.TryParse(_applicationObject.Version, NumberStyles.Number, CultureInfo.InvariantCulture, out double version))
2126
if (version >= 11.0)
2227
_whitespaceRegex = "[^\\S\\r\\n]+(?=\\r?$)";
2328

29+
_textReplacer = textReplacer;
2430
_saved = false;
2531

2632
_documentEvents.DocumentSaved += DocumentEvents_DocumentSaved;
2733
}
2834

2935
private void DocumentEvents_DocumentSaved(Document document)
3036
{
37+
ThreadHelper.ThrowIfNotOnUIThread();
38+
3139
if (!_saved)
3240
{
3341
try
@@ -41,20 +49,11 @@ private void DocumentEvents_DocumentSaved(Document document)
4149
{
4250
var tabSize = (short)props.Item("TabSize").Value;
4351

44-
_applicationObject.Find.FindReplace(vsFindAction.vsFindActionReplaceAll, "\t",
45-
(int)vsFindOptions.vsFindOptionsRegularExpression,
46-
new string(' ', tabSize),
47-
vsFindTarget.vsFindTargetCurrentDocument, string.Empty, string.Empty,
48-
vsFindResultsLocation.vsFindResultsNone);
52+
_textReplacer.Replace("\t", new string(' ', tabSize), document);
4953
}
5054

5155
// Remove all the trailing whitespaces.
52-
_applicationObject.Find.FindReplace(vsFindAction.vsFindActionReplaceAll,
53-
_whitespaceRegex,
54-
(int)vsFindOptions.vsFindOptionsRegularExpression,
55-
string.Empty,
56-
vsFindTarget.vsFindTargetCurrentDocument, string.Empty, string.Empty,
57-
vsFindResultsLocation.vsFindResultsNone);
56+
_textReplacer.Replace(_whitespaceRegex, string.Empty, document);
5857

5958
_saved = true;
6059
document.Save();

Shared/Shared.projitems

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
</PropertyGroup>
1111
<ItemGroup>
1212
<None Include="$(MSBuildThisFileDirectory)ExtensionKey.pfx" />
13-
<None Include="$(MSBuildThisFileDirectory)LICENSE" />
1413
</ItemGroup>
1514
<ItemGroup>
15+
<Compile Include="$(MSBuildThisFileDirectory)ITextReplacer.cs" />
1616
<Compile Include="$(MSBuildThisFileDirectory)SaveCommandPackage.cs" />
1717
<Compile Include="$(MSBuildThisFileDirectory)SaveEventHandler.cs" />
1818
</ItemGroup>

WhitespaceCleaner.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WhitespaceCleanerExtension"
66
EndProject
77
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Shared", "Shared\Shared.shproj", "{5DBA3B95-A4E9-4CA9-8EDB-D1CD707AF7BB}"
88
EndProject
9+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WhitespaceCleanerExtension2022", "WhitespaceCleanerExtension2022\WhitespaceCleanerExtension2022.csproj", "{2F77D666-4729-4CB5-95D7-A800BE80590F}"
10+
EndProject
911
Global
1012
GlobalSection(SharedMSBuildProjectFiles) = preSolution
13+
Shared\Shared.projitems*{2f77d666-4729-4cb5-95d7-a800be80590f}*SharedItemsImports = 4
1114
Shared\Shared.projitems*{3a5eacc9-1e83-4d1c-bc07-f76eb241eb0d}*SharedItemsImports = 4
1215
Shared\Shared.projitems*{5dba3b95-a4e9-4ca9-8edb-d1cd707af7bb}*SharedItemsImports = 13
1316
EndGlobalSection
@@ -20,6 +23,10 @@ Global
2023
{3A5EACC9-1E83-4D1C-BC07-F76EB241EB0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
2124
{3A5EACC9-1E83-4D1C-BC07-F76EB241EB0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
2225
{3A5EACC9-1E83-4D1C-BC07-F76EB241EB0D}.Release|Any CPU.Build.0 = Release|Any CPU
26+
{2F77D666-4729-4CB5-95D7-A800BE80590F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27+
{2F77D666-4729-4CB5-95D7-A800BE80590F}.Debug|Any CPU.Build.0 = Debug|Any CPU
28+
{2F77D666-4729-4CB5-95D7-A800BE80590F}.Release|Any CPU.ActiveCfg = Release|Any CPU
29+
{2F77D666-4729-4CB5-95D7-A800BE80590F}.Release|Any CPU.Build.0 = Release|Any CPU
2330
EndGlobalSection
2431
GlobalSection(SolutionProperties) = preSolution
2532
HideSolutionNode = FALSE

WhitespaceCleanerExtension/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@
2929
// You can specify all the values or you can default the Build and Revision Numbers
3030
// by using the '*' as shown below:
3131
// [assembly: AssemblyVersion("1.0.*")]
32-
[assembly: AssemblyVersion("1.0.0.0")]
33-
[assembly: AssemblyFileVersion("1.0.0.0")]
32+
[assembly: AssemblyVersion("1.0.0.4")]
33+
[assembly: AssemblyFileVersion("1.0.0.4")]
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using EnvDTE;
2+
using EnvDTE80;
3+
using Shared;
4+
5+
namespace WhitespaceCleanerExtension
6+
{
7+
public sealed class TextReplacer : ITextReplacer
8+
{
9+
private DTE2 _applicationObject;
10+
11+
public TextReplacer(DTE2 applicationObject)
12+
{
13+
_applicationObject = applicationObject;
14+
}
15+
16+
public void Replace(string whatRegex, string with, Document document)
17+
{
18+
_applicationObject.Find.FindReplace(vsFindAction.vsFindActionReplaceAll, whatRegex,
19+
(int)vsFindOptions.vsFindOptionsRegularExpression,
20+
with,
21+
vsFindTarget.vsFindTargetCurrentDocument, string.Empty, string.Empty,
22+
vsFindResultsLocation.vsFindResultsNone);
23+
}
24+
}
25+
}

WhitespaceCleanerExtension/WhitespaceCleanerExtension.csproj

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
<DebugType>full</DebugType>
4040
<Optimize>false</Optimize>
4141
<OutputPath>..\bin\Debug\</OutputPath>
42-
<DefineConstants>DEBUG;TRACE</DefineConstants>
42+
<DefineConstants>TRACE;DEBUG;VS2015</DefineConstants>
4343
<ErrorReport>prompt</ErrorReport>
4444
<WarningLevel>4</WarningLevel>
4545
<Prefer32Bit>false</Prefer32Bit>
@@ -49,17 +49,21 @@
4949
<DebugType>none</DebugType>
5050
<Optimize>true</Optimize>
5151
<OutputPath>..\bin\Release\</OutputPath>
52-
<DefineConstants>
53-
</DefineConstants>
52+
<DefineConstants>VS2015</DefineConstants>
5453
<ErrorReport>prompt</ErrorReport>
5554
<WarningLevel>4</WarningLevel>
5655
<Prefer32Bit>false</Prefer32Bit>
5756
<RunCodeAnalysis>false</RunCodeAnalysis>
5857
</PropertyGroup>
5958
<ItemGroup>
6059
<Compile Include="Properties\AssemblyInfo.cs" />
60+
<Compile Include="TextReplacer.cs" />
6161
</ItemGroup>
6262
<ItemGroup>
63+
<Content Include="..\LICENSE">
64+
<Link>LICENSE</Link>
65+
<IncludeInVSIX>true</IncludeInVSIX>
66+
</Content>
6367
<None Include="ExtensionKey.pfx" />
6468
<None Include="source.extension.vsixmanifest">
6569
<SubType>Designer</SubType>
@@ -72,6 +76,9 @@
7276
<PackageReference Include="envdte80">
7377
<Version>8.0.0</Version>
7478
</PackageReference>
79+
<PackageReference Include="Microsoft.VisualStudio.ComponentModelHost">
80+
<Version>14.0.25424</Version>
81+
</PackageReference>
7582
<PackageReference Include="Microsoft.VisualStudio.Shell.14.0">
7683
<Version>14.3.25407</Version>
7784
</PackageReference>

WhitespaceCleanerExtension/source.extension.vsixmanifest

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
33
<Metadata>
4-
<Identity Id="WhitespaceCleanerExtension.Krzysztof Rapacki.876ffc7a-66dc-4aa0-8c52-971819604b60" Version="1.0.3" Language="en-US" Publisher="Krzysztof Rapacki" />
4+
<Identity Id="WhitespaceCleanerExtension.Krzysztof Rapacki.876ffc7a-66dc-4aa0-8c52-971819604b60" Version="1.0.4" Language="en-US" Publisher="Krzysztof Rapacki" />
55
<DisplayName>WhitespaceCleanerExtension</DisplayName>
66
<Description xml:space="preserve">WhitespaceCleaner Extension for Visual Studio 2015 and newer
77

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
// General Information about an assembly is controlled through the following
6+
// set of attributes. Change these attribute values to modify the information
7+
// associated with an assembly.
8+
[assembly: AssemblyTitle("WhitespaceCleanerExtension2022")]
9+
[assembly: AssemblyDescription("")]
10+
[assembly: AssemblyConfiguration("")]
11+
[assembly: AssemblyCompany("")]
12+
[assembly: AssemblyProduct("WhitespaceCleanerExtension2022")]
13+
[assembly: AssemblyCopyright("shauren.dev@gmail.com")]
14+
[assembly: AssemblyTrademark("")]
15+
[assembly: AssemblyCulture("")]
16+
17+
// Setting ComVisible to false makes the types in this assembly not visible
18+
// to COM components. If you need to access a type in this assembly from
19+
// COM, set the ComVisible attribute to true on that type.
20+
[assembly: ComVisible(true)]
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 Build and Revision Numbers
30+
// by using the '*' as shown below:
31+
// [assembly: AssemblyVersion("1.0.*")]
32+
[assembly: AssemblyVersion("1.0.0.4")]
33+
[assembly: AssemblyFileVersion("1.0.0.4")]
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using EnvDTE;
2+
using Microsoft.VisualStudio.Editor;
3+
using Microsoft.VisualStudio.Shell;
4+
using Microsoft.VisualStudio.Text;
5+
using Microsoft.VisualStudio.Text.Operations;
6+
using Microsoft.VisualStudio.TextManager.Interop;
7+
using Shared;
8+
using System;
9+
using WhitespaceCleanerExtension;
10+
11+
namespace WhitespaceCleanerExtension2022
12+
{
13+
public sealed class TextReplacer : ITextReplacer
14+
{
15+
public void Replace(string whatRegex, string with, Document document)
16+
{
17+
ThreadHelper.ThrowIfNotOnUIThread();
18+
19+
if (TryGetTextBufferAt(document.FullName, out var textBuffer))
20+
{
21+
var findService = SaveCommandPackage.Instance.ComponentModel.GetService<IFindService>();
22+
23+
var finderFactory = findService.CreateFinderFactory(whatRegex, with, FindOptions.UseRegularExpressions);
24+
var finder = finderFactory.Create(textBuffer.CurrentSnapshot);
25+
26+
using (var edit = textBuffer.CreateEdit())
27+
{
28+
foreach (var match in finder.FindForReplaceAll())
29+
edit.Replace(match.Match, match.Replace);
30+
31+
edit.Apply();
32+
}
33+
}
34+
}
35+
36+
private static bool TryGetTextBufferAt(string filePath, out ITextBuffer textBuffer)
37+
{
38+
if (VsShellUtilities.IsDocumentOpen(SaveCommandPackage.Instance, filePath, Guid.Empty, out var _, out var _, out var windowFrame))
39+
{
40+
IVsTextView view = VsShellUtilities.GetTextView(windowFrame);
41+
if (view.GetBuffer(out var lines) == 0)
42+
{
43+
if (lines is IVsTextBuffer buffer)
44+
{
45+
var editorAdapterFactoryService = SaveCommandPackage.Instance.ComponentModel.GetService<IVsEditorAdaptersFactoryService>();
46+
textBuffer = editorAdapterFactoryService.GetDataBuffer(buffer);
47+
return true;
48+
}
49+
}
50+
}
51+
52+
textBuffer = null;
53+
return false;
54+
}
55+
}
56+
}

0 commit comments

Comments
 (0)