using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Operations;
using Microsoft.VisualStudio.Utilities;
Public Sub New(ByVal sourceProvider As TestCompletionSourceProvider, ByVal textBuffer As ITextBuffer)
m_sourceProvider = sourceProvider
m_textBuffer = textBuffer
End Sub
void ICompletionSource.AugmentCompletionSession(ICompletionSession session, IList<CompletionSet> completionSets)
{
List<string> strList = new List<string>();
strList.Add("addition");
strList.Add("adaptation");
strList.Add("subtraction");
strList.Add("summation");
m_compList = new List<Completion>();
foreach (string str in strList)
m_compList.Add(new Completion(str, str, str, null, null));
completionSets.Add(new CompletionSet(
"Tokens", //the non-localized title of the tab
"Tokens", //the display title of the tab
FindTokenSpanAtPosition(session.GetTriggerPoint(m_textBuffer),
session),
m_compList,
null));
}
Private Sub AugmentCompletionSession(ByVal session As ICompletionSession, ByVal completionSets As IList(Of CompletionSet)) Implements ICompletionSource.AugmentCompletionSession
Dim strList As New List(Of String)()
strList.Add("addition")
strList.Add("adaptation")
strList.Add("subtraction")
strList.Add("summation")
m_compList = New List(Of Completion)()
For Each str As String In strList
m_compList.Add(New Completion(str, str, str, Nothing, Nothing))
Next str
completionSets.Add(New CompletionSet(
"Tokens",
"Tokens",
FindTokenSpanAtPosition(session.GetTriggerPoint(m_textBuffer),
session),
m_compList,
Nothing))
End Sub
Private Function FindTokenSpanAtPosition(ByVal point As ITrackingPoint, ByVal session As ICompletionSession) As ITrackingSpan
Dim currentPoint As SnapshotPoint = (session.TextView.Caret.Position.BufferPosition) - 1
Dim navigator As ITextStructureNavigator = m_sourceProvider.NavigatorService.GetTextStructureNavigator(m_textBuffer)
Dim extent As TextExtent = navigator.GetExtentOfWord(currentPoint)
Return currentPoint.Snapshot.CreateTrackingSpan(extent.Span, SpanTrackingMode.EdgeInclusive)
End Function
private bool m_isDisposed;
public void Dispose()
{
if (!m_isDisposed)
{
GC.SuppressFinalize(this);
m_isDisposed = true;
}
}
Private m_isDisposed As Boolean
Public Sub Dispose() Implements IDisposable.Dispose
If Not m_isDisposed Then
GC.SuppressFinalize(Me)
m_isDisposed = True
End If
End Sub
public ICompletionSource TryCreateCompletionSource(ITextBuffer textBuffer)
{
return new TestCompletionSource(this, textBuffer);
}
Public Function TryCreateCompletionSource(ByVal textBuffer As ITextBuffer) As ICompletionSource Implements ICompletionSourceProvider.TryCreateCompletionSource
Return New TestCompletionSource(Me, textBuffer)
End Function
using System;
using System.ComponentModel.Composition;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Utilities;
public void VsTextViewCreated(IVsTextView textViewAdapter)
{
ITextView textView = AdapterService.GetWpfTextView(textViewAdapter);
if (textView == null)
return;
Func<TestCompletionCommandHandler> createCommandHandler = delegate() { return new TestCompletionCommandHandler(textViewAdapter, textView, this); };
textView.Properties.GetOrCreateSingletonProperty(createCommandHandler);
}
Public Sub VsTextViewCreated(ByVal textViewAdapter As IVsTextView) Implements IVsTextViewCreationListener.VsTextViewCreated
Dim textView As ITextView = AdapterService.GetWpfTextView(textViewAdapter)
If textView Is Nothing Then
Return
End If
Dim createCommandHandler As Func(Of TestCompletionCommandHandler) = Function() New TestCompletionCommandHandler(textViewAdapter, textView, Me)
textView.Properties.GetOrCreateSingletonProperty(createCommandHandler)
End Sub
Private m_nextCommandHandler As IOleCommandTarget
Private m_textView As ITextView
Private m_provider As TestCompletionHandlerProvider
Private m_session As ICompletionSession
internal TestCompletionCommandHandler(IVsTextView textViewAdapter, ITextView textView, TestCompletionHandlerProvider provider)
{
this.m_textView = textView;
this.m_provider = provider;
//add the command to the command chain
textViewAdapter.AddCommandFilter(this, out m_nextCommandHandler);
}
Friend Sub New(ByVal textViewAdapter As IVsTextView, ByVal textView As ITextView, ByVal provider As TestCompletionHandlerProvider)
Me.m_textView = textView
Me.m_provider = provider
'add the command to the command chain
textViewAdapter.AddCommandFilter(Me, m_nextCommandHandler)
End Sub
public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
{
return m_nextCommandHandler.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
}
Public Function QueryStatus(ByRef pguidCmdGroup As Guid, ByVal cCmds As UInteger, ByVal prgCmds() As OLECMD, ByVal pCmdText As IntPtr) As Integer Implements IOleCommandTarget.QueryStatus
Return m_nextCommandHandler.QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText)
End Function
public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
{
if (VsShellUtilities.IsInAutomationFunction(m_provider.ServiceProvider))
{
return m_nextCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
}
//make a copy of this so we can look at it after forwarding some commands
uint commandID = nCmdID;
char typedChar = char.MinValue;
//make sure the input is a char before getting it
if (pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.TYPECHAR)
{
typedChar = (char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn);
}
//check for a commit character
if (nCmdID == (uint)VSConstants.VSStd2KCmdID.RETURN
|| nCmdID == (uint)VSConstants.VSStd2KCmdID.TAB
|| (char.IsWhiteSpace(typedChar) || char.IsPunctuation(typedChar)))
{
//check for a selection
if (m_session != null && !m_session.IsDismissed)
{
//if the selection is fully selected, commit the current session
if (m_session.SelectedCompletionSet.SelectionStatus.IsSelected)
{
m_session.Commit();
//also, don't add the character to the buffer
return VSConstants.S_OK;
}
else
{
//if there is no selection, dismiss the session
m_session.Dismiss();
}
}
}
//pass along the command so the char is added to the buffer
int retVal = m_nextCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
bool handled = false;
if (!typedChar.Equals(char.MinValue) && char.IsLetterOrDigit(typedChar))
{
if (m_session == null || m_session.IsDismissed) // If there is no active session, bring up completion
{
this.TriggerCompletion();
m_session.Filter();
}
else //the completion session is already active, so just filter
{
m_session.Filter();
}
handled = true;
}
else if (commandID == (uint)VSConstants.VSStd2KCmdID.BACKSPACE //redo the filter if there is a deletion
|| commandID == (uint)VSConstants.VSStd2KCmdID.DELETE)
{
if (m_session != null && !m_session.IsDismissed)
m_session.Filter();
handled = true;
}
if (handled) return VSConstants.S_OK;
return retVal;
}
Public Function Exec(ByRef pguidCmdGroup As Guid, ByVal nCmdID As UInteger, ByVal nCmdexecopt As UInteger, ByVal pvaIn As IntPtr, ByVal pvaOut As IntPtr) As Integer Implements IOleCommandTarget.Exec
If VsShellUtilities.IsInAutomationFunction(m_provider.ServiceProvider) Then
Return m_nextCommandHandler.Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut)
End If
'make a copy of this so we can look at it after forwarding some commands
Dim commandID As UInteger = nCmdID
Dim typedChar As Char = Char.MinValue
'make sure the input is a char before getting it
If pguidCmdGroup = VSConstants.VSStd2K AndAlso nCmdID = CUInt(VSConstants.VSStd2KCmdID.TYPECHAR) Then
typedChar = CChar(ChrW(CUShort(Marshal.GetObjectForNativeVariant(pvaIn))))
End If
'check for a commit character
If nCmdID = CUInt(VSConstants.VSStd2KCmdID.RETURN) OrElse nCmdID = CUInt(VSConstants.VSStd2KCmdID.TAB) OrElse (Char.IsWhiteSpace(typedChar) OrElse Char.IsPunctuation(typedChar)) Then
'check for a selection
If m_session IsNot Nothing AndAlso (Not m_session.IsDismissed) Then
'if the selection is fully selected, commit the current session
If m_session.SelectedCompletionSet.SelectionStatus.IsSelected Then
m_session.Commit()
'also, don't add the character to the buffer
Return VSConstants.S_OK
Else
'if there is no selection, dismiss the session
m_session.Dismiss()
End If
End If
End If
'pass along the command so the char is added to the buffer
Dim retVal As Integer = m_nextCommandHandler.Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut)
Dim handled As Boolean = False
If (Not typedChar.Equals(Char.MinValue)) AndAlso Char.IsLetterOrDigit(typedChar) Then
If m_session Is Nothing OrElse m_session.IsDismissed Then ' If there is no active session, bring up completion
Me.TriggerCompletion()
m_session.Filter()
Else 'the completion session is already active, so just filter
m_session.Filter()
End If
handled = True
ElseIf commandID = CUInt(VSConstants.VSStd2KCmdID.BACKSPACE) OrElse commandID = CUInt(VSConstants.VSStd2KCmdID.DELETE) Then 'redo the filter if there is a deletion
If m_session IsNot Nothing AndAlso (Not m_session.IsDismissed) Then
m_session.Filter()
End If
handled = True
End If
If handled Then
Return VSConstants.S_OK
End If
Return retVal
End Function
private bool TriggerCompletion()
{
//the caret must be in a non-projection location
SnapshotPoint? caretPoint =
m_textView.Caret.Position.Point.GetPoint(
textBuffer => (!textBuffer.ContentType.IsOfType("projection")), PositionAffinity.Predecessor);
if (!caretPoint.HasValue)
{
return false;
}
m_session = m_provider.CompletionBroker.CreateCompletionSession
(m_textView,
caretPoint.Value.Snapshot.CreateTrackingPoint(caretPoint.Value.Position, PointTrackingMode.Positive),
true);
//subscribe to the Dismissed event on the session
m_session.Dismissed += this.OnSessionDismissed;
m_session.Start();
return true;
}
Private Function TriggerCompletion() As Boolean
'the caret must be in a non-projection location
Dim caretPoint As SnapshotPoint? = m_textView.Caret.Position.Point.GetPoint(Function(textBuffer) ((Not textBuffer.ContentType.IsOfType("projection"))), PositionAffinity.Predecessor)
If Not caretPoint.HasValue Then
Return False
End If
m_session = m_provider.CompletionBroker.CreateCompletionSession(m_textView, caretPoint.Value.Snapshot.CreateTrackingPoint(caretPoint.Value.Position, PointTrackingMode.Positive), True)
'subscribe to the Dismissed event on the session
AddHandler m_session.Dismissed, AddressOf OnSessionDismissed
m_session.Start()
Return True
End Function
Private Sub OnSessionDismissed(ByVal sender As Object, ByVal e As EventArgs)
RemoveHandler m_session.Dismissed, AddressOf OnSessionDismissed
m_session = Nothing
End Sub