如何使用投影从编辑器中隐藏代码

时间:2014-02-11 15:13:48

标签: visual-studio-2012 visual-studio-extensions vsx vs-extensibility visual-studio-sdk

我正在开发自定义语言服务。该语言的代码文件包含元数据和源代码,因此元数据存储为标题(在文件的开头;不能更改此要求)。语言服务提供两个逻辑视图;一个用于代码,另一个用于编辑元数据。

现在,问题是我想隐藏代码编辑器视图中的元数据 - 我认为使用投影实现它是可行的方法,但是Visual Studio SDK既没有包含任何示例,也没有关于如何实现实现这样的功能。关于这个概念的简短解释见:Inside the Editor, Projection

我还在Codeplex找到了一个语言服务项目:Python Tools for Visual Studio,它支持Django(在这个项目中,投影缓冲区用于混合HTML标记和Python代码),但这似乎是一个不同的场景。 。

这就是我试过的......

在我的编辑器工厂中,我创建了一个IVsTextLines实例,代码编辑器视图使用以下代码...

private IVsTextLines GetTextBuffer(IntPtr docDataExisting)
{
    if (docDataExisting == IntPtr.Zero)
    {
        Type t = typeof(IVsTextLines);
        Guid clsId = typeof(VsTextBufferClass).GUID;
        Guid interfaceId = t.GUID;

        IVsTextLines bufferInstance;
        if ((bufferInstance = this.Package.CreateInstance(ref clsId, ref interfaceId, t) as IVsTextLines) != null)
        {
            object oleServiceProvider = this.GetService(typeof(IServiceProvider));
            var withSite = (IObjectWithSite)bufferInstance;
            withSite.SetSite(oleServiceProvider);
            return bufferInstance;
        }
    }

    return null;
}

据我所见,IVsTextLines界面与IProjectionBufferITextBuffer等不兼容。我从Python Tools项目中了解到,我可以使用IVsEditorAdaptersFactoryServiceITextBuffer对象获取IVsTextLines实例;适配器工厂服务(以及一些其他必需的服务实例)通过MEF注入我的编辑器工厂......

IVsTextBuffer textBuffer = this.GetTextBuffer(...);
ITextBuffer documentBuffer = this.editorAdaptersFactoryService.GetDocumentBuffer(textBuffer);

ITextBuffer可以用作投影的源缓冲区...我的想法是创建一个必须跨越的省略缓冲区;一个用于元数据,一个用于代码,因此将省略元数据跨度,这使得代码消失,并使用此省略缓冲区作为投影。这就是我试过的......

private ITextBuffer CreateBuffer(
    IProjectionEditResolver editResolver, 
    ITextBuffer documentBuffer)
{
    IContentType contentType = this.ContentTypeRegistryService.GetContentType("...");

    ITextSnapshot currentSnapshot = documentBuffer.CurrentSnapshot;

    string text = currentSnapshot.GetText(0, currentSnapshot.Length);
    TextRange textRange = Parser.GetMetadataTextRange(text); // parse code; return a text range representing the code to elide

    ITrackingSpan elideSpan = currentSnapshot.CreateTrackingSpan(textRange.Start, textRange.Length, SpanTrackingMode.EdgeExclusive);

    int offset = textRange.Start + textRange.Length;
    ITrackingSpan expandSpan = currentSnapshot.CreateTrackingSpan(offset, currentSnapshot.Length - offset, SpanTrackingMode.EdgeInclusive);

    SnapshotSpan elide = elideSpan.GetSpan(currentSnapshot);
    SnapshotSpan expand = expandSpan.GetSpan(currentSnapshot);

    var snapshotSpans = new List<SnapshotSpan>
       {
           elide, 
           expand
       };

    var spanCollection = new NormalizedSnapshotSpanCollection(snapshotSpans);

    const ElisionBufferOptions BufferOptions = ElisionBufferOptions.FillInMappingMode;
    IElisionBuffer buffer = this.ProjectionBufferFactoryService.CreateElisionBuffer(editResolver, spanCollection, BufferOptions, contentType);
    buffer.ModifySpans(new NormalizedSpanCollection(elide), new NormalizedSpanCollection(expand));  

    return buffer;
}

创建elision缓冲区后,我使用SetDataBuffer方法将其与编辑器连接...

ITextBuffer buffer = this.CreateBuffer(..., documentBuffer);
this.editorAdaptersFactory.SetDataBuffer(textBuffer, buffer);

这适用于某些家庭;至少元数据代码从代码编辑器中消失了,但是一旦尝试编辑代码,我得到InvalidOperationException,如果我只用一个跨度创建elision缓冲区,或者如果我不隐藏elideSpan

ActivityLog报告以下错误:

System.InvalidOperationException: Shim buffer length mismatch. Document=11594 Surface=11577 Difference at 0&#x000D;&#x000A;   at
Microsoft.VisualStudio.Editor.Implementation.VsTextBufferAdapter.OnTextBufferChanged(Object sender, TextContentChangedEventArgs e)&#x000D;&#x000A;   at 
Microsoft.VisualStudio.Text.Utilities.GuardedOperations.RaiseEvent[TArgs](Object sender, EventHandler`1 eventHandlers, TArgs args)

我认为我非常接近最终解决方案;那么我做错了什么?

0 个答案:

没有答案