8

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

语言“示例语言”的源文件有两个主要文件扩展名:.e1.e2. 我的扩展有一个扩展ExampleLanguagePackagePackage

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

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

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

4

1 回答 1

15

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

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

  • 您已经实现了一个抽象类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)]

接下来,在 的Initialize方法中,在调用之后ExampleLanguagePackage添加调用。RegisterEditorFactorybase.Initialize()

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

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

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

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

[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编辑器工厂关联起来

此步骤为原始问题 1 中描述的 .e1 和 .e2 文件提供“打开方式...”支持。此步骤通过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)]

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

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

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

最后的笔记

这个答案没有涵盖几个细节。

于 2013-03-07T05:27:15.920 回答