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

Code before:
                // If the user clicked off to the right side of the prompt, we
                // want to send keystrokes to the last character in the prompt +1.
                //
                // We don't want to send too many here. In CMD, if the user's
                // last command is longer than what they've currently typed, and
                // they press right arrow at the end of the prompt, COOKED_READ
                // will fill in characters from the previous command.
                //
                // By only sending keypresses to the end of the command + 1, we
                // should leave the cursor at the very end of the prompt,
                // without adding any characters from a previous command.

                // terminalPosition is viewport-relative.
                const auto bufferPos = _terminal->GetViewport().Origin() + terminalPosition;
                const auto bufferSize = _terminal->GetTextBuffer().GetSize();

                auto clampedClick = bufferPos;
                if (clampedClick.y > lastNonSpace.y)
                {
                    // Clicked under the prompt. Bail.
                    return;
                }
                else if (clampedClick > lastNonSpace)
                {
                    clampedClick = lastNonSpace + til::point{ 1, 0 };
                    bufferSize.Clamp(clampedClick);
                }

                if (clampedClick >= end)
                {
                    // Get the distance between the cursor and the click, in cells.

                    // 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;

                    std::wstring buffer;
                    const auto append = [&](TerminalInput::OutputType&& out) {
                        if (out)
                        {
                            buffer.append(std::move(*out));
                        }
                    };

                    // Send an up and a down once per cell. This won't

Review comment (bug):
`lastNonSpace` cannot be larger than `bufferSize` (unless there's a bug in `GetLastNonSpaceCharacter`, but I think it'd be fine if we assume there isn't). As such we can simplify this code a bit. We just need to turn the `if a > b` into a `if a >= b + 1` and we get:
```cpp
const auto bufferPos = _terminal->GetViewport().Origin() + terminalPosition;
if (bufferPos.y > lastNonSpace.y)
{
    // Clicked under the prompt. Bail.
    return;
}

// Limit the click to 1 past the last character on the last line.
const auto clampedClick = std::min(bufferPos, lastNonSpace + til::point{ 1, 0 });
if (clampedClick >= end)
// ...
```

However, `+ til::point` doesn't do line wrapping. This breaks the `if (bufferPos.y > lastNonSpace.y)` check at a minimum. As such it may be necessary to do
```cpp
bufferSize.IncrementInBounds(lastNonSpace, true);

const auto bufferPos = _terminal->GetViewport().Origin() + terminalPosition;
if (bufferPos.y > lastNonSpace.y)
{
    // Clicked under the prompt. Bail.
    return;
}

// Limit the click to 1 past the last character on the last line.
const auto clampedClick = std::min(bufferPos, lastNonSpace);
if (clampedClick >= end)
// ...
```

Code after:
                bufferSize.IncrementInBounds(lastNonSpace, true);

                // If the user clicked off to the right side of the prompt, we
                // want to send keystrokes to the last character in the prompt +1.
                //
                // We don't want to send too many here. In CMD, if the user's
                // last command is longer than what they've currently typed, and
                // they press right arrow at the end of the prompt, COOKED_READ
                // will fill in characters from the previous command.
                //
                // By only sending keypresses to the end of the command + 1, we
                // should leave the cursor at the very end of the prompt,
                // without adding any characters from a previous command.

                // terminalPosition is viewport-relative.
                const auto bufferPos = _terminal->GetViewport().Origin() + terminalPosition;
                if (bufferPos.y > lastNonSpace.y)
                {
                    // Clicked under the prompt. Bail.
                    return;
                }

                // Limit the click to 1 past the last character on the last line.
                const auto clampedClick = std::min(bufferPos, lastNonSpace);

                if (clampedClick >= end)
                {
                    // Get the distance between the cursor and the click, in cells.

                    // 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;

                    std::wstring buffer;
                    const auto append = [&](TerminalInput::OutputType&& out) {
                        if (out)
                        {
                            buffer.append(std::move(*out));
                        }
                    };

                    // 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.