diff --git a/src/plugins/coreplugin/outputwindow.cpp b/src/plugins/coreplugin/outputwindow.cpp index b27b91afc03..1417eb1e3d8 100644 --- a/src/plugins/coreplugin/outputwindow.cpp +++ b/src/plugins/coreplugin/outputwindow.cpp @@ -32,6 +32,7 @@ #include "icore.h" #include +#include #include #include @@ -45,6 +46,10 @@ #include #endif +#include + +const int chunkSize = 10000; + using namespace Utils; namespace Core { @@ -68,7 +73,10 @@ public: IContext *outputWindowContext = nullptr; QString settingsKey; OutputFormatter formatter; + QList> queuedOutput; + QTimer queueTimer; + bool flushRequested = false; bool scrollToBottom = true; bool linksActive = true; bool zoomEnabled = false; @@ -98,6 +106,10 @@ OutputWindow::OutputWindow(Context context, const QString &settingsKey, QWidget setUndoRedoEnabled(false); d->formatter.setPlainTextEdit(this); + d->queueTimer.setSingleShot(true); + d->queueTimer.setInterval(10); + connect(&d->queueTimer, &QTimer::timeout, this, &OutputWindow::handleNextOutputChunk); + d->settingsKey = settingsKey; d->outputWindowContext = new IContext; @@ -224,6 +236,7 @@ void OutputWindow::keyPressEvent(QKeyEvent *ev) void OutputWindow::setLineParsers(const QList &parsers) { + reset(); d->formatter.setLineParsers(parsers); } @@ -370,18 +383,26 @@ void OutputWindow::filterNewContent() scrollToBottom(); } -void OutputWindow::setMaxCharCount(int count) +void OutputWindow::handleNextOutputChunk() { - d->maxCharCount = count; - setMaximumBlockCount(count / 100); + QTC_ASSERT(!d->queuedOutput.isEmpty(), return); + auto &chunk = d->queuedOutput.first(); + if (chunk.first.size() <= chunkSize) { + handleOutputChunk(chunk.first, chunk.second); + d->queuedOutput.removeFirst(); + } else { + handleOutputChunk(chunk.first.left(chunkSize), chunk.second); + chunk.first.remove(0, chunkSize); + } + if (!d->queuedOutput.isEmpty()) + d->queueTimer.start(); + else if (d->flushRequested) { + d->formatter.flush(); + d->flushRequested = false; + } } -int OutputWindow::maxCharCount() const -{ - return d->maxCharCount; -} - -void OutputWindow::appendMessage(const QString &output, OutputFormat format) +void OutputWindow::handleOutputChunk(const QString &output, OutputFormat format) { QString out = output; if (out.size() > d->maxCharCount) { @@ -422,6 +443,27 @@ void OutputWindow::appendMessage(const QString &output, OutputFormat format) enableUndoRedo(); } +void OutputWindow::setMaxCharCount(int count) +{ + d->maxCharCount = count; + setMaximumBlockCount(count / 100); +} + +int OutputWindow::maxCharCount() const +{ + return d->maxCharCount; +} + +void OutputWindow::appendMessage(const QString &output, OutputFormat format) +{ + if (d->queuedOutput.isEmpty() || d->queuedOutput.last().second != format) + d->queuedOutput << qMakePair(output, format); + else + d->queuedOutput.last().first.append(output); + if (!d->queueTimer.isActive()) + d->queueTimer.start(); +} + bool OutputWindow::isScrollbarAtBottom() const { return verticalScrollBar()->value() == verticalScrollBar()->maximum(); @@ -461,9 +503,32 @@ void OutputWindow::clear() void OutputWindow::flush() { + const int totalQueuedSize = std::accumulate(d->queuedOutput.cbegin(), d->queuedOutput.cend(), 0, + [](int val, const QPair &c) { return val + c.first.size(); }); + if (totalQueuedSize > 5 * chunkSize) { + d->flushRequested = true; + return; + } + d->queueTimer.stop(); + for (const auto &chunk : d->queuedOutput) + handleOutputChunk(chunk.first, chunk.second); + d->queuedOutput.clear(); d->formatter.flush(); } +void OutputWindow::reset() +{ + flush(); + d->queueTimer.stop(); + d->formatter.reset(); + if (!d->queuedOutput.isEmpty()) { + d->queuedOutput.clear(); + d->formatter.appendMessage(tr("[Discarding excessive amount of pending output.]\n"), + ErrorMessageFormat); + } + d->flushRequested = false; +} + void OutputWindow::scrollToBottom() { verticalScrollBar()->setValue(verticalScrollBar()->maximum()); diff --git a/src/plugins/coreplugin/outputwindow.h b/src/plugins/coreplugin/outputwindow.h index 7bf300ebb95..d717fbe4f63 100644 --- a/src/plugins/coreplugin/outputwindow.h +++ b/src/plugins/coreplugin/outputwindow.h @@ -67,6 +67,7 @@ public: void grayOutOldContent(); void clear(); void flush(); + void reset(); void scrollToBottom(); @@ -109,6 +110,8 @@ private: QElapsedTimer m_lastMessage; void enableUndoRedo(); void filterNewContent(); + void handleNextOutputChunk(); + void handleOutputChunk(const QString &output, Utils::OutputFormat format); Internal::OutputWindowPrivate *d = nullptr; }; diff --git a/src/plugins/projectexplorer/buildmanager.cpp b/src/plugins/projectexplorer/buildmanager.cpp index db59d90e295..ce39023c7ae 100644 --- a/src/plugins/projectexplorer/buildmanager.cpp +++ b/src/plugins/projectexplorer/buildmanager.cpp @@ -703,7 +703,7 @@ void BuildManager::nextStep() connect(d->m_currentBuildStep, &BuildStep::finished, instance(), finishedHandler); connect(d->m_currentBuildStep, &BuildStep::progress, instance(), &BuildManager::progressChanged); - d->m_outputWindow->outputFormatter()->reset(); + d->m_outputWindow->reset(); d->m_currentBuildStep->setupOutputFormatter(d->m_outputWindow->outputFormatter()); d->m_currentBuildStep->run(); } else { diff --git a/src/plugins/projectexplorer/compileoutputwindow.cpp b/src/plugins/projectexplorer/compileoutputwindow.cpp index 27c08886337..97ab9b69be1 100644 --- a/src/plugins/projectexplorer/compileoutputwindow.cpp +++ b/src/plugins/projectexplorer/compileoutputwindow.cpp @@ -285,6 +285,11 @@ void CompileOutputWindow::flush() m_outputWindow->flush(); } +void CompileOutputWindow::reset() +{ + m_outputWindow->reset(); +} + void CompileOutputWindow::setSettings(const CompileOutputSettings &settings) { m_settings = settings; diff --git a/src/plugins/projectexplorer/compileoutputwindow.h b/src/plugins/projectexplorer/compileoutputwindow.h index caed6e8d66c..a146ea16cb7 100644 --- a/src/plugins/projectexplorer/compileoutputwindow.h +++ b/src/plugins/projectexplorer/compileoutputwindow.h @@ -78,6 +78,7 @@ public: void showPositionOf(const Task &task); void flush(); + void reset(); const CompileOutputSettings &settings() const { return m_settings; } void setSettings(const CompileOutputSettings &settings);