Skip to content

Commit 7e9aa7f

Browse files
committed
Implement Go To Definition - Native command.
Fixes #4 Fixes #8
1 parent 6ce75a4 commit 7e9aa7f

File tree

6 files changed

+53
-11
lines changed

6 files changed

+53
-11
lines changed

Ref12.Tests/Extensions.cs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
using System;
2-
using System.Globalization;
32
using System.Windows.Threading;
4-
using Microsoft.VisualStudio;
53
using Microsoft.VisualStudio.OLE.Interop;
64
using Microsoft.VisualStudio.Text;
75
using Microsoft.VisualStudio.Text.Editor;
86
using Microsoft.VisualStudio.TextManager.Interop;
7+
using SLaks.Ref12;
98

109
namespace Ref12.Tests {
1110
static class Extensions {
@@ -17,13 +16,8 @@ public static SnapshotSpan FindSpan(this ITextView textView, string search) {
1716
throw new ArgumentException("String " + search + " occurs multiple times. Please use a unique string");
1817
return new SnapshotSpan(textView.TextBuffer.CurrentSnapshot, startIndex, search.Length);
1918
}
20-
21-
public static void Execute(this IVsTextView textView, Enum commandId, IntPtr inHandle = default(IntPtr), IntPtr outHandle = default(IntPtr)) {
22-
Execute((IOleCommandTarget)textView, commandId, inHandle, outHandle);
23-
}
24-
public static void Execute(this IOleCommandTarget target, Enum commandId, IntPtr inHandle = default(IntPtr), IntPtr outHandle = default(IntPtr)) {
25-
var c = commandId.GetType().GUID;
26-
ErrorHandler.ThrowOnFailure(target.Exec(ref c, Convert.ToUInt32(commandId, CultureInfo.InvariantCulture), 0, inHandle, outHandle));
19+
public static void Execute(this IVsTextView textView, Enum commandId, uint execOptions = 0, IntPtr inHandle = default(IntPtr), IntPtr outHandle = default(IntPtr)) {
20+
((IOleCommandTarget)textView).Execute(commandId, execOptions, inHandle, outHandle);
2721
}
2822

2923

Ref12/Commands/CommandTargetBase.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ internal abstract class CommandTargetBase<TCommandEnum> : IOleCommandTarget wher
1313

1414
public Guid CommandGroup { get; set; }
1515
public ReadOnlyCollection<uint> CommandIds { get; private set; }
16+
protected IOleCommandTarget NextTarget { get { return nextCommandTarget; } }
1617

1718
public CommandTargetBase(IVsTextView adapter, ITextView textView, params TCommandEnum[] commandIds) : this(adapter, textView, typeof(TCommandEnum).GUID, Array.ConvertAll(commandIds, e => Convert.ToUInt32(e))) { }
1819
public CommandTargetBase(IVsTextView adapter, ITextView textView, Guid commandGroup, params uint[] commandIds) {
@@ -41,7 +42,7 @@ public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pv
4142
return nextCommandTarget.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
4243
}
4344

44-
public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) {
45+
public virtual int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) {
4546
if (pguidCmdGroup != CommandGroup)
4647
return nextCommandTarget.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
4748

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System;
2+
using Microsoft.VisualStudio;
3+
using Microsoft.VisualStudio.OLE.Interop;
4+
using Microsoft.VisualStudio.Text.Editor;
5+
using Microsoft.VisualStudio.TextManager.Interop;
6+
7+
namespace SLaks.Ref12.Commands {
8+
class GoToDefintionNativeCommand : CommandTargetBase<Ref12Command> {
9+
public GoToDefintionNativeCommand(IVsTextView adapter, IWpfTextView textView) : base(adapter, textView, Ref12Command.GoToDefinitionNative) {
10+
}
11+
protected override bool Execute(Ref12Command commandId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) {
12+
NextTarget.Execute(VSConstants.VSStd97CmdID.GotoDefn, nCmdexecopt, pvaIn, pvaOut);
13+
return true;
14+
}
15+
16+
protected override bool IsEnabled() {
17+
// We override QueryStatus directly to pass the raw arguments
18+
// to the inner command, so this method will never be called.
19+
throw new NotImplementedException();
20+
}
21+
public override int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) {
22+
if (pguidCmdGroup != CommandGroup || cCmds != 1 || prgCmds[0].cmdID != CommandIds[0])
23+
return NextTarget.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
24+
var innerGuid = typeof(VSConstants.VSStd97CmdID).GUID;
25+
var innerCommands = new[] { new OLECMD {
26+
cmdID = (uint)VSConstants.VSStd97CmdID.GotoDefn,
27+
cmdf=prgCmds[0].cmdf
28+
} };
29+
int result = NextTarget.QueryStatus(ref innerGuid, 1, innerCommands, pCmdText);
30+
prgCmds[0].cmdf = innerCommands[0].cmdf;
31+
return result;
32+
}
33+
}
34+
}

Ref12/Commands/TextViewListener.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ public async void SubjectBuffersConnected(IWpfTextView textView, ConnectionReaso
4141
if (!TextDocumentFactoryService.TryGetTextDocument(textView.TextDataModel.DocumentBuffer, out document))
4242
return;
4343

44+
// Register the native command first, so that it ends up earlier in
45+
// the command chain than our interceptor. This prevents the native
46+
// comand from being intercepted too.
47+
textView.Properties.GetOrCreateSingletonProperty(() => new GoToDefintionNativeCommand(textViewAdapter, textView));
4448
textView.Properties.GetOrCreateSingletonProperty(() => new GoToDefinitionInterceptor(ReferenceProviders, ServiceProvider, textViewAdapter, textView, document));
4549
}
4650
public void SubjectBuffersDisconnected(IWpfTextView textView, ConnectionReason reason, Collection<ITextBuffer> subjectBuffers) {

Ref12/Extensions.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
using System;
2+
using System.Globalization;
23
using System.Linq;
4+
using Microsoft.VisualStudio;
5+
using Microsoft.VisualStudio.OLE.Interop;
36
using Microsoft.VisualStudio.Text;
47
using Microsoft.VisualStudio.Text.Editor;
58
using Microsoft.VisualStudio.Text.Projection;
69

710
namespace SLaks.Ref12 {
8-
static class Extensions {
11+
public static class Extensions {
912
public static SnapshotPoint? GetCaretPoint(this ITextView textView, Predicate<ITextSnapshot> match) {
1013
CaretPosition position = textView.Caret.Position;
1114
SnapshotSpan? snapshotSpan = textView.BufferGraph.MapUpOrDownToFirstMatch(new SnapshotSpan(position.BufferPosition, 0), match);
@@ -24,5 +27,10 @@ static class Extensions {
2427
private static bool IsSourceBuffer(IProjectionBufferBase top, ITextBuffer bottom) {
2528
return top.SourceBuffers.Contains(bottom) || top.SourceBuffers.Any((ITextBuffer tb) => tb is IProjectionBufferBase && IsSourceBuffer((IProjectionBufferBase)tb, bottom));
2629
}
30+
31+
public static void Execute(this IOleCommandTarget target, Enum commandId, uint execOptions = 0, IntPtr inHandle = default(IntPtr), IntPtr outHandle = default(IntPtr)) {
32+
var c = commandId.GetType().GUID;
33+
ErrorHandler.ThrowOnFailure(target.Exec(ref c, Convert.ToUInt32(commandId, CultureInfo.InvariantCulture), execOptions, inHandle, outHandle));
34+
}
2735
}
2836
}

Ref12/Ref12.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
</ItemGroup>
100100
<ItemGroup>
101101
<Compile Include="Commands\CommandTargetBase.cs" />
102+
<Compile Include="Commands\GoToDefintionNativeCommand.cs" />
102103
<Compile Include="Commands\GoToDefinitionInterceptor.cs" />
103104
<Compile Include="Commands\TextViewListener.cs" />
104105
<Compile Include="Extensions.cs" />

0 commit comments

Comments
 (0)