Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Fixed: removing trailing workspaces did not work on document save #5

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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 0 additions & 52 deletions RemoveTrailingWhitespaces/RemoveTrailingWhitespaces.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -62,58 +62,6 @@
<WarningLevel>4</WarningLevel>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<ItemGroup>
<Reference Include="envdte100, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<EmbedInteropTypes>True</EmbedInteropTypes>
</Reference>
<Reference Include="envdte80, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<EmbedInteropTypes>True</EmbedInteropTypes>
</Reference>
<Reference Include="envdte90, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<EmbedInteropTypes>True</EmbedInteropTypes>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.VisualStudio.OLE.Interop" />
<Reference Include="Microsoft.VisualStudio.Shell.Immutable.10.0" />
<Reference Include="Microsoft.VisualStudio.Shell.Immutable.11.0" />
<Reference Include="Microsoft.VisualStudio.Shell.Immutable.12.0" />
<Reference Include="Microsoft.VisualStudio.Shell.Interop, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="Microsoft.VisualStudio.Shell.Interop.8.0, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="Microsoft.VisualStudio.Shell.Interop.9.0, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="Microsoft.VisualStudio.TextManager.Interop, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="Microsoft.VisualStudio.TextManager.Interop.12.0, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="netstandard" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.Data.Linq" />
<Reference Include="System.Design" />
<Reference Include="System.Drawing" />
<Reference Include="System.Drawing.Design" />
<Reference Include="System.Management" />
<Reference Include="System.Numerics" />
<Reference Include="System.Transactions" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml" />
<Reference Include="UIAutomationProvider" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<COMReference Include="stdole">
<Guid>{00020430-0000-0000-C000-000000000046}</Guid>
<VersionMajor>2</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>primary</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>False</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup>
<Compile Include="Guids.cs" />
<Compile Include="PkcCmdIDList.cs" />
Expand Down
93 changes: 57 additions & 36 deletions RemoveTrailingWhitespaces/RemoveTrailingWhitespacesPackage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,7 @@ public int OnBeforeSave(uint docCookie)
{
if (_pkg.RemoveOnSave())
{
RunningDocumentInfo runningDocumentInfo = new RunningDocumentInfo(_pkg.rdt, docCookie);
EnvDTE.Document document = _pkg.dte.Documents.OfType<EnvDTE.Document>().SingleOrDefault(x => x.FullName == runningDocumentInfo.Moniker);
if (document == null)
return VSConstants.S_OK;
if (document.Object("TextDocument") is TextDocument textDoc)
_pkg.RemoveTrailingWhiteSpaces(textDoc);
_pkg.RemoveTrailingWhiteSpaces(docCookie);
}
return VSConstants.S_OK;
}
Expand Down Expand Up @@ -100,6 +95,11 @@ public int OnBeforeLastDocumentUnlock(uint docCookie, uint dwRDTLockType, uint d
[ProvideOptionPage(typeof(OptionsPage), "Remove Trailing Whitespaces", "Options", 1000, 1001, true)]
[ProvideMenuResource("Menus.ctmenu", 1)]
[ProvideAutoLoad("{f1536ef8-92ec-443c-9ed7-fdadf150da82}", PackageAutoLoadFlags.BackgroundLoad)]
[ProvideUIContextRule("{f1536ef8-92ec-443c-9ed7-fdadf150da82}",
name: "Trigger for autoloading the RemoveTrailingWhitespaces extension",
expression: "DocOpen",
termNames: new[] { "DocOpen" },
termValues: new[] { "HierSingleSelectionName:.$" })]
public sealed class RemoveTrailingWhitespacesPackage : AsyncPackage
{
/// <summary>
Expand All @@ -118,7 +118,7 @@ public RemoveTrailingWhitespacesPackage()
/////////////////////////////////////////////////////////////////////////////
// Overridden Package Implementation
#region Package Members
public DTE dte;
public _DTE dte;
public IVsRunningDocumentTable rdt;
public IFindService findService;
private uint rdtCookie;
Expand All @@ -130,7 +130,7 @@ public RemoveTrailingWhitespacesPackage()
/// </summary>
protected override async Task InitializeAsync(System.Threading.CancellationToken cancellationToken, IProgress<ServiceProgressData> progress)
{
dte = await GetServiceAsync(typeof(EnvDTE.DTE)) as EnvDTE.DTE;
dte = await GetServiceAsync(typeof(_DTE)) as _DTE;
Assumes.Present(dte);
rdt = await GetServiceAsync(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable;
Assumes.Present(rdt);
Expand Down Expand Up @@ -186,7 +186,9 @@ private void OnRemoveTrailingWhitespacesPressed(object sender, EventArgs e)
{
if (dte.ActiveDocument == null) return;
if (!(dte.ActiveDocument.Object() is TextDocument textDocument)) return;
RemoveTrailingWhiteSpaces(textDocument);

uint docCookie = GetDocCookie(dte.ActiveDocument.FullName);
RemoveTrailingWhiteSpaces(docCookie);
}

private IFinder GetFinder(string findWhat, string replacement, ITextBuffer textBuffer)
Expand All @@ -196,33 +198,12 @@ private IFinder GetFinder(string findWhat, string replacement, ITextBuffer textB
return finderFactory.Create(textBuffer.CurrentSnapshot);
}

internal static ITextBuffer GettextBufferAt(TextDocument textDocument, IComponentModel componentModel, IServiceProvider serviceProvider)
internal static ITextBuffer GettextBufferAt(IVsTextBuffer textBuffer, IComponentModel componentModel)
{
ThreadHelper.ThrowIfNotOnUIThread();
IVsWindowFrame windowFrame;
if (VsShellUtilities.IsDocumentOpen(
serviceProvider,
textDocument.Parent.FullName,
Guid.Empty,
out var _,
out var _,
out windowFrame))
{
IVsTextView view = VsShellUtilities.GetTextView(windowFrame);
IVsTextLines lines;
if (view.GetBuffer(out lines) == 0)
{
var buffer = lines as IVsTextBuffer;
if (buffer != null)
{
var editorAdapterFactoryService = componentModel.GetService<IVsEditorAdaptersFactoryService>();
return editorAdapterFactoryService.GetDataBuffer(buffer);
}
}
}

return null;
var editorAdapterFactoryService = componentModel.GetService<IVsEditorAdaptersFactoryService>();
return editorAdapterFactoryService.GetDataBuffer(textBuffer);
}

private static void ReplaceAll(ITextBuffer textBuffer, IEnumerable<FinderReplacement> replacements)
{
if (replacements.Any())
Expand All @@ -239,9 +220,49 @@ private static void ReplaceAll(ITextBuffer textBuffer, IEnumerable<FinderReplace
}
}

public void RemoveTrailingWhiteSpaces(TextDocument textDocument)
public uint GetDocCookie(string docFullName)
{
var textBuffer = GettextBufferAt(textDocument, componentModel, this);
IVsHierarchy hierarchy = null;
uint itemid = 0;
IntPtr docDataUnk = IntPtr.Zero;
uint lockCookie = 0;

IEnumRunningDocuments allDocs;
if (VSConstants.S_OK != rdt.GetRunningDocumentsEnum(out allDocs))
return 0;
uint[] array = new uint[1];
uint pceltFetched = 0;
while (VSConstants.S_OK == allDocs.Next(1, array, out pceltFetched) && (pceltFetched == 1))
{
uint pgrfRDTFlags;
uint pdwReadLocks;
uint pdwEditLocks;
string pbstrMkDocument;
IVsHierarchy ppHier;
uint pitemid;
IntPtr ppunkDocData;
rdt.GetDocumentInfo(array[0], out pgrfRDTFlags, out pdwReadLocks, out pdwEditLocks, out pbstrMkDocument, out ppHier, out pitemid, out ppunkDocData);
if (pbstrMkDocument == docFullName)
return array[0];
}

return 0;
}

public void RemoveTrailingWhiteSpaces(uint docCookie)
{
RunningDocumentInfo runningDocumentInfo = new RunningDocumentInfo(rdt, docCookie);

IVsHierarchy hierarchy = null;
uint itemid = 0;
IntPtr docDataUnk = IntPtr.Zero;
uint lockCookie = 0;

int hr = rdt.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_ReadLock, runningDocumentInfo.Moniker, out hierarchy, out itemid, out docDataUnk, out lockCookie);
if (hr != VSConstants.S_OK || !(Marshal.GetUniqueObjectForIUnknown(docDataUnk) is IVsTextBuffer vsTextBuffer))
return;

var textBuffer = GettextBufferAt(vsTextBuffer, componentModel);
ReplaceAll(textBuffer, GetFinder("[^\\S\\r\\n]+(?=\\r?$)", "", textBuffer).FindForReplaceAll());
}

Expand Down
2 changes: 1 addition & 1 deletion RemoveTrailingWhitespaces/source.extension.vsixmanifest
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<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">
<Metadata>
<Identity Id="22c372db-a793-4294-9fdb-83228aaf2a23" Version="1.05" Language="en-US" Publisher="Predelnik" />
<Identity Id="22c372db-a793-4294-9fdb-83228aaf2a23" Version="1.06" Language="en-US" Publisher="Predelnik" />
<DisplayName>RemoveTrailingWhitespaces</DisplayName>
<Description>Trailing whitespace removal tool. Removes either manually or on file save.</Description>
<License>LICENSE.txt</License>
Expand Down