From 7a4175ff605d69dcafa4eb6aaf7aee3cf2620035 Mon Sep 17 00:00:00 2001 From: Semih Yavuz Date: Tue, 23 May 2023 15:02:50 +0200 Subject: [PATCH] qmlls: Fix TextSynchronization The offset from a given range was incorrectly calculated in findBlockByNumber because textblocks that are used to obtain that position were mistakenly ignoring the newline character. This were leading us to setting a different text than what we actually typed. Add an extra text block if the text ends with \n. Add a manual test but exclude it from tst_qmlformat as it is not a valid qml document. Fixes: QTBUG-113725 Change-Id: Ifb1b4121fd8af46df7627d986303ae67e170e50c Reviewed-by: Fabian Kosmale --- src/qmlls/qtextdocument.cpp | 24 ++++++++---- tests/auto/qml/qmlformat/tst_qmlformat.cpp | 1 + tests/manual/qmllsformatter/test.qml | 45 ++++++++++++++++++++++ 3 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 tests/manual/qmllsformatter/test.qml diff --git a/src/qmlls/qtextdocument.cpp b/src/qmlls/qtextdocument.cpp index 826deddbb5..54e200274e 100644 --- a/src/qmlls/qtextdocument.cpp +++ b/src/qmlls/qtextdocument.cpp @@ -68,22 +68,30 @@ void TextDocument::setPlainText(const QString &text) m_content = text; m_blocks.clear(); - int blockStart = 0; - int blockNumber = 0; - while (blockStart < text.size()) { + const auto appendToBlocks = [this](int blockNumber, int start, int length) { Block block; - block.textBlock.setBlockNumber(blockNumber++); - block.textBlock.setPosition(blockStart); + block.textBlock.setBlockNumber(blockNumber); + block.textBlock.setPosition(start); block.textBlock.setDocument(this); + block.textBlock.setLength(length); + m_blocks.append(block); + }; + int blockStart = 0; + int blockNumber = -1; + while (blockStart < text.size()) { int blockEnd = text.indexOf(u'\n', blockStart) + 1; if (blockEnd == 0) blockEnd = text.size(); - - block.textBlock.setLength(blockEnd - blockStart); - m_blocks.append(block); + appendToBlocks(++blockNumber, blockStart, blockEnd - blockStart); blockStart = blockEnd; } + // Add an empty block if the text ends with \n. This is required for retrieving + // the actual line of the text editor if requested, for example, in findBlockByNumber. + // Consider a case with text aa\nbb\n\n. You are on 4th line of the text editor and even + // if it is an empty line, we introduce a text block for it to maybe use later. + if (text.endsWith(u'\n')) + appendToBlocks(++blockNumber, blockStart, 0); } bool TextDocument::isModified() const diff --git a/tests/auto/qml/qmlformat/tst_qmlformat.cpp b/tests/auto/qml/qmlformat/tst_qmlformat.cpp index cb3206069c..48efab4b3a 100644 --- a/tests/auto/qml/qmlformat/tst_qmlformat.cpp +++ b/tests/auto/qml/qmlformat/tst_qmlformat.cpp @@ -87,6 +87,7 @@ void TestQmlformat::initTestCase() m_excludedDirs << "doc/src/snippets/qtquick1/qtbinding"; m_excludedDirs << "doc/src/snippets/qtquick1/imports"; m_excludedDirs << "tests/manual/v4"; + m_excludedDirs << "tests/manual/qmllsformatter"; m_excludedDirs << "tests/auto/qml/ecmascripttests"; m_excludedDirs << "tests/auto/qml/qmllint"; diff --git a/tests/manual/qmllsformatter/test.qml b/tests/manual/qmllsformatter/test.qml new file mode 100644 index 0000000000..1b466ee3fd --- /dev/null +++ b/tests/manual/qmllsformatter/test.qml @@ -0,0 +1,45 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +// Start Test +// Open that test.qml file in a text editor that has a client for qmlls + +//////////////////////////////////////////////////////////// +// Test Case - 1 +// Type the following line manually + +import QtQml + +Window { + + +} + +// Then, execute "Format Document" in the text editor + +// Expected Result +import QtQml + +Window { +} + +//////////////////////////////////////////////////////////// +// Test Case - 2 +// Type the following line manually + +import QtQml + +Window { + aa a: { + } +} + +// Then, execute "Format Document" in the text editor + +// Expected Result +import QtQml + +Window { + aa: { + } +}