Custom Plugin - understanding GeneratedDocumentService and Code Behind
Hi Mr,
I'm currently implementing a similar plugin to the T4 templates - handling a custom language implementation which generates c# code as output in "code behind".
Needless to say I have been analyzing the PSI plugin code - as well as the ForTea T4 templates plugin project (amazing work by the author there!)
I have more or less the basics setup:
* General custom language implementation etc... pretty much following the examples and your code...
* Parser / Lexer is implemented - files are parsed and PSI is generated...
* Simple syntax highlightning - with the CSharp implementation backing it...
* Simple error messages output for just the parsing (no code analysis yet...)
What I'm currently trying to figure out is the "CodeBehind" concept:
* GeneratedDocumentService
I was hoping that perhaps you could help me out understand what this is used for?
- I do understand that this service generates a C# PSI(or whatever you choose as language) file for the custom language, and I have also plugged a custom GeneratedDocumentService in my solution, which generates some sample code...
- But it doesn't seem like this is actually used in the compilation of the projects or anything like that right? / nor does it seem to add any additional "Document view" to the ProjectItem to be displayed.
- My naive thought was that this probably generates the C# code that is generated in the "code behind" file that you can open in VS - but that seems to bee completely unrealated...
- So is the result of this only used internally by Resharper to add "code navigation" / "syntax highlighting" / "code analysis"?
I would really appreciate if anyone could help me with some pointers on the subject! :)
While I'm at it - what is the purpose of the "FileDependency" class? - what is it used for?
- Is it used for "code analysis" / "syntax coloring" internally by Resharper?
- As it seems to be a ShellComponent - it seems like it's per Solution basis? (would that mean it also keeps track of the required extenral assemblies too? etc..?)
Thank you,
/Peter
Please sign in to leave a comment.
Hi Peter!
In genereal answer is Yes, generated docs are used by ReSharper for navigation, higlightings, analyses.
There are projections of regions of generated code to original file, and highlightings, features, analyses & etc of language of generated code automatically available there.
For example, C# context actions and quix fixes on c# inline code in ASPX pages, or JavaScript features inside script tag in Html.
Hi, thank you for taking the time to respond! :)
Ok, so lets say we have the following scenario:
* custom language integration, that should be interoperable with "existing 'typedeclarations' in c# code", for example the following syntax:
1. Will the generated code behind affect the available "refactorings" / "quick fixes" in my custom language what so ever? (my unerstanding is that I would need to create custom error handling and quick fixes etc... so so in that perspective it will not affect at all?)
2. Will the code behind affect "referring" to ".net / c#" types in any way - or intellisense in my custom language file?
3. Or perhaps it is the other way around - that it will give intellisense to "my generated" files when editing some other .cs file?
* It would be really great if you could give me an example of what the generated document would do, for example:
- generating the following, would mean that this type appears in ... etc...
Thank you, really appreciate it!
/Peter
1. If they are intersecting - yes. For example, rename. Should it rename C# type at caret or your custom rename at the same point? You decide.
2. Again, if you writing custom intellisense you decide what to show over there. If at the same point available C# construction - C# intellisense will be there.
3. Yes, that files are part of project. If you don't want appear anywhere else - generate them private.
About example, let take Razor.
For this file
We have this code-behind file
Some parts of generated code projecting to original file, and all feature and highlightings over there going to original razor file.
Some parts are internal, for correct syntax structure of code. Obiosly, they are depended on languge in which written code-behind file (here is C#)
Thank you again :)
So, given your example mentioned above - the generated codebehind is not used by the compiler in any way right?
- I mean, the microsoft compiler can potentially generate something completely different code behind...
If that is true - what I'm having trouble understanding, is what intellisense / refactoring options would change depending on what I generate in the code behind.
If we take the example you specified:
Razor file:
Generates the following output as you showed:
Code behind:
Now I do a refactoring in the "Razor file":
- I do a "Rename" on the "UserName" so that it is called "MyRenamedUserName":
Razor file after refactoring:
Given that I have mapped the ranges correctly between the two files, I expect the codebehind to be updated accordingly(i'm not sure if resharper reparses the file and generates new code behind, or just modyfies the codebehind "in-place"...):
So far so good - this I can understand, however, what I don't understad is why this matters?
- Lets say that I would implement this differently for Razor - lets say that instead of the output in your example, this would be the output instead:
Code behind:
How would this affect resharper in any way - I mean, the "Code behind" is just "in memory" for ReSharper, the user doesn't see this in any way?
- how would this affect highlightning / intellisense / etc?
Another example, perhaps having more "refactoring" options:
My custom language file :
The following "CodeBehind" is generated:
Code behind:
What if I would generate the following in codebehind instead?:
Lets just imagine that this is the output that I would generate from my custom language definition - then my custom MSBuild task would pick this file during the compilation process... but what value does ReSharper have from this "Code Behind" genration?
I'm sorry for asking so many questions... I kind of almost feel dumb :p ... but I simply don't understand the "value" of this "code behind" since it's only used for reshaper internals?
- but I do understand that I'm missing some point here, because all the other "custom language plugins" are generating some code behind :)
Thank you again :)
/Regards
/Peter
Hi Peter. The generated document is an in-memory representation only. It's not passed to the compilers, and is only used by ReSharper.
You define a mapping from the original file to this in-memory file. So, you can have "islands" of C# in your original file, and ReSharper knows the context of those islands by looking at their actual locations in the in-memory generated version. You now have all of the normal analyses, context actions, navigations and code completion as would be available at that point in the generated file.
For example, writing this in a .cshtml file:
maps to this:
public override Execute() { // [snipped] Write(Html.AntiForgeryToken()); // [snipped] }Which means ReSharper knows that "Html.AntiForgeryToken()" is being passed as a parameter to Write, and is being called from the Execute method, which lives in a class named after the view and deriving from (something like) WebViewPage<YourModel>. So, it knows that there is a property called Html which is of type HtmlHelper. So, if you hit "." after Html, ReSharper knows to display code completion for the HtmlHelper type, and can give you the AntiForgeryToken as an item in the list. Similarly, it knows that the Model property has type "YourModel" and can provide code completion and navigation based on that.
If you try to use a property or method that doesn't exist, e.g. @UnknownProperty, ReSharper knows that property doesn't exist in the class in the in-memory version, so displays it as a red error. Similarly, if you define a helper method:
Then ReSharper will generate this as a method on the class in the in-memory version. ReSharper now knows that the current class has a DisplayPrice method, and if you type "@this." then DisplayPrice will appear in the code completion list.
Does this help?
Thanks
Matt