diff --git a/src/libs/utils/outputformatter.cpp b/src/libs/utils/outputformatter.cpp index f0fba1f812a92e0500e67eb2937d9ac0c068718c..ee85d8e5c9b206fea05fca9a3748bd1a04a0ee27 100644 --- a/src/libs/utils/outputformatter.cpp +++ b/src/libs/utils/outputformatter.cpp @@ -73,8 +73,7 @@ void OutputFormatter::appendMessage(const QString &text, const QTextCharFormat & QTextCursor cursor(m_plainTextEdit->document()); cursor.movePosition(QTextCursor::End); - foreach (const FormattedText &output, - m_escapeCodeHandler->parseText(FormattedText(text, format))) { + foreach (const FormattedText &output, parseAnsi(text, format)) { int startPos = 0; int crPos = -1; while ((crPos = output.text.indexOf(QLatin1Char('\r'), startPos)) >= 0) { @@ -92,6 +91,11 @@ QTextCharFormat OutputFormatter::charFormat(OutputFormat format) const return m_formats[format]; } +QList<FormattedText> OutputFormatter::parseAnsi(const QString &text, const QTextCharFormat &format) +{ + return m_escapeCodeHandler->parseText(FormattedText(text, format)); +} + void OutputFormatter::append(QTextCursor &cursor, const QString &text, const QTextCharFormat &format) { diff --git a/src/libs/utils/outputformatter.h b/src/libs/utils/outputformatter.h index 6dba8e5f10e114f8651ca8d51dfe8e5f62fbd1bf..de2a78f3d48ebd49c1ed0b177e73163cd99dce64 100644 --- a/src/libs/utils/outputformatter.h +++ b/src/libs/utils/outputformatter.h @@ -47,6 +47,7 @@ QT_END_NAMESPACE namespace Utils { class AnsiEscapeCodeHandler; +class FormattedText; class QTCREATOR_UTILS_EXPORT OutputFormatter : public QObject { @@ -71,6 +72,7 @@ protected: void initFormats(); virtual void clearLastLine(); QTextCharFormat charFormat(OutputFormat format) const; + QList<Utils::FormattedText> parseAnsi(const QString &text, const QTextCharFormat &format); void append(QTextCursor &cursor, const QString &text, const QTextCharFormat &format); private: diff --git a/src/plugins/qtsupport/qtoutputformatter.cpp b/src/plugins/qtsupport/qtoutputformatter.cpp index 0e337590f5231d97e78afb824e9e0212a4ceeb91..acf7729ed4e15c5b09add1b77e8b0e952eb4442d 100644 --- a/src/plugins/qtsupport/qtoutputformatter.cpp +++ b/src/plugins/qtsupport/qtoutputformatter.cpp @@ -32,6 +32,7 @@ #include <coreplugin/editormanager/editormanager.h> #include <projectexplorer/project.h> +#include <utils/ansiescapecodehandler.h> #include <utils/theme/theme.h> #include <QPlainTextEdit> @@ -100,10 +101,12 @@ LinkResult QtOutputFormatter::matchLine(const QString &line) const void QtOutputFormatter::appendMessage(const QString &txt, Utils::OutputFormat format) { - QTextCursor cursor(plainTextEdit()->document()); - cursor.movePosition(QTextCursor::End); - cursor.beginEditBlock(); + appendMessage(txt, charFormat(format)); +} +void QtOutputFormatter::appendMessagePart(QTextCursor &cursor, const QString &txt, + const QTextCharFormat &format) +{ QString deferredText; int start = 0; @@ -117,7 +120,7 @@ void QtOutputFormatter::appendMessage(const QString &txt, Utils::OutputFormat fo LinkResult lr = matchLine(line); if (!lr.href.isEmpty()) { // Found something && line continuation - cursor.insertText(deferredText, charFormat(format)); + cursor.insertText(deferredText, format); deferredText.clear(); clearLastLine(); appendLine(cursor, lr, line, format); @@ -131,7 +134,7 @@ void QtOutputFormatter::appendMessage(const QString &txt, Utils::OutputFormat fo const QString line = txt.mid(start, pos - start + 1); LinkResult lr = matchLine(line); if (!lr.href.isEmpty()) { - cursor.insertText(deferredText, charFormat(format)); + cursor.insertText(deferredText, format); deferredText.clear(); appendLine(cursor, lr, line, format); } else { @@ -151,7 +154,7 @@ void QtOutputFormatter::appendMessage(const QString &txt, Utils::OutputFormat fo LinkResult lr = matchLine(line); if (!lr.href.isEmpty()) { // Found something && line continuation - cursor.insertText(deferredText, charFormat(format)); + cursor.insertText(deferredText, format); deferredText.clear(); clearLastLine(); appendLine(cursor, lr, line, format); @@ -164,7 +167,7 @@ void QtOutputFormatter::appendMessage(const QString &txt, Utils::OutputFormat fo m_lastLine = txt.mid(start); LinkResult lr = matchLine(m_lastLine); if (!lr.href.isEmpty()) { - cursor.insertText(deferredText, charFormat(format)); + cursor.insertText(deferredText, format); deferredText.clear(); appendLine(cursor, lr, m_lastLine, format); } else { @@ -172,23 +175,44 @@ void QtOutputFormatter::appendMessage(const QString &txt, Utils::OutputFormat fo } } } - cursor.insertText(deferredText, charFormat(format)); + cursor.insertText(deferredText, format); +} + +void QtOutputFormatter::appendMessage(const QString &txt, const QTextCharFormat &format) +{ + QTextCursor cursor(plainTextEdit()->document()); + cursor.movePosition(QTextCursor::End); + cursor.beginEditBlock(); + + foreach (const FormattedText &output, parseAnsi(txt, format)) + appendMessagePart(cursor, output.text, output.format); + cursor.endEditBlock(); } void QtOutputFormatter::appendLine(QTextCursor &cursor, const LinkResult &lr, const QString &line, Utils::OutputFormat format) { - const QTextCharFormat normalFormat = charFormat(format); - cursor.insertText(line.left(lr.start), normalFormat); - - QTextCharFormat linkFormat = normalFormat; - linkFormat.setForeground(creatorTheme()->color(Theme::QtOutputFormatter_LinkTextColor)); - linkFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline); - linkFormat.setAnchor(true); - linkFormat.setAnchorHref(lr.href); - cursor.insertText(line.mid(lr.start, lr.end - lr.start), linkFormat); - cursor.insertText(line.mid(lr.end), normalFormat); + appendLine(cursor, lr, line, charFormat(format)); +} + +static QTextCharFormat linkFormat(const QTextCharFormat &inputFormat, const QString &href) +{ + QTextCharFormat result = inputFormat; + result.setForeground(creatorTheme()->color(Theme::QtOutputFormatter_LinkTextColor)); + result.setUnderlineStyle(QTextCharFormat::SingleUnderline); + result.setAnchor(true); + result.setAnchorHref(href); + + return result; +} + +void QtOutputFormatter::appendLine(QTextCursor &cursor, const LinkResult &lr, + const QString &line, const QTextCharFormat &format) +{ + cursor.insertText(line.left(lr.start), format); + cursor.insertText(line.mid(lr.start, lr.end - lr.start), linkFormat(format, lr.href)); + cursor.insertText(line.mid(lr.end), format); } void QtOutputFormatter::handleLink(const QString &href) @@ -274,6 +298,8 @@ void QtOutputFormatter::updateProjectFileList() using namespace QtSupport::Internal; +Q_DECLARE_METATYPE(QTextCharFormat); + class TestQtOutputFormatter : public QtOutputFormatter { public: @@ -359,4 +385,87 @@ void QtSupportPlugin::testQtOutputFormatter() QCOMPARE(formatter.column, column); } +static QTextCharFormat blueFormat() +{ + QTextCharFormat result; + result.setForeground(QColor(0, 0, 127)); + return result; +} + +void QtSupportPlugin::testQtOutputFormatter_appendMessage_data() +{ + QTest::addColumn<QString>("inputText"); + QTest::addColumn<QString>("outputText"); + QTest::addColumn<QTextCharFormat>("inputFormat"); + QTest::addColumn<QTextCharFormat>("outputFormat"); + + QTest::newRow("pass through") + << QString::fromLatin1("test\n123") + << QString::fromLatin1("test\n123") + << QTextCharFormat() + << QTextCharFormat(); + QTest::newRow("Qt error") + << QString::fromLatin1("Object::Test in test.cpp:123") + << QString::fromLatin1("Object::Test in test.cpp:123") + << QTextCharFormat() + << linkFormat(QTextCharFormat(), QLatin1String("test.cpp:123")); + QTest::newRow("colored") + << QString::fromLatin1("blue da ba dee") + << QString::fromLatin1("blue da ba dee") + << blueFormat() + << blueFormat(); + QTest::newRow("ANSI color change") + << QString::fromLatin1("\x1b[38;2;0;0;127mHello") + << QString::fromLatin1("Hello") + << QTextCharFormat() + << blueFormat(); +} + +void QtSupportPlugin::testQtOutputFormatter_appendMessage() +{ + QPlainTextEdit edit; + TestQtOutputFormatter formatter; + formatter.setPlainTextEdit(&edit); + + QFETCH(QString, inputText); + QFETCH(QString, outputText); + QFETCH(QTextCharFormat, inputFormat); + QFETCH(QTextCharFormat, outputFormat); + + formatter.appendMessage(inputText, inputFormat); + + QCOMPARE(edit.toPlainText(), outputText); + QCOMPARE(edit.currentCharFormat(), outputFormat); +} + +void QtSupportPlugin::testQtOutputFormatter_appendMixedAssertAndAnsi() +{ + QPlainTextEdit edit; + TestQtOutputFormatter formatter; + formatter.setPlainTextEdit(&edit); + + const QString inputText = QString::fromLatin1( + "\x1b[38;2;0;0;127mHello\n" + "Object::Test in test.cpp:123\n" + "\x1b[38;2;0;0;127mHello\n"); + const QString outputText = QString::fromLatin1( + "Hello\n" + "Object::Test in test.cpp:123\n" + "Hello\n"); + + formatter.appendMessage(inputText, QTextCharFormat()); + + QCOMPARE(edit.toPlainText(), outputText); + + edit.moveCursor(QTextCursor::Start); + QCOMPARE(edit.currentCharFormat(), blueFormat()); + + edit.moveCursor(QTextCursor::Down); + edit.moveCursor(QTextCursor::EndOfLine); + QCOMPARE(edit.currentCharFormat(), linkFormat(QTextCharFormat(), QLatin1String("test.cpp:123"))); + + edit.moveCursor(QTextCursor::End); + QCOMPARE(edit.currentCharFormat(), blueFormat()); +} + #endif // WITH_TESTS diff --git a/src/plugins/qtsupport/qtoutputformatter.h b/src/plugins/qtsupport/qtoutputformatter.h index 4f283436d965f19a580106732574d6d906323cb0..c89f7090517b85764ee834642cf34ff61d25f637 100644 --- a/src/plugins/qtsupport/qtoutputformatter.h +++ b/src/plugins/qtsupport/qtoutputformatter.h @@ -63,8 +63,8 @@ class QTSUPPORT_EXPORT QtOutputFormatter public: explicit QtOutputFormatter(ProjectExplorer::Project *project); - void appendMessage(const QString &text, - Utils::OutputFormat format); + void appendMessage(const QString &text, Utils::OutputFormat format); + void appendMessage(const QString &text, const QTextCharFormat &format); void handleLink(const QString &href); protected: @@ -76,8 +76,11 @@ private slots: private: LinkResult matchLine(const QString &line) const; + void appendMessagePart(QTextCursor &cursor, const QString &txt, const QTextCharFormat &format); void appendLine(QTextCursor &cursor, const LinkResult &lr, const QString &line, Utils::OutputFormat); + void appendLine(QTextCursor &cursor, const LinkResult &lr, const QString &line, + const QTextCharFormat &format); mutable QRegExp m_qmlError; mutable QRegExp m_qtError; diff --git a/src/plugins/qtsupport/qtsupportplugin.h b/src/plugins/qtsupport/qtsupportplugin.h index 9212320c5472cb32e32d58692ef50e907ef2fd7d..70d576a0fc6f5dc703fa5d9f91b613c3b5abec81 100644 --- a/src/plugins/qtsupport/qtsupportplugin.h +++ b/src/plugins/qtsupport/qtsupportplugin.h @@ -54,6 +54,9 @@ private slots: void testQtOutputParser(); void testQtOutputFormatter_data(); void testQtOutputFormatter(); + void testQtOutputFormatter_appendMessage_data(); + void testQtOutputFormatter_appendMessage(); + void testQtOutputFormatter_appendMixedAssertAndAnsi(); #endif };