Support for custom file extensions in the Visual Studio custom language service

I am working on a Visual Studio custom language service and ask a few questions about how file extensions are associated with a specific language service.

The source files for the Example Language language have two main file extensions: .e1 and .e2 . My extension has an ExampleLanguagePackage class that extends Package .

  • When you use File -> Open a command and select a C # file (for example), the "Open" button has a down arrow that allows you to select "Open with ...". When you click this button, you are offered the options to open the file in “CSharp Editor (default)”, “Encoding CSharp Editor”, or any of several other options. How can I provide a similar function for my language, offering the options "Example language (default)" and "Example language with encoding"?

  • When you open Tools → Options ... → Text Editor → File Extension, you have the option to associate (for example) the .foo extension with "Microsoft Visual C #" or with any of several other parameters. How can I extend this page to allow user-defined file extensions to be associated with an “example language”?

  • What else should I observe when registering these items?

+8
visual-studio languageservice vsx
source share
1 answer

Most of these elements are addressed by adding a custom IVsEditorFactory implementation for your language and using a combination of registration attributes to register it. The actual implementation of this interface is beyond the scope of this question, but the documentation is for the interface itself (and related to this page), as well as the DjangoEditorFactory example in The Python Tools for Visual Studio project helped me with my initial implementation.

To support the language of the example, I will make the following assumptions.

  • You have implemented the abstract class ExampleEditorFactory , which provides the main implementation of IVsEditorFactory . The class must have a protected constructor with a bool argument to indicate whether the factory should request the encoding from the user (similar to one of the DjangoEditorFactory constructors).
    • You have an ExampleEditorFactoryWithoutEncoding class that extends ExampleEditorFactory and builds a base class that defines false for the promptForEncoding argument. This class must be marked with the [Guid] attribute.
    • You have an ExampleEditorFactoryWithEncoding class that extends ExampleEditorFactory and creates a base class that defines true for the promptForEncoding argument. This class must be marked with the [Guid] attribute.
  • The following entries have been added to the VSPackage.resx resource file. Constants can be changed, but keep in mind that I used the constant values ​​101 and 102 below.
    • 101 = Language example

    • 102 = Language example with encoding

Registration of editorial factories

The first thing to do is register your editors factories. This is done in two parts.

First use ProvideEditorFactoryAttribute . This attribute associates the resource identifier for the display name factory with the type factory itself.

 [ProvideEditorFactory(typeof(ExampleEditorFactoryWithoutEncoding), 101)] [ProvideEditorFactory(typeof(ExampleEditorFactoryWithEncoding), 102)] 

Next, in the Initialize method of ExampleLanguagePackage , add RegisterEditorFactory calls after calling base.Initialize() .

 protected override void Initialize() { base.Initialize(); RegisterEditorFactory(new ExampleEditorFactoryWithoutEncoding(this)); RegisterEditorFactory(new ExampleEditorFactoryWithEncoding(this)); } 

Associate Logical View with Editor Factories

I did not find all the information I would like to use for the ProvideEditorLogicalViewAttribute attributes, but it is important to include at least the following. Be sure to register a boolean view with both factories you created.

 [ProvideEditorLogicalView(typeof(ExampleEditorFactoryWithoutEncoding), VSConstants.LOGVIEWID.TextView_string)] [ProvideEditorLogicalView(typeof(ExampleEditorFactoryWithEncoding), VSConstants.LOGVIEWID.TextView_string)] 

If this step is not performed, the function in which double-clicking in the output window can lead you to a line of code will not work properly. For example, suppose the output window contains the following line.

 c:\dev\file.e1(14,3): unexpected expression 

Linking the logical view of TextView allows the IDE to use your factory by double-clicking on this output line to go to line 14, column 3 of the file c: \ dev \ file.e1. Otherwise, another factory will be used to open a new copy of your document, and a lot of functions will probably be missing in the new window.

Associate Standard .e1 and .e2 with Editor .e2

This step provides "Open With ..." support for the .e1 and .e2 files described in source question 1. This step is performed using ProvideEditorExtensionAttribute .

The default priority for the primary factory seems to be 50. An explicitly encoded factory should take precedence less than this, and 49 seems like a good choice. Please note that it is not necessary to specify the NameResourceID named parameter, as it was already specified when using the ProvideEditorFactoryAttribute above (the generated registry keys are identical).

 [ProvideEditorExtension(typeof(ExampleEditorFactoryWithoutEncoding), ".e1", 50)] [ProvideEditorExtension(typeof(ExampleEditorFactoryWithoutEncoding), ".e2", 50)] [ProvideEditorExtension(typeof(ExampleEditorFactoryWithEncoding), ".e1", 49)] [ProvideEditorExtension(typeof(ExampleEditorFactoryWithEncoding), ".e2", 49)] 

Associate an extension .* With editor factories

This step provides support for "Open With ..." for all other files and adds support for the file extension options described in source question 2. This step also uses the ProvideEditorExtensionAttribute attribute, but uses a much lower priority value to ensure that the default editor for other types of files will not be overridden by the setting. As in the previous step, a factory with explicit encoding gets a lower priority.

 [ProvideEditorExtension(typeof(ExampleEditorFactoryWithoutEncoding), ".*", 2)] [ProvideEditorExtension(typeof(ExampleEditorFactoryWithEncoding), ".*", 1)] 

Concluding notes

This answer does not contain a few details.

+15
source share

All Articles