예제 #1
0
        public static void Release(ref OleCommandData oleCommandData)
        {
            if (oleCommandData.VariantIn != IntPtr.Zero)
            {
                NativeMethods.VariantClear(oleCommandData.VariantIn);
                Marshal.FreeCoTaskMem(oleCommandData.VariantIn);
            }

            if (oleCommandData.VariantOut != IntPtr.Zero)
            {
                NativeMethods.VariantClear(oleCommandData.VariantOut);
                Marshal.FreeCoTaskMem(oleCommandData.VariantOut);
            }

            oleCommandData = new OleCommandData();
        }
예제 #2
0
        public static void Release(ref OleCommandData oleCommandData)
        {
            if (oleCommandData.VariantIn != IntPtr.Zero)
            {
                NativeMethods.VariantClear(oleCommandData.VariantIn);
                Marshal.FreeCoTaskMem(oleCommandData.VariantIn);
            }

            if (oleCommandData.VariantOut != IntPtr.Zero)
            {
                NativeMethods.VariantClear(oleCommandData.VariantOut);
                Marshal.FreeCoTaskMem(oleCommandData.VariantOut);
            }

            oleCommandData = new OleCommandData();
        }
예제 #3
0
        int IOleCommandTarget.Exec(ref Guid commandGroup, uint commandId, uint commandExecOpt, IntPtr variantIn, IntPtr variantOut)
        {
            try
            {
                EditCommand editCommand;
                if (TryConvert(commandGroup, commandId, variantIn, out editCommand))
                {
                    if (editCommand.IsUndo)
                    {
                        // The user hit the undo button.  Don't attempt to map anything here and instead just
                        // run a single Vim undo operation
                        _buffer.UndoRedoOperations.Undo(1);
                        return(NativeMethods.S_OK);
                    }
                    else if (editCommand.IsRedo)
                    {
                        // The user hit the redo button.  Don't attempt to map anything here and instead just
                        // run a single Vim redo operation
                        _buffer.UndoRedoOperations.Redo(1);
                        return(NativeMethods.S_OK);
                    }
                    else if (editCommand.HasKeyInput)
                    {
                        var keyInput = editCommand.KeyInput;

                        // Discard the input if it's been flagged by a previous QueryStatus
                        if (_bufferCoordinator.DiscardedKeyInput.IsSome(keyInput))
                        {
                            return(NativeMethods.S_OK);
                        }

                        // Try and process the command with the IVimBuffer
                        var commandData = new OleCommandData(commandId, commandExecOpt, variantIn, variantOut);
                        if (TryProcessWithBuffer(ref commandGroup, ref commandData, keyInput))
                        {
                            return(NativeMethods.S_OK);
                        }
                    }
                }
            }
            finally
            {
                _bufferCoordinator.DiscardedKeyInput = FSharpOption <KeyInput> .None;
            }

            return(_nextTarget.Exec(commandGroup, commandId, commandExecOpt, variantIn, variantOut));
        }
예제 #4
0
        /// <summary>
        /// Try and exec this KeyInput in an intercepted fashion
        /// </summary>
        private bool TryExecIntercepted(ref Guid commandGroup, ref OleCommandData oleCommandData, KeyInput originalKeyInput, KeyInput mappedKeyInput)
        {
            bool           intercepted;
            bool           result;
            Guid           mappedCommandGroup;
            OleCommandData mappedOleCommandData;

            if (originalKeyInput == mappedKeyInput)
            {
                // No changes so just use the original OleCommandData
                result = VSConstants.S_OK == _nextTarget.Exec(
                    ref commandGroup,
                    oleCommandData.CommandId,
                    oleCommandData.CommandExecOpt,
                    oleCommandData.VariantIn,
                    oleCommandData.VariantOut);
                intercepted = true;
            }
            else if (OleCommandUtil.TryConvert(mappedKeyInput, out mappedCommandGroup, out mappedOleCommandData))
            {
                result = VSConstants.S_OK == _nextTarget.Exec(
                    ref mappedCommandGroup,
                    mappedOleCommandData.CommandId,
                    mappedOleCommandData.CommandExecOpt,
                    mappedOleCommandData.VariantIn,
                    mappedOleCommandData.VariantOut);
                intercepted = true;
                OleCommandData.Release(ref mappedOleCommandData);
            }
            else
            {
                // If we couldn't process it using intercepting mechanism then just go straight to the IVimBuffer
                // for processing.
                result      = _buffer.Process(originalKeyInput);
                intercepted = false;
            }

            if (intercepted)
            {
                // We processed the input and bypassed the IVimBuffer instance.  We need to tell IVimBuffer this
                // KeyInput was processed so it can track it for macro purposes.  Make sure to track the mapped
                // KeyInput value.  The SimulateProcessed method does not mapping
                _buffer.SimulateProcessed(mappedKeyInput);
            }

            return(result);
        }
