我正在开发一个自定义的Visual Studio语言服务,并且有几个关于文件扩展名绑定到特定语言服务的方式的问题。
“示例语言”语言的源文件有两个主要文件扩展名:.e1
和.e2
。我的扩展程序有一个ExampleLanguagePackage
类,扩展了Package
。
当您使用文件→打开命令并选择C#文件(例如)时,“打开”按钮有一个下拉箭头,您可以选择“打开方式...”。单击该按钮时,将显示“CSharp Editor(默认)”,“带编码的CSharp Editor”或任何其他选项中打开文件的选项。如何为我的语言提供类似功能,提供“示例语言(默认)”和“带编码的示例语言”选项?
当您打开工具→选项...→文本编辑器→文件扩展名时,您可以将.foo
扩展名绑定到“Microsoft Visual C#”或其他任何一个选项。如何扩展此页面以允许用户定义的文件扩展名与“示例语言”相关联?
注册这些项目时还应注意什么?
答案 0 :(得分:15)
通过为您的语言添加IVsEditorFactory
的自定义实现并使用注册属性的组合来注册它,可以解决大多数这些问题。这个界面的实际实现超出了这个问题的范围,但是界面本身的文档(并链接到该页面)以及DjangoEditorFactory
项目中的示例Python Tools for Visual Studio实现帮助了我我的初步实施。
为了支持Example语言,我将做出以下假设。
ExampleEditorFactory
,它提供了IVsEditorFactory
的核心实现。该类应该有一个带有bool
参数的受保护构造函数,以指定工厂是否应该提示用户进行编码(类似于DjangoEditorFactory
的构造函数之一)。
要做的第一件事就是注册你的编辑工厂。这分为两部分。
首先,使用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)]
这个答案不包括几个细节。
ProvideEditorExtensionAttribute
以获取有关新(以及其他文档较少)属性Cannot get custom editor to use the provisional tab的详细信息。ProvideEditorFactoryAttribute
不支持指定ProvideEditorFactoryAttribute.CommonPhysicalViewAttributes
值(向下搜索页面)。此值通常会添加到ExampleEditorFactoryWithEncoding
的注册中,值将为ExampleEditorFactoryWithoutEncoding
的GUID。