Project File Language Service
If a custom language defines a ProjectFileType, it must also associate that file type with a PSI language type, which ReSharper can use to build a PSI tree of the file's contents. The IProjectFileLanguageService interface provides this functionality, and can be considered as a bridge between the Project Model and the PSI.
The project file language service is implemented as a per-file type component. Given a ProjectFileType, it is possible to retrieve that file type's project file language service, which exposes the custom language's PsiLanguageType. This can be used as the key to retrieve all per-language components, and get access to the custom language's lexer and parser, to build a PSI tree.
The IProjectFileLanguageService interface is as follows:
The members are as follows:
LanguageType- confusingly calledLanguageType, this is the singleton instance of the derivedProjectFileTypeclass that represents the Project Model file type of this language.Icon- theIconIdof the icon used to represent this file. This is used whenever ReSharper needs to display the icon for a file of this type, such as in the Find Results tool window. See the section on icons for more details on icons.GetPreprocessorDefines- retrieves a list of preprocessor symbols that are defined for the current project, as this affects the parsing of the PSI tree. This is typically only required for compiled languages in a project where the project itself has a specific language, e.g. a C# project.
The GetPsiLanguageType method
The GetPsiLanguageType method returns the PsiLanguageType derived instance that represents the custom language of the given project file. Generally speaking, this is very simple to implement, and involves returning the static instance of the PSI language type, after checking the IProjectFile.LanguageType is the required ProjectFileType (or a derived instance thereof). For example:
Note that we return UnknownLanguage.Instance if the actual language instance isn't available. This can happen if the language feature has been disabled.
This method can be a bit more complex. For example, the JavaScriptProjectFileLanguageService checks to see if the current project is a Windows JavaScript application, in which case, it returns JavaScriptWinRTLanguage.Instance. Otherwise it returns the standard JavaScriptLanguage.Instance.
PSI source file properties
The GetPsiProperties method returns an instance of IPsiSourceFileProperties that defines how the given file should be handled by the PSI, such as if a PSI tree should be built for the file.
Typically, this can be an instance of, or derived from DefaultPsiProjectFileProperties, which provides a default implementation, given an IProjectFile and an IPsiSourceFile.
The IPsiSourceFileProperties interface is as follows:
The interface members are:
ShouldBuildPsi- returntrueif ReSharper should build a PSI tree of this file. The default implementation will returntrueif theProjectFileTypeis a known language.IsGeneratedFile- returntrueif the file is generated. ReSharper will build a PSI tree for the file, but won't run inspections. The default implementation defers toGeneratedUtils.IsGeneratedFile, which verifies the file name and path against the masks in the Generated Code options page.IsICacheParticipant- this is a flag to indicate if the caching subsystem should be notified whenever the file is changed. This is typicallytrue.ProvidesCodeModel- returntrueif this file contributes to the semantic code model of the project. Iffalse, functionality such as inspections and rename is not available. Generally, this value matchesShouldBuildPsi, but can be different for features such as "external sources" - decompiled or downloaded source files.IsNonUserFile- returntrueif the file is not a user-editable file. This is similar toIsGeneratedFilebut does not indicate that the code is generated. Inspections and modifications are disabled when this value istrue.GetPreImportedNamespaces- returns a list of namespaces that are implicitly imported. For example,.aspxpages can have namespaces imported by entries in theweb.configfile.GetDefaultNamespace- returns the default namespace of this file. Typically defined in the project settings of a CLR project. This setting is not used for non-CLR project files, e.g. JavaScript. Should returnstring.Emptyif not required.GetDefines- returns the pre-processor symbols defined for the project. Again, this comes from the project settings, and only makes sense for compiled languages, such as C#.
Lexer factory
The GetMixedLexerFactory method returns a factory that is used to create the lexer for a file of this type. Typically, this is just a call to the PSI language service's GetPrimaryLexerFactory method.
However, if the file type is a "mixed" file, that is, it contains secondary PSI trees, such as an .aspx or HTML file that can contain HTML, CSS, JavaScript and even C#, this method should return a "mixed" lexer. Deriving from the MixedProjectFileLanguageService will provide a suitable implementation here. See the section on Secondary PSI files for more details.
Default base classes
ReSharper provides the ProjectFileLanguageService and MixedProjectFileLanguageService abstract base classes that provide a good base implementation of IProjectFileLanguageService. While many of the type members are virtual, the only abstract members that need implementing are:
PsiLanguageTypeIconGetMixedLexerFactory-MixedProjectFileLanguageServiceprovides a default implementation of this.
Custom PSI properties provider
Some languages also implement IProjectFileCustomPsiPropertiesProvider, which is a per-file type component that will return a specific subclass of ICustomPsiSourceFileProperties.
This is also a bridge between the Project Model and the PSI, as it provides access to custom project properties, via the GetCustomProperties<T> extension method on IPsiSourceFile. For example, using this extension method on a C# file can retrieve the ICSharpPsiSourceFileProperties interface, which provides a WarningsAsErrors property. This allows PSI based inspections and analyses to set the severity level of a highlight.