예제 #5
0
파일: Extensions.cs 프로젝트: renjiec/VsVim
        internal static int QueryStatus(this IOleCommandTarget oleCommandTarget, OleCommandData oleCommandData, out OLECMD command)
        {
            var commandGroup = oleCommandData.Group;
            var cmds         = new OLECMD[1];

            cmds[0] = new OLECMD {
                cmdID = oleCommandData.Id
            };
            var result = oleCommandTarget.QueryStatus(
                ref commandGroup,
                1,
                cmds,
                oleCommandData.VariantIn);

            command = cmds[0];
            return(result);
        }
예제 #6
0
        /// <summary>
        /// Try and process the given KeyInput for insert mode in the middle of an Exec.  This is
        /// called for commands which can't be processed directly like edits.  We'd prefer these
        /// go through Visual Studio's command system so items like Intellisense work properly.
        /// </summary>
        private bool TryProcessWithExec(Guid commandGroup, OleCommandData oleCommandData, IInsertMode insertMode, KeyInput originalKeyInput, KeyInput mappedKeyInput)
        {
            Func <bool> customProcess =
                () =>
            {
                var            versionNumber = _textBuffer.CurrentSnapshot.Version.VersionNumber;
                int?           hr            = null;
                Guid           mappedCommandGroup;
                OleCommandData mappedOleCommandData;
                if (originalKeyInput == mappedKeyInput)
                {
                    // No changes so just use the original OleCommandData
                    hr = _nextTarget.Exec(
                        ref commandGroup,
                        oleCommandData.CommandId,
                        oleCommandData.CommandExecOpt,
                        oleCommandData.VariantIn,
                        oleCommandData.VariantOut);
                }
                else if (OleCommandUtil.TryConvert(mappedKeyInput, out mappedCommandGroup, out mappedOleCommandData))
                {
                    hr = _nextTarget.Exec(
                        ref mappedCommandGroup,
                        mappedOleCommandData.CommandId,
                        mappedOleCommandData.CommandExecOpt,
                        mappedOleCommandData.VariantIn,
                        mappedOleCommandData.VariantOut);
                    OleCommandData.Release(ref mappedOleCommandData);
                }

                if (hr.HasValue)
                {
                    // 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.Value) || versionNumber < _textBuffer.CurrentSnapshot.Version.VersionNumber);
                }

                // Couldn't map to a Visual Studio command so it didn't succeed
                return(false);
            };

            return(insertMode.CustomProcess(mappedKeyInput, customProcess.ToFSharpFunc()));
        }
예제 #7
0
        int IOleCommandTarget.Exec(ref Guid commandGroup, uint commandId, uint commandExecOpt, IntPtr variantIn, IntPtr variantOut)
        {
            try
            {
                EditCommand editCommand;
                if (TryConvert(commandGroup, commandId, variantIn, out editCommand))
                {
                    if (editCommand.IsUndo)
                    {
                        _buffer.UndoRedoOperations.Undo(1);
                        return(NativeMethods.S_OK);
                    }
                    else if (editCommand.IsRedo)
                    {
                        _buffer.UndoRedoOperations.Redo(1);
                        return(NativeMethods.S_OK);
                    }
                    else if (editCommand.HasKeyInput)
                    {
                        var keyInput = editCommand.KeyInput;

                        // Swallow the input if it's been flagged by a previous QueryStatus
                        if (SwallowIfNextExecMatches.IsSome() && SwallowIfNextExecMatches.Value == keyInput)
                        {
                            return(NativeMethods.S_OK);
                        }

                        var commandData = new OleCommandData(commandId, commandExecOpt, variantIn, variantOut);
                        if (TryExec(ref commandGroup, ref commandData, keyInput))
                        {
                            return(NativeMethods.S_OK);
                        }
                    }
                }
            }
            finally
            {
                SwallowIfNextExecMatches = FSharpOption <KeyInput> .None;
            }

            return(_nextTarget.Exec(commandGroup, commandId, commandExecOpt, variantIn, variantOut));
        }
