void Scraper::resizeImpl()

in src/agent/Scraper.cc [186:317]


void Scraper::resizeImpl(const ConsoleScreenBufferInfo &origInfo)
{
    ASSERT(m_console.frozen());
    const int cols = m_ptySize.X;
    const int rows = m_ptySize.Y;
    Coord finalBufferSize;

    {
        //
        // To accommodate Windows 10, erase all lines up to the top of the
        // visible window.  It's hard to tell whether this is strictly
        // necessary.  It ensures that the sync marker won't move downward,
        // and it ensures that we won't repeat lines that have already scrolled
        // up into the scrollback.
        //
        // It *is* possible for these blank lines to reappear in the visible
        // window (e.g. if the window is made taller), but because we blanked
        // the lines in the line buffer, we still don't output them again.
        //
        const Coord origBufferSize = origInfo.bufferSize();
        const SmallRect origWindowRect = origInfo.windowRect();

        if (m_directMode) {
            for (ConsoleLine &line : m_bufferData) {
                line.reset();
            }
        } else {
            m_consoleBuffer->clearLines(0, origWindowRect.Top, origInfo);
            clearBufferLines(0, origWindowRect.Top);
            if (m_syncRow != -1) {
                createSyncMarker(std::min(
                    m_syncRow,
                    BUFFER_LINE_COUNT - rows
                                      - SYNC_MARKER_LEN
                                      - SYNC_MARKER_MARGIN));
            }
        }

        finalBufferSize = Coord(
            cols,
            // If there was previously no scrollback (e.g. a full-screen app
            // in direct mode) and we're reducing the window height, then
            // reduce the console buffer's height too.
            (origWindowRect.height() == origBufferSize.Y)
                ? rows
                : std::max<int>(rows, origBufferSize.Y));

        // Reset the console font size.  We need to do this before shrinking
        // the window, because we might need to make the font bigger to permit
        // a smaller window width.  Making the font smaller could expand the
        // screen buffer, which would hang the conhost process in the
        // Windows 10 (10240 build) if the console selection is in progress, so
        // unfreeze it first.
        m_console.setFrozen(false);
        setSmallFont(m_consoleBuffer->conout(), cols, m_console.isNewW10());
    }

    // We try to make the font small enough so that the entire screen buffer
    // fits on the monitor, but it can't be guaranteed.
    const auto largest =
        GetLargestConsoleWindowSize(m_consoleBuffer->conout());
    const short visibleCols = std::min<short>(cols, largest.X);
    const short visibleRows = std::min<short>(rows, largest.Y);

    {
        // Make the window small enough.  We want the console frozen during
        // this step so we don't accidentally move the window above the cursor.
        m_console.setFrozen(true);
        const auto info = m_consoleBuffer->bufferInfo();
        const auto &bufferSize = info.dwSize;
        const int tmpWindowWidth = std::min(bufferSize.X, visibleCols);
        const int tmpWindowHeight = std::min(bufferSize.Y, visibleRows);
        SmallRect tmpWindowRect(
            0,
            std::min<int>(bufferSize.Y - tmpWindowHeight,
                          info.windowRect().Top),
            tmpWindowWidth,
            tmpWindowHeight);
        if (cursorInWindow(info)) {
            tmpWindowRect = tmpWindowRect.ensureLineIncluded(
                info.cursorPosition().Y);
        }
        m_consoleBuffer->moveWindow(tmpWindowRect);
    }

    {
        // Resize the buffer to the final desired size.
        m_console.setFrozen(false);
        m_consoleBuffer->resizeBufferRange(finalBufferSize);
    }

    {
        // Expand the window to its full size.
        m_console.setFrozen(true);
        const ConsoleScreenBufferInfo info = m_consoleBuffer->bufferInfo();

        SmallRect finalWindowRect(
            0,
            std::min<int>(info.bufferSize().Y - visibleRows,
                          info.windowRect().Top),
            visibleCols,
            visibleRows);

        //
        // Once a line in the screen buffer is "dirty", it should stay visible
        // in the console window, so that we continue to update its content in
        // the terminal.  This code is particularly (only?) necessary on
        // Windows 10, where making the buffer wider can rewrap lines and move
        // the console window upward.
        //
        if (!m_directMode && m_dirtyLineCount > finalWindowRect.Bottom + 1) {
            // In theory, we avoid ensureLineIncluded, because, a massive
            // amount of output could have occurred while the console was
            // unfrozen, so that the *top* of the window is now below the
            // dirtiest tracked line.
            finalWindowRect = SmallRect(
                0, m_dirtyLineCount - visibleRows,
                visibleCols, visibleRows);
        }

        // Highest priority constraint: ensure that the cursor remains visible.
        if (cursorInWindow(info)) {
            finalWindowRect = finalWindowRect.ensureLineIncluded(
                info.cursorPosition().Y);
        }

        m_consoleBuffer->moveWindow(finalWindowRect);
        m_dirtyWindowTop = finalWindowRect.Top;
    }

    ASSERT(m_console.frozen());
}