Ejemplo n.º 1
0
        /// <summary>
        /// Try and process the KeyInput from the Exec method
        /// </summary>
        private bool TryExec(ref Guid commandGroup, ref OleCommandData oleCommandData, KeyInput keyInput)
        {
            if (!_buffer.CanProcess(keyInput))
            {
                // If the IVimBuffer can't process it then it doesn't matter
                return(false);
            }

            // Next we need to determine if we can process this directly or not.  The only mode
            // we actively intercept KeyInput for is InsertMode because we need to route it
            // through IOleCommandTarget to get Intellisense and many other features.
            var mode = _buffer.ModeKind == ModeKind.Insert
                ? _buffer.InsertMode
                : null;

            if (mode == null)
            {
                return(_buffer.Process(keyInput));
            }

            // 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
            KeyInput mapped;

            if (!TryGetSingleMapping(KeyRemapMode.Insert, keyInput, out mapped) || CanProcessDirectly(mode, mapped))
            {
                return(_buffer.Process(keyInput));
            }

            // At this point we've determined that we need to intercept this
            return(TryExecIntercepted(ref commandGroup, ref oleCommandData, keyInput, mapped));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Last chance at custom handling of user input.  At this point we have the
        /// advantage that WPF has properly converted the user input into a char which
        /// can be effeciently mapped to a KeyInput value.
        /// </summary>
        public override void TextInput(TextCompositionEventArgs args)
        {
            bool handled = false;

            if (!String.IsNullOrEmpty(args.Text) && 1 == args.Text.Length && !IgnoreTextInput)
            {
                // Only want to intercept text coming from the keyboard.  Let other
                // components edit without having to come through us
                var keyboard = args.Device as KeyboardDevice;
                if (keyboard != null)
                {
                    var ki = KeyUtil.CharAndModifiersToKeyInput(args.Text[0], keyboard.Modifiers);
                    handled = _buffer.CanProcess(ki) && _buffer.Process(ki);
                }
            }

            if (handled)
            {
                args.Handled = true;
            }
            else
            {
                base.TextInput(args);
            }
        }
Ejemplo n.º 3
0
 public void QueryStatus_IgnoreEscapeIfCantProcess()
 {
     _buffer.SwitchMode(ModeKind.Disabled, ModeArgument.None);
     Assert.False(_buffer.CanProcess(KeyInputUtil.EscapeKey));
     _nextTarget.SetupQueryStatus().Verifiable();
     RunQueryStatus(KeyInputUtil.EscapeKey);
     _factory.Verify();
 }
Ejemplo n.º 4
0
        public void CanProcess_Simple()
        {
            var keyInput = KeyInputUtil.CharToKeyInput('c');
            var normal   = CreateAndAddNormalMode(MockBehavior.Loose);

            normal.Setup(x => x.CanProcess(keyInput)).Returns(true).Verifiable();
            _vimBuffer.SwitchMode(ModeKind.Normal, ModeArgument.None);
            Assert.IsTrue(_vimBuffer.CanProcess(keyInput));
            normal.Verify();
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Try and process the KeyInput from the Exec method
        /// </summary>
        private bool TryProcessWithBuffer(ref Guid commandGroup, ref OleCommandData oleCommandData, KeyInput keyInput)
        {
            if (!_buffer.CanProcess(keyInput))
            {
                // If the IVimBuffer can't process it then it doesn't matter
                return(false);
            }

            // Next we need to determine if we can process this directly or not.  The only mode
            // we actively intercept KeyInput for is InsertMode because we need to route it
            // through IOleCommandTarget to get Intellisense and many other features.
            var insertMode = _buffer.ModeKind == ModeKind.Insert
                ? _buffer.InsertMode
                : null;

            if (insertMode == null)
            {
                return(_buffer.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
            KeyInput mapped;

            if (!TryGetSingleMapping(keyInput, out mapped) || !ShouldProcessWithCommandTargetOverInsertMode(insertMode, mapped))
            {
                return(_buffer.Process(keyInput).IsAnyHandled);
            }

            // We are now intentionally by passing insert mode here.  If there is an active
            // IWordCompletionSession here we need to manually dismiss it.  Else it will remain
            // as we start typing a new word
            if (insertMode.ActiveWordCompletionSession.IsSome())
            {
                insertMode.ActiveWordCompletionSession.Value.Dismiss();
            }

            // We've successfully mapped the KeyInput (even if t's a no-op) and determined that
            // we don't want to process it directly if possible.  Now we try and process the
            // potentially mapped value
            if (TryProcessWithExec(commandGroup, oleCommandData, insertMode, keyInput, mapped))
            {
                return(true);
            }

            // If we couldn't map the KeyInput value into a Visual Studio command then go straight to the
            // ITextBuffer.  Insert mode is already designed to handle these KeyInput values we'd just prefer
            // to pass them through Visual Studio..  Remember to use the original KeyInput value here as
            // going through IVimBuffer will process mappings
            return(_buffer.Process(keyInput).IsAnyHandled);
        }
Ejemplo n.º 6
0
        internal bool TryProcess(VimKey vimKey, int clickCount = 1)
        {
            var keyInput = KeyInputUtil.ApplyKeyModifiersToKey(vimKey, _keyboardDevice.KeyModifiers);

            keyInput = KeyInputUtil.ApplyClickCount(keyInput, clickCount);

            // If the user has explicitly set the mouse to be <nop> then we don't want to report this as
            // handled.  Otherwise it will swallow the mouse event and as a consequence disable other
            // features that begin with a mouse click.
            //
            // There is really no other way for the user to opt out of mouse behavior besides mapping the
            // key to <nop> otherwise that would be done here.
            var keyInputSet = _vimBuffer.GetKeyInputMapping(keyInput).KeyInputSet;

            if (keyInputSet.Length > 0 && keyInputSet.KeyInputs[0].Key == VimKey.Nop)
            {
                return(false);
            }

            if (_vimBuffer.CanProcess(keyInput))
            {
                return(_vimBuffer.Process(keyInput).IsAnyHandled);
            }

            return(false);
        }
Ejemplo n.º 7
0
        internal bool TryProcess(VimKey vimKey)
        {
            var keyInput = KeyInputUtil.VimKeyToKeyInput(vimKey);

            if (_vimBuffer.CanProcess(keyInput))
            {
                return(_vimBuffer.Process(keyInput).IsAnyHandled);
            }

            return(false);
        }
Ejemplo n.º 8
0
        private CommandStatus QueryStatus(EditCommand editCommand)
        {
            if (editCommand.HasKeyInput && _vimBuffer.CanProcess(editCommand.KeyInput))
            {
                var commandStatus = QueryStatusCore(editCommand.KeyInput);
                if (commandStatus.HasValue)
                {
                    return(commandStatus.Value);
                }
            }

            return(CommandStatus.PassOn);
        }
Ejemplo n.º 9
0
        private bool TryProcess(KeyEventArgs e, KeyInput keyInput)
        {
            if (KeyEventIsDeadChar(e))
            {
                // When a dead key combination is pressed we will get the key down events in
                // sequence after the combination is complete.  The dead keys will come first
                // and be followed the final key which produces the char.  That final key
                // is marked as DeadCharProcessed.
                //
                // All of these should be ignored.  They will produce a TextInput value which
                // we can process in the TextInput event
                return(false);
            }

            if ((_vimBuffer.ModeKind.IsAnyInsert() || _vimBuffer.ModeKind.IsAnySelect()) &&
                !_vimBuffer.CanProcessAsCommand(keyInput) &&
                keyInput.Char > 0x1f &&
                _vimBuffer.BufferedKeyInputs.IsEmpty &&
                !_vimBuffer.Vim.MacroRecorder.IsRecording)
            {
                return(false);
            }

            if (_completionBroker.IsCompletionActive(_textView) && !IsEscapeKey(e))
            {
                return(false);
            }

            if (_signatureHelpBroker.IsSignatureHelpActive(_textView) && !IsEscapeKey(e))
            {
                return(false);
            }

            if (_inlineRenameListenerFactory.InRename)
            {
                return(false);
            }

            if (_vimBuffer.ModeKind.IsAnyInsert() && e.Characters == "\t")
            {
                // Allow tab key to work for snippet completion
                //
                // TODO: We should only really do this when the characters
                // to the left of the caret form a valid snippet
                return(false);
            }

            return(_vimBuffer.CanProcess(keyInput) && _vimBuffer.Process(keyInput).IsAnyHandled);
        }
Ejemplo n.º 10
0
        /// <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);
        }
Ejemplo n.º 11
0
 /// <summary>
 /// Try and process the given KeyInput with the IVimBuffer.  This is overridable by
 /// derived classes in order for them to prevent any KeyInput from reaching the
 /// IVimBuffer
 /// </summary>
 protected virtual bool TryProcess(KeyInput keyInput)
 {
     return(_vimBuffer.CanProcess(keyInput) && _vimBuffer.Process(keyInput).IsAnyHandled);
 }
Ejemplo n.º 12
0
        /// <summary>
        /// Helper for the CanProcess function which maps the VimKey to a KeyInput value
        /// </summary>
        public static bool CanProcess(this IVimBuffer buffer, VimKey key)
        {
            var keyInput = KeyInputUtil.VimKeyToKeyInput(key);

            return(buffer.CanProcess(keyInput));
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Helper for the CanProcess function which maps the char to a KeyInput value
        /// </summary>
        public static bool CanProcess(this IVimBuffer buffer, char c)
        {
            var keyInput = KeyInputUtil.CharToKeyInput(c);

            return(buffer.CanProcess(keyInput));
        }
Ejemplo n.º 14
0
        /// <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);
            }

            // 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())
            {
                // The one exception to this rule is R#.  We can't accurately determine if
                // R# has intellisense active or not so we have to pretend like it always
                // does.  We limit this to insert mode only though.
                if (!_resharperUtil.IsInstalled || _vimBuffer.ModeKind != ModeKind.Insert)
                {
                    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
            KeyInput mapped;

            if (!TryGetSingleMapping(keyInput, out mapped))
            {
                return(_vimBuffer.Process(keyInput).IsAnyHandled);
            }

            // If the key actually being processed is a display window key and the display window
            // is active then we allow IOleCommandTarget to control the key
            if (IsDisplayWindowKey(mapped))
            {
                return(false);
            }

            var 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);
        }