예제 #8
0
        /// <summary>
        /// Try and convert the given insert command to an OleCommand.  This should only be done
        /// for InsertCommand values which we want to custom process
        /// </summary>
        private bool TryGetOleCommandData(InsertCommand command, out OleCommandData commandData)
        {
            if (command.IsBack)
            {
                commandData = new OleCommandData(VSConstants.VSStd2KCmdID.BACKSPACE);
                return(true);
            }

            if (command.IsDelete)
            {
                commandData = new OleCommandData(VSConstants.VSStd2KCmdID.DELETE);
                return(true);
            }

            if (command.IsInsert)
            {
                var insert = (InsertCommand.Insert)command;
                if (insert.Item != null && insert.Item.Length == 1)
                {
                    commandData = OleCommandData.CreateTypeChar(insert.Item[0]);
                    return(true);
                }
            }

            if (command.IsInsertTab)
            {
                commandData = new OleCommandData(VSConstants.VSStd2KCmdID.TAB);
                return(true);
            }

            if (command.IsInsertNewLine)
            {
                commandData = new OleCommandData(VSConstants.VSStd2KCmdID.RETURN);
                return(true);
            }

            commandData = OleCommandData.Empty;
            return(false);
        }
예제 #9
0
        internal static bool TryConvert(EditCommand editCommand, out OleCommandData oleCommandData)
        {
            switch (editCommand.EditCommandKind)
            {
            case EditCommandKind.GoToDefinition:
                oleCommandData = new OleCommandData(VSConstants.VSStd97CmdID.GotoDecl);
                return(true);

            case EditCommandKind.Paste:
                oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.PASTE);
                return(true);

            case EditCommandKind.Undo:
                oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.UNDO);
                return(true);

            case EditCommandKind.Redo:
                oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.REDO);
                return(true);

            case EditCommandKind.Comment:
                oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.COMMENTBLOCK);
                return(true);

            case EditCommandKind.Uncomment:
                oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.UNCOMMENTBLOCK);
                return(true);

            case EditCommandKind.UserInput:
                return(TryConvert(editCommand.KeyInput, out oleCommandData));

            case EditCommandKind.VisualStudioCommand:
            default:
                oleCommandData = OleCommandData.Empty;
                return(false);
            }
        }
예제 #10
0
        /// <summary>
        /// Try and convert the given insert command to an OleCommand.  This should only be done
        /// for InsertCommand values which we want to custom process
        /// </summary>
        private bool TryGetOleCommandData(InsertCommand command, out OleCommandData commandData)
        {
            if (command.IsBack)
            {
                commandData = new OleCommandData(VSConstants.VSStd2KCmdID.BACKSPACE);
                return(true);
            }

            if (command.IsDelete)
            {
                commandData = new OleCommandData(VSConstants.VSStd2KCmdID.DELETE);
                return(true);
            }

            if (command.IsDirectInsert)
            {
                var directInsert = (InsertCommand.DirectInsert)command;
                commandData = OleCommandData.CreateTypeChar(directInsert.Item);
                return(true);
            }

            if (command.IsInsertTab)
            {
                commandData = new OleCommandData(VSConstants.VSStd2KCmdID.TAB);
                return(true);
            }

            if (command.IsInsertNewLine)
            {
                commandData = new OleCommandData(VSConstants.VSStd2KCmdID.RETURN);
                return(true);
            }

            commandData = OleCommandData.Empty;
            return(false);
        }
예제 #11
0
 /// <summary>
 /// Try and convert the KeyInput into the appropriate Visual Studio command.  The conversion will be done
 /// without any consideration of Visual Studio standard commands.  It will map as if VsVim was in
 /// complete control of key bindings
 /// </summary>
 internal static bool TryConvert(KeyInput keyInput, out OleCommandData oleCommandData)
 {
     return(TryConvert(keyInput, false, out oleCommandData));
 }
예제 #12
0
        /// <summary>
        /// Try and convert the given insert command to an OleCommand.  This should only be done
        /// for InsertCommand values which we want to custom process
        /// </summary>
        private bool TryGetOleCommandData(InsertCommand command, out OleCommandData commandData)
        {
            if (command.IsBack)
            {
                commandData = new OleCommandData(VSConstants.VSStd2KCmdID.BACKSPACE);
                return true;
            }

            if (command.IsDelete)
            {
                commandData = new OleCommandData(VSConstants.VSStd2KCmdID.DELETE);
                return true;
            }

            if (command.IsDirectInsert)
            {
                var directInsert = (InsertCommand.DirectInsert)command;
                commandData = OleCommandData.CreateTypeChar(directInsert.Item);
                return true;
            }

            if (command.IsInsertTab)
            {
                commandData = new OleCommandData(VSConstants.VSStd2KCmdID.TAB);
                return true;
            }

            if (command.IsInsertNewLine)
            {
                commandData = new OleCommandData(VSConstants.VSStd2KCmdID.RETURN);
                return true;
            }

            commandData = OleCommandData.Empty;
            return false;
        }
