diff options
author | David Schulz <david.schulz@qt.io> | 2023-06-06 07:31:33 +0200 |
---|---|---|
committer | David Schulz <david.schulz@qt.io> | 2023-06-14 10:05:12 +0000 |
commit | 9091c994298f75ca76a9e1244236925320f60e15 (patch) | |
tree | e8d4a0a8a805573d87a8a287a47370965d7408d9 | |
parent | 196245c8f63d75eb10d3af3e7e7721d1575deaa8 (diff) |
TextEditor: correctly highlight preedit text
Fixes: QTCREATORBUG-29134
Change-Id: I8c5cdab8c5b2e5a2380c9e4aeadaf1bd72e60e09
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
-rw-r--r-- | src/plugins/texteditor/highlighter_test.cpp | 22 | ||||
-rw-r--r-- | src/plugins/texteditor/highlighter_test.h | 1 | ||||
-rw-r--r-- | src/plugins/texteditor/syntaxhighlighter.cpp | 49 | ||||
-rw-r--r-- | tests/auto/texteditor/highlighter/tst_highlighter.cpp | 24 |
4 files changed, 91 insertions, 5 deletions
diff --git a/src/plugins/texteditor/highlighter_test.cpp b/src/plugins/texteditor/highlighter_test.cpp index f0652a780b3..89b5196a864 100644 --- a/src/plugins/texteditor/highlighter_test.cpp +++ b/src/plugins/texteditor/highlighter_test.cpp @@ -185,6 +185,28 @@ void GenerigHighlighterTests::testChange() compareFormats(actualFormats.at(i), formatRanges.at(i)); } +void GenerigHighlighterTests::testPreeditText() +{ + QTextBlock block = m_editor->textDocument()->document()->findBlockByNumber(2); + QVERIFY(block.isValid()); + + block.layout()->setPreeditArea(7, "uaf"); + m_editor->textDocument()->syntaxHighlighter()->rehighlight(); + + const FormatRanges formatRanges = {{0, 4, toFormat(C_VISUAL_WHITESPACE)}, + {4, 3, toFormat(C_TYPE)}, + {10, 3, toFormat(C_TYPE)}, + {13, 1, toFormat(C_FUNCTION)}, + {14, 1, toFormat(C_VISUAL_WHITESPACE)}, + {15, 6, toFormat(C_STRING)}, + {21, 1, toFormat(C_FUNCTION)}}; + const QList<QTextLayout::FormatRange> actualFormats = block.layout()->formats(); + // full hash calculation for QTextCharFormat fails so just check the important entries of format + QCOMPARE(actualFormats.size(), formatRanges.size()); + for (int i = 0; i < formatRanges.size(); ++i) + compareFormats(actualFormats.at(i), formatRanges.at(i)); +} + void GenerigHighlighterTests::cleanupTestCase() { if (m_editor) diff --git a/src/plugins/texteditor/highlighter_test.h b/src/plugins/texteditor/highlighter_test.h index 30c2848c5c1..3e638783d54 100644 --- a/src/plugins/texteditor/highlighter_test.h +++ b/src/plugins/texteditor/highlighter_test.h @@ -17,6 +17,7 @@ private slots: void testHighlight_data(); void testHighlight(); void testChange(); + void testPreeditText(); void cleanupTestCase(); private: diff --git a/src/plugins/texteditor/syntaxhighlighter.cpp b/src/plugins/texteditor/syntaxhighlighter.cpp index 6d2616193ef..21db8c0cd32 100644 --- a/src/plugins/texteditor/syntaxhighlighter.cpp +++ b/src/plugins/texteditor/syntaxhighlighter.cpp @@ -17,6 +17,12 @@ namespace TextEditor { +enum HighlighterTypeProperty +{ + SyntaxHighlight = QTextFormat::UserProperty + 1, + SemanticHighlight = QTextFormat::UserProperty + 2 +}; + class SyntaxHighlighterPrivate { SyntaxHighlighter *q_ptr = nullptr; @@ -98,9 +104,9 @@ void SyntaxHighlighterPrivate::applyFormatChanges(int from, int charsRemoved, in QVector<QTextLayout::FormatRange> ranges; QVector<QTextLayout::FormatRange> oldRanges; - std::tie(ranges, oldRanges) + std::tie(oldRanges, ranges) = Utils::partition(layout->formats(), [](const QTextLayout::FormatRange &range) { - return range.format.property(QTextFormat::UserProperty).toBool(); + return range.format.property(SyntaxHighlight).toBool(); }); if (currentBlock.contains(from)) { @@ -129,8 +135,23 @@ void SyntaxHighlighterPrivate::applyFormatChanges(int from, int charsRemoved, in while (i < formatChanges.count() && formatChanges.at(i) == r.format) ++i; + r.format.setProperty(SyntaxHighlight, true); r.length = i - r.start; + const QString preeditText = currentBlock.layout()->preeditAreaText(); + if (!preeditText.isEmpty()) { + const int preeditPosition = currentBlock.layout()->preeditAreaPosition(); + if (r.start >= preeditPosition) { + r.start += preeditText.length(); + } else if (r.start + r.length > preeditPosition) { + QTextLayout::FormatRange beforePreeditRange = r; + r.start = preeditPosition + preeditText.length(); + r.length = r.length - (r.start - preeditPosition); + beforePreeditRange.length = preeditPosition - beforePreeditRange.start; + newRanges << beforePreeditRange; + } + } + newRanges << r; } @@ -656,6 +677,24 @@ void SyntaxHighlighter::setExtraFormats(const QTextBlock &block, if (block.layout() == nullptr || blockLength == 0) return; + const QString preeditText = block.layout()->preeditAreaText(); + if (!preeditText.isEmpty()) { + QVector<QTextLayout::FormatRange> additionalRanges; + const int preeditPosition = block.layout()->preeditAreaPosition(); + for (QTextLayout::FormatRange &r : formats) { + if (r.start >= preeditPosition) { + r.start += preeditText.length(); + } else if (r.start + r.length > preeditPosition) { + QTextLayout::FormatRange afterPreeditRange = r; + afterPreeditRange.start = preeditPosition + preeditText.length(); + afterPreeditRange.length = r.length - (preeditPosition - r.start); + additionalRanges << afterPreeditRange; + r.length = preeditPosition - r.start; + } + } + formats << additionalRanges; + } + Utils::sort(formats, byStartOfRange); const QVector<QTextLayout::FormatRange> all = block.layout()->formats(); @@ -663,11 +702,11 @@ void SyntaxHighlighter::setExtraFormats(const QTextBlock &block, QVector<QTextLayout::FormatRange> formatsToApply; std::tie(previousSemanticFormats, formatsToApply) = Utils::partition(all, [](const QTextLayout::FormatRange &r) { - return r.format.hasProperty(QTextFormat::UserProperty); + return r.format.property(SemanticHighlight).toBool(); }); for (auto &format : formats) - format.format.setProperty(QTextFormat::UserProperty, true); + format.format.setProperty(SemanticHighlight, true); if (formats.size() == previousSemanticFormats.size()) { Utils::sort(previousSemanticFormats, byStartOfRange); @@ -694,7 +733,7 @@ void SyntaxHighlighter::clearExtraFormats(const QTextBlock &block) const QVector<QTextLayout::FormatRange> formatsToApply = Utils::filtered(block.layout()->formats(), [](const QTextLayout::FormatRange &r) { - return !r.format.hasProperty(QTextFormat::UserProperty); + return !r.format.property(SemanticHighlight).toBool(); }); bool wasInReformatBlocks = d->inReformatBlocks; diff --git a/tests/auto/texteditor/highlighter/tst_highlighter.cpp b/tests/auto/texteditor/highlighter/tst_highlighter.cpp index e3f4e3dced6..7c30d3371ea 100644 --- a/tests/auto/texteditor/highlighter/tst_highlighter.cpp +++ b/tests/auto/texteditor/highlighter/tst_highlighter.cpp @@ -26,6 +26,7 @@ private slots: void test_setExtraAdditionalFormats(); void test_clearExtraFormats(); void test_incrementalApplyAdditionalFormats(); + void test_preeditText(); void cleanup(); private: @@ -235,6 +236,7 @@ void tst_highlighter::test_incrementalApplyAdditionalFormats() formatHash); formats = firstBlock.layout()->formats(); + QCOMPARE(formats.size(), 1); QCOMPARE(formats.at(0).format.fontItalic(), true); QCOMPARE(formats.at(0).format.fontOverline(), false); QCOMPARE(formats.at(0).start, 0); @@ -338,6 +340,28 @@ void tst_highlighter::test_incrementalApplyAdditionalFormats() QCOMPARE(formats.at(1).length, 2); } +void tst_highlighter::test_preeditText() +{ + QCOMPARE(doc->blockCount(), 4); + + QTextBlock firstBlock = doc->findBlockByNumber(0); + firstBlock.layout()->setPreeditArea(2, "uaf"); + + SemanticHighlighter::setExtraAdditionalFormats(highlighter, highlightingResults(), formatHash); + + auto formats = firstBlock.layout()->formats(); + QCOMPARE(formats.size(), 2); + QCOMPARE(formats.at(0).format.fontItalic(), true); + QCOMPARE(formats.at(0).format.fontOverline(), false); + QCOMPARE(formats.at(0).start, 0); + QCOMPARE(formats.at(0).length, 2); + + QCOMPARE(formats.at(1).format.fontItalic(), true); + QCOMPARE(formats.at(1).format.fontOverline(), false); + QCOMPARE(formats.at(1).start, 5); + QCOMPARE(formats.at(1).length, 3); +} + void tst_highlighter::cleanup() { delete doc; |