如何在Visual Studio编辑器中使用投影缓冲区来支持嵌入式语言

时间:2014-04-14 12:18:59

标签: c# visual-studio languageservice

在此link的第一段末尾,它指出:

  

Visual Studio文本概述功能是通过使用投影缓冲区隐藏折叠文本来实现的,而 ASP.NET页面的Visual Studio编辑器使用投影来支持嵌入式语言,如Visual Basic和C#

我已经搜索过但没有找到任何示例或文档来完成此任务,有没有人知道如何做到这一点?我已经进行了分类工作并创建了一个我想要归类为C#代码的跨度的投影缓冲区。我将缓冲区上下文类型设置为" CSharp"但是跨度从未被分类。我还试图将我的内容类型基于"投影"但现在确实有效。

4 个答案:

答案 0 :(得分:6)

Visual Studio中的投影缓冲区主要用于处理一种语言区域嵌入另一种语言的场景。经典的例子是HTML中的CSS和Javascript。同样,ASP.NET或Razor中的C#或VB。事实上,HTML编辑器处理许多语言,其投影缓冲区架构是可扩展的(我写了很多部分)。这样,样式块内的所有功能都由CSS编辑器处理,HTML编辑器不需要做太多。

当你得到它的工作方式时,投影缓冲区并不复杂。投影缓冲区形成图形,顶层缓冲区显示在视图中。投影缓冲区没有自己的内容,它由投影范围组成,而投影范围又是跟踪跨度(ITrackingSpan)或惰性区域(字符串)。

考虑HTML中的样式块。首先,您需要创建内容类型为"投影"的投影缓冲区。或者来自"投影"的其他内容类型。然后创建投影缓冲区,其中包含内容类型为" CSS"的CSS。从磁盘读取的文件位于文本缓冲区中,内容类型为" HTMLX" (" HTML"内容类型保留给经典Web窗体编辑器)。 HTML编辑器解析文件并将样式块内容和内联样式提取到单独的字符串中。内联样式片段被装饰到类中,因此它们看起来很好地形成了CSS编辑器。

现在构建投影映射。第一个CSS投影缓冲区填充有惰性字符串(它们表示用户不可见的CSS,如内联样式的装饰)以及从磁盘缓冲区(HTML)创建的跟踪跨度,用于定义用户可见的区域 - 具体来说,样式的内容块(多个)。

然后构建视图(顶层)缓冲区的投影。这些投影是一个跟踪跨度列表,它是从CSS编辑器投影缓冲区(不是HTML磁盘缓冲区)创建的跟踪跨度和从HTML磁盘缓冲区创建的跟踪跨距的组合,代表视图的HTML部分。

图表大致与此类似

  View Buffer [ContentType = "projection"]
    |      \
    |     CSS Projection [ContentType = CSS]
    |      /
  Disk Buffer [ContentType = HTMLX]

对视图缓冲区的HTML部分所做的编辑反映到磁盘缓冲区,HTML语言服务提供完成,语法检查等。样式块中的编辑转到CSS项目缓冲区,CSS编辑器提供完成和语法检查。它们也通过第二级投影反射到磁盘缓冲区。

现在,将命令转发到嵌入式语言(例如上下文菜单调用)并为Javascript或C#维护正确的断点映射是一个单独的代码。预测仅对与视图相关的事物有所帮助,控制器链和调试器操作必须单独处理。 HTML编辑器命令控制器可以识别嵌入式语言,并根据插入符位置将命令转发到相应的语言服务。

答案 1 :(得分:5)

我终于成功地将投影缓冲区嵌入到工具窗口中,并将它们连接到C#的语言服务。一个警告:这种方法仅适用于使用Roslyn的Visual Studio。我已发布了您可以使用的Github project以及随附的blog post

你的问题的答案很长,涉及很多动人的部分,它不适合StackOverflow风格的Q& A。话虽如此,我将总结必要的步骤并包括一些相关的代码。

以下示例创建一个文件的投影缓冲区,该文件由文件的前100个字符组成。

