Repository: microsoft/terminal
File: src/cascadia/TerminalControl/ControlCore.cpp (C++)

Code before:
                }
            }

            _updateSelectionUI();
        }
    }

    // Method Description:
    // - Updates the renderer's representation of the selection as well as the selection marker overlay in TermControl
    void ControlCore::_updateSelectionUI()
    {
        _renderer->TriggerSelection();
        // only show the markers if we're doing a keyboard selection or in mark mode
        const bool showMarkers{ _terminal->SelectionMode() >= ::Microsoft::Terminal::Core::Terminal::SelectionInteractionMode::Keyboard };
        _UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(!showMarkers));
    }

    void ControlCore::AttachUiaEngine(::Microsoft::Console::Render::IRenderEngine* const pEngine)
    {
        // _renderer will always exist since it's introduced in the ctor
        _renderer->AddRenderEngine(pEngine);
    }
    void ControlCore::DetachUiaEngine(::Microsoft::Console::Render::IRenderEngine* const pEngine)
    {
        _renderer->RemoveRenderEngine(pEngine);
    }

    bool ControlCore::IsInReadOnlyMode() const
    {
        return _isReadOnly;
    }

    void ControlCore::ToggleReadOnlyMode()
    {
        _isReadOnly = !_isReadOnly;
    }

    void ControlCore::SetReadOnlyMode(const bool readOnlyState)
    {
        _isReadOnly = readOnlyState;
    }

    void ControlCore::_raiseReadOnlyWarning()
    {
        auto noticeArgs = winrt::make<NoticeEventArgs>(NoticeLevel::Info, RS_(L"TermControlReadOnly"));
        _RaiseNoticeHandlers(*this, std::move(noticeArgs));
    }
    void ControlCore::_connectionOutputHandler(const hstring& hstr)
    {
        try
        {

Review comment (refactor):
For purposes like this it would be nice if we could stop flushing our input pipe so that the keystrokes are sent as a unison. For both pwsh and cmd this would avoid re-printing the entire commandline on every cursor navigation. One option would be to do something like `_terminal->CorkInputPipe()` and `UncorkInputPipe()` (borrowing `TCP_CORK` terminology), but I also somewhat feel like it would be better if we instead made it so that `SendKeyEvent` will never flush the input pipe and instead we add a `_terminal->FlushInput()` function which you need to call when you're done generating input. Alternatively, we could also extract `TerminalInput` out of `Terminal`s control and accumulate a `std::string` here before sending it off. Or we just generate cursor sequences ourselves. I don't think there's any fantastic solution, but there's a lot of alright ones. 🙂

(xterm.js does this as well btw.)

Code after:
                    _terminal->GetTextBuffer().GetSize().Clamp(clampedClick);
                }

                if (clampedClick >= end)
                {
                    // Get the distance between the cursor and the click, in cells.
                    const auto bufferSize = _terminal->GetTextBuffer().GetSize();

                    // First, make sure to iterate from the first point to the
                    // second. The user may have clicked _earlier_ in the
                    // buffer!
                    auto goRight = clampedClick > cursorPos;
                    const auto startPoint = goRight ? cursorPos : clampedClick;
                    const auto endPoint = goRight ? clampedClick : cursorPos;

                    const auto delta = _terminal->GetTextBuffer().GetCellDistance(startPoint, endPoint);

                    const WORD key = goRight ? VK_RIGHT : VK_LEFT;
                    // Send an up and a down once per cell. This won't
                    // accurately handle wide characters, or continuation
                    // prompts, or cases where a single escape character in the
                    // command (e.g. ^[) takes up two cells.
                    for (size_t i = 0u; i < delta; i++)
                    {
                        _terminal->SendKeyEvent(key, 0, {}, true);
                        _terminal->SendKeyEvent(key, 0, {}, false);
                    }
                }
            }
        }
        _updateSelectionUI();
    }

    // Method Description:
    // - Updates the renderer's representation of the selection as well as the selection marker overlay in TermControl
    void ControlCore::_updateSelectionUI()
    {
        _renderer->TriggerSelection();
        // only show the markers if we're doing a keyboard selection or in mark mode
        const bool showMarkers{ _terminal->SelectionMode() >= ::Microsoft::Terminal::Core::Terminal::SelectionInteractionMode::Keyboard };
        _UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(!showMarkers));
    }

    void ControlCore::AttachUiaEngine(::Microsoft::Console::Render::IRenderEngine* const pEngine)
    {
        // _renderer will always exist since it's introduced in the ctor
        _renderer->AddRenderEngine(pEngine);
    }
    void ControlCore::DetachUiaEngine(::Microsoft::Console::Render::IRenderEngine* const pEngine)
    {
        _renderer->RemoveRenderEngine(pEngine);