/// <summary> /// Try and custom process the given InsertCommand when it's appropriate to override /// with Visual Studio specific behavior /// </summary> public bool TryCustomProcess(InsertCommand command) { var oleCommandData = OleCommandData.Empty; try { if (!TryGetOleCommandData(command, out oleCommandData)) { // Not a command that we custom process return(false); } if (_vim.InBulkOperation && !command.IsInsertNewLine) { // If we are in the middle of a bulk operation we don't want to forward any // input to IOleCommandTarget because it will trigger actions like displaying // Intellisense. Definitely don't want intellisense popping up during say a // repeat of a 'cw' operation or macro. // // The one exception to this rule though is the Enter key. Every single language // formats Enter in a special way that we absolutely want to preserve in a change // or macro operation. Go ahead and let it go through here and we'll dismiss // any intellisense which pops up as a result return(false); } var versionNumber = _textBuffer.CurrentSnapshot.Version.VersionNumber; int hr = _nextTarget.Exec(oleCommandData); // Whether or not an Exec succeeded is a bit of a heuristic. IOleCommandTarget implementations like // C++ will return E_ABORT if Intellisense failed but the character was actually inserted into // the ITextBuffer. VsVim really only cares about the character insert. However we must also // consider cases where the character successfully resulted in no action as a success return(ErrorHandler.Succeeded(hr) || versionNumber < _textBuffer.CurrentSnapshot.Version.VersionNumber); } finally { if (oleCommandData != null) { oleCommandData.Dispose(); } if (_vim.InBulkOperation && _broker.IsCompletionActive) { _broker.DismissDisplayWindows(); } } }
public void DismissDisplayWindows1() { _quickInfoBroker.Setup(x => x.IsQuickInfoActive(_textView.Object)).Returns(true).Verifiable(); _quickInfoBroker.Setup(x => x.GetSessions(_textView.Object)).Returns(new List <IQuickInfoSession>().AsReadOnly()).Verifiable(); _broker.DismissDisplayWindows(); _quickInfoBroker.Verify(); }
/// <summary> /// Try and custom process the given InsertCommand when it's appropriate to override /// with Visual Studio specific behavior /// </summary> public bool TryCustomProcess(InsertCommand command) { // Don't want to let VS process insert commands during clean macro recording. Doing so // will pop up UI, auto complete braces, etc ... which interfere with recording. if (_vim.MacroRecorder.IsRecording && _vimApplicationSettings.CleanMacros) { return(false); } VimTrace.TraceInfo($"TryCustomProcess {command} and completion {_broker.IsCompletionActive}"); var oleCommandData = OleCommandData.Empty; try { if (_vim.InBulkOperation && !command.IsInsertNewLine) { // If we are in the middle of a bulk operation we don't want to forward any // input to IOleCommandTarget because it will trigger actions like displaying // Intellisense. Definitely don't want intellisense popping up during say a // repeat of a 'cw' operation or macro. // // The one exception to this rule though is the Enter key. Every single language // formats Enter in a special way that we absolutely want to preserve in a change // or macro operation. Go ahead and let it go through here and we'll dismiss // any intellisense which pops up as a result return(false); } if (!_vimApplicationSettings.UseEditorTabAndBackspace && (command.IsBack || command.IsInsertTab)) { // When the user has opted into 'softtabstop' then Vim has a better understanding of // <BS> than Visual Studio. Allow that processing to win return(false); } if (!TryGetOleCommandData(command, out oleCommandData)) { // Not a command that we custom process return(false); } var versionNumber = _textBuffer.CurrentSnapshot.Version.VersionNumber; var hr = _nextCommandTarget.Exec(oleCommandData); // Whether or not an Exec succeeded is a bit of a heuristic. IOleCommandTarget implementations like // C++ will return E_ABORT if Intellisense failed but the character was actually inserted into // the ITextBuffer. VsVim really only cares about the character insert. However we must also // consider cases where the character successfully resulted in no action as a success return(ErrorHandler.Succeeded(hr) || versionNumber < _textBuffer.CurrentSnapshot.Version.VersionNumber); } finally { if (oleCommandData != null) { oleCommandData.Dispose(); } if (_vim.InBulkOperation && _broker.IsCompletionActive) { _broker.DismissDisplayWindows(); } } }
/// <summary> /// Try and process the KeyInput from the Exec method. This method decides whether or not /// a key should be processed directly by IVimBuffer or if should be going through /// IOleCommandTarget. Generally the key is processed by IVimBuffer but for many intellisense /// scenarios we want the key to be routed to Visual Studio directly. Issues to consider /// here are ... /// /// - How should the KeyInput participate in Macro playback? /// - Does both VsVim and Visual Studio need to process the key (Escape mainly) /// /// </summary> private bool TryProcessWithBuffer(KeyInput keyInput) { // If the IVimBuffer can't process it then it doesn't matter if (!_vimBuffer.CanProcess(keyInput)) { return(false); } // In the middle of a word completion session let insert mode handle the input. It's // displaying the intellisense itself and this method is meant to let custom intellisense // operate normally if (_vimBuffer.ModeKind == ModeKind.Insert && _vimBuffer.InsertMode.ActiveWordCompletionSession.IsSome()) { return(_vimBuffer.Process(keyInput).IsAnyHandled); } // If we are in a peek definition window and normal mode we need to let the Escape key // pass on to the next command target. This is necessary to close the peek definition // window if (_vimBuffer.ModeKind == ModeKind.Normal && _textView.IsPeekView() && keyInput == KeyInputUtil.EscapeKey) { return(false); } // The only time we actively intercept keys and route them through IOleCommandTarget // is when one of the IDisplayWindowBroker windows is active // // In those cases if the KeyInput is a command which should be handled by the // display window we route it through IOleCommandTarget to get the proper // experience for those features if (!_broker.IsAnyDisplayActive()) { return(_vimBuffer.Process(keyInput).IsAnyHandled); } // Next we need to consider here are Key mappings. The CanProcess and Process APIs // will automatically map the KeyInput under the hood at the IVimBuffer level but // not at the individual IMode. Have to manually map here and test against the // mapped KeyInput if (!TryGetSingleMapping(keyInput, out KeyInput mapped)) { return(_vimBuffer.Process(keyInput).IsAnyHandled); } bool handled; if (IsDisplayWindowKey(mapped)) { // If the key which actually needs to be processed is a display window key, say // down, up, etc..., then forward it on to the next IOleCommandTarget. It is responsible // for mapping that key to action against the display window handled = ErrorHandler.Succeeded(_nextOleCommandTarget.Exec(mapped)); } else { // Intentionally using keyInput here and not mapped. Process will do mapping on the // provided input hence we should be using the original keyInput here not mapped handled = _vimBuffer.Process(keyInput).IsAnyHandled; } // The Escape key should always dismiss the active completion session. However Vim // itself is mostly ignorant of display windows and typically won't dismiss them // as part of processing Escape (one exception is insert mode). Dismiss it here if // it's still active if (mapped.Key == VimKey.Escape && _broker.IsAnyDisplayActive()) { _broker.DismissDisplayWindows(); } return(handled); }