Last active
August 29, 2015 14:00
-
-
Save tomasr/88d86d087a2ee86af554 to your computer and use it in GitHub Desktop.
Projection Buffer with TextDataModel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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