예제 #13
0
        /// <summary>
        /// Try and convert the KeyInput value into an OleCommandData instance
        /// </summary>
        internal static bool TryConvert(KeyInput keyInput, out Guid commandGroup, out OleCommandData oleCommandData)
        {
            var success = true;
            commandGroup = VSConstants.VSStd2K;
            switch (keyInput.Key)
            {
                case VimKey.Enter:
                    oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.RETURN);
                    break;
                case VimKey.Escape:
                    oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.CANCEL);
                    break;
                case VimKey.Delete:
                    oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.DELETE);
                    break;
                case VimKey.Back:
                    oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.BACKSPACE);
                    break;
                case VimKey.Up:
                    oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.UP);
                    break;
                case VimKey.Down:
                    oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.DOWN);
                    break;
                case VimKey.Left:
                    oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.LEFT);
                    break;
                case VimKey.Right:
                    oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.RIGHT);
                    break;
                case VimKey.Tab:
                    oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.TAB);
                    break;
                case VimKey.PageUp:
                    oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.PAGEUP);
                    break;
                case VimKey.PageDown:
                    oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.PAGEDN);
                    break;
                default:
                    if (keyInput.RawChar.IsSome())
                    {
                        oleCommandData = OleCommandData.Allocate(keyInput.Char);
                    }
                    else
                    {
                        oleCommandData = new OleCommandData();
                        success = false;
                    }
                    break;
            }

            return success;
        }
예제 #14
0
 internal static bool TryConvert(EditCommand editCommand, out OleCommandData oleCommandData)
 {
     switch (editCommand.EditCommandKind)
     {
         case EditCommandKind.GoToDefinition:
             oleCommandData = new OleCommandData(VSConstants.VSStd97CmdID.GotoDecl);
             return true;
         case EditCommandKind.Paste:
             oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.PASTE);
             return true;
         case EditCommandKind.Undo:
             oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.UNDO);
             return true;
         case EditCommandKind.Redo:
             oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.REDO);
             return true;
         case EditCommandKind.Comment:
             oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.COMMENTBLOCK);
             return true;
         case EditCommandKind.Uncomment:
             oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.UNCOMMENTBLOCK);
             return true;
         case EditCommandKind.UserInput:
             return TryConvert(editCommand.KeyInput, out oleCommandData);
         case EditCommandKind.VisualStudioCommand:
         default:
             oleCommandData = OleCommandData.Empty;
             return false;
     }
 }
예제 #15
0
        /// <summary>
        /// Try and convert the KeyInput value into an OleCommandData instance
        /// </summary>
        internal static bool TryConvert(KeyInput keyInput, out Guid commandGroup, out OleCommandData oleCommandData)
        {
            var success = true;

            commandGroup = VSConstants.VSStd2K;
            switch (keyInput.Key)
            {
            case VimKey.Enter:
                oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.RETURN);
                break;

            case VimKey.Escape:
                oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.CANCEL);
                break;

            case VimKey.Delete:
                oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.DELETE);
                break;

            case VimKey.Back:
                oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.BACKSPACE);
                break;

            case VimKey.Up:
                oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.UP);
                break;

            case VimKey.Down:
                oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.DOWN);
                break;

            case VimKey.Left:
                oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.LEFT);
                break;

            case VimKey.Right:
                oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.RIGHT);
                break;

            case VimKey.Tab:
                oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.TAB);
                break;

            case VimKey.PageUp:
                oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.PAGEUP);
                break;

            case VimKey.PageDown:
                oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.PAGEDN);
                break;

            case VimKey.Insert:
                oleCommandData = new OleCommandData(VSConstants.VSStd2KCmdID.TOGGLE_OVERTYPE_MODE);
                break;

            default:
                if (keyInput.RawChar.IsSome())
                {
                    oleCommandData = OleCommandData.Allocate(keyInput.Char);
                }
                else
                {
                    oleCommandData = new OleCommandData();
                    success        = false;
                }
                break;
            }

            return(success);
        }
