From 07ad76bf99038435261047d2cc399dd7bb476a29 Mon Sep 17 00:00:00 2001 From: Jared Parsons Date: Sun, 18 Sep 2016 21:51:40 -0700 Subject: [PATCH 1/4] Print location of the dumped keyboard file --- Src/VsVim/VsVimPackage.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Src/VsVim/VsVimPackage.cs b/Src/VsVim/VsVimPackage.cs index 880e69bb1b..11a1be112f 100644 --- a/Src/VsVim/VsVimPackage.cs +++ b/Src/VsVim/VsVimPackage.cs @@ -73,6 +73,9 @@ private void DumpKeyboard() { keyBindingService.DumpKeyboard(streamWriter); } + + var message = string.Format("Keyboard data dumped to: {0}", filePath); + PrintToCommandWindow(message); } /// @@ -143,6 +146,17 @@ private void ToggleEnabled() _vim.IsDisabled = !_vim.IsDisabled; } + private void PrintToCommandWindow(string text) + { + var commandWindow = (IVsCommandWindow)GetService(typeof(SVsCommandWindow)); + if (commandWindow == null) + { + return; + } + + commandWindow.Print(text); + } + #region IOleCommandTarget int IOleCommandTarget.Exec(ref Guid commandGroup, uint commandId, uint commandExecOpt, IntPtr variantIn, IntPtr variantOut) From 6ae6fbd74048c9e4cef1167b2263381e506262e2 Mon Sep 17 00:00:00 2001 From: Jared Parsons Date: Sun, 18 Sep 2016 23:08:11 -0700 Subject: [PATCH 2/4] Add a VsVim.SetMode command Adds a new command to set the mode of the active VsVim buffer. Having some issues with accepting the parameter value though. Need to work that out before this can get merged in. --- Src/VsVim/PkgCmdID.cs | 1 + Src/VsVim/VsVim.vsct | 11 ++++ Src/VsVim/VsVimPackage.cs | 102 ++++++++++++++++++++++++++++---------- 3 files changed, 87 insertions(+), 27 deletions(-) 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 11a1be112f..4ba4118d25 100644 --- a/Src/VsVim/VsVimPackage.cs +++ b/Src/VsVim/VsVimPackage.cs @@ -154,44 +154,92 @@ private void PrintToCommandWindow(string text) return; } + // 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) + { + 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; + } + + var option = _vim.ActiveBuffer; + if (option.IsNone()) + { + PrintToCommandWindow("Could not detect an active vim buffer"); + return VSConstants.E_FAIL; + } + + option.Value.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; + } + #region IOleCommandTarget int IOleCommandTarget.Exec(ref Guid commandGroup, uint commandId, uint commandExecOpt, IntPtr variantIn, IntPtr variantOut) { - if (commandGroup == GuidList.VsVimCommandSet) + if (commandGroup != GuidList.VsVimCommandSet) { - 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; - default: - Debug.Assert(false); - break; - } + return VSConstants.E_FAIL; + } - return VSConstants.S_OK; + 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); + break; + default: + Debug.Assert(false); + break; } - return VSConstants.E_FAIL; + return hr; } int IOleCommandTarget.QueryStatus(ref Guid commandGroup, uint commandsCount, OLECMD[] commands, IntPtr pCmdText) From c01d05bfd4cbde94e44630d691667cf29fbf25e1 Mon Sep 17 00:00:00 2001 From: Jared Parsons Date: Mon, 19 Sep 2016 10:54:16 -0700 Subject: [PATCH 3/4] Respond to query parameter list In order for a command to accept arguments it must respond to the VSCmdOptQueryParameterList request. --- Src/VsVim/VsVimPackage.cs | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/Src/VsVim/VsVimPackage.cs b/Src/VsVim/VsVimPackage.cs index 4ba4118d25..914cc3118d 100644 --- a/Src/VsVim/VsVimPackage.cs +++ b/Src/VsVim/VsVimPackage.cs @@ -165,8 +165,14 @@ private void PrintToCommandWindow(string text) commandWindow.Print(text); } - private int SetMode(IntPtr variantIn) + 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; @@ -201,6 +207,27 @@ private string GetStringArgument(IntPtr 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) + { + ushort lo = (ushort)(nCmdexecopt & (uint)0xffff); + ushort hi = (ushort)(nCmdexecopt >> 16); + if (lo == (ushort)OLECMDEXECOPT.OLECMDEXECOPT_SHOWHELP) + { + if (hi == VsMenus.VSCmdOptQueryParameterList) + { + if (variantOut != IntPtr.Zero) + { + return true; + } + } + } + + return false; + } + #region IOleCommandTarget int IOleCommandTarget.Exec(ref Guid commandGroup, uint commandId, uint commandExecOpt, IntPtr variantIn, IntPtr variantOut) @@ -232,7 +259,7 @@ int IOleCommandTarget.Exec(ref Guid commandGroup, uint commandId, uint commandEx _vim.IsDisabled = true; break; case CommandIds.SetMode: - hr = SetMode(variantIn); + hr = SetMode(variantIn, variantOut, commandExecOpt); break; default: Debug.Assert(false); From 2375dce95ee3d5243c8c47bbd6bd2e3f48bb8724 Mon Sep 17 00:00:00 2001 From: Jared Parsons Date: Fri, 23 Sep 2016 08:24:10 -0700 Subject: [PATCH 4/4] Added command VsVim.SetMode This is available from the command window. It takes a mode name and will switch the active, or previously active, buffer to that mode. To get the list of modes just invoke the command without arguments. Example: > VsVim.SetMode Insert closes #1825 closes #741 --- Src/VsVim/VsVimPackage.cs | 16 +++++++++--- Src/VsVimShared/IVsAdapter.cs | 6 +++++ .../Implementation/Misc/VsAdapter.cs | 26 +++++++++++++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/Src/VsVim/VsVimPackage.cs b/Src/VsVim/VsVimPackage.cs index 914cc3118d..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) @@ -185,14 +188,21 @@ private int SetMode(IntPtr variantIn, IntPtr variantOut, uint commandExecOpt) return VSConstants.E_INVALIDARG; } - var option = _vim.ActiveBuffer; - if (option.IsNone()) + IWpfTextView activeTextView; + if (!_vsAdapter.TryGetActiveTextView(out activeTextView)) { PrintToCommandWindow("Could not detect an active vim buffer"); return VSConstants.E_FAIL; } - option.Value.SwitchMode(mode, ModeArgument.None); + 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; } 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 } }