语法高亮不适用于 IVsInvisibleEditor

Syntax Highlight doesn't work for IVsInvisibleEditor

我创建了一个 IVsInvisibleEditor 实例。我使用以下代码来实现此目的:

    public IWpfTextViewHost CreateEditor(string targetFile)
    {
        var componentModel = (IComponentModel)Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(SComponentModel));
        var editorAdapter = componentModel.GetService<IVsEditorAdaptersFactoryService>();
        var editorFactoryService = componentModel.GetService<ITextEditorFactoryService>();
        var invisibleEditorManager = (IVsInvisibleEditorManager)Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(SVsInvisibleEditorManager));

        IVsInvisibleEditor invisibleEditor;
        ErrorHandler.ThrowOnFailure(invisibleEditorManager.RegisterInvisibleEditor(
            targetFile,
            pProject: null,
            dwFlags: (uint)_EDITORREGFLAGS.RIEF_ENABLECACHING,
            pFactory: null,
            ppEditor: out invisibleEditor));

        var docDataPointer = IntPtr.Zero;
        Guid guidIVsTextLines = typeof(IVsTextLines).GUID;

        ErrorHandler.ThrowOnFailure(invisibleEditor.GetDocData(
            fEnsureWritable: 1,
            riid: ref guidIVsTextLines,
            ppDocData: out docDataPointer));

        //Create a code window adapter
        IVsTextLines docData = (IVsTextLines)Marshal.GetObjectForIUnknown(docDataPointer);           
        var codeWindow = editorAdapter.CreateVsCodeWindowAdapter(VisualStudioServices.OLEServiceProvider);
        ErrorHandler.ThrowOnFailure(codeWindow.SetBuffer(docData));
        IVsTextView textView;
        ErrorHandler.ThrowOnFailure(codeWindow.GetPrimaryView(out textView));

        var userData = (IVsUserData)codeWindow;
        var uniqueMoniker = Guid.NewGuid().ToString();
        Guid bufferMonikerGuid = typeof(IVsUserData).GUID;
        userData.SetData(ref bufferMonikerGuid, uniqueMoniker);
        var guid = VSConstants.VsTextBufferUserDataGuid.VsTextViewRoles_guid;
        userData.SetData(ref guid, editorFactoryService.CreateTextViewRoleSet(editorFactoryService.DefaultRoles).ToString());

        var  host = editorAdapter.GetWpfTextViewHost(textView);
        host.TextView.Options.SetOptionValue(DefaultTextViewHostOptions.ZoomControlId, false);

        return host;
    }

一切正常,除了没有语法突出显示,例如,如果我使用 C# (.cs) 文件在不可见的编辑器中显示。经过一些研究,我发现我还需要向 RDT 添加一个文档,这是我使用以下函数完成的:

    uint RegisterDocument(string targetFile)
    {
        //Then when creating the IVsInvisibleEditor, find and lock the document 
        uint itemID;
        IntPtr docData;
        uint docCookie;
        IVsHierarchy hierarchy;
        var runningDocTable = (IVsRunningDocumentTable)Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(SVsRunningDocumentTable));

        var result = runningDocTable.FindAndLockDocument(
            dwRDTLockType: (uint)_VSRDTFLAGS.RDT_EditLock, 
            pszMkDocument: targetFile,
            ppHier: out hierarchy,
            pitemid: out itemID,
            ppunkDocData: out docData,
            pdwCookie: out docCookie);

        return docCookie;
    }

现在,如果我显示 C# 文件,则会显示高亮显示(智能感知也有效),但是如果我显示 sql 文件,那么我又一次没有语法高亮显示。现在,我进一步调查了一下,意识到也许我应该在文档上附加语言服务,所以我使用这段代码来实现:

        Guid sqlGuid = LanguageServices.Guids.TSQL;
        docData.SetLanguageServiceID(ref sqlGuid);

瞧,它起作用了,现在语法突出显示也适用于 sql 文件,但现在我有另一个问题,sql 文件上的多视图不起作用。例如,如果我有一个文件 MyQuery.sql 并且我用隐形编辑器打开它,它将被打开,语法将被显示并且一切都按预期工作,但是现在,如果我尝试打开同一个文件(虽然不可见编辑器仍然打开)然后我收到以下消息:

我认为使用 sql 文件时 RDT 的某些内容不正确,似乎当未附加语言服务时,添加到 RDT 会以某种方式被忽略,这很奇怪,因为相同的代码适用于C#文件。有没有其他方法可以使用隐形编辑器打开特定文件(可以是任何类型),我错过了什么吗?

在这个问题上花了几天时间,我终于找到了问题所在。所以,如果其他人也遇到麻烦,这里的解释是:

创建 InvisibleEditor 时,会发生很多事情 "underneath",应该设置的一件事也是特定 ITextBuffer 的 ContentType。当使用 sql 文件(作为名字参数传递给 RegisterInvisibleEditor 方法)时,ContentType 设置为纯文本(但对于 csharp 文件,它设置为 CSharp ContentType),这显然是错误的,但是,呼叫:

    Guid sqlGuid = LanguageServices.Guids.TSQL;
    docData.SetLanguageServiceID(ref sqlGuid);

应该可以解决这个问题,设置语言服务将设置正确的 ContentType,但出于某种原因,在我的情况下这不起作用。经过一些调试后,我发现当在解决方案资源管理器中通过 dbl 单击打开时,ContentType 与预期的不同。它是 "Sql Server Tools" ContentType 而不是 "T-SQL90",因此,我尝试使用 IVsTextBuffer 查找该类型的 guid:

        Guid langId;
        vsTextBuffer.GetLanguageServiceID(out langId);

这给了我正确的 guid,所以当替换为我的 tsql languange 服务时,它按预期工作。如果有人需要这些指南,可以在 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio.0\Languages (取决于 VS 安装)。

最后,这是我用来映射这些 guid 的助手 class:

    public static class LanguageServices
    {
        public static class Guids
        {
            public static Guid VisualBasic = new Guid("E34ACDC0-BAAE-11D0-88BF-00A0C9110049");
            public static Guid CSharp = new Guid("694DD9B6-B865-4C5B-AD85-86356E9C88DC");
            public static Guid FSharp = new Guid("bc6dd5a5-d4d6-4dab-a00d-a51242dbaf1b");
            public static Guid CPlusPlus = new Guid("B2F072B0-ABC1-11D0-9D62-00C04FD9DFD9");
            public static Guid Css = new Guid("A764E898-518D-11d2-9A89-00C04F79EFC3");
            public static Guid Html = new Guid("58E975A0-F8FE-11D2-A6AE-00104BCC7269");
            public static Guid JavaScript = new Guid("59E2F421-410A-4fc9-9803-1F4E79216BE8");
            public static Guid TSQL = new Guid("43AF1158-FED5-432e-8E8F-23B6FD592857");
            public static Guid SQL = new Guid("ed1a9c1c-d95c-4dc1-8db8-e5a28707a864");
            public static Guid Xaml = new Guid("c9164055-039b-4669-832d-f257bd5554d4");
            public static Guid Xml = new Guid("f6819a78-a205-47b5-be1c-675b3c7f0b8e");
        }
    }