예제 #16
0
        /// <summary>
        /// Try and exec this KeyInput in an intercepted fashion
        /// </summary>
        private bool TryExecIntercepted(ref Guid commandGroup, ref OleCommandData oleCommandData, KeyInput originalKeyInput, KeyInput mappedKeyInput)
        {
            bool intercepted;
            bool result;
            Guid mappedCommandGroup;
            OleCommandData mappedOleCommandData;
            if (originalKeyInput == mappedKeyInput)
            {
                // No changes so just use the original OleCommandData
                result = VSConstants.S_OK == _nextTarget.Exec(
                    ref commandGroup,
                    oleCommandData.CommandId,
                    oleCommandData.CommandExecOpt,
                    oleCommandData.VariantIn,
                    oleCommandData.VariantOut);
                intercepted = true;
            }
            else if (OleCommandUtil.TryConvert(mappedKeyInput, out mappedCommandGroup, out mappedOleCommandData))
            {
                result = VSConstants.S_OK == _nextTarget.Exec(
                    ref mappedCommandGroup,
                    mappedOleCommandData.CommandId,
                    mappedOleCommandData.CommandExecOpt,
                    mappedOleCommandData.VariantIn,
                    mappedOleCommandData.VariantOut);
                intercepted = true;
                OleCommandData.Release(ref mappedOleCommandData);
            }
            else
            {
                // If we couldn't process it using intercepting mechanism then just go straight to the IVimBuffer
                // for processing.
                result = _buffer.Process(originalKeyInput);
                intercepted = false;
            }

            if (intercepted)
            {
                // We processed the input and bypassed the IVimBuffer instance.  We need to tell IVimBuffer this
                // KeyInput was processed so it can track it for macro purposes.  Make sure to track the mapped
                // KeyInput value.  The SimulateProcessed method does not mapping
                _buffer.SimulateProcessed(mappedKeyInput);
            }

            return result;
        }
예제 #17
0
        int IOleCommandTarget.Exec(ref Guid commandGroup, uint commandId, uint commandExecOpt, IntPtr variantIn, IntPtr variantOut)
        {
            try
            {
                EditCommand editCommand;
                if (TryConvert(commandGroup, commandId, variantIn, out editCommand))
                {
                    if (editCommand.IsUndo)
                    {
                        _buffer.UndoRedoOperations.Undo(1);
                        return NativeMethods.S_OK;
                    }
                    else if (editCommand.IsRedo)
                    {
                        _buffer.UndoRedoOperations.Redo(1);
                        return NativeMethods.S_OK;
                    }
                    else if (editCommand.HasKeyInput)
                    {
                        var keyInput = editCommand.KeyInput;

                        // Swallow the input if it's been flagged by a previous QueryStatus
                        if (SwallowIfNextExecMatches.IsSome() && SwallowIfNextExecMatches.Value == keyInput)
                        {
                            return NativeMethods.S_OK;
                        }

                        var commandData = new OleCommandData(commandId, commandExecOpt, variantIn, variantOut);
                        if (TryExec(ref commandGroup, ref commandData, keyInput))
                        {
                            return NativeMethods.S_OK;
                        }
                    }
                }
            }
            finally
            {
                SwallowIfNextExecMatches = FSharpOption<KeyInput>.None;
            }

            return _nextTarget.Exec(commandGroup, commandId, commandExecOpt, variantIn, variantOut);
        }
예제 #18
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 mode = _buffer.ModeKind == ModeKind.Insert
                ? _buffer.InsertMode
                : null;
            if (mode == 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(KeyRemapMode.Insert, keyInput, out mapped) || CanProcessWithInsertMode(mode, mapped))
            {
                return _buffer.Process(keyInput).IsAnyHandled;
            }

            // 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
            return TryProcessWithExec(ref commandGroup, ref oleCommandData, keyInput, mapped);
        }
