Skip to content

Instantly share code, notes, and snippets.

@tomasr
Last active August 29, 2015 14:00
Show Gist options
  • Save tomasr/88d86d087a2ee86af554 to your computer and use it in GitHub Desktop.
Save tomasr/88d86d087a2ee86af554 to your computer and use it in GitHub Desktop.
Projection Buffer with TextDataModel
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.TextManager.Interop;
using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
using Microsoft.VisualStudio.Utilities;
using Microsoft.VisualStudio.Text.Projection;
using Microsoft.VisualStudio;
using System.Collections.Generic;
namespace Company.NoDeveloperMargin
{
[Guid("2713ff5b-29c3-4779-9df6-2fb2dfc20070")]
public class MyToolWindow : ToolWindowPane, IOleCommandTarget
{
IVsInvisibleEditorManager _InvisibleEditorManager;
IVsTextView _ViewAdapter;
IVsTextBuffer _BufferAdapter;
IVsEditorAdaptersFactoryService _EditorAdapterFactory;
IOleServiceProvider _OleServiceProvider;
ITextBufferFactoryService _BufferFactory;
IWpfTextViewHost _TextViewHost;
IProjectionBufferFactoryService _ProjectionBufferFactory;
IContentTypeRegistryService _contentTypeRegistry;
ITextEditorFactoryService _EditorFactory;
IEditorOptionsFactoryService _EditorOptionsFactory;
public MyToolWindow() : base(null)
{
BitmapResourceID = 301;
BitmapIndex = 1;
//init services
var componentModel = (IComponentModel)Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(SComponentModel));
this._InvisibleEditorManager = VisualStudioServices.ServiceProvider.GetService<SVsInvisibleEditorManager, IVsInvisibleEditorManager>();
_OleServiceProvider = (IOleServiceProvider)GetService(typeof(IOleServiceProvider));
_BufferFactory = componentModel.GetService<ITextBufferFactoryService>();
_EditorAdapterFactory = componentModel.GetService<IVsEditorAdaptersFactoryService>();
_EditorAdapterFactory = componentModel.GetService<IVsEditorAdaptersFactoryService>();
_ProjectionBufferFactory = componentModel.GetService<IProjectionBufferFactoryService>();
_contentTypeRegistry = componentModel.GetService<IContentTypeRegistryService>();
_EditorFactory = componentModel.GetService<ITextEditorFactoryService>();
_EditorOptionsFactory = componentModel.GetService<IEditorOptionsFactoryService>();
}
override public object Content
{
get { return TextViewHost; }
}
private IVsInvisibleEditor getInvisibleEditor(string filePath)
{
IVsInvisibleEditor invisibleEditor;
ErrorHandler.ThrowOnFailure(this._InvisibleEditorManager.RegisterInvisibleEditor(
filePath
, pProject: null
, dwFlags: (uint)_EDITORREGFLAGS.RIEF_ENABLECACHING
, pFactory: null
, ppEditor: out invisibleEditor));
return invisibleEditor;
}
private void InitializeEditor(string filePath = @"C:\tomasr\viasfora\Viasfora\TextEditor.cs", int start = 0, int end = 100)
{
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);
ITextBuffer docBuffer = _EditorAdapterFactory.GetDocumentBuffer((IVsTextBuffer)docData);
IVsTextBuffer docAdapter = _EditorAdapterFactory.GetBufferAdapter(docBuffer);
int length = end - start;
SnapshotSpan subsetSnapshot = new SnapshotSpan(docBuffer.CurrentSnapshot, start, length);
//Create projection buffer without a content type. (Defaults to "projection")
var projBuffer = _ProjectionBufferFactory.CreateElisionBuffer(
null
, new NormalizedSnapshotSpanCollection(subsetSnapshot)
, ElisionBufferOptions.None);
//IVsTextBuffer bufferAdapter = _EditorAdapterFactory.CreateVsTextBufferAdapterForSecondaryBuffer(VisualStudioServices.OLEServiceProvider, projBuffer);
_EditorAdapterFactory.SetDataBuffer(docAdapter, projBuffer);
var codeWindow = _EditorAdapterFactory.CreateVsCodeWindowAdapter(VisualStudioServices.OLEServiceProvider);
codeWindow.SetBuffer((IVsTextLines)docAdapter);
codeWindow.GetPrimaryView(out _ViewAdapter);
_TextViewHost = _EditorAdapterFactory.GetWpfTextViewHost(_ViewAdapter);
}
public IWpfTextViewHost TextViewHost
{
get
{
if (_TextViewHost == null)
{
InitializeEditor();
var data = _ViewAdapter as IVsUserData;
if (data != null)
{
var guid = Microsoft.VisualStudio.Editor.DefGuidList.guidIWpfTextViewHost;
object obj;
var hr = data.GetData(ref guid, out obj);
if ((hr == Microsoft.VisualStudio.VSConstants.S_OK) &&
obj != null && obj is IWpfTextViewHost)
{
_TextViewHost = obj as IWpfTextViewHost;
}
}
}
return _TextViewHost;
}
}
public override void OnToolWindowCreated()
{
// --- Register key bindings to use in the editor
var windowFrame = (IVsWindowFrame)Frame;
var cmdUi = Microsoft.VisualStudio.VSConstants.GUID_TextEditorFactory;
windowFrame.SetGuidProperty((int)__VSFPROPID.VSFPROPID_InheritKeyBindings,
ref cmdUi);
base.OnToolWindowCreated();
}
protected override bool PreProcessMessage(ref Message m)
{
if (TextViewHost != null)
{
// copy the Message into a MSG[] array, so we can pass
// it along to the active core editor's IVsWindowPane.TranslateAccelerator
var pMsg = new MSG[1];
pMsg[0].hwnd = m.HWnd;
pMsg[0].message = (uint)m.Msg;
pMsg[0].wParam = m.WParam;
pMsg[0].lParam = m.LParam;
var vsWindowPane = (IVsWindowPane)_ViewAdapter;
return vsWindowPane.TranslateAccelerator(pMsg) == 0;
}
return base.PreProcessMessage(ref m);
}
int IOleCommandTarget.Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt,
IntPtr pvaIn, IntPtr pvaOut)
{
var hr =
(int)Microsoft.VisualStudio.OLE.Interop.Constants.OLECMDERR_E_NOTSUPPORTED;
if (_ViewAdapter != null)
{
var cmdTarget = (IOleCommandTarget)_ViewAdapter;
hr = cmdTarget.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
}
return hr;
}
int IOleCommandTarget.QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[]
prgCmds, IntPtr pCmdText)
{
var hr =
(int)Microsoft.VisualStudio.OLE.Interop.Constants.OLECMDERR_E_NOTSUPPORTED;
if (_ViewAdapter != null)
{
var cmdTarget = (IOleCommandTarget)_ViewAdapter;
hr = cmdTarget.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
}
return hr;
}
class ProjectionTextDataModel : ITextDataModel {
private ITextBuffer textBuffer;
private ITextBuffer projectionBuffer;
private IContentType contentType;
public IContentType ContentType {
get { return contentType; }
}
public event EventHandler<TextDataModelContentTypeChangedEventArgs> ContentTypeChanged;
public ITextBuffer DataBuffer {
get { return this.projectionBuffer; }
}
public ITextBuffer DocumentBuffer {
get { return this.textBuffer; }
}
public ProjectionTextDataModel(ITextBuffer textBuffer, ITextBuffer projectionBuffer) {
this.textBuffer = textBuffer;
this.projectionBuffer = projectionBuffer;
this.contentType = this.textBuffer.ContentType;
this.textBuffer.ContentTypeChanged += dataBuffer_ContentTypeChanged;
}
void dataBuffer_ContentTypeChanged(object sender, ContentTypeChangedEventArgs e) {
IContentType old = this.contentType;
this.contentType = this.textBuffer.ContentType;
var temp = this.ContentTypeChanged;
if ( temp != null )
temp(this, new TextDataModelContentTypeChangedEventArgs(old, this.ContentType));
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment