LineEndingsUnifier
LineEndingsUnifier copied to clipboard
(Incomplete) Refactor to support VS2022
Ref #38
This PR is intended to update LineEndingsUnifier to work with Visual Studio 2022, which requires 64 bit extensions and updated build tools. The instructions here and the example here informed the changes made here, and I have kept all other changes as minimal as I could along the way.
This now successfully produces a perfectly good Line Endings Unifier 2022
extension, testable, installable, and fully working.
However, somewhere along the way something seems to have got messed up in the dependencies for the original Line Endings Unifier
project, which builds without error but crashes on my local machine when it tries to load Microsoft.VisualStudio.Shell.15.0, Version=17.0.0.0
. Relevant excerpt from ActivityLog.xml
:
<entry>
<record>3454</record>
<time>2021/11/11 10:31:08.209</time>
<type>Error</type>
<source>VisualStudio</source>
<description>CreateInstance failed for package [LineEndingsUnifierAsyncPackage]Source: 'mscorlib' Description: Could not load file or assembly 'Microsoft.VisualStudio.Shell.15.0, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.VisualStudio.Shell.15.0, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
File name: 'Microsoft.VisualStudio.Shell.15.0, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
 at System.Reflection.RuntimeAssembly.GetType(RuntimeAssembly assembly, String name, Boolean throwOnError, Boolean ignoreCase, ObjectHandleOnStack type)
 at System.Reflection.RuntimeAssembly.GetType(String name, Boolean throwOnError, Boolean ignoreCase)
 at System.Activator.CreateInstanceFromInternal(String assemblyFile, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, Evidence securityInfo)
 at System.AppDomain.CreateInstanceFrom(String assemblyFile, String typeName)