예제 #19
0
        /// <summary>
        /// Try and convert the KeyInput value into an OleCommandData instance.  If simulateStandardKeyBindings is set
        /// to true then "standard" Visual Studio key bindings will be assumed and this will be reflected in the
        /// resulting command information
        /// </summary>
        internal static bool TryConvert(KeyInput keyInput, bool simulateStandardKeyBindings, out OleCommandData oleCommandData)
        {
            var hasShift = 0 != (keyInput.KeyModifiers & KeyModifiers.Shift);

            VSConstants.VSStd2KCmdID?cmdId = null;
            switch (keyInput.Key)
            {
            case VimKey.Enter:
                cmdId = VSConstants.VSStd2KCmdID.RETURN;
                break;

            case VimKey.Escape:
                cmdId = VSConstants.VSStd2KCmdID.CANCEL;
                break;

            case VimKey.Delete:
                cmdId = VSConstants.VSStd2KCmdID.DELETE;
                break;

            case VimKey.Back:
                cmdId = VSConstants.VSStd2KCmdID.BACKSPACE;
                break;

            case VimKey.Up:
                cmdId = simulateStandardKeyBindings && hasShift
                        ? VSConstants.VSStd2KCmdID.UP_EXT
                        : VSConstants.VSStd2KCmdID.UP;
                break;

            case VimKey.Down:
                cmdId = simulateStandardKeyBindings && hasShift
                        ? VSConstants.VSStd2KCmdID.DOWN_EXT
                        : VSConstants.VSStd2KCmdID.DOWN;
                break;

            case VimKey.Left:
                cmdId = simulateStandardKeyBindings && hasShift
                        ? VSConstants.VSStd2KCmdID.LEFT_EXT
                        : VSConstants.VSStd2KCmdID.LEFT;
                break;

            case VimKey.Right:
                cmdId = simulateStandardKeyBindings && hasShift
                        ? VSConstants.VSStd2KCmdID.RIGHT_EXT
                        : VSConstants.VSStd2KCmdID.RIGHT;
                break;

            case VimKey.Tab:
                cmdId = simulateStandardKeyBindings && hasShift
                        ? VSConstants.VSStd2KCmdID.BACKTAB
                        : VSConstants.VSStd2KCmdID.TAB;
                break;

            case VimKey.PageUp:
                cmdId = simulateStandardKeyBindings && hasShift
                        ? VSConstants.VSStd2KCmdID.PAGEUP_EXT
                        : VSConstants.VSStd2KCmdID.PAGEUP;
                break;

            case VimKey.PageDown:
                cmdId = simulateStandardKeyBindings && hasShift
                        ? VSConstants.VSStd2KCmdID.PAGEDN_EXT
                        : VSConstants.VSStd2KCmdID.PAGEDN;
                break;

            case VimKey.Insert:
                cmdId = VSConstants.VSStd2KCmdID.TOGGLE_OVERTYPE_MODE;
                break;
            }

            if (cmdId.HasValue)
            {
                oleCommandData = new OleCommandData(cmdId.Value);
                return(true);
            }

            if (keyInput.RawChar.IsSome())
            {
                oleCommandData = OleCommandData.CreateTypeChar(keyInput.Char);
                return(true);
            }
            else
            {
                oleCommandData = OleCommandData.Empty;
                return(false);
            }
        }
