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 -
.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
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
[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
.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
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.