在自定义Visual Studio语言服务中支持用户指定的文件扩展名

Sam*_*ell 8 vsx visual-studio languageservice

我正在开发一个自定义的Visual Studio语言服务,并且有几个关于文件扩展名绑定到特定语言服务的方式的问题.

"示例语言"语言的源文件有两个主文件扩展名:.e1.e2.我的分机有一类ExampleLanguagePackage延伸Package.

  1. 当您使用文件→打开命令并选择一个C#文件(例如)时,"打开"按钮有一个下拉箭头,您可以选择"打开方式...".单击该按钮时,将显示"CSharp Editor(默认)","带编码的CSharp Editor"或任何其他选项中打开文件的选项.如何为我的语言提供类似的功能,提供"示例语言(默认)"和"带编码的示例语言"选项?

  2. 当您打开工具→选项...→文本编辑器→文件扩展名时,您可以将(例如).foo扩展名绑定到"Microsoft Visual C#"或任何其他几个选项.如何扩展此页面以允许用户定义的文件扩展名与"示例语言"相关联?

  3. 注册这些物品时我还应该注意什么?

Sam*_*ell 15

大多数这些项目都是通过IVsEditorFactory为您的语言添加自定义实现并使用注册属性的组合来注册它来解决的.这个接口的实际实现超出了这个问题的范围,但是接口本身的文档(并链接到该页面),以及Visual Studio项目DjangoEditorFactoryPython工具中的示例实现帮助我完成了初始实现.

为了支持Example语言,我将做出以下假设.

  • 您已经实现了一个抽象类ExampleEditorFactory,它提供了核心实现IVsEditorFactory.该类应该有一个带有bool参数的受保护构造函数,以指定工厂是否应该提示用户进行编码(类似于其中一个构造函数DjangoEditorFactory).
    • 您有一个类ExampleEditorFactoryWithoutEncoding,它扩展ExampleEditorFactory并构造falsepromptForEncoding参数指定的基类.该类应标有[Guid]属性.
    • 您有一个类ExampleEditorFactoryWithEncoding,它扩展ExampleEditorFactory并构造truepromptForEncoding参数指定的基类.该类应标有[Guid]属性.
  • 您已将以下条目添加到VSPackage.resx资源文件中.常量可以更改,但请注意我已使用下面的常量值101和102.
    • 101 =示例语言

    • 102 =带编码的示例语言

注册编辑器工厂

首先要注册编辑器工厂.这分为两部分.

首先,使用ProvideEditorFactoryAttribute.此属性将工厂的显示名称的资源标识符与工厂类型本身相关联.

[ProvideEditorFactory(typeof(ExampleEditorFactoryWithoutEncoding), 101)]
[ProvideEditorFactory(typeof(ExampleEditorFactoryWithEncoding), 102)]
Run Code Online (Sandbox Code Playgroud)

接下来,在Initialize方法中ExampleLanguagePackage,在调用RegisterEditorFactory后添加调用base.Initialize().

protected override void Initialize()
{
    base.Initialize();

    RegisterEditorFactory(new ExampleEditorFactoryWithoutEncoding(this));
    RegisterEditorFactory(new ExampleEditorFactoryWithEncoding(this));
}
Run Code Online (Sandbox Code Playgroud)

将逻辑视图与编辑器工厂相关联

我没有找到关于ProvideEditorLogicalViewAttribute属性用例的所有信息,但至少包括以下内容非常重要.确保使用您创建的两个工厂注册逻辑视图.

[ProvideEditorLogicalView(typeof(ExampleEditorFactoryWithoutEncoding), VSConstants.LOGVIEWID.TextView_string)]
[ProvideEditorLogicalView(typeof(ExampleEditorFactoryWithEncoding), VSConstants.LOGVIEWID.TextView_string)]
Run Code Online (Sandbox Code Playgroud)

如果未执行此步骤,则在输出窗口中双击可以将您带到一行代码的功能将无法按预期工作.例如,假设输出窗口包含如下所示的行.

c:\dev\file.e1(14,3): unexpected expression
Run Code Online (Sandbox Code Playgroud)

关联TextView逻辑视图允许IDE在双击此输出行时使用您的工厂,以转到文件c:\ dev\file.e1的第14行第3行.否则,它将使用不同的工厂打开文档的新副本,新窗口可能会丢失许多功能.

关联标准文件扩展名.e1,并.e2与编辑器厂

此步骤为原始问题1中描述的.e1和.e2文件提供"Open With ..."支持.此步骤由ProvideEditorExtensionAttribute属性完成.

主工厂的默认优先级显示为50.具有显式编码的工厂应具有小于此的优先级,49似乎是一个不错的选择.请注意,不需要指定NameResourceID命名参数,因为它已由ProvideEditorFactoryAttribute上面的用法指定(生成的注册表键是相同的).

[ProvideEditorExtension(typeof(ExampleEditorFactoryWithoutEncoding), ".e1", 50)]
[ProvideEditorExtension(typeof(ExampleEditorFactoryWithoutEncoding), ".e2", 50)]
[ProvideEditorExtension(typeof(ExampleEditorFactoryWithEncoding), ".e1", 49)]
[ProvideEditorExtension(typeof(ExampleEditorFactoryWithEncoding), ".e2", 49)]
Run Code Online (Sandbox Code Playgroud)

.*扩展与编辑器工厂相关联

此步骤为所有其他文件提供"Open With ..."支持,并添加对原始问题2中描述的文件扩展选项的支持.此步骤也使用该ProvideEditorExtensionAttribute属性,但使用低得多的优先级值来确保默认值其他文件类型的编辑器不会被设置覆盖.与上一步一样,具有显式编码的工厂的优先级较低.

[ProvideEditorExtension(typeof(ExampleEditorFactoryWithoutEncoding), ".*", 2)]
[ProvideEditorExtension(typeof(ExampleEditorFactoryWithEncoding), ".*", 1)]
Run Code Online (Sandbox Code Playgroud)

最后的笔记

这个答案不包括几个细节.