I started working on a custom templating language plugin and couldn't find much documentation. Therefore I'm creating this post, I hope it'll help others and it can also help me in the future when creating another plugin.
There is a good tutorial for Custom language plugins, which however doesn't cover templating languages. You should have read this tutorial and you should have an idea how to build a custom language (non-templating) before proceeding with this tutorial.
(I based my work mainly on this forum, so you may have a look at it as well).
I haven't found any open source example of a templating language, so here you have mine. This commits changes my non-templating language into a templating one.
Step 1: Lexer
You will need to lex the whole file, while lexing out only parts of your language and leaving the rest untouched. All the parts of the outer language must be returned as one IElementType, e.g. called TEMPLATE_HTML_TEXT.
Then you need to create a TemplateDataElementType pointing to that outer element type. You'll inject this into the PsiFile created for outer language in your FileViewProvider (next step), so that the HTML file knows which tokens should be taken out.
Step 2: FileViewProvider
Create a custom FileViewProvider by extending from MultiplePsiFilesPerDocumentFileViewProvider and also implementing TemplateLanguageFileViewProvider.
MultiplePsiFilesPerDocumentFileViewProvider allow you to have more PSI trees in one file. The first one created is for your templating language, the other will be for the inner language (e.g. HTML).
You'll need to find the languages being used (your lang + outer lang), usually in constructor, and save those somewhere so you have a nice access to them. You'll return those from the method getLanguages().
When you're asked for a PsiFile (method createFile) of outer language, you need to specify its contentElementType as theTemplateDataElementType created in step 1.
Step 3: FileViewProviderFactory
Last step is to create a factory for your FileViewProvider, which would probably consist of only one line of code - creating an instance of MyLangFileViewProvider.
Then, register this factory in plugin.xml file as an extension point for lang.fileViewProviderFactory while specifying name of your language, for which it'll be associated for.
That should be enough I hope (if I didn't miss something). Njoy