This was only tested with Visual Studio 2015 Community, but from what I could see in MSDN, the interfaces in use are also available in previous versions of VS.
Details
Diff Detail
Event Timeline
This is definitely a nice to have, it would be nice in the future to have an option that only reformatted the changed lines only, nice idea though
I also don't know anything about how this plugin works, I just build it :) I'm hoping Manuel can take a look.
I'll need to try to build / install it. I'll take a couple of days, I'm
currently swamped. Hope that's ok.
It's not falling into oblivion, but it's not going to happen before next
week, unless somebody else picks the review up.
I tried downloaded the diff and tried this, I met a couple of issues with applying the patch due to line endings in .cs file and csproj (but that could be my fault) - (I was using 2013 to build clang library and clang format)
I also had to up the version because I had previously installed a 3.8.0 version of the extension from the trunk, but I suspect that an uninstall/reinstall would have solved that.
my csproj needed me to re-add the ComponentModel reference (which I think requires the VS 2010 SDK which I'm not sure was required before)
So my line in the CS proj ended up being a little different (Version Public Key etc..)
<Reference Include="Microsoft.VisualStudio.ComponentModelHost, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
But it seem to work well in the version I tried (namely VS2013 Premium and VS2015 Enterprise)
but VS2010 did not work for me, it installed ok, but initially it was disabled by default, (not sure why), going to the extension manager and enabling and restarting devenv didn't make it work.
Very nice feature for forcing the change across a file.
Actually the 2010 failure may be my fault, I only have Visual C# installed for VS2010 and not the C++ compilers, as such it doesn't seem to understand C/C++ as the content type
if (!textBuffer.ContentType.IsOfType("C/C++"))
is failing because the ContentType is "plaintext", my guess is unless you install the C++ parts of VS it doesn't add the "File Type" or C/C++ and hence it can't detect that a .h file is anything other than plaintext, let me recheck VS2010 support after adding in the C++ support
Having installed the VS2010 C++ compilers the format on save does work BUT... you have to disable and enable the setting in tools->options->LLVM/Clang first, its as if the setting is NOT read on startup
Well, the format on save setting is disabled by default, do you mean you had to enable it twice? Or you had it enabled without the C++ development tools, and after the installation you had to disable and enable it again?
I went back and retested VS2010, VS2013 and VS2015. so in all cases I
- start Visual studio
- open a .h file (with incorrect style) - (via the recent file menu)
- make a minor edit of whitespace
- hit save file
In allcases it does NOT reformat the file
Now do
Tools->Options->LLVM/CLang
The setting is currently True for reformat on save
Turn it to False press OK
Tools->Options->LLVM/CLang
The setting is now False
Turn it to True press ok
now return to the file and press save
The file will now be reformatted.
After this point any subsequent edits and save will reformat the page, perhaps others can try.
After a little digging, the problem is based on the fact that the extension doesn't load until we use it, so the nBeforeSave won't fire, so after doing Ctrl-R,Ctrl-F once it will work
This exact same problem is mentioned here
http://schmalls.com/2015/01/19/adventures-in-visual-studio-extension-development-part-2
Quote:
So, we implement all of the event functionality and try out the extension. The first time we save a file, no arranging happens. If we run the arrange command from the menu item, it runs fine and then subsequent file saves also get arranged. That seems weird. It turns out that Visual Studio only loads the extensions as needed. We have to add another one of our provide attributes, ProvideAutoLoadAttribute, to the VSPackage class to get the extension to load sooner.
[ProvideAutoLoad("ADFC4E64-0397-11D1-9F4E-00A0C911004F")]
I found the GUID to pass to this from a blog post I found to get the extension to load as soon as possible. After further research on MSDN, it turns out to be the same as the UIContextGuids80.NoSolution field. The remarks seem to indicate that it would only become active when a solution is closed or Visual Studio is started with the "Show Empty Environment" option set in startup; however, it looks like it happens when Visual Studio is started no matter the value of the startup setting. There are other useful contexts in the UIContextGuids80 Class. The attribute can be rewritten as shown.
Update the diff with the ProvideAutoLoad attribute.
Thanks @MyDeveloperDay for the review and tips!
+aaron for windows specific knowledge
+rnk to see whether we can get a reviewer with more MS VS experience (perhaps somebody from MS :)
My main concern is that this adds a lot of things that I have no idea whether they are needed or whether there are simpler variants.
LGTM, but someone who understands VS plugins better should give the final sign-off.
tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs | ||
---|---|---|
441 | Cute. :-P |
Ping. rnk, do you have a moment to look this over? My C#-fu is a bit rusty, but this seems reasonable to me.
tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs | ||
---|---|---|
195 | I did more tests on my side, and apparently this line does not work on VS2012, componentModel is null. I don't know at all why and how to fix it, and it works fine starting with VS2013. |
tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs | ||
---|---|---|
195 | Our minimum supported MSVC version for development is 2013. Do we document supported versions for clang-format? Do we want to support versions older than the development version we're on? |
tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs | ||
---|---|---|
195 | The manifest claims support for 2010 and later. I usually test with 2012 when I build the weekly snapshot. Our clang-cl VS integration also tries to support 2010 and later, so I think it would be nice if the clang-format plugin does too. |
tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs | ||
---|---|---|
195 | Thank you for the information! That sounds good to me. Then I think berenm's issue should be resolved if possible. |
Add debugging ideas.
tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs | ||
---|---|---|
195 | I haven't had time to dig into this too much, but here's an idea: You're only getting the IComponentModel to get the IVsEditorAdaptersFactoryService, which in turn is only used to get at the document's text buffer in OnBeforeSave. It seems to me there *should* be a more straightforward way to do that without involving COM interop. Unfortunately, I don't know what it is :-) Google around, and this article describes something similar: I don't know if maybe you have the wrong RunningDocumentTable service, it seems very COM-styled, compared to the one used in the article. |
- Patch rebased on trunk
- Small cleanups in the RunningDocumentTable usage
- Successfully tested on VS >= 2012
tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs | ||
---|---|---|
195 | In this blog post, they go through another interface to modify the file contents. I wanted to re-use the FormatTextBuffer method, that was operating on an ITextBuffer, and getting this ITextBuffer from a IDontKnowWhatDocument requires to go through this ComponentModel thing. I did some small changes and some new quick testing and I think everything now works on VS2012 and later. I haven't tested the plugin on VS2010 though. | |
441 | Sorry I dropped this part :'( |
I think we'll want somebody to find out whether there are simpler ways to
implement this.
For information, I just tested the current diff under Visual Studio 2010 SP1 and everything looks fine as well.
Actually, the main issue that I see is the difficulty to build the plugin itself. The project does not build out-of-the-box on VS2013, and I had to change the assembly references by hand.
I have a patch to get the required assemblies in a more portable way using nuget packages, but I didn't want to include that in this revision. I'll open a separate one if that's useful.
Just in case someone is interested. I figured out a hack with VCMD that actually does the job.
using EnvDTE; using EnvDTE80; public class E : VisualCommanderExt.IExtension { public void SetSite(EnvDTE80.DTE2 DTE_, Microsoft.VisualStudio.Shell.Package package) { DTE = DTE_; events = DTE.Events; documentEvents = events.DocumentEvents; documentEvents.DocumentSaved += OnDocumentSaved; } public void Close() { documentEvents.DocumentSaved -= OnDocumentSaved; } private void OnDocumentSaved(EnvDTE.Document doc) { if(doc.Language == "C/C++") { DTE.ExecuteCommand("Edit.SelectAll"); DTE.ExecuteCommand("Tools.ClangFormat"); DTE.ExecuteCommand("View.NavigateBackward"); } } private EnvDTE80.DTE2 DTE; private EnvDTE.Events events; private EnvDTE.DocumentEvents documentEvents; }
This will invoke clang format whenever a c++ related file is saved
A slightly improved version of @jasjuang code.
Restores current selection and really saves if modified.
Also works when saving all documents.
using EnvDTE; using EnvDTE80; public class E : VisualCommanderExt.IExtension { public void SetSite(EnvDTE80.DTE2 DTE_, Microsoft.VisualStudio.Shell.Package package) { DTE = DTE_; events = DTE.Events; documentEvents = events.DocumentEvents; documentEvents.DocumentSaved += OnDocumentSaved; } public void Close() { documentEvents.DocumentSaved -= OnDocumentSaved; } private void OnDocumentSaved(EnvDTE.Document doc) { if (doc.Language == "C/C++") { Document current = DTE.ActiveDocument; doc.Activate(); TextSelection selection = doc.Selection as TextSelection; int begin = selection.TopPoint.AbsoluteCharOffset; int end = selection.BottomPoint.AbsoluteCharOffset; selection.SelectAll(); DTE.ExecuteCommand("Tools.ClangFormatSelection"); if (!doc.Saved) { doc.Save(); } // As the old selection may not be selectable, be cautious. try { selection.MoveToAbsoluteOffset(begin, false); } catch {} try { selection.MoveToAbsoluteOffset(end, true); } catch {} current.Activate(); } } private EnvDTE80.DTE2 DTE; private EnvDTE.Events events; private EnvDTE.DocumentEvents documentEvents; }
Format on save was implemented by D29221.
What's the new functionality in the reformat implementation?
Always trigger a (re)format even if there are no changes? Probably not a good idea.
I did more tests on my side, and apparently this line does not work on VS2012, componentModel is null. I don't know at all why and how to fix it, and it works fine starting with VS2013.