WRN: Assembly binding logging is turned OFF.
To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.
Note: There is some performance penalty associated with assembly bind failure logging.
To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].
</description>
<guid>{1CE34AED-D80B-4E02-AFC9-BD0BD3848443}</guid>
<hr>80004005 - E_FAIL</hr>
<errorinfo></errorinfo>
</entry>
I've been fiddling around with this for a while, including trying to downgrade various dependencies (ref this list for some guidance), without success. I managed to find one other mention of the same problem in an unhelpfully closed issue at https://github.com/microsoft/VSExtensibility/issues/24 which really didn't illuminate the issue at all.
I'm afraid I'm a bit stumped now. 🤷♂️ I have no experience with developing extensions (I decided to do this as a learning exercise, and since I saw that #38 had gone unanswered for some time), so if anybody knows what needs to be done to fix the issue with the <=VS2019 project, I'd love some advice/guidance.
@jwfxpr The main point of having separate projects for 2022+ and <=2019 is to have the two target different versions of the SDK. The <=2019 version cannot use the Microsoft.VisualStudio.SDK 17.0 package, and needs to use the older reference assemblies corresponding to the assemblies available in the lowest supported version. It also should target a lower version of .NET Framework, matching what the reference assemblies target.
Have a look at https://github.com/Naine/LineEndingsUnifier/tree/vs2022, where I've undertaken similar work.
As an aside, the current master in this repo has broken compatibility with 2015 and earlier in the latest PR that supports async loading. My branch also fixes support for 2015 but drops support for 2012-2013, since these versions do not have AsyncPackage. Because the "Microsoft.VisualStudio.SDK" metapackage only exists for 2017 onward, my 2015-2019 project does not use it, but has still been modernized to get everything from nuget.
@Naine seems like you've got the VS2022 refactor sorted much more capably than I did in my branch, if you'd like to open a PR here I'm happy to close mine. Alternatively if you publish your version, please let us (all) know, as I'm not sure if @jakubbielawa is actively maintaining this these days. 😊
I'm happy to open a PR here but I might not get to it for a few days. I have a bunch of unrelated changes on that branch that I should separate out into separate PRs.
I was not able to properly build @Naine's PR, at least not in Visual Studio 2022. The build tools were outdated and I had big issues with the reference assemblies.
So I decided to build further on your fork and and as a result successfully migrated to the <PackageReference>
format, updated to the recommended metapackage and got rid of a bunch of analyzer errors.
Feel free to build it locally or publish it to the markeplace. Take note that this package only works with VS2022.
https://github.com/silkfire/LineEndingsUnifier
I was not able to properly build @Naine's PR, at least not in Visual Studio 2022. The build tools were outdated and I had big issues with the reference assemblies.
So I decided to build further on your fork and and as a result successfully migrated to the
<PackageReference>
format, updated to the recommended metapackage and got rid of a bunch of analyzer errors.Feel free to build it locally or publish it to the markeplace. Take note that this package only works with VS2022.
https://github.com/silkfire/LineEndingsUnifier
Thank you for sharing! Any chances of uploading a release, so others can avoid the hassle of setting up the environment for making extension builds?
I was not able to properly build @Naine's PR, at least not in Visual Studio 2022. The build tools were outdated and I had big issues with the reference assemblies. So I decided to build further on your fork and and as a result successfully migrated to the
<PackageReference>
format, updated to the recommended metapackage and got rid of a bunch of analyzer errors. Feel free to build it locally or publish it to the markeplace. Take note that this package only works with VS2022. https://github.com/silkfire/LineEndingsUnifierThank you for sharing! Any chances of uploading a release, so others can avoid the hassle of setting up the environment for making extension builds?
Here you go.
Here you go.
You're too good man, this is quite a time saver. Much appreciated 🙏
Sadly, it doesn't work at the moment. After some debugging, I found out that calling Ide.Documents
in GetDocumentFromDocCookie()
throws the exception The data necessary to complete this operation is not yet available. (Exception from HRESULT: 0x8000000A)
, on THIS line.
I found THIS report about this issue and it looks like a bug in Visual Studio. I've commented on the report, that we experience the same issue, mentioning your fork, hope they fix it soon.
This bug seems to come with Visual Studio 17.7.0, that came out this August. Tried 17.8 beta version - still broken. I've installed 17.6.6 and it works fine there. Problem is, if you are using community edition, the VS Installer doesn't allow you to downgrade. You can install specific versions from HERE, but only Enterprise and Professionals are listed :( So now I'm using a trial Professional until this gets fixed. Then I'll just go back to 2019 :(
Also reported in the VS community: https://developercommunity.visualstudio.com/t/DTE2Documents-Exception-0x8000000A/10457457 Feel free to up-vote.
So many years passed and we're still arguing how to write new-line endings! DAMN!
@NibbleByte Sorry to hear that the forked extension didn't work for you. I'm running the extension in the latest VS as of writing this (v17.7.3) and don't have the issue you're describing. But I was interested to see whether I could reproduce the problem, and while debugging it in the experimental instance of VS, I did encounter the same exception as you.
I only got the exception the first time I used the Unify Line Endings command, though. Perhaps the property isn't initialized internally the first time it's being accessed. Is this something that is still bothering you even after subsequent runs of the command?
Well, this is odd. For me the exception keeps happening every time I try to save in the debugged VS.
If I run normal VS with the plugin, trying to save doesn't fix the endings. I tried enabling the "Write Report to the Output Window" and nothing gets logged (while it does in previous versions). I have a freshly installed VS 2022, no other plugins, except the Unity stuff.
I noticed that after debugged VS instance start it takes quite some time for the InitializeAsync()
to run and setup stuff. At that point, the Ide.Documents
still throws this exception. Calling Ide.ActiveDocumment
works fine. Tried removing the cache in the Ide
property, so it gets fetched every time, nothing changed, so I don't think "we're calling it at the wrong time". :(
These are my settings:
I see what you mean now. I tried to bump the dependencies used in the project to their latest version but alas that didn't help - the exception was still there. Let's wait and see what comes out of MSFT's investigation, hopefully it's just a short-lived bug in this particular version of VS.
@NibbleByte Just an update. It seems like the issue has been identified and resolved and the fix should come out in a future Visual Studio release (hopefully soon).
In the meantime I discovered that LEU was using text replacement APIs which are deprecated as of Visual Studio 2022; in response to this I decided to migrate to the APIs using the IFinder
interface. These are also used by Find in Files in Visual Studio and is very fast. As a result I've also scrapped any functionality that relies on Regex
which improved performance of the unifying process considerably. This wasn't easy as there's zero documentation on how to do this but with some trial and error I was successful in the end.
Since these changes, I don't seem to be getting the exception The data necessary to complete this operation is not yet available. (Exception from HRESULT: 0x8000000A)
anymore.
Would you be able to try this new version and see if works for you?
This sounds great :)
I've downloaded the plugin, installed it to my community edition (the same version) and it still doesn't work. I've made sure the settings are as in the screenshot above. Nothing in the output window as well.
I've re-downloaded your repo, ran it in debug and the exception still happens :(
Strange that you're getting a bug I'm no longer getting 😆
Anyway, I did some further tinkering and at last, I found a workaround to the problem that simply involves avoiding to iterate over the Documents
property in the first place and operating via the ITextBuffer
interface instead.
Let me know if this version works better for you.
This does seem to work, but it has issues. :(
When you save, it marks all lines as "edited and saved" on the left of the document - the green bar here. Usually it only stretches to lines that were edited this session.
In addition, it adds it as an undo operation that gets in the way and feels weird.
Every time I save, it scrolls down one line (even if there are no changes to the document).
Is it not because actually all the lines were replaced with the selected line ending? So I would believe Git detects line changes on every line.
How would it work without an undo operation? The procedure operates on the document by using an Replace action. Naturally this is added to the Undo history of VS. And this is also using the modern edit APIs.
As to the view scrolling down, it has to do with how text views work. I'll see if I can make it revert to the previous position, but documentation is extremely scarce.
You're right, undo worked the same way before.
The green lines replaced - it highlights always all the lines, not just the ones that line endings were changed, including when there are no changes to save in the document. The original plugin just modified the ones with the wrong line ending, tested on VS 2019. Maybe don't modify the document unless needed to?
I wasn't able to reproduce the green lines in my environment, for some reason VS doesn't see switching of newlines as an actual change.
On the other hand I know why all lines look like they've been edited, as the Find API is looking for any type of newline and replaces them all, even when it's with the same value. I'll see if I can tweak the logic there to prevent that.
Could you try out this new version and see how it works for you?
I think now it's perfect. Thanks a lot :)
@NibbleByte Not that you might need it anymore, but just wanted to let you know that a fix for the DTE2.Documents
enumeration bug has been shipped in the latest release of VS, 17.7.5 - released today.
The october version doesn't load on my VS 2022 Community edition:
SetSite failed for package [LineEndingsUnifierAsyncPackage]Source: 'LineEndingsUnifier' Description: Method not found: 'Microsoft.VisualStudio.Threading.JoinableTaskFactory Microsoft.VisualStudio.Shell.AsyncPackage.get_JoinableTaskFactory()'. System.MissingMethodException: Method not found: 'Microsoft.VisualStudio.Threading.JoinableTaskFactory Microsoft.VisualStudio.Shell.AsyncPackage.get_JoinableTaskFactory()'. at LineEndingsUnifier.LineEndingsUnifierAsyncPackage.<InitializeAsync>d__16.MoveNext() at System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start[TStateMachine](TStateMachine& stateMachine) at LineEndingsUnifier.LineEndingsUnifierAsyncPackage.InitializeAsync(CancellationToken cancellationToken, IProgress`1 progress) at Microsoft.VisualStudio.Shell.AsyncPackage.<>c__DisplayClass21_0.<<Microsoft-VisualStudio-Shell-Interop-IAsyncLoadablePackageInitialize-Initialize>b__1>d.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Microsoft.VisualStudio.Services.VsTask.RethrowException(AggregateException e) at Microsoft.VisualStudio.Services.VsTask.InternalGetResult(Boolean ignoreUIThreadCheck)