diff --git a/Src/VsVim/PkgCmdID.cs b/Src/VsVim/PkgCmdID.cs
index f27d41d0bf..62c1d8a9a5 100644
--- a/Src/VsVim/PkgCmdID.cs
+++ b/Src/VsVim/PkgCmdID.cs
@@ -13,5 +13,6 @@ internal static class CommandIds
internal const uint ToggleEnabled = 0x103;
internal const uint SetEnabled = 0x104;
internal const uint SetDisabled = 0x105;
+ internal const uint SetMode = 0x106;
};
}
\ No newline at end of file
diff --git a/Src/VsVim/VsVim.vsct b/Src/VsVim/VsVim.vsct
index bb2adc78a4..b27dbcdd3a 100644
--- a/Src/VsVim/VsVim.vsct
+++ b/Src/VsVim/VsVim.vsct
@@ -123,6 +123,16 @@
+
@@ -151,6 +161,7 @@
+
diff --git a/Src/VsVim/VsVimPackage.cs b/Src/VsVim/VsVimPackage.cs
index 880e69bb1b..3fefed37f8 100644
--- a/Src/VsVim/VsVimPackage.cs
+++ b/Src/VsVim/VsVimPackage.cs
@@ -4,6 +4,7 @@
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.Text.Editor;
using Microsoft.Win32;
using System;
using System.ComponentModel.Composition.Hosting;
@@ -31,6 +32,7 @@ public sealed class VsVimPackage : Package, IOleCommandTarget
private IComponentModel _componentModel;
private ExportProvider _exportProvider;
private IVim _vim;
+ private IVsAdapter _vsAdapter;
public VsVimPackage()
{
@@ -43,6 +45,7 @@ protected override void Initialize()
_componentModel = (IComponentModel)GetService(typeof(SComponentModel));
_exportProvider = _componentModel.DefaultExportProvider;
_vim = _exportProvider.GetExportedValue();
+ _vsAdapter = _exportProvider.GetExportedValue();
}
protected override void Dispose(bool disposing)
@@ -73,6 +76,9 @@ private void DumpKeyboard()
{
keyBindingService.DumpKeyboard(streamWriter);
}
+
+ var message = string.Format("Keyboard data dumped to: {0}", filePath);
+ PrintToCommandWindow(message);
}
///
@@ -143,41 +149,134 @@ private void ToggleEnabled()
_vim.IsDisabled = !_vim.IsDisabled;
}
- #region IOleCommandTarget
+ private void PrintToCommandWindow(string text)
+ {
+ var commandWindow = (IVsCommandWindow)GetService(typeof(SVsCommandWindow));
+ if (commandWindow == null)
+ {
+ return;
+ }
- int IOleCommandTarget.Exec(ref Guid commandGroup, uint commandId, uint commandExecOpt, IntPtr variantIn, IntPtr variantOut)
+ // Only print the text if a command is being run in the command window. If it's being run via another extension
+ // then don't print any output.
+ int running;
+ if (VSConstants.S_OK != commandWindow.RunningCommandWindowCommand(out running) || running == 0)
+ {
+ return;
+ }
+
+ commandWindow.Print(text);
+ }
+
+ private int SetMode(IntPtr variantIn, IntPtr variantOut, uint commandExecOpt)
+ {
+ if (IsQueryParameterList(variantIn, variantOut, commandExecOpt))
+ {
+ Marshal.GetNativeVariantForObject("mode", variantOut);
+ return VSConstants.S_OK;
+ }
+
+ var name = GetStringArgument(variantIn) ?? "";
+
+ ModeKind mode;
+ if (!Enum.TryParse(name, out mode))
+ {
+ PrintToCommandWindow(string.Format("Invalid mode name: {0}", name));
+
+ var all = string.Join(", ", Enum.GetNames(typeof(ModeKind)));
+ PrintToCommandWindow(string.Format("Valid names: {0}", all));
+ return VSConstants.E_INVALIDARG;
+ }
+
+ IWpfTextView activeTextView;
+ if (!_vsAdapter.TryGetActiveTextView(out activeTextView))
+ {
+ PrintToCommandWindow("Could not detect an active vim buffer");
+ return VSConstants.E_FAIL;
+ }
+
+ IVimBuffer vimBuffer;
+ if (!_vim.TryGetVimBuffer(activeTextView, out vimBuffer))
+ {
+ PrintToCommandWindow("Active view isn't a vim buffer");
+ return VSConstants.E_FAIL;
+ }
+
+ vimBuffer.SwitchMode(mode, ModeArgument.None);
+ return VSConstants.S_OK;
+ }
+
+ private string GetStringArgument(IntPtr variantIn)
+ {
+ if (variantIn == IntPtr.Zero)
+ {
+ return null;
+ }
+
+ var obj = Marshal.GetObjectForNativeVariant(variantIn);
+ return obj as string;
+ }
+
+ ///
+ /// Used to determine if the shell is querying for the parameter list of our command.
+ ///
+ private static bool IsQueryParameterList(IntPtr variantIn, IntPtr variantOut, uint nCmdexecopt)
{
- if (commandGroup == GuidList.VsVimCommandSet)
+ ushort lo = (ushort)(nCmdexecopt & (uint)0xffff);
+ ushort hi = (ushort)(nCmdexecopt >> 16);
+ if (lo == (ushort)OLECMDEXECOPT.OLECMDEXECOPT_SHOWHELP)
{
- switch (commandId)
+ if (hi == VsMenus.VSCmdOptQueryParameterList)
{
- case CommandIds.Options:
- ShowOptionPage(typeof(Vim.VisualStudio.Implementation.OptionPages.KeyboardOptionPage));
- break;
- case CommandIds.DumpKeyboard:
- DumpKeyboard();
- break;
- case CommandIds.ClearTSQLBindings:
- ClearTSQLBindings();
- break;
- case CommandIds.ToggleEnabled:
- ToggleEnabled();
- break;
- case CommandIds.SetEnabled:
- _vim.IsDisabled = false;
- break;
- case CommandIds.SetDisabled:
- _vim.IsDisabled = true;
- break;
- default:
- Debug.Assert(false);
- break;
+ if (variantOut != IntPtr.Zero)
+ {
+ return true;
+ }
}
+ }
- return VSConstants.S_OK;
+ return false;
+ }
+
+ #region IOleCommandTarget
+
+ int IOleCommandTarget.Exec(ref Guid commandGroup, uint commandId, uint commandExecOpt, IntPtr variantIn, IntPtr variantOut)
+ {
+ if (commandGroup != GuidList.VsVimCommandSet)
+ {
+ return VSConstants.E_FAIL;
}
- return VSConstants.E_FAIL;
+ var hr = VSConstants.S_OK;
+ switch (commandId)
+ {
+ case CommandIds.Options:
+ ShowOptionPage(typeof(Vim.VisualStudio.Implementation.OptionPages.KeyboardOptionPage));
+ break;
+ case CommandIds.DumpKeyboard:
+ DumpKeyboard();
+ break;
+ case CommandIds.ClearTSQLBindings:
+ ClearTSQLBindings();
+ break;
+ case CommandIds.ToggleEnabled:
+ ToggleEnabled();
+ break;
+ case CommandIds.SetEnabled:
+ _vim.IsDisabled = false;
+ break;
+ case CommandIds.SetDisabled:
+ _vim.IsDisabled = true;
+ break;
+ case CommandIds.SetMode:
+ hr = SetMode(variantIn, variantOut, commandExecOpt);
+ break;
+ default:
+ Debug.Assert(false);
+ break;
+ }
+
+ return hr;
}
int IOleCommandTarget.QueryStatus(ref Guid commandGroup, uint commandsCount, OLECMD[] commands, IntPtr pCmdText)
diff --git a/Src/VsVimShared/IVsAdapter.cs b/Src/VsVimShared/IVsAdapter.cs
index 390f1c899c..b5b58a5eec 100644
--- a/Src/VsVimShared/IVsAdapter.cs
+++ b/Src/VsVimShared/IVsAdapter.cs
@@ -117,6 +117,12 @@ public interface IVsAdapter
Result GetTextBufferForDocCookie(uint cookie);
+ ///
+ /// Get the which has focus.
+ ///
+ ///
+ bool TryGetActiveTextView(out IWpfTextView textView);
+
///
/// Open a file with the specified name in Visual Studio
///
diff --git a/Src/VsVimShared/Implementation/Misc/VsAdapter.cs b/Src/VsVimShared/Implementation/Misc/VsAdapter.cs
index 6123938d5f..189dbf6b82 100644
--- a/Src/VsVimShared/Implementation/Misc/VsAdapter.cs
+++ b/Src/VsVimShared/Implementation/Misc/VsAdapter.cs
@@ -461,6 +461,27 @@ private void OpenFile(string filePath)
}
}
+ private bool TryGetActiveTextView(out IWpfTextView textView)
+ {
+ var textManager = _serviceProvider.GetService();
+ if (textManager == null)
+ {
+ textView = null;
+ return false;
+ }
+
+ IVsTextView vsTextView;
+ var hr = textManager.GetActiveView2(fMustHaveFocus: 0, pBuffer: null, grfIncludeViewFrameType: (uint)_VIEWFRAMETYPE.vftCodeWindow, ppView: out vsTextView);
+ if (ErrorHandler.Failed(hr))
+ {
+ textView = null;
+ return false;
+ }
+
+ textView = _editorAdaptersFactoryService.GetWpfTextView(vsTextView);
+ return textView != null;
+ }
+
#region IVsAdapter
bool IVsAdapter.InAutomationFunction
@@ -563,6 +584,11 @@ void IVsAdapter.OpenFile(string filePath)
OpenFile(filePath);
}
+ bool IVsAdapter.TryGetActiveTextView(out IWpfTextView textView)
+ {
+ return TryGetActiveTextView(out textView);
+ }
+
#endregion
}
}