// Our immediate window filter has to override this behavior in the default
        // AbstractOLECommandTarget because they'll send us SCROLLUP when the key typed was CANCEL
        // (see below)
        protected override int ExecuteVisualStudio2000(ref Guid pguidCmdGroup, uint commandId, uint executeInformation, IntPtr pvaIn, IntPtr pvaOut)
        {
            // We have to ask the buffer to make itself writable, if it isn't already
            _context.DebuggerTextLines.GetStateFlags(out var bufferFlags);
            _context.DebuggerTextLines.SetStateFlags((uint)((BUFFERSTATEFLAGS)bufferFlags & ~BUFFERSTATEFLAGS.BSF_USER_READONLY));

            var result = VSConstants.S_OK;

            // If the caret is outside our projection, defer to the next command target.
            var caretPosition = _context.DebuggerTextView.GetCaretPoint(_context.Buffer);

            if (caretPosition == null)
            {
                return(NextCommandTarget.Exec(ref pguidCmdGroup, commandId, executeInformation, pvaIn, pvaOut));
            }

            switch ((VSConstants.VSStd2KCmdID)commandId)
            {
            // If we see a RETURN, and we're in the immediate window, we'll want to rebuild
            // spans after all the other command handlers have run.
            case VSConstants.VSStd2KCmdID.RETURN:
                result = NextCommandTarget.Exec(ref pguidCmdGroup, commandId, executeInformation, pvaIn, pvaOut);
                _context.RebuildSpans();
                break;

            // After handling typechar of '?', start completion.
            case VSConstants.VSStd2KCmdID.TYPECHAR:
                result = NextCommandTarget.Exec(ref pguidCmdGroup, commandId, executeInformation, pvaIn, pvaOut);

                if ((char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn) == '?')
                {
                    if (_context.CompletionStartsOnQuestionMark)
                    {
                        // The subject buffer passed in through the command
                        // target isn't the one we want, because we've
                        // definitely remapped buffers. Ask our context for
                        // the real subject buffer.
                        NextCommandTarget.Exec(VSConstants.VSStd2K, (uint)VSConstants.VSStd2KCmdID.SHOWMEMBERLIST,
                                               executeInformation, pvaIn, pvaOut);
                    }
                }

                break;

            default:
                return(base.ExecuteVisualStudio2000(ref pguidCmdGroup, commandId, executeInformation, pvaIn, pvaOut));
            }

            _context.DebuggerTextLines.SetStateFlags(bufferFlags);

            return(result);
        }
        // Our immediate window filter has to override this behavior in the default
        // AbstractOLECommandTarget because they'll send us SCROLLUP when the key typed was CANCEL
        // (see below)
        protected override int ExecuteVisualStudio2000(ref Guid pguidCmdGroup, uint commandId, uint executeInformation, IntPtr pvaIn, IntPtr pvaOut, ITextBuffer subjectBuffer, IContentType contentType)
        {
            // We have to ask the buffer to make itself writable, if it isn't already
            uint bufferFlags;

            _context.DebuggerTextLines.GetStateFlags(out bufferFlags);
            _context.DebuggerTextLines.SetStateFlags((uint)((BUFFERSTATEFLAGS)bufferFlags & ~BUFFERSTATEFLAGS.BSF_USER_READONLY));

            int result       = VSConstants.S_OK;
            var guidCmdGroup = pguidCmdGroup;

            // If the caret is outside our projection, defer to the next command target.
            var caretPosition = _context.DebuggerTextView.GetCaretPoint(_context.Buffer);

            if (caretPosition == null)
            {
                return(NextCommandTarget.Exec(ref guidCmdGroup, commandId, executeInformation, pvaIn, pvaOut));
            }

            Action executeNextCommandTarget = () =>
            {
                result = NextCommandTarget.Exec(ref guidCmdGroup, commandId, executeInformation, pvaIn, pvaOut);
            };

            switch ((VSConstants.VSStd2KCmdID)commandId)
            {
            // HACK: If you look at EditCtlStatementCompletion.cpp, they translate CANCEL to
            // SCROLLUP to do some hacking around their own command infrastructure and the
            // legacy stuff they interfaced with. That means we get SCROLLUP if the user
            // types escape, so treat SCROLLUP like CANCEL. It's actually a CANCEL.
            case VSConstants.VSStd2KCmdID.SCROLLUP:
                ExecuteCancel(subjectBuffer, contentType, executeNextCommandTarget);
                break;

            // If we see a RETURN, and we're in the immediate window, we'll want to rebuild
            // spans after all the other command handlers have run.
            case VSConstants.VSStd2KCmdID.RETURN:
                ExecuteReturn(subjectBuffer, contentType, executeNextCommandTarget);
                _context.RebuildSpans();
                break;

            // After handling typechar of '?', start completion.
            case VSConstants.VSStd2KCmdID.TYPECHAR:
                ExecuteTypeCharacter(pvaIn, subjectBuffer, contentType, executeNextCommandTarget);
                if ((char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn) == '?')
                {
                    if (_context.CompletionStartsOnQuestionMark)
                    {
                        // The subject buffer passed in through the command
                        // target isn't the one we want, because we've
                        // definitely remapped buffers. Ask our context for
                        // the real subject buffer.
                        this.ExecuteInvokeCompletionList(_context.Buffer, _context.ContentType, executeNextCommandTarget);
                    }
                }

                break;

            default:
                return(base.ExecuteVisualStudio2000(ref pguidCmdGroup, commandId, executeInformation, pvaIn, pvaOut, subjectBuffer, contentType));
            }

            _context.DebuggerTextLines.SetStateFlags(bufferFlags);

            return(result);
        }