11 comments
Comment actions Permalink

Take a look at the AgentSmith source in the R#6.1 branch. This is pretty much exactly what you're trying to do.

http://code.google.com/p/agentsmithplugin/source/browse/#svn%2Fbranches%2FR%236.1%2Fsrc%2FAgentSmith%2FComments%2FReflow

0
Comment actions Permalink

Thank you very much! :)

0
Comment actions Permalink

Also worth noting that the current Agent Smith beta may actually do what you were trying to write a plugin for...

0
Comment actions Permalink

The question is whether it will have the same level of customization.

I can't just copy/paste the code due to abstractions of the API there and permissions of the authors.

Can you please give me a small example based on the code I posted ? hopefully it's not much to ask. :)

0
Comment actions Permalink

The two interfaces that you're most interested in are:

IDocCommentBlockNode
IDocCommentBlockOwnerNode


The owner node is an item in the document tree that can own a comment. Alas pretty much the only way to work out what to do in the ReSharper API is to use Reflector or DotPeek to analyse derived types. If you look at the derived types on IDocCommentBlockOwnerNode then it's basically types, type members and enums and enum members.

From the "Process" method of your cleanup code, you can search through the current file and find things that could own doc comments by doing:


            IFile file = sourceFile.GetPsiFile<CSharpLanguage>();



            file.GetPsiServices().PsiManager.DoTransaction(
                () =>
                {
                    using (_shellLocks.UsingWriteLock())
                        file.ProcessChildren<IDocCommentBlockOwnerNode>(x => MyFunctionWhichProcessesOwners(x));
                },
                "My Cleanup Process Name");


...

public void MyFunctionWhichProcessesOwners(IDocCommentBlockOwnerNode owner) { ... }




Now your function will be called for every doc comment owner in the file. Once you've got the owner then you can call owner.GetDocCommentBlockNode() to get the actual comment (or null if there is no comment).

There are several ways you can then process the comments:

- Via XML
- Process the raw comment lines.

The first one is easy, you just call GetXML(null) on the comment block and you'll get back either an XML node containing the xml parsed comment text or null if the xml is malformed. This last part is the trick - GetXML only works if the comment is reasonably well constructed.

The second one is slightly trickier. You can iterate over the IDocCommentNodes (lines of the comment block) within the comment block by looking at the FirstChild of the IDocCommentBlockNode (to get the frst IDocCommentNode) and then calling NextSibling on that to go through the various lines (note the IDocCommentNode is a CSharp only construct - no idea how it works in VB).

Each IDocCommentNode has a CommentText property which will give you the text for that line.

Once you have applied whatever your logic is to transform/generate your new comment text, you need to generate a new IDocCommentBlockNode from it. You can do this in two ways:

- First (and easiest) is to create a new factory and use it to create the block node:


            CSharpElementFactory factory = CSharpElementFactory.GetInstance(owner.GetPsiModule());

            IDocCommentBlockNode comment = factory.CreateDocCommentBlock(newCommentText);


  Unfortunately ReSharper feels the need to mess around with the whitespace in your text if you do it this way (empty lines are removed). The up side is that the text you pass only needs to be the actual content. ReSharper will add the /// and whitespace.



- Second way (which avoids the issues with whitespace) is to ask the factory to create a whole new code element with the given comment and then steal the block node that that created. You can see this in the AgentSmith code in the "SetDocComment" function in CommentReflowAction.cs. Note that, if you use this approach, you literally get what you asked for so you need to fully construct all the comment plumbiing.



Once you have the IDocCommentBlockNode then you can call SetDocCommentBlockNode on the IDocCommentBlockOwnerNode to actually apply the new comment.



So, the MyFunctionWhichProcessesOwners should look something like (completely untested :)) :


public void MyFunctionWhichProcessesOwners(IDocCommentBlockOwnerNode owner)
{
     IDocCommentBlockNode oldComment = owner.GetDocCommentBlockNode();

     // Get the XML
     XmlNode memberXmlNode = oldComment.GetXML(null);
     XmlElement memberElement = memberXmlNode as XmlElement;

     // Get the "Summary" text.
     XmlNodeList summaryNodes = memberElement.GetElementsByTagName("summary", "");
     if (summaryNodes.Count == 0) return;
     XmlNode summaryNode = summaryNodes[0];
     string summaryText = summaryNode.InnerXML;

     // Make some modifications
     summaryNode.InnerXML = summaryText.Replace("hello", "hi");

     // Create the new comment block
     CSharpElementFactory factory = CSharpElementFactory.GetInstance(owner.GetPsiModule());
     IDocCommentBlockNode comment = factory.CreateDocCommentBlock(memberElement.InnerXML);

     // And update the comment on the owner
     owner.SetDocCommentBlockNode(comment);
}



Hope this helps,
Chris

0
Comment actions Permalink

Btw, sorry for the terrible whitespace - the comment system seems to have its own ideas about how my text should be formatted.

0
Comment actions Permalink

wow! thank you for the detailed explanation, I think I got enough info to get started.;)

0
Comment actions Permalink

wow! thank you for the detailed explanation, I think I got enough info to get started.;)

0
Comment actions Permalink

You might want to check out the Comments section of the Plugin Development Guide, which specifically deals with the creation and manipulation of comments.

0
Comment actions Permalink

Is IDocCommentBlockOwnerNode available in the SDK still? I am having trouble finding this interface. How can I modify the xml comments on a method or class using ReSharper SDK 9.2?

0
Comment actions Permalink

IDocCommentBlockOwnerNode was renamed IDocCommentBlockOwner. It's the same, otherwise. A couple of other nodes were renamed like that, too.

0

Please sign in to leave a comment.