예제 #20
0
        /// <summary>
        /// Try and process the given KeyInput for insert mode in the middle of an Exec.  This is 
        /// called for commands which can't be processed directly like edits.  We'd prefer these 
        /// go through Visual Studio's command system so items like Intellisense work properly.
        /// </summary>
        private bool TryProcessWithExec(ref Guid commandGroup, ref OleCommandData oleCommandData, KeyInput originalKeyInput, KeyInput mappedKeyInput)
        {
            var versionNumber = _textBuffer.CurrentSnapshot.Version.VersionNumber;
            int? hr = null;
            Guid mappedCommandGroup;
            OleCommandData mappedOleCommandData;
            if (originalKeyInput == mappedKeyInput)
            {
                // No changes so just use the original OleCommandData
                hr = _nextTarget.Exec(
                    ref commandGroup,
                    oleCommandData.CommandId,
                    oleCommandData.CommandExecOpt,
                    oleCommandData.VariantIn,
                    oleCommandData.VariantOut);
            }
            else if (OleCommandUtil.TryConvert(mappedKeyInput, out mappedCommandGroup, out mappedOleCommandData))
            {
                hr = _nextTarget.Exec(
                    ref mappedCommandGroup,
                    mappedOleCommandData.CommandId,
                    mappedOleCommandData.CommandExecOpt,
                    mappedOleCommandData.VariantIn,
                    mappedOleCommandData.VariantOut);
                OleCommandData.Release(ref mappedOleCommandData);
            }

            if (hr.HasValue)
            {
                // 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
                var result = ErrorHandler.Succeeded(hr.Value) || versionNumber < _textBuffer.CurrentSnapshot.Version.VersionNumber;

                // We processed the input and bypassed the IVimBuffer instance.  We need to tell IVimBuffer this
                // KeyInput was processed so it can track it for macro purposes.  Make sure to track the mapped
                // KeyInput value.  The SimulateProcessed method does not do any mapping
                if (result)
                {
                    _buffer.SimulateProcessed(mappedKeyInput);
                }

                // Whether or not this succeeded it was processed to the fullest possible extent
                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.
            return _buffer.Process(originalKeyInput).IsAnyHandled;
        }
예제 #21
0
        internal static bool TryConvert(OleCommandData oleCommandData, out KeyInput keyInput)
        {
            EditCommandKind editCommandKind;

            return(TryConvert(oleCommandData.Group, oleCommandData.Id, oleCommandData.VariantIn, out keyInput, out editCommandKind));
        }
예제 #22
0
        /// <summary>
        /// Try and convert the KeyInput value into an OleCommandData instance.  If simulateStandardKeyBindings is set
        /// to true then "standard" Visual Studio key bindings will be assumed and this will be reflected in the 
        /// resulting command information
        /// </summary>
        internal static bool TryConvert(KeyInput keyInput, bool simulateStandardKeyBindings, out OleCommandData oleCommandData)
        {
            var hasShift = 0 != (keyInput.KeyModifiers & KeyModifiers.Shift);
            VSConstants.VSStd2KCmdID? cmdId = null;
            switch (keyInput.Key)
            {
                case VimKey.Enter:
                    cmdId = VSConstants.VSStd2KCmdID.RETURN;
                    break;
                case VimKey.Escape:
                    cmdId = VSConstants.VSStd2KCmdID.CANCEL;
                    break;
                case VimKey.Delete:
                    cmdId = VSConstants.VSStd2KCmdID.DELETE;
                    break;
                case VimKey.Back:
                    cmdId = VSConstants.VSStd2KCmdID.BACKSPACE;
                    break;
                case VimKey.Up:
                    cmdId = simulateStandardKeyBindings && hasShift
                        ? VSConstants.VSStd2KCmdID.UP_EXT
                        : VSConstants.VSStd2KCmdID.UP;
                    break;
                case VimKey.Down:
                    cmdId = simulateStandardKeyBindings && hasShift
                        ? VSConstants.VSStd2KCmdID.DOWN_EXT
                        : VSConstants.VSStd2KCmdID.DOWN;
                    break;
                case VimKey.Left:
                    cmdId = simulateStandardKeyBindings && hasShift
                        ? VSConstants.VSStd2KCmdID.LEFT_EXT
                        : VSConstants.VSStd2KCmdID.LEFT;
                    break;
                case VimKey.Right:
                    cmdId = simulateStandardKeyBindings && hasShift
                        ? VSConstants.VSStd2KCmdID.RIGHT_EXT
                        : VSConstants.VSStd2KCmdID.RIGHT;
                    break;
                case VimKey.Tab:
                    cmdId = simulateStandardKeyBindings && hasShift
                        ? VSConstants.VSStd2KCmdID.BACKTAB
                        : VSConstants.VSStd2KCmdID.TAB;
                    break;
                case VimKey.PageUp:
                    cmdId = simulateStandardKeyBindings && hasShift
                        ? VSConstants.VSStd2KCmdID.PAGEUP_EXT
                        : VSConstants.VSStd2KCmdID.PAGEUP;
                    break;
                case VimKey.PageDown:
                    cmdId = simulateStandardKeyBindings && hasShift
                        ? VSConstants.VSStd2KCmdID.PAGEDN_EXT
                        : VSConstants.VSStd2KCmdID.PAGEDN;
                    break;
                case VimKey.Insert:
                    cmdId = VSConstants.VSStd2KCmdID.TOGGLE_OVERTYPE_MODE;
                    break;
            }

            if (cmdId.HasValue)
            {
                oleCommandData = new OleCommandData(cmdId.Value);
                return true;
            }

            if (keyInput.RawChar.IsSome())
            {
                oleCommandData = OleCommandData.CreateTypeChar(keyInput.Char);
                return true;
            }
            else
            {
                oleCommandData = OleCommandData.Empty;
                return false;
            }
        }
예제 #23
0
 /// <summary>
 /// Try and convert the KeyInput into the appropriate Visual Studio command.  The conversion will be done
 /// without any consideration of Visual Studio standard commands.  It will map as if VsVim was in 
 /// complete control of key bindings
 /// </summary>
 internal static bool TryConvert(KeyInput keyInput, out OleCommandData oleCommandData)
 {
     return TryConvert(keyInput, false, out oleCommandData);
 }
예제 #24
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;
        }
예제 #25
0
 internal static bool TryConvert(OleCommandData oleCommandData, out KeyInput keyInput)
 {
     EditCommandKind editCommandKind;
     return TryConvert(oleCommandData.Group, oleCommandData.Id, oleCommandData.VariantIn, out keyInput, out editCommandKind);
 }
