Registering a Project File Type
If a custom language is to be the primary language of a certain file, it should register a file type with the Project Model.
Every file that is included in a project in the Project Model exposes its file type via the IProjectFile.LanguageType
property. This is an instance of a subclass of ProjectFileType
, which is the root class in a hierarchy of classes that represent file types.
There are two classes that directly derive from ProjectFileType
. The first is KnownFileType
, which is an abstract class that represents a file type that ReSharper knows about, and is the base class for all known file types. It can be used instead of an explicit file type to indicate any or all known file types. The second is UnknownFileType
, which is a sealed class, and only used when a file doesn't have a known file type.
A new file type for a custom language should derive from KnownProjectFileType
, and specify a programmatic name, a presentable name and the file extensions that identify the file.
For example, here is the HTML file type:
Note that this file type registers two file extensions - .html
and .htm
. The programmatic name is "HTML"
, which is also available as a public constant, should anyone else need to identify the file type by name. The presentable name is "Html"
. (For clarity the C# file type has a programmatic name of CSHARP
and a presentable name of C#
.)
Each class is marked with the [ProjectFileTypeDefinition]
attribute, which is a Component Model part attribute used by the implementation of IProjectFileTypes
to find and instantiate the file type. This is not a standard Component Model attribute such as [ShellComponent]
or [SolutionComponent]
. The lifecycle is different, and only the default constructor is used - injection is not supported. Furthermore, when the IProjectFileTypes
implementation creates an instance of the file type, it also sets the static Instance
field, which means the file types are singletons.
The HTML file type above has more than one constructor. Typically, these aren't used, but are available for derived file types. For example, the AspProjectFileType
, which provides a file type for .aspx
, .ascx
, .master
and .asax
files, derives from HtmlProjectFileType
(and uses one of the protected constructors to override the HTML
name). Deriving from another file type creates an "is a" relationship, and the deriving file type "inherits" traits and services of the base file type. So, a .aspx
file "is a" HTML file, and any services that are targeted at HTML files also apply to .aspx
files (but not vice versa). Similarly, the TypeScriptProjectFileType
is a subclass of JavaScriptProjectFileType
, which makes sense, as TypeScript is a superset of JavaScript.
File extension mapping
A file's project file type can be fetched via its file extension, by using the IProjectFileExtensions
shell component.
This interface allows getting the file type from an extension, including the dot (.e.g .cs
). It will also get the list of extensions supported by a file type, and raise a signal if this information changes.
The information for the file extension mapping comes from various IFileExtensionMapping
shell components. The default implementation uses the extensions given in the ProjectFileType
instances, but ReSharper also provides an implementation that retrieves information from Visual Studio. It fetches the list of editors that Visual Studio knows about, and the file extensions registered with each editor. It then uses any IVsEditorGuidToFileTypeConverter
shell components to convert an editor's GUID
to a ProjectFileType
. This allows ReSharper to correctly handle files that have a non-standard file extension, but have been opened in a specific editor in Visual Studio. The IFileExtensoinMapping
interface might also be useful if adding support for a language that Visual Studio already supports.