aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Schulz <david.schulz@qt.io>2023-06-06 07:31:33 +0200
committerDavid Schulz <david.schulz@qt.io>2023-06-14 10:05:12 +0000
commit9091c994298f75ca76a9e1244236925320f60e15 (patch)
treee8d4a0a8a805573d87a8a287a47370965d7408d9
parent196245c8f63d75eb10d3af3e7e7721d1575deaa8 (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.cpp22
-rw-r--r--src/plugins/texteditor/highlighter_test.h1
-rw-r--r--src/plugins/texteditor/syntaxhighlighter.cpp49
-rw-r--r--tests/auto/texteditor/highlighter/tst_highlighter.cpp24
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;