예제 #26
0
        /// <summary>
        /// Try and process the given KeyInput for insert mode in the middle of an Exec.  This is 
        /// called for commands which can't be processed directly like edits.  We'd prefer these 
        /// go through Visual Studio's command system so items like Intellisense work properly.
        /// </summary>
        private bool TryProcessWithExec(Guid commandGroup, OleCommandData oleCommandData, IInsertMode insertMode, KeyInput originalKeyInput, KeyInput mappedKeyInput)
        {
            Func<bool> customProcess =
                () =>
                {
                    var versionNumber = _textBuffer.CurrentSnapshot.Version.VersionNumber;
                    int? hr = null;
                    Guid mappedCommandGroup;
                    OleCommandData mappedOleCommandData;
                    if (originalKeyInput == mappedKeyInput)
                    {
                        // No changes so just use the original OleCommandData
                        hr = _nextTarget.Exec(
                            ref commandGroup,
                            oleCommandData.CommandId,
                            oleCommandData.CommandExecOpt,
                            oleCommandData.VariantIn,
                            oleCommandData.VariantOut);
                    }
                    else if (OleCommandUtil.TryConvert(mappedKeyInput, out mappedCommandGroup, out mappedOleCommandData))
                    {
                        hr = _nextTarget.Exec(
                            ref mappedCommandGroup,
                            mappedOleCommandData.CommandId,
                            mappedOleCommandData.CommandExecOpt,
                            mappedOleCommandData.VariantIn,
                            mappedOleCommandData.VariantOut);
                        OleCommandData.Release(ref mappedOleCommandData);
                    }

                    if (hr.HasValue)
                    {
                        // 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.Value) || versionNumber < _textBuffer.CurrentSnapshot.Version.VersionNumber;
                    }

                    // Couldn't map to a Visual Studio command so it didn't succeed
                    return false;
                };

            return insertMode.CustomProcess(mappedKeyInput, customProcess.ToFSharpFunc());
        }
예제 #27
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);
        }
예제 #28
0
        int IOleCommandTarget.Exec(ref Guid commandGroup, uint commandId, uint commandExecOpt, IntPtr variantIn, IntPtr variantOut)
        {
            try
            {
                EditCommand editCommand;
                if (TryConvert(commandGroup, commandId, variantIn, out editCommand))
                {
                    if (editCommand.IsUndo)
                    {
                        // The user hit the undo button.  Don't attempt to map anything here and instead just
                        // run a single Vim undo operation
                        _buffer.UndoRedoOperations.Undo(1);
                        return NativeMethods.S_OK;
                    }
                    else if (editCommand.IsRedo)
                    {
                        // The user hit the redo button.  Don't attempt to map anything here and instead just
                        // run a single Vim redo operation
                        _buffer.UndoRedoOperations.Redo(1);
                        return NativeMethods.S_OK;
                    }
                    else if (editCommand.HasKeyInput)
                    {
                        var keyInput = editCommand.KeyInput;

                        // Discard the input if it's been flagged by a previous QueryStatus
                        if (_bufferCoordinator.DiscardedKeyInput.IsSome(keyInput))
                        {
                            return NativeMethods.S_OK;
                        }

                        // Try and process the command with the IVimBuffer
                        var commandData = new OleCommandData(commandId, commandExecOpt, variantIn, variantOut);
                        if (TryProcessWithBuffer(ref commandGroup, ref commandData, keyInput))
                        {
                            return NativeMethods.S_OK;
                        }
                    }
                }
            }
            finally
            {
                _bufferCoordinator.DiscardedKeyInput = FSharpOption<KeyInput>.None;
            }

            return _nextTarget.Exec(commandGroup, commandId, commandExecOpt, variantIn, variantOut);
        }
예제 #29
0
파일: Extensions.cs 프로젝트: renjiec/VsVim
        internal static int QueryStatus(this IOleCommandTarget oleCommandTarget, OleCommandData oleCommandData)
        {
            OLECMD command;

            return(QueryStatus(oleCommandTarget, oleCommandData, out command));
        }
예제 #30
0
        /// <summary>
        /// Try and convert the given insert command to an OleCommand.  This should only be done
        /// for InsertCommand values which we want to custom process
        /// </summary>
        private bool TryGetOleCommandData(InsertCommand command, out OleCommandData commandData)
        {
            if (command.IsBack)
            {
                commandData = new OleCommandData(VSConstants.VSStd2KCmdID.BACKSPACE);
                return true;
            }

            if (command.IsDelete)
            {
                commandData = new OleCommandData(VSConstants.VSStd2KCmdID.DELETE);
                return true;
            }

            if (command.IsInsert)
            {
                var insert = (InsertCommand.Insert)command;
                if (insert.Item != null && insert.Item.Length == 1)
                {
                    commandData = OleCommandData.CreateTypeChar(insert.Item[0]);
                    return true;
                }
            }

            if (command.IsInsertTab)
            {
                commandData = new OleCommandData(VSConstants.VSStd2KCmdID.TAB);
                return true;
            }

            if (command.IsInsertNewLine)
            {
                commandData = new OleCommandData(VSConstants.VSStd2KCmdID.RETURN);
                return true;
            }

            commandData = OleCommandData.Empty;
            return false;
        }