我们首先为给定的文件路径创建IVsInvisibleEditor并为其创建代码窗口。我们将此代码窗口的内容设置为IVsTextLines的{​​{1}}。

然后,我们在此代码窗口的文本缓冲区中设置自定义角色IVsInvisibleEditor。此角色允许我们通过MEF导出"CustomProjectionRole"来自定义文本缓冲区。

ITextViewModelProvider

我们现在创建一个public IWpfTextViewHost CreateEditor(string filePath, int start = 0, int end = 100) { //IVsInvisibleEditors are in-memory represenations of typical Visual Studio editors. //Language services, highlighting and error squiggles are hooked up to these editors //for us once we convert them to WpfTextViews. var invisibleEditor = GetInvisibleEditor(filePath); var docDataPointer = IntPtr.Zero; Guid guidIVsTextLines = typeof(IVsTextLines).GUID; ErrorHandler.ThrowOnFailure(invisibleEditor.GetDocData( fEnsureWritable: 1 , riid: ref guidIVsTextLines , ppDocData: out docDataPointer)); IVsTextLines docData = (IVsTextLines)Marshal.GetObjectForIUnknown(docDataPointer); //Create a code window adapter var codeWindow = _editorAdapter.CreateVsCodeWindowAdapter(VisualStudioServices.OLEServiceProvider); ErrorHandler.ThrowOnFailure(codeWindow.SetBuffer(docData)); //Get a text view for our editor which we will then use to get the WPF control for that editor. IVsTextView textView; ErrorHandler.ThrowOnFailure(codeWindow.GetPrimaryView(out textView)); //We add our own role to this text view. Later this will allow us to selectively modify //this editor without getting in the way of Visual Studio's normal editors. var roles = _editorFactoryService.DefaultRoles.Concat(new string[] { "CustomProjectionRole" }); var vsTextBuffer = docData as IVsTextBuffer; var textBuffer = _editorAdapter.GetDataBuffer(vsTextBuffer); textBuffer.Properties.AddProperty("StartPosition", start); textBuffer.Properties.AddProperty("EndPosition", end); var guid = VSConstants.VsTextBufferUserDataGuid.VsTextViewRoles_guid; ((IVsUserData)codeWindow).SetData(ref guid, _editorFactoryService.CreateTextViewRoleSet(roles).ToString()); _currentlyFocusedTextView = textView; var textViewHost = _editorAdapter.GetWpfTextViewHost(textView); return textViewHost; } 来创建并返回IVsTextViewModelProvider。这个ProjectionTextViewModel在其Visual Buffer中保存了一个投影缓冲区。这意味着当显示此缓冲区时,投影缓冲区就是显示的内容。但是,后备数据缓冲区的语言服务正常运行。

ProjectionTextViewModel

希望这会让未来的访客有一个良好的开端。

答案 2 :(得分:1)

可以找到一个工作示例here,但根据警告评论,这不是一项简单的任务。

// Abandon all hope ye who enters here.
// https://twitter.com/Schabse/status/393092191356076032
// https://twitter.com/jasonmalinowski/status/393094145398407168

// Based on decompiled code from Microsoft.VisualStudio.Html.ContainedLanguage.Server
// Thanks to Jason Malinowski for helping me navigate this mess.
// All of this can go away when the Roslyn editor ships.

答案 3 :(得分:0)

您留下的评论似乎是在讨论大纲但不支持嵌入式语言。如果您尝试隐藏文字,可以查看此IntraText Code

如果您通过将启动项目设置为devenv并将命令args设置为/ RootSuffix Exp来下载并安装或调试它,则可以打开文本文件并键入#CCCCCC或任何其他十六进制Web颜色。代码将崩溃并显示一个简单的图形。

据我所知,支持嵌入式语言,您必须编写自己的自定义语言服务。我希望能够支持现有的语言服务intellisense功能。然而,在视觉工作室中,当涉及到这种行为时,你似乎必须重新发明轮子。