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

时间:2013-03-07 05:27:16

标签: visual-studio vsx languageservice

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

“示例语言”语言的源文件有两个主要文件扩展名:.e1.e2。我的扩展程序有一个ExampleLanguagePackage类,扩展了Package

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

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

  3. 注册这些项目时还应注意什么?

1 个答案:

答案 0 :(得分:15)

通过为您的语言添加IVsEditorFactory的自定义实现并使用注册属性的组合来注册它,可以解决大多数这些问题。这个界面的实际实现超出了这个问题的范围,但是界面本身的文档(并链接到该页面)以及DjangoEditorFactory项目中的示例Python Tools for Visual Studio实现帮助了我我的初步实施。

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

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

    • 102 =带编码的示例语言

注册编辑器工厂

要做的第一件事就是注册你的编辑工厂。这分为两部分。

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

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

接下来,在ExampleLanguagePackage的{​​{3}}方法中,在致电base.Initialize()后添加对Initialize的来电。

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

    RegisterEditorFactory(new ExampleEditorFactoryWithoutEncoding(this));
    RegisterEditorFactory(new ExampleEditorFactoryWithEncoding(this));
}

将逻辑视图与编辑器工厂

相关联

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

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

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

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

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

将标准文件扩展名.e1.e2与编辑器工厂

相关联

此步骤提供"打开..."支持原始问题中描述的.e1和.e2文件1.此步骤使用ProvideEditorLogicalViewAttribute属性完成。

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

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

.*扩展名与编辑器工厂

相关联

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

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

最后的笔记

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